'Declarations symbol rpm_set = w4 symbol tach_in = w5 symbol tach_ave = w6 symbol tach_delta = w7 symbol pwm_old = w8 symbol pwm_new = w9 symbol pwm_step_up = b2 symbol pwm_step_down = b3 symbol pwm_max = w10 symbol baud = N4800_16 'communication with OLED module init: rpm_set=0 tach_ave=0 tach_delta=0 pwm_old=0 pwm_new=0 low B.2 ' switch-off motor relay setfreq m16 'set internal frequency at 16MHz without external 16MHz resonator pwmout C.2, 234, 0 'set 17kHz PWM at pin 13 at zero (100% value = 939) pause 4000 serout C.6,baud,(254,1) ' clear OLED display pause 1000 'hintsetup %00000010 ' enable hint1 pin 22 setint %00000000, %00000010, B ' trigger interrupt when pin 22 is low main: readadc10 A.0, rpm_set 'rpm input reading rpm_set = rpm_set*61/48 'make rmp_set 1300 at 1024 input pwm_max = rpm_set*47/130+281 ' calculate dynamic max value of pwm based on speed setting if pinB.0=1 then ' check if dead-man switch is open low B.2 ' switch-off motor relay pwmduty C.2,0 'pwm output at zero pwm_new=0 ' reset PWM pwm_old=0 ' reset PWM serout C.6,baud,(254,128) serout C.6,baud,("STOPPED ") serout C.6,baud,(254,192) serout C.6,baud,("SET:") serout C.6,baud,(254,196) serout C.6,baud,(#rpm_set," ") 'show the RPM set value goto main endif if rpm_set < 2 then ' check whether rpm setting is below minimum threshold low B.2 ' switch-off motor relay pwmduty C.2,0 'pwm output at zero pwm_new=0 ' reset PWM pwm_old=0 ' reset PWM serout C.6,baud,(254,128) serout C.6,baud,("STOPPED ") serout C.6,baud,(254,192) serout C.6,baud,("INCR RPM") 'warning message that RPM setting is too low goto main endif high B.2 count C.1, 60, tach_in 'tacho reading 15msec gives 5 counts min and 66 counts max tach_in=tach_in*204/11 ' make 66 counts = 1223 rpm if rpm_set > tach_in then 'check rpm_set vs tach_in and increase pwm_new pwm_new=pwm_old+1 min 4 max pwm_max ' slowly increase PWM and dynamic max duty-cycle endif if tach_in > rpm_set AND pwm_old > 4 then 'check rpm_set vs tach_in and decrase pwm_new and avoid underflow pwm_new=pwm_old-1 min 4 max pwm_max 'slowly decrease PWM and min 4 duty-cycle endif if rpm_set = tach_in then 'keep pwm_new same as pwm_old pwm_new=pwm_old min 4 max pwm_max ' dynamic max duty-cycle endif if pwm_new > pwm_old then 'calculate PWM increase step pwm_step_up = pwm_new - pwm_old endif if pwm_old > pwm_new then 'calculate PWM decrease step pwm_step_down = pwm_old - pwm_new endif if pwm_step_up < 5 AND pwm_step_down < 5 then 'only increase PWM when step size is less than 5 pwmduty C.2, pwm_new 'pwm output endif tach_ave=tach_ave+tach_in ' calculate average tacho b0=b0+1 if b0=10 then tach_ave=tach_ave/10 ' calculate average tacho serout C.6,baud,(254,128) serout C.6,baud,("RUNNING~") serout C.6,baud,(254,192) serout C.6,baud,("RPM:") serout C.6,baud,(254,196) serout C.6,baud,(#tach_ave," ") ' display average RPM b0=0 tach_ave=0 endif pwm_old=pwm_new 'make old pwm equal to new pwm goto main interrupt: 'when interrupt is triggered low B.2 ' switch-off motor relay pwmduty C.2,0 'pwm output at zero pwm_new=0 ' reset PWM pwm_old=0 ' reset PWM serout C.6,baud,(254,128) serout C.6,baud,("FAULT ") 'show fault message serout C.6,baud,(254,192) serout C.6,baud,("MOTOR DR") if pinB.0 = 0 then interrupt ' loop if pin 21 is low (motor active);interrupt can only be reset by opening deadman switch setint %00000000, %00000010, B ' reset interrupt trigger on pin 22 is low return