; motor servo program for 16f1823 ; Bill Thompson - 03-29-2015 ; ; Revision 2 - Fall 2018 ; 09/29/2018 many changes to use internal comparator ; 10/23/2018 first running version with internal comparator ; 10/28/2018 code cleanup, no functional changes ; 10/30/2018 enable brownout reset & watchdog timer ; 11/15/2018 reorder interrupt logic for speed ; 11/21/2018 added 3rd speed to encoder ; 11/24/2018 added provision for 8mHz xtal, 32 mHz pll cpu clock ; 12/03/2018 add debounce code for encoder ; 12/28/2012 tweaks for ramp code due to changes in timing from debounce revs ; 03/03/2019 all port write now to latch instead of direct ; 03/04/2019 remove hysteresis on encoder port ; 03/04/2019 add delayed eeprom write enable at startup ;------------------------------------------------------ ;conditional options ;#define rampup ;comment this out to disable ramp-up #define mhz8 ;comment this out to use 4mhHz xtal ;------------------------------------------------------------ ; PORT bit definitions ; port A ;tach0 RA0 ;+ input from tachometer ;tach1 RA1 ;- input from tachometer ;gpout RA2 ;output to integrator ; port C ;gp78 RC2 ;low for 78 speed ;gp33 RC3 ;low for 33 speed ;both high for 45 speed ;encode RC0-1 ;rotary encoder bits ;speed sel RC2-3 ;avail RC4-5 ;available list p=16F1823 #include;------------------------------------------------------------- ; ; CONFIGURATION WORD SETUP ; use 8mHz xtal with 4x pll for system clock of 32mHz ; or 4mHz xtal with 4x pll for system clock of 16mHz ; reset pin disabled, lv pgm off ; enable brownout reset and watchdog timer 10/25/2018 ; add provision for 8mHz xtal, 32 mHz cpu clock 11/24/2018 ; ;------------------------------------------------------------------------------ ; configuration in Microchip convention #ifdef mhz8 cfg1a equ _FOSC_HS & _WDTE_SWDTEN & _PWRTE_ON & _MCLRE_OFF & _CP_OFF cfg1 equ cfg1a & _CPD_OFF & _BOREN_ON & _CLKOUTEN_OFF & _IESO_OFF & _FCMEN_OFF #else cfg1a equ _FOSC_XT & _WDTE_SWDTEN & _PWRTE_ON & _MCLRE_OFF & _CP_OFF cfg1 equ cfg1a & _CPD_OFF & _BOREN_ON & _CLKOUTEN_OFF & _IESO_OFF & _FCMEN_OFF #endif cfg2 equ _WRT_OFF & _PLLEN_ON & _STVREN_ON & _BORV_HI & _LVP_OFF ; configuration in plain binary ; use _FOSC_XT for 4mHz xtal or _FOSC_HS for 8mHz xtal #ifdef mhz8 __CONFIG _CONFIG1, b'00111110001010' ;0 0 1 11 1 1 0 0 01 010 -- 00 1111 1000 1010 -- 0f8a #else __CONFIG _CONFIG1, b'00111110001001' ;0 0 1 11 1 1 0 0 01 001 -- 00 1111 1000 1001 -- 0f89 #endif __CONFIG _CONFIG2, b'01101111111111' ;0 1 1 0 1 1 111 1 11 11 -- 01 1011 1111 1111 -- 1bff ;------------------------------------------------------------------------------ ; VARIABLE DEFINITIONS ; ;initial timer values for speed determination ;assuming 32mHz timer clock (8mHz xtal) ;or 16mHz timer clock (4mHz xtal) ;these are the values in eeprom the first time ;the pic is powered up. they are then ;updated by encoder adjustments as needed. ;updated these from actual measurement - thorens td-124 04/20/2015 ;11/28/2018 add data for 8mHz xtal #ifdef mhz8 l78 equ 0x86 ;78 low byte h78 equ 0xea ;78 high byte l45 equ 0x71 ;45 low byte h45 equ 0xda ;45 high byte l33 equ 0x3c ;33 low byte h33 equ 0xcd ;33 high byte #else l78 equ 0x53 ;78 low byte h78 equ 0xf5 ;78 high byte l45 equ 0x4b ;45 low byte h45 equ 0xed ;45 high byte l33 equ 0xa9 ;33 low byte h33 equ 0xe6 ;33 high byte #endif ;speed limits for encoder adjustments (high byte only) #ifdef mhz8 hilim equ d'240' ;high speed limit lolim equ d'100' ;low speed limit #else hilim equ d'251' ;high speed limit lolim equ d'200' ;low speed limit #endif ; encoder speed constants ; change step size depending on ; speed of encoder rotation e_slow equ 1 ;1 step when slow e_med equ 8 ;8 steps when med. e_fast equ 32 ;32 steps when fast ;encoder debounce count read encoder mult times ;all reads must agree for valid change ;# of encoder reads = dcount+1 dcount equ 3 ;repeat encoder read 4 times ;ramp speed variables #ifdef mhz8 rampspdh equ 0x40 ;8 mHz ramp speed divider 0x01=fast - 0xff=slow #else rampspdh equ 0x20 ;4 mHz ramp speed divider 0x01=fast - 0xff=slow #endif ;rampspd can be increased for further slowing of ramp ;it may get shifted left by up to 4 bits at ;higher motor speed so 0x08 is max legal value rampspd equ 1 ;fine ramp speed 0x08 max. startspd equ 0x7f ;high byte motor start speed ;------------------------------------------------------------------------------ ; Data Memory ;------------------------------------------------------------------------------ CBLOCK 0x20 ; all data memory in bank 0 ;ram storage for speed parameters ;loaded from eeprom during initialization ;holds speed setting for 3 speeds which may ;be updated by the encoder during operation and ;then updated in eeprom. spl78 ;78 sph78 spl45 ;45 sph45 spl33 ;33 sph33 ;16 bit timer 1 preset storage ;holds countdown value used to determine motor speed. ;loaded from above depending on speed selection timl timh ;ramp timer follows timl:timh ramping up and jumping down ;if rampup is enabled so abrupt increase in speed does not throw belts! rtiml rtimh rampcnt ;holds ramp speed for countdown rampcnth ;holds ramp speed divider for countdown sptemp ;temp for ramp speed calc ;32 mS 8 bit counter for encoder rotation speed enctim ;20 second 16 bit counter for eeprom updates eetiml eetimh ;storage for rotary encoder operations ;store encoder bits encold encnew ;debounce storage elast ;debounce last read encnt ;debounce counter ;temp for encoder calculations. etmp etmp2 ;output encoder data encspd ;encoder speed 0=no change 1=slow 8=fast encdir ;encoder direction 0=ccw 1=cw enclast ;holds last state for debounce ;eeprom read-write address pointer ee_addr ;eeprom address read/write ;counter for initial integrator reset to make sure ;motor starts up slowly counta countb countc ;delay enabling eeprom writes at startup stdel ;end of data memory ENDC ;eeprom address pointers for motor speed data ;these point to physical addr starting at 0xf010 ;and are used for eeprom read/write operations ee equ 0x10 el78 equ ee ;78 rpm eh78 equ ee+1 el45 equ ee+2 ;45 rpm eh45 equ ee+3 el33 equ ee+4 ;33 rpm eh33 equ ee+5 ;------------------------------------------------------------------------------ ; ; EEPROM INITIAL PROGRAMMING ; The 16F1823 has 256 bytes of non-volatile EEPROM, starting at address 0xF000 ; This is referenced as 0x00-0xFF in read/write operations ; ;------------------------------------------------------------------------------ USRID ORG 0X8000 ;0x334578 USER id DE 0x33 DE 0X45 DE 0X78 DE 0 DATAEE ORG 0xf000 DE "BillThompson.us" ;Place creator at address 0-14 ORG 0xf010 ;initial speed data in eeprom 0x10-0x15 DE l78 ;78rpm ;programmed at burn time, updated later DE h78 ;by encoder DE l45 ;45rpm DE h45 DE l33 ;33rpm DE h33 ;------------------------------------------------------------------------------ ; RESET VECTOR ;------------------------------------------------------------------------------ ORG 0x0000 ;processor reset vector GOTO init ;initialize and start pgm ;------------------------------------------------------------------------------ ; INTERRUPT SERVICE ROUTINE ; there are 2 interrupts, one from the tachometer when it ; changes state, the other from the timer when it overflows. ; the hardware integrator adjusts the motor speed to get a 50% ; duty cycle. ; If the interrupt is not the timer it must be the tachometer. ;------------------------------------------------------------------------------ ORG 0x0004 ;16f1823 has automatic context save for interrupts ;see if interrupt was from the timer ;if yes, output low (integrate up), stop timer, preset timer ;if no, its the tachometer, output high (integrate down), restart timer (already preset) ;write port directly to save banksel 05/19/2015 ;reverse interrupt order for speed 11/15/2018 ;write to latch, not port for integrator drive 03/03/2019 ; banksel 0 ;could be in any bank when interrupt happens btfss PIR1,TMR1IF ;a timer interrupt? goto tach1 ;no, its tachometer, go handle it ;--------------------------------------------------------- ;interrupt is from timer 1 overflow ;RA2 is the only port A output, clearing the whole port ;only affects RA2. timi1 banksel LATA ;use latch 03/03/2019 clrf LATA ;out low, integrate up banksel 0 bcf T1CON,TMR1ON ;stop timer movf rtiml,W ;preset timer to countdown value movwf TMR1L ;from speed ramp counter 05/11/2015 movf rtimh,W movwf TMR1H bcf PIR1,TMR1IF ;clear timer interrupt retfie ;return from interrupt ;--------------------------------------------------------- ;interrupt is from tachometer comparator state change tach1 banksel LATA ;use latch 03/03/2019 bsf LATA,RA2 ;out high, integrate down banksel 0 bsf T1CON,TMR1ON ;restart timer (already preset) clrf PIR2 ;clear comparator interrupt retfie ;return from interrupt ;--------------------------------------------------------- ;-------------------------------------------------------------------- ; main program starts here ; initialize everything ;-------------------------------------------------------------------- init banksel INTCON clrf INTCON ;make sure interrupts are disabled banksel WDTCON ;set up watchdog movlw b'00001110' ;set watchdog 128ms time and disable for now movwf WDTCON banksel OSCCON ;xtal clock, PLL movlw b'10000000' movwf OSCCON ; set analog inputs for comparator banksel ANSELA ;RA0-1 analog inputs for comparator movlw b'00000011' ;all other inputs digital movwf ANSELA clrf ANSELC ;RC port all digital - same bank as ansela ; set up comparator banksel CM1CON0 movlw b'10000110' ;enable comparator w/ normal power, hysteresis movwf CM1CON0 movlw b'11000000' ;interrupt on both pos and neg transition movwf CM1CON1 ;cm1con1 is in same bank as cm1con0 ;set up timer 1 for system clock, no prescaler, no sync banksel T1CON movlw b'01000100' ;tmr1 sys clock, no sync, timer stopped movwf T1CON clrf T1GCON ;no timer 1 gate control banksel OPTION_REG movlw b'00000111' ;global weak pullup, movwf OPTION_REG ;tmr0 sys clock with 1/256 prescale ; weak pullups on RC2,3 banksel WPUC ;weak pullups on RC2-3 movlw b'001100' ;for speed sel switch movwf WPUC clrf WPUA ;no weak pullups on PORTA banksel PIE1 clrf PIE1 ;disable all PIE1 interrupts except bsf PIE1,TMR1IE ;enable timer 1 overflow interrupt clrf PIE2 ;disable all PIE2 interrupts except bsf PIE2,C1IE ;enable comparator 1 interrupt banksel PIR1 clrf PIR1 ;clear any pending timer interrupts clrf PIR2 ;and comparator interrupts ; set port I/O types and preset encoder to current state banksel TRISA movlw B'111011' ;RA2 & RC<4-5> = outputs movwf TRISA ;RA<4-5> inputs for xtal movlw B'001111' ;RC0-1 encoder inputs, RC<2-3> speed sel.inputs movwf TRISC ;and RC4-5 enc.as outputs banksel LATA clrf LATA ;clear port a latches clrf LATC ;and port c banksel 0 ;------------------------------------------------------------- ;start things in a known state ;timer 1 banksel 0 ;back to bank 0 clrf timl ;set rpm timer at start speed clrf rtiml ;and ramp timer movlw startspd ;initial motor start speed (high byte only) movwf timh ;main and ramp timers movwf rtimh movlw rampspd ;set ramp speed movwf rampcnt ;8 bit counter for encoder speed clrf enctim ;set encoder speed counter to slow (0xff) decf enctim,f ;16 bit counter for eeprom update clrf eetiml ;clear (stop) eeprom update counter clrf eetimh ;delayed eeprom write enable movlw 0xff ;preset movwf stdel ;load speed data from eeprom ;(as updated by last adjustments) movlw el78 call eerd1 ;get 78 data from eeprom movwf spl78 ;store it in ram movlw eh78 call eerd1 ;get 78 data from eeprom movwf sph78 ;store it in ram movlw el45 call eerd1 ;get 45 data from eeprom movwf spl45 ;store it in ram movlw eh45 call eerd1 ;get 45 data from eeprom movwf sph45 ;store it in ram movlw el33 call eerd1 ;get 33 data from eeprom movwf spl33 ;store it in ram movlw eh33 call eerd1 ;get 33 data from eeprom movwf sph33 ;store it in ram ;------------------------------------------------------------------------ ;start with integrator low ;integrate down and wait, then start polling loop. ;let integrator ramp up from low at start banksel LATA bsf LATA,RA2 ;integrate down, stop motor banksel 0 clrf counta ;preset counter clrf countb ;for startup delay movlw d'251' ;4x longer startup delay movwf countc ;when rampup function used ;------------------------------------------------------------------------ ;delay while integrate down for slow start if using slow start ramp ca incfsz counta,f goto ca incfsz countb,f goto ca #ifdef rampup ;longer startup delay if using rampup incfsz countc,f goto ca #endif banksel LATA clrf LATA ;integrate up, start motor banksel 0 ;------------------------------------------------------------------------- banksel WDTCON ;now start watchdog timer bsf WDTCON,SWDTEN banksel 0 movlw b'11000000' ;enable global and peripheral interrupts movwf INTCON ;------------------------------------------------------------------------ ;initialization done, main program loop starts here ;speed ramp here to start motor gradually. ;executed if "rampup" is defined ;this may help prevent throwing belts! ;ramp up motor slowly initially or if speed changes ;executes in main loop before polling routines ;rampcnt and rampcnth define how many main loops are executed ;before the ramp code executes. This sets the ramp speed. ;there is additional code to slow down the ramp as motor ;approaches higher speeds. poll_ramp ;---------------------------------------------------------- banksel 0 clrwdt ;reset watchdog on each loop ;----------------------------------------------------------- ;delay enabling eeprom writes for a bit at startup sdel movf stdel,W ;read startup delay iorlw 0 ;zero? btfsc STATUS,Z goto sdel2 ;yes, do nothing sdel1 movf PORTC,W ;yes, read port C to W andlw b'00000011' ;mask all but RC0-1 (encoder) movwf encold ;preset encoder storage to current state movwf encnew movwf elast movwf etmp movlw dcount ;preset debounce movwf encnt clrf eetiml ;stop eeprom timer clrf eetimh decf stdel,f ;count down banksel LATC ;turn off all leds clrf LATC banksel 0 sdel2 ;continue ;----------------------------------------------------------------- #ifdef rampup ;if ramp-up speed enabled decfsz rampcnth,f ;decrement divider goto poll ;skip ramp if divider not 0 movlw rampspdh ;else reset divider movwf rampcnth decfsz rampcnt,f goto poll ;only ramp when ramp counter reaches 0 ;skip ramp if tim=rtim movf rtiml,W ;low byte equal? xorwf timl,W btfss STATUS,Z goto ramp0 ;no, may need ramp movf rtimh,W ;yes, high byte equal? xorwf timh,W btfsc STATUS,Z goto poll ;yes, skip ramp code if rtim=tim ramp0 movlw rampspd ;not equal, may need ramp, reset ramp counter movwf rampcnt ;see if updated speed is higher or lower, ramp up but not down movf rtiml,W ;get ramp timer subwf timl,W ;subtract from low byte movf rtimh,W subwfb timh,W ;borrow to high byte btfss STATUS,C ;carry set if rtim < tim goto noramp ;don't ramp if equal or more (equal shouldn't get here) ;new speed is faster so ramp up ;-------------------------------------------------------- ;slow the up ramp rate at faster speeds 02/22/2016 ;rampcnt determines ramp speed - higher is slower ;each left shift results in 1/2 ramp speed movf rtimh,W ;get hi speed byte in W andlw 0xf0 ;mask low nibble addlw 0x40 ;add for countdown, check for wrap btfss STATUS,C ;slowdown not needed if no wrap goto ramp1 ;skip slowdown if not needed movwf sptemp ;here if ramp slowdown needed swapf sptemp,f ;swap nibbles for loop counter incf sptemp,f ;add 1 to count for decrement rmploop ;loop for 1/2-1/16 speed lslf rampcnt,f ;shift for 1/2 speed decfsz sptemp,f ;required number of times goto rmploop ;loop for speed/2 again ;------------------------------------------------------------------ ;ramp-up routine ;increment 16 bit time by 1 ramp1 incfsz rtiml,f ;ramp up 1 if less goto poll ;go polling if no hi byte incr incf rtimh,f ;increment hi byte if low byte wrapped goto poll ;and go do polling #endif ;end if ramp-up speed ;------------------------------------------------------------------ ;here if new speed is lower - jump speed down noramp movf timl,W ;set fully ramped movwf rtiml ;make sure rtim = tim movf timh,W movwf rtimh ;start main polling routines ; ;polling includes: ;1. servicing counters for encoder rotation speed detection and eeprom update timing ;2. reading encoder ;3. reading speed selector switch ;4. updating speed data based on encoder readings for ; whichever of 3 speeds is selected ;check our master .5mS counter (timer 0) poll banksel 0 btfss INTCON,TMR0IF ;timer 0 overflow? goto poll_ramp ;no loop ;-------------------------------------------------------------------- ;each .5mS, service encoder rate and eeprom update counters tm0clr ;yes, reset .5ms timer and update counters ;set timing for 8 or 4 mHz xtal 11/26/2018 #ifdef mhz8 ;for 8 mHz xtal movlw b'11110000' ;preset timer 0 to overflow in 16 prescale clocks #else ;else for 4 mHz xtal movlw b'11111000' ;preset timer 0 to overflow in 8 prescale clocks #endif movwf TMR0 ;for a total of .5mS bcf INTCON,TMR0IF ;clear timer0 overflow for next time ;increment counters - there are 2 counters. ; ;The first is a 16 bit counter for eeprom writing. ;if its 0, its not incremented. When there's an encoder change ;its set to a constant and then counts up for approx 20 sec. ;Every encoder change presets it to the constant for about 20 sec. ;so it starts over. When there's been no encoder change for ;approx 20 sec, it wraps to 0, causes an eeprom write, and then ;stays at 0 until there's another encoder change. ; ;The second counter determines speed of encoder rotation and ;is used to specify step size for course and fine speed adjustment. ;Every encoder change reads this counter value ;and then resets it. When it reaches 0xff its held there to specify ;the slow rotation. Not timed out causes one of 2 the faster adjustments ;depending on the counter value. It should reach 0xff in approx. 32mS. ;turning the encoder faster therefor results in faster changes per step. movf eetiml,W ;running? iorwf eetimh,W ;not if 0x0000 btfss STATUS,Z ;Z set if not running goto ckee banksel 0 goto noup ;no eeprom update if counter not running ;increment eeprom update counter, when it reaches 0:0 ;initiate an eeprom update write and then leave counter ;at 0:0 until there's an encoder change ;------------------------------------------------- ckee banksel LATC bsf LATC,RC5 ;turn on RC5 led banksel 0 incfsz eetiml,f ;count up eeprom update counter goto noup ;if not 0 no increment hi, no eeprom update movlw 0x80 ;shorter delay time 03/03/2019 iorwf eetimh,f incfsz eetimh,f ;increment hi, timed out if 0 goto noup ;if not 0, not timed out. no eeprom update ;------------------------------------------------------------ ;update eeprom data if eeprom update timer timed out call eeupd ;if 0:0, update, stay at 0:0 till next encoder change banksel LATC clrf LATC ;turn off all leds when no pending write banksel 0 ;increment encoder speed timer, noup incfsz enctim,f ;increment encoder rotation timer goto encrd decf enctim,f ;hold at 0xff if max time ;------------------------------------------------------------------- ;encoder service - flag if change, store speed and direction ;restart eeprom write timer ;12/03/2018 added debounce code encrd ;-------------------------------------------------------------------------- banksel 0 clrf encspd ;preset set encoder speed at 0 for no change movf PORTC,W ;read port C to W andlw b'00000011' ;mask all but RC0-1 (encoder) movwf etmp ;keep it to tmp xorwf elast,W ;match last read? btfsc STATUS,Z goto en0 ;yes, continue movf etmp,W ;no, update last read movwf elast movlw dcount ;restart debounce count movwf encnt goto cks2 ;and continue without encoder update en0 decfsz encnt,f ;decrement debounce count goto cks2 ;if not 0, continue without encoder update movlw dcount ;if 0, preset debounce count movwf encnt ;and process encoder ;--------------------------------------------------------------------------- encrd1 movf encnew,W ;move the previous "New" value movwf encold ;to "Old" file register movf etmp,W ;then move the new value movwf encnew ;to "New" file register xorwf encold,W ;xor old and new btfsc STATUS,Z ;xor=0=no change goto cks2 ;nothing changed, goto speed selector ;---------------------------------------------------------------------- ;encoder changed, restart eeprom update timer on each change espd clrf eetiml clrf eetimh bsf eetimh,7 ;preset eeprom update counter for approx 20 sec. count ;---------------------------------------------------------------------- ;determine encoder rotation speed incfsz enctim,W ;see if encoder timer timed out goto emed ;no, set fast or med speed eslow banksel LATC ;turn off RC4 led if slow bcf LATC,RC4 banksel 0 movlw e_slow ;yes, get slow speed constant in W goto ckenc emed banksel LATC ;turn on RC4 led if not slow bsf LATC,RC4 banksel 0 sublw 0x10 ;add 3rd speed 11/20/2018 btfsc STATUS,C ;encoder turning really fast? goto efast ;yes, go set fast speed movlw e_med ;no, get med speed constant in W goto ckenc efast movlw e_fast ;get fast speed constant in W ckenc movwf encspd ;store encoder speed movlw b'11000000' ;reset encoder timer for 64 counts (32mS) movwf enctim ;----------------------------------------------------------------------- ;get encoder direction clrf encdir ;assume ccw direction movf encold,W ;move the right andlw b'00000001' ;bit of the movwf etmp2 ;OLD value to etmp2 movf encnew,W ;move the left andlw b'00000010' ;bit of the movwf etmp ;new value to etmp lsrf etmp,W ;shift right one bit etmp xorwf etmp2,W ;xor them. if it is zero CCW else CW btfss STATUS,Z ;leave at 0 if ccw (skip next) bsf encdir,1 ;else make it 1 if CW ;end encoder service ;--------------------------------------------------------------------- ;speed selection and update motor speed ;read turntable speed selector switch cks2 banksel 0 btfss PORTC,RC2 ;78 selected? goto tim78 ;yes, do 78 btfsc PORTC,RC3 ;33 selected? goto tim45 ;no, do 45 ;yes, fall into tim33 ;---------------------------------------------------------------- ;speed select routines ;get constants for appropriate speed and update ;speed data based on last encoder change if any tim33 movf spl33,W ;pulse width for 33 rpm movwf timl ;get current 33 constants movf sph33,W movwf timh call timadj ;adjust time by encoder data if changed movf timl,W ;update speed data in ram movwf spl33 movf timh,w movwf sph33 goto poll_ramp ;back to top of main loop tim45 movf spl45,W ;pulse width for 45 rpm movwf timl ;get current 45 constants movf sph45,W movwf timh call timadj ;adjust time by encoder data if changed movf timl,W ;update speed data in ram movwf spl45 movf timh,w movwf sph45 goto poll_ramp ;back to top of main loop tim78 movf spl78,W ;pulse width for 78 rpm movwf timl ;get current 78 constants movf sph78,W movwf timh call timadj ;adjust time by encoder data if changed movf timl,W ;update speed data in ram movwf spl78 movf timh,W movwf sph78 goto poll_ramp ;back to top of main loop ;end of main polling loop ;--------------------subroutines------------------------------- ;subroutine to adjust speed data per encoder ;returns with 16 bit adjusted data in timl, timh ;just return doing nothing if no encoder change timadj clrw ;see if encoder speed adj value is 0 iorwf encspd,W ;if its 0, no encoder change btfsc STATUS,Z return ;do nothing if its 0, else continue btfss encdir,1 ;get direction (1 is cw) goto eccw ;skip if not cw ;add if cw ecw movf encspd,W ;get speed adj addwf timl,f ;add to low byte clrw addwfc timh,f ;carry to high byte ;check if over limit, set to limit if so movlw (d'256'-hilim) ;get high time limit (subtr from 256) addwf timh,W ;add to time high byte btfss STATUS,C ;over? goto hok ;no leave alone movlw hilim ;yes, set at high limit movwf timh clrf timl hok clrf encspd ;zero out enc speed so we don't update again return ;subtract if ccw eccw movf encspd,W ;get speed adj subwf timl,f ;subtract from to low byte clrw subwfb timh,f ;borrow to high byte ;check if under limit, set to limit if so movlw lolim ;get low time limit subwf timh,W ;subtract from time low byte btfsc STATUS,C ;under? goto lok ;no leave alone movlw lolim ;yes, set at low limit movwf timh clrf timl lok clrf encspd ;zero out enc speed so we don't update again return ;--------------------------------------------------- ;subroutine to update eeprom speed data ;do this after encoder activity followed ;by 20 sec of inactivity ;read eeprom and compare to current setting ;only update what's changed eeupd movlw el33 ;get eeprom data in W movwf ee_addr ;33 low byte call eeread xorwf spl33,W ;changed? btfsc STATUS,Z goto xh33 movf spl33,W ;yes, write new call eewrt xh33 movlw eh33 ;get eeprom data in W movwf ee_addr ;33 high byte call eeread xorwf sph33,W ;changed? btfsc STATUS,Z goto xl45 movf sph33,W ;yes, write new call eewrt xl45 movlw el45 ;get eeprom data in W movwf ee_addr ;45 low byte call eeread xorwf spl45,W ;changed? btfsc STATUS,Z goto xh45 movf spl45,W ;yes, write new call eewrt xh45 movlw eh45 ;get eeprom data in W movwf ee_addr ;45 high byte call eeread xorwf sph45,W ;changed? btfsc STATUS,Z goto xl78 movf sph45,W ;yes, write new call eewrt xl78 movlw el78 ;get eeprom data in W movwf ee_addr ;78 low byte call eeread xorwf spl78,W ;changed? btfsc STATUS,Z goto xh78 movf spl78,W ;yes, write new call eewrt xh78 movlw eh78 ;get eeprom data in W movwf ee_addr ;78 high byte call eeread xorwf sph78,W ;changed? btfsc STATUS,Z return ;no, we're done, return movf sph78,W ;yes, write new call eewrt return ;and return, all updates done ;---------------------------------------------------------------- ;eeprom read and write subroutines ;subroutine for EEPROM write ;address in ee_addr, byte to write in W eewrt banksel EEDATL movwf EEDATL ;Data Memory Value to write in W banksel 0 movf ee_addr,W ;get address to write banksel EEADRL movwf EEADRL ;Data Memory Address to write bcf EECON1,CFGS ;Deselect Configuration space bcf EECON1,EEPGD ;Point to DATA memory bsf EECON1,WREN ;Enable writes bcf INTCON,GIE ;Disable Interrupts. movlw 0x55 movwf EECON2 ;Write 55h movlw 0xAA movwf EECON2 ;Write AAh bsf EECON1,WR ;Set WR bit to begin write bsf INTCON,GIE ;Enable Interrupts bcf EECON1,WREN ;Disable further writes eewait btfsc EECON1,WR ;Wait for write to complete goto eewait banksel 0 ;done, back to bank 0 default return ;and return after write ;subroutine for EEPROM read ;Address to read is in eeaddrl ;returns with value in W ;there are 2 entry points, the first with the addr to read ;in ee_addr, the second with the addr to read in W eeread ;enter here with addr in ee_addr movf ee_addr,W ;get addr to read in W eerd1 ;enter here with addr in W banksel EEADRL ;or start here with addr to read in W movwf EEADRL ;set addr to read bcf EECON1,CFGS ;Deselect Config space bcf EECON1,EEPGD ;Point to DATA memory bsf EECON1,RD ;EE Read movf EEDATL,W ;W = read data banksel 0 ;back to bank 0 default return ;return with requested data in W END