// Swordfish BASIC three channel software PWM using TMR2 and ADC inputs
device = 18F2221
clock = 32
include "intosc.bas"
// do NOT include setdigitalio
// to use PORTB for the ADC all pins must be in analog mode due to the way
// these old pics map ADC inputs
include "adc.bas"
// ADC pot inputs
// used to set the PWM duty cycle for PWM1-PWM3
// connect pot upper lug = VDD, lower lug = GND, wiper = port IO
dim
POT1 as PORTB.0, // RB0/AN12
POT2 as PORTB.1, // RB1/AN10
POT3 as PORTB.2 // RB2/AN8
// ADC channels
const
CH_POT1 = 12, // AN12
CH_POT2 = 10, // AN10
CH_POT3 = 8 // AN8
// PWM outputs
dim
PWM1 as PORTA.5,
PWM2 as PORTA.6,
PWM3 as PORTA.7
// pwm duty cycles (from ADC) 0=min, 255=max
dim
pwm1_duty as byte,
pwm2_duty as byte,
pwm3_duty as byte
dim pwm_period as byte
// pwm timer TMR2
dim
TMR2IF as PIR1.bits(1),
TMR2IE as PIE1.bits(1),
TMR2ON as T2CON.bits(2)
// set IO pin directions and initial settings
sub InitIO()
// set inputs
input(POT1)
input(POT2)
input(POT3)
// set outputs (low to start)
low(PWM1)
low(PWM2)
low(PWM3)
end sub
// pwm TMR2 interrupt
interrupt tmr2_isr()
TMR2IF = 0
pwm_period = pwm_period + 1
if (pwm_period >= pwm1_duty) then
PWM1 = 0
else
PWM1 = 1
endif
if (pwm_period >= pwm2_duty) then
PWM2 = 1
else
PWM2 = 0
endif
if (pwm_period >= pwm3_duty) then
PWM3 = 1
else
PWM3 = 0
endif
end interrupt
main:
InitIO()
// ADC setup
ADCON1 = $00 // all pins set to analog mode, VREF = VDD/GND
ADCON2 = ADC.FRC // ADC clock = Frc
ADC.ADFM = 0 // left justify (we only use the 8 MSB's)
ADC.SetAcqTime(100) // 100us delay
pwm_period = 0
pwm1_duty = 0
pwm2_duty = 0
pwm3_duty = 0
// setup pwm timer TMR2
// 25KHz = 40us/bit -> 40us x 256 = 10240us period, ~10ms period (100Hz)
T2CON = %00000001 // T2OUTPS<3:0>=%000 (1:1), TMR2ON=0, T2CKPS<1:0>=%01 (1:4)
PR2 = 176
TMR2 = 0
TMR2IF = 0
TMR2IE = 1
TMR2ON = 1
enable(tmr2_isr)
while (true)
pwm1_duty = ADC.Read(CH_POT1) >> 8
pwm2_duty = ADC.Read(CH_POT2) >> 8
pwm3_duty = ADC.Read(CH_POT3) >> 8
end while