Assembler program for motor controller

; motor servo program for 16f1823
; Bill Thompson - 03-29-2015
;
; Use this code as you like but don't blame me for anything
; bad that goes wrong ;-)
;
; uses a counter in main polling loop which counts up
; every time timer 0 wraps. This is used for a master timer
; for the encoder rotation speed detection and for eeprom write timing.
;
; now using external comparator. Its already on the PCB
; as part of the dual amp used for the integrator
; and this will keep the board compatible with the
; older 12f629 design.
;
; enabled eeprom update write 04/17/2015
;
; added kludgy code to effect a slow motor rampup on start
; this prevents throwing belts on belt drive turntables ;-) 05/01/2015
; this code is conditional at assemble time
;
;#define rampup         ;comment this out to disable ramp-up
;------------------------------------------------------------

; PORT bit definitions

; port A
;gp78   RA0             ;switch for 78 speed
;gp33   RA1             ;switch for 33 speed

;gpin   RA3             ;input from tachometer
;gpout  RA2             ;output to integrator

; port C
;encode RC0-1           ;rotary encoder bits
;led's  RC2-5           ;debugging led's

        list            p=16F1823
        #include        

;------------------------------------------------------------------------------
;
; CONFIGURATION WORD SETUP
; use 4mHz xtal with 4x pll for system clock of 16mHz
; reset pin disabled
;
;------------------------------------------------------------------------------    

;    __CONFIG _CONFIG1, _FOSC_XT & _WDTE_OFF & _PWRTE_ON & _MCLRE_OFF & _CP_OFF & _CPD_OFF & _BOREN_OFF & _CLKOUTEN_OFF & _IESO_OFF & _FCMEN_OFF
;    __CONFIG _CONFIG2, _WRT_OFF & _PLLEN_ON & _STVREN_OFF & _BORV_LO & _LVP_OFF

; config word generated by above has issues, maybe something with the
; crazy Microchip convention, using plain binary for now

        __CONFIG _CONFIG1, b'00100110000001' ;0 0 1 00 1 1 0 0 00 001 -- 00 1001 1000 0001 -- 0981
        __CONFIG _CONFIG2, b'01111111111111' ;0 1 1 1 1 1 111 1 11 11 -- 01 1111 1111 1111 -- 1FFF

;------------------------------------------------------------------------------
; VARIABLE DEFINITIONS
;
;initial timer values for speed determination
;assuming 16mHz timer clock
;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 04/20/2015

;thorens td-124 
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

;speed limits for encoder adjustments (high byte only)
hilim   equ     d'251'          ;high speed limit
lolim   equ     d'200'          ;low speed limit

; encoder speed constants
; change step size depending on
; speed of encoder rotation

e_slow  equ     1               ;1 bit step when slow
e_fast  equ     8               ;8 bit steps when fast

;ramp speed variables
rampspd         equ     0x8     ;ramp speed 00=fast - 0xff=slow
startspd        equ     0x7f    ;high byte motor start speed


;------------------------------------------------------------------------------
; Data Memory
;------------------------------------------------------------------------------

    CBLOCK 0x20 ; all in bank 0

;port a is read during the tachometer interrupt and stored here.
;the polling loop reads this rather than the port itself
;to avoid collision issues with interrupt-on-change.    
gpcopy                          ;storage for PORTA read during interrupt.

;ram storage for speed parameters
;loaded from eeprom during initialization
;holds speed setting for 3 speeds which may
;be updated 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
;so abrupt increase in speed does not throw belts!
rtiml
rtimh
rampcnt                         ;sets ramp speed

;32 mS 8 bit counter for encoder rotation speed
enctim

;32 second 16 bit counter for eeprom updates
eetiml
eetimh

;storage for rotary encoder operations
;store encoder bits
encold
encnew
;temp for encoder calculation.
etmp
etmp2
;output encoder data
encspd                          ;encoder speed 0=no change 1=slow 8=fast
encdir                          ;encoder direction 0=ccw 1=cw

;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

        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                  ;0x784533 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 times out.
; the hardware integrator adjusts the motor speed to get a 50%
; duty cycle +/- a small amount determined by the fine adjust
; control. (if used)
; If the interrupt is not the timer it must be the tachometer.
;------------------------------------------------------------------------------

        ORG      0x0004

;see if interrupt was from the timer
;if not, its the tachometer, restart timer and output high (integrate down)
;if so, output low (integrate up,) and wait for tachometer change
;write port directly to save banksel 05/19/2015
;
;16f1823 has automatic context save for interrupts
        banksel 0               ;(could be in any bank when interrupt happens)
        btfsc   PIR1,TMR1IF     ;a timer interrupt? (false if so)
        goto    timi1           ;yes, go handle it

;else interrupt is from tachometer state change
        bsf     PORTA,RA2       ;out high, integrate down write port directly 05/19/2015
        bsf     T1CON,TMR1ON    ;restart timer (already preset)

        movf    PORTA,W         ;read port A for int on change sync
        movwf   gpcopy          ;and store it for read in main loop

        banksel IOCAF
        clrf    IOCAF           ;clear interrupt on change

        retfie                  ;return from interrupt          

;interrupt is from timer 1 overflow
;RA2 is the only port A output, clearing the whole port
;only affects RA2.
timi1
        clrf    PORTA           ;out low, integrate up - write port directly 05/19/2015
        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

        clrf    PIR1            ;clear timer interrupt

        retfie                  ;return from interrupt
        
;--------------------------------------------------------------------
; main program starts here
; initialize everything
;--------------------------------------------------------------------
init
        banksel INTCON
        clrf    INTCON          ;make sure interrupts are disabled

        banksel OSCCON          ;XT xtal clock, PLL
        movlw   b'10000000'
        movwf   OSCCON

        banksel ANSELA          ;no analog inputs, all digital
        clrf    ANSELA
        clrf    ANSELC

;set up timer 1 for system clock, no prescaler, no sync
        banksel T1CON
        movlw   b'01000100'     ;tmr1 clock=sys, no sync, timer stopped
        movwf   T1CON
        clrf    T1GCON          ;no timer 1 gate control
        
        banksel OPTION_REG
        movlw   b'00000111'
        movwf   OPTION_REG      ;global weak pullup, tmr0 sys clk. 256 tmr0 prescale
        
        banksel WPUA            ;weak pullups on RA0-1 speed sel sw.
        movlw   b'000011'       ;for speed sel switch
        movwf   WPUA
        clrf    WPUC            ;no weak pullups on PORTC

        banksel PIE1
        clrf    PIE1            ;disable all PIE1 interrupts except
        bsf     PIE1,TMR1IE     ;enable timer 1 overflow interrupt
        clrf    PIE2            ;disable all PIE2 interrupts

        banksel PIR1
        clrf    PIR1            ;clear any pending timer interrupts
        clrf    PIR2
        banksel IOCAF
        clrf    IOCAF           ;clear interrupt on change
        
        banksel TRISA
        movlw   B'111011'       ;Set RA2 as output
        movwf   TRISA           ;all others as inputs - RA used for xtal
        movlw   B'000011'       ;Set RC0-1 inputs for encoder
        movwf   TRISC           ;and RC2-5 outputs for diag led's

        banksel LATA
        clrf    LATA            ;clear port latches
        clrf    LATC            ;and turn led's off

        banksel IOCAN           ;interrupt on change for tachometer.
        movlw   b'001000'       ;both directions on RA3
        movwf   IOCAN
        movwf   IOCAP
        
        banksel 0               ;back to bank 0
        
        
;-------------------------------------------------------------
        
;start things in a known state  
;timer 1
        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  
        
;read current encoder bits
        movf    PORTC,W         ;read port C to W
        andlw   b'00000011'     ;mask all but RC0-1 (encoder)
        movwf   encold          ;preset encoder storage to current state
        movwf   encnew
        
;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 for .05 sec, then start polling loop.
;let integrator ramp up from low at start       
        
        bsf     PORTA,RA2       ;integrate down, stop motor
        
        clrf    counta          ;preset counter
        clrf    countb          ;for .05 sec. delay

;delay approx .05 sec
ca
        incfsz  counta,f
        goto    ca
cb
        incfsz  countb,f
        goto    ca

        clrf    PORTA   ;integrate up, start motor
        
;-------------------------------------------------------------------------
;now enable interrupts
        movlw   b'11001000'     ;enable global and peripheral interrupts
        movwf   INTCON          ;and global int on change

;------------------------------------------------------------------------       

;initialization done, main program loop starts here

;speed ramp here to start motor gradually.
;this may help prevent throwing belts!
;05/11/2015

;ramp up motor slowly initially or if speed changes
;executes in main loop before polling routines
;rampcnt defines 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.

;don't waste time once motor has stabilized

ramp

;----------------------------------------------------------

#ifdef rampup                   ;if ramp-up speed
        decfsz  rampcnt,f
        goto    poll            ;only ramp when ramp counter wraps

;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, 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
;--------------------------------------------------------
;adjust to slow the up ramp at faster speeds
        movf    rtimh,W         ;get hi byte ramp timer
        andlw   b'11110000'     ;mask low nibble
        xorlw   0xc0            ;4th fastest range?
        btfsc   STATUS,Z
        goto    rampc3          ;yes, 1/2 speed
        
rampa   movf    rtimh,W         ;get hi byte ramp timer
        andlw   b'11110000'     ;mask low nibble
        xorlw   0xd0            ;3rd fastest range?
        btfsC   STATUS,Z
        goto    rampc2          ;yes 1/4 speed
        
rampb
        movf    rtimh,W         ;get hi byte ramp timer
        andlw   b'11110000'     ;mask low nibble
        xorlw   0xe0            ;2nd fastest range?
        btfsC   STATUS,Z
        goto    rampc1          ;yes 1/8 speed
        
rampc
        movf    rtimh,W         ;get hi byte ramp timer
        andlw   b'11110000'     ;mask low nibble
        xorlw   0xf0            ;fastest range?
        btfss   STATUS,Z
        goto    ramp1           ;no, must be slower, no adjustment

rampc0  lslf    rampcnt,f       ;1/16 speed
rampc1  lslf    rampcnt,f       ;1/8 speed
rampc2  lslf    rampcnt,f       ;1/4 speed
rampc3  lslf    rampcnt,f       ;1/2 speed
;------------------------------------------------------------------

;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
        btfss   INTCON,TMR0IF   ;timer 0 overflow?
        goto    encrd           ;no go look at encoder

;--------------------------------------------------------------------

;each .5mS, service encoder speed and eeprom update counters
tm0clr                          ;yes, reset .5ms timer and update counters
        movlw   b'11111000'     ;preset timer 0 to overflow in 8 prescale clocks
        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 1 and then counts up. Every encoder change presets it
;to 1 so it starts over. When there's been no encoder change for
;approx 32 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 slowest rotation measurement. Not timed out causes the
;faster adjustment to be used. It should reach 0xff in approx. 32mS.
;so steps less than 32mS apart use the faster speed and steps
;more than 32mS apart use the slower speed
;04/22/2015 - now turn off all led's after eeprom write.
        
;watch eeprom update timer on RC5 led
        movf    eetiml,W ;running?
        iorwf   eetimh,W ;not if 0x0000
        btfss   STATUS,Z ;Z set if not running
        goto    on5

off5
        banksel LATC            ;eeprom counter is not running
        clrf    LATC            ;set all leds off if not running
        banksel 0
        goto    noup            ;no eeprom update if counter not running

on5
        banksel LATC            ;eeprom counter is running
        bsf     LATC,RC5        ;set led 5 on if running
        banksel 0
        
;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
        incfsz  eetiml,f        ;here if counter is running, count up
        goto    noup            ;if not 0 no increment hi, no eeprom update
        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

;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 change, note speed and direction
;read encoder, see if it changed
encrd
        clrf    encspd          ;preset set encoder speed at 0 for no change
        movf    PORTC,W         ;read port B to W
        andlw   b'00000011'     ;mask all but RC0-1 (encoder)
        movwf   etmp            ;keep it to tmp

        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    ckspeed         ;nothing changed, goto speed selector

;-------------------------------------------------------------------    

;here if encoder has changed
;restart eeprom update counter and determine encoder rotation speed
;toggle rc2 led on each encoder change
        movlw   b'000100'
        banksel LATC
        xorwf   LATC,f          ;toggle rc2 led
        banksel 0

;restart eeprom update timer on each encoder change
espd
        clrf    eetiml
        clrf    eetimh
        incf    eetiml,f        ;preset eeprom update counter for approx 32 sec count

;determine encoder rotation speed
        incfsz  enctim,W        ;see if encoder timer timed out
        goto    efast           ;no, set fast speed

;get constant for fast or slow encoder speed
;indicate slow speed by turning off led 4
eslow
        banksel LATC
        bcf     LATC,RC4        ;clear led 4
        banksel 0
        movlw   e_slow          ;get slow speed constant in W
        goto    ckenc

;indicate fast speed by turning on led 4
efast   
        banksel LATC
        bsf     LATC,RC4
        banksel 0
        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          ;preset timer starting count value (always counting)

;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

;---------------------------------------------------------------------  

;show encoder direction on rc3 led
ckspeed
        movf    eetiml,W        ;only turn led on if eeprom counter is running
        iorwf   eetimh,W        ;not if 0x0000
        btfsc   STATUS,Z        ;Z set if not running
        goto    cks1            ;don't check further if not running

        btfss   encdir,1        ;else, is it cw?
        goto    cks1            ;no, turn led off

        banksel LATC
        bsf     LATC,RC3        ;yes, turn on
        banksel 0
        goto    cks2
        
cks1
        banksel LATC            ;turn off led
        bcf     LATC,RC3
        banksel 0

;---------------------------------------------------------------------
        
;speed selection and update motor speed
;read turntable speed selector switch   
cks2
        btfss   gpcopy,1        ;78 selected?
        goto    tim78           ;yes, do 78
        btfsc   gpcopy,0        ;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         ;delay 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    ramp            ;back to top of main loop

tim45
        movf    spl45,W         ;delay 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    ramp            ;back to top of main loop

tim78
        movf    spl78,W         ;delay 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    ramp            ;back to top of main 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 ccw
        
;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 32 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

Listing output from Microchip assembler

MPASM 5.51 SERVO-1823-BT-T2S.ASM 1-20-2016 16:38:05 PAGE 1 LOC OBJECT CODE LINE SOURCE TEXT VALUE 00001 ; motor servo program for 16f1823 00002 ; Bill Thompson - 03-29-2015 00003 ; 00004 ; Use this code as you like but don't blame me for anything 00005 ; bad that goes wrong ;-) 00006 ; 00007 ; uses a counter in main polling loop which counts up 00008 ; every time timer 0 wraps. This is used for a master timer 00009 ; for the encoder rotation speed detection and for eeprom write timing. 00010 ; 00011 ; now using external comparator. Its already on the PCB 00012 ; as part of the dual amp used for the integrator 00013 ; and this will keep the board compatible with the 00014 ; older 12f629 design. 00015 ; 00016 ; enabled eeprom update write 04/17/2015 00017 ; 00018 ; added kludgy code to effect a slow motor rampup on start 00019 ; this prevents throwing belts on belt drive turntables ;-) 05/01/2015 00020 ; this code is conditional at assemble time 00021 ; 00022 ;#define rampup ;comment this out to disable ramp-up 00023 ;------------------------------------------------------------ 00024 00025 ; PORT bit definitions 00026 00027 ; port A 00028 ;gp78 RA0 ;switch for 78 speed 00029 ;gp33 RA1 ;switch for 33 speed 00030 00031 ;gpin RA3 ;input from tachometer 00032 ;gpout RA2 ;output to integrator 00033 00034 ; port C 00035 ;encode RC0-1 ;rotary encoder bits 00036 ;led's RC2-5 ;debugging led's 00037 00038 list p=16F1823 00039 #include 00001 LIST 00002 00003 ;========================================================================== 00004 ; MPASM PIC16F1823 processor include 00005 ; 00006 ; (c) Copyright 1999-2013 Microchip Technology, All rights reserved 00007 ;========================================================================== 00008 01153 LIST 00040 00041 ;------------------------------------------------------------------------------ 00042 ; 00043 ; CONFIGURATION WORD SETUP 00044 ; use 4mHz xtal with 4x pll for system clock of 16mHz MPASM 5.51 SERVO-1823-BT-T2S.ASM 1-20-2016 16:38:05 PAGE 2 LOC OBJECT CODE LINE SOURCE TEXT VALUE 00045 ; reset pin disabled 00046 ; 00047 ;------------------------------------------------------------------------------ 00048 00049 ; __CONFIG _CONFIG1, _FOSC_XT & _WDTE_OFF & _PWRTE_ON & _MCLRE_OFF & _CP_OFF & _CPD_OFF & _BOREN_OFF & _CLKOUTEN_OFF & _IESO_OFF & _FCMEN_OFF 00050 ; __CONFIG _CONFIG2, _WRT_OFF & _PLLEN_ON & _STVREN_OFF & _BORV_LO & _LVP_OFF 00051 00052 ; config word generated by above has issues, maybe something with the 00053 ; crazy Microchip convention, using plain binary for now 00054 8007 0981 00055 __CONFIG _CONFIG1, b'00100110000001' ;0 0 1 00 1 1 0 0 00 001 -- 00 1001 1000 0001 -- 0981 8008 1FFF 00056 __CONFIG _CONFIG2, b'01111111111111' ;0 1 1 1 1 1 111 1 11 11 -- 01 1111 1111 1111 -- 1FFF 00057 00058 ;------------------------------------------------------------------------------ 00059 ; VARIABLE DEFINITIONS 00060 ; 00061 ;initial timer values for speed determination 00062 ;assuming 16mHz timer clock 00063 ;these are the values in eeprom the first time 00064 ;the pic is powered up. they are then 00065 ;updated by encoder adjustments as needed. 00066 00067 ;updated these from actual measurement 04/20/2015 00068 00069 ;thorens td-124 00000053 00070 l78 equ 0x53 ;78 low byte 000000F5 00071 h78 equ 0xf5 ;78 high byte 00072 0000004B 00073 l45 equ 0x4b ;45 low byte 000000ED 00074 h45 equ 0xed ;45 high byte 00075 000000A9 00076 l33 equ 0xa9 ;33 low byte 000000E6 00077 h33 equ 0xe6 ;33 high byte 00078 00079 ;speed limits for encoder adjustments (high byte only) 000000FB 00080 hilim equ d'251' ;high speed limit 000000C8 00081 lolim equ d'200' ;low speed limit 00082 00083 ; encoder speed constants 00084 ; change step size depending on 00085 ; speed of encoder rotation 00086 00000001 00087 e_slow equ 1 ;1 bit step when slow 00000008 00088 e_fast equ 8 ;8 bit steps when fast 00089 00090 ;ramp speed variables 00000008 00091 rampspd equ 0x8 ;ramp speed 00=fast - 0xff=slow 0000007F 00092 startspd equ 0x7f ;high byte motor start speed 00093 00094 00095 ;------------------------------------------------------------------------------ 00096 ; Data Memory MPASM 5.51 SERVO-1823-BT-T2S.ASM 1-20-2016 16:38:05 PAGE 3 LOC OBJECT CODE LINE SOURCE TEXT VALUE 00097 ;------------------------------------------------------------------------------ 00098 00099 CBLOCK 0x20 ; all in bank 0 00100 00101 ;port a is read during the tachometer interrupt and stored here. 00102 ;the polling loop reads this rather than the port itself 00103 ;to avoid collision issues with interrupt-on-change. 00000020 00104 gpcopy ;storage for PORTA read during interrupt. 00105 00106 ;ram storage for speed parameters 00107 ;loaded from eeprom during initialization 00108 ;holds speed setting for 3 speeds which may 00109 ;be updated during operation and 00110 ;then updated in eeprom. 00000021 00111 spl78 ;78 00000022 00112 sph78 00113 00000023 00114 spl45 ;45 00000024 00115 sph45 00116 00000025 00117 spl33 ;33 00000026 00118 sph33 00119 00120 ;16 bit timer 1 preset storage 00121 ;holds countdown value used to determine motor speed. 00122 ;loaded from above depending on speed selection 00000027 00123 timl 00000028 00124 timh 00125 00126 ;ramp timer follows timl:timh ramping up and jumping down 00127 ;so abrupt increase in speed does not throw belts! 00000029 00128 rtiml 0000002A 00129 rtimh 0000002B 00130 rampcnt ;sets ramp speed 00131 00132 ;32 mS 8 bit counter for encoder rotation speed 0000002C 00133 enctim 00134 00135 ;32 second 16 bit counter for eeprom updates 0000002D 00136 eetiml 0000002E 00137 eetimh 00138 00139 ;storage for rotary encoder operations 00140 ;store encoder bits 0000002F 00141 encold 00000030 00142 encnew 00143 ;temp for encoder calculation. 00000031 00144 etmp 00000032 00145 etmp2 00146 ;output encoder data 00000033 00147 encspd ;encoder speed 0=no change 1=slow 8=fast 00000034 00148 encdir ;encoder direction 0=ccw 1=cw 00149 MPASM 5.51 SERVO-1823-BT-T2S.ASM 1-20-2016 16:38:05 PAGE 4 LOC OBJECT CODE LINE SOURCE TEXT VALUE 00150 ;eeprom read-write address pointer 00000035 00151 ee_addr ;eeprom address read/write 00152 00153 ;counter for initial integrator reset to make sure 00154 ;motor starts up slowly 00000036 00155 counta 00000037 00156 countb 00157 00158 ENDC 00159 00160 ;eeprom address pointers for motor speed data 00161 ;these point to physical addr starting at 0xf010 00162 ;and are used for eeprom read/write operations 00000010 00163 ee equ 0x10 00164 00000010 00165 el78 equ ee ;78 rpm 00000011 00166 eh78 equ ee+1 00167 00000012 00168 el45 equ ee+2 ;45 rpm 00000013 00169 eh45 equ ee+3 00170 00000014 00171 el33 equ ee+4 ;33 rpm 00000015 00172 eh33 equ ee+5 00173 00174 ;------------------------------------------------------------------------------ 00175 ; 00176 ; EEPROM INITIAL PROGRAMMING 00177 ; The 16F1823 has 256 bytes of non-volatile EEPROM, starting at address 0xF000 00178 ; This is referenced as 0x00-0xFF in read/write operations 00179 ; 00180 ;------------------------------------------------------------------------------ 00181 8000 00182 USRID ORG 0X8000 ;0x784533 USER id 8000 0033 00183 DE 0x33 8001 0045 00184 DE 0X45 8002 0078 00185 DE 0X78 8003 0000 00186 DE 0 00187 F000 00188 DATAEE ORG 0xf000 F000 0042 0069 006C 00189 DE "BillThompson.us" ;Place creator at address 0-14 006C 0054 0068 006F 006D 0070 0073 006F 006E 002E 0075 0073 00190 F010 00191 ORG 0xf010 ;initial speed data in eeprom 0x10-0x15 F010 0053 00192 DE l78 ;78rpm ;programmed at burn time, updated later F011 00F5 00193 DE h78 ;by encoder F012 004B 00194 DE l45 ;45rpm F013 00ED 00195 DE h45 F014 00A9 00196 DE l33 ;33rpm F015 00E6 00197 DE h33 00198 MPASM 5.51 SERVO-1823-BT-T2S.ASM 1-20-2016 16:38:05 PAGE 5 LOC OBJECT CODE LINE SOURCE TEXT VALUE 00199 ;------------------------------------------------------------------------------ 00200 ; RESET VECTOR 00201 ;------------------------------------------------------------------------------ 00202 0000 00203 ORG 0x0000 ;processor reset vector 0000 2816 00204 GOTO init ;initialize and start pgm 00205 00206 ;------------------------------------------------------------------------------ 00207 ; INTERRUPT SERVICE ROUTINE 00208 ; there are 2 interrupts, one from the tachometer when it 00209 ; changes state, the other from the timer when it times out. 00210 ; the hardware integrator adjusts the motor speed to get a 50% 00211 ; duty cycle +/- a small amount determined by the fine adjust 00212 ; control. (if used) 00213 ; If the interrupt is not the timer it must be the tachometer. 00214 ;------------------------------------------------------------------------------ 00215 0004 00216 ORG 0x0004 00217 00218 ;see if interrupt was from the timer 00219 ;if not, its the tachometer, restart timer and output high (integrate down) 00220 ;if so, output low (integrate up,) and wait for tachometer change 00221 ;write port directly to save banksel 05/19/2015 00222 ; 00223 ;16f1823 has automatic context save for interrupts 0004 0020 00224 banksel 0 ;(could be in any bank when interrupt happens) 0005 1811 00225 btfsc PIR1,TMR1IF ;a timer interrupt? (false if so) 0006 280E 00226 goto timi1 ;yes, go handle it 00227 00228 ;else interrupt is from tachometer state change 0007 150C 00229 bsf PORTA,RA2 ;out high, integrate down write port directly 05/19/2015 0008 1418 00230 bsf T1CON,TMR1ON ;restart timer (already preset) 00231 0009 080C 00232 movf PORTA,W ;read port A for int on change sync 000A 00A0 00233 movwf gpcopy ;and store it for read in main loop 00234 000B 0027 00235 banksel IOCAF 000C 0193 00236 clrf IOCAF ;clear interrupt on change 00237 000D 0009 00238 retfie ;return from interrupt 00239 00240 ;interrupt is from timer 1 overflow 00241 ;RA2 is the only port A output, clearing the whole port 00242 ;only affects RA2. 000E 00243 timi1 000E 018C 00244 clrf PORTA ;out low, integrate up - write port directly 05/19/2015 000F 1018 00245 bcf T1CON,TMR1ON ;stop timer 00246 0010 0829 00247 movf rtiml,W ;preset timer to countdown value 0011 0096 00248 movwf TMR1L ;from speed ramp counter 05/11/2015 0012 082A 00249 movf rtimh,W 0013 0097 00250 movwf TMR1H 00251 MPASM 5.51 SERVO-1823-BT-T2S.ASM 1-20-2016 16:38:05 PAGE 6 LOC OBJECT CODE LINE SOURCE TEXT VALUE 0014 0191 00252 clrf PIR1 ;clear timer interrupt 00253 0015 0009 00254 retfie ;return from interrupt 00255 00256 ;-------------------------------------------------------------------- 00257 ; main program starts here 00258 ; initialize everything 00259 ;-------------------------------------------------------------------- 0016 00260 init 0016 0020 00261 banksel INTCON 0017 018B 00262 clrf INTCON ;make sure interrupts are disabled 00263 0018 0021 00264 banksel OSCCON ;XT xtal clock, PLL 0019 3080 00265 movlw b'10000000' 001A 0099 00266 movwf OSCCON 00267 001B 0023 00268 banksel ANSELA ;no analog inputs, all digital 001C 018C 00269 clrf ANSELA 001D 018E 00270 clrf ANSELC 00271 00272 ;set up timer 1 for system clock, no prescaler, no sync 001E 0020 00273 banksel T1CON 001F 3044 00274 movlw b'01000100' ;tmr1 clock=sys, no sync, timer stopped 0020 0098 00275 movwf T1CON 0021 0199 00276 clrf T1GCON ;no timer 1 gate control 00277 0022 0021 00278 banksel OPTION_REG 0023 3007 00279 movlw b'00000111' 0024 0095 00280 movwf OPTION_REG ;global weak pullup, tmr0 sys clk. 256 tmr0 prescale 00281 0025 0024 00282 banksel WPUA ;weak pullups on RA0-1 speed sel sw. 0026 3003 00283 movlw b'000011' ;for speed sel switch 0027 008C 00284 movwf WPUA 0028 018E 00285 clrf WPUC ;no weak pullups on PORTC 00286 0029 0021 00287 banksel PIE1 002A 0191 00288 clrf PIE1 ;disable all PIE1 interrupts except 002B 1411 00289 bsf PIE1,TMR1IE ;enable timer 1 overflow interrupt 002C 0192 00290 clrf PIE2 ;disable all PIE2 interrupts 00291 002D 0020 00292 banksel PIR1 002E 0191 00293 clrf PIR1 ;clear any pending timer interrupts 002F 0192 00294 clrf PIR2 0030 0027 00295 banksel IOCAF 0031 0193 00296 clrf IOCAF ;clear interrupt on change 00297 0032 0021 00298 banksel TRISA 0033 303B 00299 movlw B'111011' ;Set RA2 as output 0034 008C 00300 movwf TRISA ;all others as inputs - RA<4-5> used for xtal 0035 3003 00301 movlw B'000011' ;Set RC0-1 inputs for encoder 0036 008E 00302 movwf TRISC ;and RC2-5 outputs for diag led's 00303 0037 0022 00304 banksel LATA MPASM 5.51 SERVO-1823-BT-T2S.ASM 1-20-2016 16:38:05 PAGE 7 LOC OBJECT CODE LINE SOURCE TEXT VALUE 0038 018C 00305 clrf LATA ;clear port latches 0039 018E 00306 clrf LATC ;and turn led's off 00307 003A 0027 00308 banksel IOCAN ;interrupt on change for tachometer. 003B 3008 00309 movlw b'001000' ;both directions on RA3 003C 0092 00310 movwf IOCAN 003D 0091 00311 movwf IOCAP 00312 003E 0020 00313 banksel 0 ;back to bank 0 00314 00315 00316 ;------------------------------------------------------------- 00317 00318 ;start things in a known state 00319 ;timer 1 003F 01A7 00320 clrf timl ;set rpm timer at start speed 0040 01A9 00321 clrf rtiml ;and ramp timer 00322 0041 307F 00323 movlw startspd ;initial motor start speed (high byte only) 0042 00A8 00324 movwf timh ;main and ramp timers 0043 00AA 00325 movwf rtimh 00326 0044 3008 00327 movlw rampspd ;set ramp speed 0045 00AB 00328 movwf rampcnt 00329 00330 ;8 bit counter for encoder speed 0046 01AC 00331 clrf enctim ;set encoder speed counter to slow (0xff) 0047 03AC 00332 decf enctim,f 00333 00334 ;16 bit counter for eeprom update 0048 01AD 00335 clrf eetiml ;clear (stop) eeprom update counter 0049 01AE 00336 clrf eetimh 00337 00338 ;read current encoder bits 004A 080E 00339 movf PORTC,W ;read port C to W 004B 3903 00340 andlw b'00000011' ;mask all but RC0-1 (encoder) 004C 00AF 00341 movwf encold ;preset encoder storage to current state 004D 00B0 00342 movwf encnew 00343 00344 ;load speed data from eeprom 00345 ;(as updated by last adjustments) 004E 3010 00346 movlw el78 004F 2147 00347 call eerd1 ;get 78 data from eeprom 0050 00A1 00348 movwf spl78 ;store it in ram 0051 3011 00349 movlw eh78 0052 2147 00350 call eerd1 ;get 78 data from eeprom 0053 00A2 00351 movwf sph78 ;store it in ram 00352 0054 3012 00353 movlw el45 0055 2147 00354 call eerd1 ;get 45 data from eeprom 0056 00A3 00355 movwf spl45 ;store it in ram 0057 3013 00356 movlw eh45 0058 2147 00357 call eerd1 ;get 45 data from eeprom MPASM 5.51 SERVO-1823-BT-T2S.ASM 1-20-2016 16:38:05 PAGE 8 LOC OBJECT CODE LINE SOURCE TEXT VALUE 0059 00A4 00358 movwf sph45 ;store it in ram 00359 005A 3014 00360 movlw el33 005B 2147 00361 call eerd1 ;get 33 data from eeprom 005C 00A5 00362 movwf spl33 ;store it in ram 005D 3015 00363 movlw eh33 005E 2147 00364 call eerd1 ;get 33 data from eeprom 005F 00A6 00365 movwf sph33 ;store it in ram 00366 00367 ;------------------------------------------------------------------------ 00368 ;start with integrator low 00369 ;integrate down and wait for .05 sec, then start polling loop. 00370 ;let integrator ramp up from low at start 00371 0060 150C 00372 bsf PORTA,RA2 ;integrate down, stop motor 00373 0061 01B6 00374 clrf counta ;preset counter 0062 01B7 00375 clrf countb ;for .05 sec. delay 00376 00377 ;delay approx .05 sec 0063 00378 ca 0063 0FB6 00379 incfsz counta,f 0064 2863 00380 goto ca 0065 00381 cb 0065 0FB7 00382 incfsz countb,f 0066 2863 00383 goto ca 00384 0067 018C 00385 clrf PORTA ;integrate up, start motor 00386 00387 ;------------------------------------------------------------------------- 00388 ;now enable interrupts 0068 30C8 00389 movlw b'11001000' ;enable global and peripheral interrupts 0069 008B 00390 movwf INTCON ;and global int on change 00391 00392 ;------------------------------------------------------------------------ 00393 00394 ;initialization done, main program loop starts here 00395 00396 ;speed ramp here to start motor gradually. 00397 ;this may help prevent throwing belts! 00398 ;05/11/2015 00399 00400 ;ramp up motor slowly initially or if speed changes 00401 ;executes in main loop before polling routines 00402 ;rampcnt defines how many main loops are executed 00403 ;before the ramp code executes. This sets the ramp speed. 00404 ;there is additional code to slow down the ramp as motor 00405 ;approaches higher speeds. 00406 00407 ;don't waste time once motor has stabilized 00408 006A 00409 ramp 00410 MPASM 5.51 SERVO-1823-BT-T2S.ASM 1-20-2016 16:38:05 PAGE 9 LOC OBJECT CODE LINE SOURCE TEXT VALUE 00411 ;---------------------------------------------------------- 00412 00413 #ifdef rampup ;if ramp-up speed 00414 decfsz rampcnt,f 00415 goto poll ;only ramp when ramp counter wraps 00416 00417 ;skip ramp if tim=rtim 00418 movf rtiml,W ;low byte equal? 00419 xorwf timl,W 00420 btfss STATUS,Z 00421 goto ramp0 ;no, may need ramp 00422 00423 movf rtimh,W ;yes, high byte equal? 00424 xorwf timh,W 00425 btfsc STATUS,Z 00426 goto poll ;yes, skip ramp code if rtim=tim 00427 00428 ramp0 movlw rampspd ;not equal, reset ramp counter 00429 movwf rampcnt 00430 00431 ;see if updated speed is higher or lower, ramp up but not down 00432 movf rtiml,W ;get ramp timer 00433 subwf timl,W ;subtract from low byte 00434 movf rtimh,W 00435 subwfb timh,W ;borrow to high byte 00436 00437 btfss STATUS,C ;carry set if rtim < tim 00438 goto noramp ;don't ramp if equal or more (equal shouldn't get here) 00439 00440 ;new speed is faster so ramp up 00441 ;-------------------------------------------------------- 00442 ;adjust to slow the up ramp at faster speeds 00443 movf rtimh,W ;get hi byte ramp timer 00444 andlw b'11110000' ;mask low nibble 00445 xorlw 0xc0 ;4th fastest range? 00446 btfsc STATUS,Z 00447 goto rampc3 ;yes, 1/2 speed 00448 00449 rampa movf rtimh,W ;get hi byte ramp timer 00450 andlw b'11110000' ;mask low nibble 00451 xorlw 0xd0 ;3rd fastest range? 00452 btfsC STATUS,Z 00453 goto rampc2 ;yes 1/4 speed 00454 00455 rampb 00456 movf rtimh,W ;get hi byte ramp timer 00457 andlw b'11110000' ;mask low nibble 00458 xorlw 0xe0 ;2nd fastest range? 00459 btfsC STATUS,Z 00460 goto rampc1 ;yes 1/8 speed 00461 00462 rampc 00463 movf rtimh,W ;get hi byte ramp timer MPASM 5.51 SERVO-1823-BT-T2S.ASM 1-20-2016 16:38:05 PAGE 10 LOC OBJECT CODE LINE SOURCE TEXT VALUE 00464 andlw b'11110000' ;mask low nibble 00465 xorlw 0xf0 ;fastest range? 00466 btfss STATUS,Z 00467 goto ramp1 ;no, must be slower, no adjustment 00468 00469 rampc0 lslf rampcnt,f ;1/16 speed 00470 rampc1 lslf rampcnt,f ;1/8 speed 00471 rampc2 lslf rampcnt,f ;1/4 speed 00472 rampc3 lslf rampcnt,f ;1/2 speed 00473 ;------------------------------------------------------------------ 00474 00475 ;ramp-up routine 00476 ;increment 16 bit time by 1 00477 ramp1 00478 incfsz rtiml,f ;ramp up 1 if less 00479 goto poll ;go polling if no hi byte incr 00480 incf rtimh,f ;increment hi byte if low byte wrapped 00481 goto poll ;and go do polling 00482 00483 #endif ;end if ramp-up speed 00484 00485 ;------------------------------------------------------------------ 00486 00487 ;here if new speed is lower - jump speed down 006A 00488 noramp 006A 0827 00489 movf timl,W ;set fully ramped 006B 00A9 00490 movwf rtiml ;make sure rtim = tim 006C 0828 00491 movf timh,W 006D 00AA 00492 movwf rtimh 00493 00494 ;start main polling routines 00495 ; 00496 ;polling includes: 00497 ;1. servicing counters for encoder rotation speed detection and eeprom update timing 00498 ;2. reading encoder 00499 ;3. reading speed selector switch 00500 ;4. updating speed data based on encoder readings for 00501 ; whichever of 3 speeds is selected 00502 00503 ;check our master .5mS counter (timer 0) 006E 00504 poll 006E 1D0B 00505 btfss INTCON,TMR0IF ;timer 0 overflow? 006F 2886 00506 goto encrd ;no go look at encoder 00507 00508 ;-------------------------------------------------------------------- 00509 00510 ;each .5mS, service encoder speed and eeprom update counters 0070 00511 tm0clr ;yes, reset .5ms timer and update counters 0070 30F8 00512 movlw b'11111000' ;preset timer 0 to overflow in 8 prescale clocks 0071 0095 00513 movwf TMR0 ;for a total of .5mS 00514 0072 110B 00515 bcf INTCON,TMR0IF ;clear timer0 overflow for next time 00516 MPASM 5.51 SERVO-1823-BT-T2S.ASM 1-20-2016 16:38:05 PAGE 11 LOC OBJECT CODE LINE SOURCE TEXT VALUE 00517 ;increment counters - there are 2 counters. 00518 ; 00519 ;The first is a 16 bit counter for eeprom writing. 00520 ;if its 0, its not incremented. When there's an encoder change 00521 ;its set to 1 and then counts up. Every encoder change presets it 00522 ;to 1 so it starts over. When there's been no encoder change for 00523 ;approx 32 sec, it wraps to 0, causes an eeprom write, and then 00524 ;stays at 0 until there's another encoder change. 00525 ; 00526 ;The second counter determines speed of encoder rotation and 00527 ;is used to specify step size for course and fine speed adjustment. 00528 ;Every encoder change reads this counter value 00529 ;and then resets it. When it reaches 0xff its held there to specify 00530 ;the slowest rotation measurement. Not timed out causes the 00531 ;faster adjustment to be used. It should reach 0xff in approx. 32mS. 00532 ;so steps less than 32mS apart use the faster speed and steps 00533 ;more than 32mS apart use the slower speed 00534 ;04/22/2015 - now turn off all led's after eeprom write. 00535 00536 ;watch eeprom update timer on RC5 led 0073 082D 00537 movf eetiml,W ;running? 0074 042E 00538 iorwf eetimh,W ;not if 0x0000 0075 1D03 00539 btfss STATUS,Z ;Z set if not running 0076 287B 00540 goto on5 00541 0077 00542 off5 0077 0022 00543 banksel LATC ;eeprom counter is not running 0078 018E 00544 clrf LATC ;set all leds off if not running 0079 0020 00545 banksel 0 007A 2883 00546 goto noup ;no eeprom update if counter not running 00547 007B 00548 on5 007B 0022 00549 banksel LATC ;eeprom counter is running 007C 168E 00550 bsf LATC,RC5 ;set led 5 on if running 007D 0020 00551 banksel 0 00552 00553 ;increment eeprom update counter, when it reaches 0:0 00554 ;initiate an eeprom update write and then leave counter 00555 ;at 0:0 until there's an encoder change 007E 00556 ckee 007E 0FAD 00557 incfsz eetiml,f ;here if counter is running, count up 007F 2883 00558 goto noup ;if not 0 no increment hi, no eeprom update 0080 0FAE 00559 incfsz eetimh,f ;increment hi, timed out if 0 0081 2883 00560 goto noup ;if not 0, not timed out. no eeprom update 00561 00562 ;update eeprom data if eeprom update timer timed out 0082 2100 00563 call eeupd ;if 0:0, update, stay at 0:0 till next encoder change 00564 00565 ;increment encoder speed timer, 0083 00566 noup 0083 0FAC 00567 incfsz enctim,f ;increment encoder rotation timer 0084 2886 00568 goto encrd 0085 03AC 00569 decf enctim,f ;hold at 0xff if max time MPASM 5.51 SERVO-1823-BT-T2S.ASM 1-20-2016 16:38:05 PAGE 12 LOC OBJECT CODE LINE SOURCE TEXT VALUE 00570 00571 ;------------------------------------------------------------------- 00572 00573 ;encoder service - flag change, note speed and direction 00574 ;read encoder, see if it changed 0086 00575 encrd 0086 01B3 00576 clrf encspd ;preset set encoder speed at 0 for no change 0087 080E 00577 movf PORTC,W ;read port B to W 0088 3903 00578 andlw b'00000011' ;mask all but RC0-1 (encoder) 0089 00B1 00579 movwf etmp ;keep it to tmp 00580 008A 0830 00581 movf encnew,W ;move the previous "New" value 008B 00AF 00582 movwf encold ;to "Old" file register 008C 0831 00583 movf etmp,W ;then move the new value 008D 00B0 00584 movwf encnew ;to "New" file register 00585 008E 062F 00586 xorwf encold,W ;xor old and new 008F 1903 00587 btfsc STATUS,Z ;xor=0=no change 0090 28B1 00588 goto ckspeed ;nothing changed, goto speed selector 00589 00590 ;------------------------------------------------------------------- 00591 00592 ;here if encoder has changed 00593 ;restart eeprom update counter and determine encoder rotation speed 00594 ;toggle rc2 led on each encoder change 0091 3004 00595 movlw b'000100' 0092 0022 00596 banksel LATC 0093 068E 00597 xorwf LATC,f ;toggle rc2 led 0094 0020 00598 banksel 0 00599 00600 ;restart eeprom update timer on each encoder change 0095 00601 espd 0095 01AD 00602 clrf eetiml 0096 01AE 00603 clrf eetimh 0097 0AAD 00604 incf eetiml,f ;preset eeprom update counter for approx 32 sec count 00605 00606 ;determine encoder rotation speed 0098 0F2C 00607 incfsz enctim,W ;see if encoder timer timed out 0099 289F 00608 goto efast ;no, set fast speed 00609 00610 ;get constant for fast or slow encoder speed 00611 ;indicate slow speed by turning off led 4 009A 00612 eslow 009A 0022 00613 banksel LATC 009B 120E 00614 bcf LATC,RC4 ;clear led 4 009C 0020 00615 banksel 0 009D 3001 00616 movlw e_slow ;get slow speed constant in W 009E 28A3 00617 goto ckenc 00618 00619 ;indicate fast speed by turning on led 4 009F 00620 efast 009F 0022 00621 banksel LATC 00A0 160E 00622 bsf LATC,RC4 MPASM 5.51 SERVO-1823-BT-T2S.ASM 1-20-2016 16:38:05 PAGE 13 LOC OBJECT CODE LINE SOURCE TEXT VALUE 00A1 0020 00623 banksel 0 00A2 3008 00624 movlw e_fast ;get fast speed constant in W 00625 00A3 00626 ckenc 00A3 00B3 00627 movwf encspd ;store encoder speed 00A4 30C0 00628 movlw b'11000000' ;reset encoder timer for 64 counts (32mS) 00A5 00AC 00629 movwf enctim ;preset timer starting count value (always counting) 00630 00631 ;get encoder direction 00A6 01B4 00632 clrf encdir ;assume ccw direction 00633 00A7 082F 00634 movf encold,W ;move the right 00A8 3901 00635 andlw b'00000001' ;bit of the 00A9 00B2 00636 movwf etmp2 ;OLD value to etmp2 00637 00AA 0830 00638 movf encnew,W ;move the left 00AB 3902 00639 andlw b'00000010' ;bit of the 00AC 00B1 00640 movwf etmp ;new value to etmp 00641 00AD 3631 00642 lsrf etmp,W ;shift right one bit etmp 00AE 0632 00643 xorwf etmp2,W ;xor them. if it is zero CCW else CW 00AF 1D03 00644 btfss STATUS,Z ;leave at 0 if ccw (skip next) 00645 00B0 14B4 00646 bsf encdir,1 ;else make it 1 if CW 00647 00648 ;--------------------------------------------------------------------- 00649 00650 ;show encoder direction on rc3 led 00B1 00651 ckspeed 00B1 082D 00652 movf eetiml,W ;only turn led on if eeprom counter is running 00B2 042E 00653 iorwf eetimh,W ;not if 0x0000 00B3 1903 00654 btfsc STATUS,Z ;Z set if not running 00B4 28BB 00655 goto cks1 ;don't check further if not running 00656 00B5 1CB4 00657 btfss encdir,1 ;else, is it cw? 00B6 28BB 00658 goto cks1 ;no, turn led off 00659 00B7 0022 00660 banksel LATC 00B8 158E 00661 bsf LATC,RC3 ;yes, turn on 00B9 0020 00662 banksel 0 00BA 28BE 00663 goto cks2 00664 00BB 00665 cks1 00BB 0022 00666 banksel LATC ;turn off led 00BC 118E 00667 bcf LATC,RC3 00BD 0020 00668 banksel 0 00669 00670 ;--------------------------------------------------------------------- 00671 00672 ;speed selection and update motor speed 00673 ;read turntable speed selector switch 00BE 00674 cks2 00BE 1CA0 00675 btfss gpcopy,1 ;78 selected? MPASM 5.51 SERVO-1823-BT-T2S.ASM 1-20-2016 16:38:05 PAGE 14 LOC OBJECT CODE LINE SOURCE TEXT VALUE 00BF 28D6 00676 goto tim78 ;yes, do 78 00C0 1820 00677 btfsc gpcopy,0 ;33 selected? 00C1 28CC 00678 goto tim45 ;no, do 45 00679 ;yes, fall into tim33 00680 00681 ;---------------------------------------------------------------- 00682 00683 ;speed select routines 00684 ;get constants for appropriate speed and update 00685 ;speed data based on last encoder change if any 00C2 00686 tim33 00C2 0825 00687 movf spl33,W ;delay for 33 rpm 00C3 00A7 00688 movwf timl ;get current 33 constants 00C4 0826 00689 movf sph33,W 00C5 00A8 00690 movwf timh 00C6 20E0 00691 call timadj ;adjust time by encoder data if changed 00C7 0827 00692 movf timl,W ;update speed data in ram 00C8 00A5 00693 movwf spl33 00C9 0828 00694 movf timh,w 00CA 00A6 00695 movwf sph33 00CB 286A 00696 goto ramp ;back to top of main loop 00697 00CC 00698 tim45 00CC 0823 00699 movf spl45,W ;delay for 45 rpm 00CD 00A7 00700 movwf timl ;get current 45 constants 00CE 0824 00701 movf sph45,W 00CF 00A8 00702 movwf timh 00D0 20E0 00703 call timadj ;adjust time by encoder data if changed 00D1 0827 00704 movf timl,W ;update speed data in ram 00D2 00A3 00705 movwf spl45 00D3 0828 00706 movf timh,w 00D4 00A4 00707 movwf sph45 00D5 286A 00708 goto ramp ;back to top of main loop 00709 00D6 00710 tim78 00D6 0821 00711 movf spl78,W ;delay for 78 rpm 00D7 00A7 00712 movwf timl ;get current 78 constants 00D8 0822 00713 movf sph78,W 00D9 00A8 00714 movwf timh 00DA 20E0 00715 call timadj ;adjust time by encoder data if changed 00DB 0827 00716 movf timl,W ;update speed data in ram 00DC 00A1 00717 movwf spl78 00DD 0828 00718 movf timh,W 00DE 00A2 00719 movwf sph78 00DF 286A 00720 goto ramp ;back to top of main loop 00721 00722 ;--------------------subroutines------------------------------- 00723 00724 ;subroutine to adjust speed data per encoder 00725 ;returns with 16 bit adjusted data in timl, timh 00726 ;just return doing nothing if no encoder change 00E0 00727 timadj 00E0 0103 00728 clrw ;see if encoder speed adj value is 0 MPASM 5.51 SERVO-1823-BT-T2S.ASM 1-20-2016 16:38:05 PAGE 15 LOC OBJECT CODE LINE SOURCE TEXT VALUE 00E1 0433 00729 iorwf encspd,W ;if its 0, no encoder change 00E2 1903 00730 btfsc STATUS,Z 00E3 0008 00731 return ;do nothing if its 0, else continue 00732 00E4 1CB4 00733 btfss encdir,1 ;get direction (1 is cw) 00E5 28F3 00734 goto eccw ;skip if not ccw 00735 00736 ;add if cw 00E6 00737 ecw 00E6 0833 00738 movf encspd,W ;get speed adj 00E7 07A7 00739 addwf timl,f ;add to low byte 00E8 0103 00740 clrw 00E9 3DA8 00741 addwfc timh,f ;carry to high byte 00742 00743 ;check if over limit, set to limit if so 00EA 3005 00744 movlw (d'256'-hilim) ;get high time limit (subtr from 256) 00EB 0728 00745 addwf timh,W ;add to time high byte 00EC 1C03 00746 btfss STATUS,C ;over? 00ED 28F1 00747 goto hok ;no leave alone 00EE 30FB 00748 movlw hilim ;yes, set at high limit 00EF 00A8 00749 movwf timh 00F0 01A7 00750 clrf timl 00F1 00751 hok 00F1 01B3 00752 clrf encspd ;zero out enc speed so we don't update again 00F2 0008 00753 return 00754 00755 ;subtract if ccw 00F3 00756 eccw 00F3 0833 00757 movf encspd,W ;get speed adj 00F4 02A7 00758 subwf timl,f ;subtract from to low byte 00F5 0103 00759 clrw 00F6 3BA8 00760 subwfb timh,f ;borrow to high byte 00761 00762 ;check if under limit, set to limit if so 00F7 30C8 00763 movlw lolim ;get low time limit 00F8 0228 00764 subwf timh,W ;subtract from time low byte 00F9 1803 00765 btfsc STATUS,C ;under? 00FA 28FE 00766 goto lok ;no leave alone 00FB 30C8 00767 movlw lolim ;yes, set at low limit 00FC 00A8 00768 movwf timh 00FD 01A7 00769 clrf timl 00FE 00770 lok 00FE 01B3 00771 clrf encspd ;zero out enc speed so we don't update again 00FF 0008 00772 return 00773 00774 ;--------------------------------------------------- 00775 00776 ;subroutine to update eeprom speed data 00777 ;do this after encoder activity followed 00778 ;by 32 sec of inactivity 00779 00780 ;read eeprom and compare to current setting 00781 ;only update what's changed MPASM 5.51 SERVO-1823-BT-T2S.ASM 1-20-2016 16:38:05 PAGE 16 LOC OBJECT CODE LINE SOURCE TEXT VALUE 00782 0100 00783 eeupd 0100 3014 00784 movlw el33 ;get eeprom data in W 0101 00B5 00785 movwf ee_addr ;33 low byte 0102 2146 00786 call eeread 0103 0625 00787 xorwf spl33,W ;changed? 0104 1903 00788 btfsc STATUS,Z 0105 2908 00789 goto xh33 0106 0825 00790 movf spl33,W ;yes, write new 0107 2131 00791 call eewrt 00792 0108 00793 xh33 0108 3015 00794 movlw eh33 ;get eeprom data in W 0109 00B5 00795 movwf ee_addr ;33 high byte 010A 2146 00796 call eeread 010B 0626 00797 xorwf sph33,W ;changed? 010C 1903 00798 btfsc STATUS,Z 010D 2910 00799 goto xl45 010E 0826 00800 movf sph33,W ;yes, write new 010F 2131 00801 call eewrt 00802 0110 00803 xl45 0110 3012 00804 movlw el45 ;get eeprom data in W 0111 00B5 00805 movwf ee_addr ;45 low byte 0112 2146 00806 call eeread 0113 0623 00807 xorwf spl45,W ;changed? 0114 1903 00808 btfsc STATUS,Z 0115 2918 00809 goto xh45 0116 0823 00810 movf spl45,W ;yes, write new 0117 2131 00811 call eewrt 00812 0118 00813 xh45 0118 3013 00814 movlw eh45 ;get eeprom data in W 0119 00B5 00815 movwf ee_addr ;45 high byte 011A 2146 00816 call eeread 011B 0624 00817 xorwf sph45,W ;changed? 011C 1903 00818 btfsc STATUS,Z 011D 2920 00819 goto xl78 011E 0824 00820 movf sph45,W ;yes, write new 011F 2131 00821 call eewrt 00822 0120 00823 xl78 0120 3010 00824 movlw el78 ;get eeprom data in W 0121 00B5 00825 movwf ee_addr ;78 low byte 0122 2146 00826 call eeread 0123 0621 00827 xorwf spl78,W ;changed? 0124 1903 00828 btfsc STATUS,Z 0125 2928 00829 goto xh78 0126 0821 00830 movf spl78,W ;yes, write new 0127 2131 00831 call eewrt 00832 0128 00833 xh78 0128 3011 00834 movlw eh78 ;get eeprom data in W MPASM 5.51 SERVO-1823-BT-T2S.ASM 1-20-2016 16:38:05 PAGE 17 LOC OBJECT CODE LINE SOURCE TEXT VALUE 0129 00B5 00835 movwf ee_addr ;78 high byte 012A 2146 00836 call eeread 012B 0622 00837 xorwf sph78,W ;changed? 012C 1903 00838 btfsc STATUS,Z 012D 0008 00839 return ;no, we're done, return 012E 0822 00840 movf sph78,W ;yes, write new 012F 2131 00841 call eewrt 00842 0130 0008 00843 return ;and return, all updates done 00844 00845 ;---------------------------------------------------------------- 00846 ;eeprom read and write subroutines 00847 00848 ;subroutine for EEPROM write 00849 ;address in ee_addr, byte to write in W 0131 00850 eewrt 0131 0023 00851 banksel EEDATL 0132 0093 00852 movwf EEDATL ;Data Memory Value to write in W 00853 0133 0020 00854 banksel 0 0134 0835 00855 movf ee_addr,W ;get address to write 0135 0023 00856 banksel EEADRL 0136 0091 00857 movwf EEADRL ;Data Memory Address to write 00858 0137 1315 00859 bcf EECON1,CFGS ;Deselect Configuration space 0138 1395 00860 bcf EECON1,EEPGD ;Point to DATA memory 0139 1515 00861 bsf EECON1,WREN ;Enable writes 00862 013A 138B 00863 bcf INTCON,GIE ;Disable Interrupts. 013B 3055 00864 movlw 0x55 013C 0096 00865 movwf EECON2 ;Write 55h 013D 30AA 00866 movlw 0xAA 013E 0096 00867 movwf EECON2 ;Write AAh 013F 1495 00868 bsf EECON1,WR ;Set WR bit to begin write 0140 178B 00869 bsf INTCON,GIE ;Enable Interrupts 0141 1115 00870 bcf EECON1,WREN ;Disable further writes 00871 0142 00872 eewait 0142 1895 00873 btfsc EECON1,WR ;Wait for write to complete 0143 2942 00874 goto eewait 00875 0144 0020 00876 banksel 0 ;done, back to bank 0 default 0145 0008 00877 return ;and return after write 00878 00879 ;subroutine for EEPROM read 00880 ;Address to read is in eeaddrl 00881 ;returns with value in W 00882 ;there are 2 entry points, the first with the addr to read 00883 ;in ee_addr, the second with the addr to read in W 0146 00884 eeread ;enter here with addr in ee_addr 0146 0835 00885 movf ee_addr,W ;get addr to read in W 0147 00886 eerd1 ;enter here with addr in W 0147 0023 00887 banksel EEADRL ;or start here with addr to read in W MPASM 5.51 SERVO-1823-BT-T2S.ASM 1-20-2016 16:38:05 PAGE 18 LOC OBJECT CODE LINE SOURCE TEXT VALUE 0148 0091 00888 movwf EEADRL ;set addr to read 00889 0149 1315 00890 bcf EECON1,CFGS ;Deselect Config space 014A 1395 00891 bcf EECON1,EEPGD ;Point to DATA memory 014B 1415 00892 bsf EECON1,RD ;EE Read 014C 0813 00893 movf EEDATL,W ;W = read data 00894 014D 0020 00895 banksel 0 ;back to bank 0 default 014E 0008 00896 return ;return with requested data in W 00897 00898 END