; 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