; Lesson15c.asm - Encoder ; ; Determine which way we are turning the encoder ; ; Depending on the direction of rotation, illuminate LED 1 ; or LED 3. If an impossible value is calculated, ; illuminate LED2. ; ; This version uses the same table lookup algorithm as in ; Lesson15b, but the inputs are debounced before use. ; ; WB8RCR - 19-Aug-04 ; $Revision: 1.6 $ $Date: 2004-10-25 08:31:14-04 $ ; ;===================================================================== processor pic16f84a include p16f84a.inc __config _XT_OSC & _WDT_OFF & _PWRTE_ON list b=4,n=70 ; Port bit assignments LED1 equ 3 ; LED1 on PORTB LED2 equ 2 ; LED2 on PORTB LED3 equ 1 ; LED3 on PORTB ENC1 equ 0 ; Encoder 1 on PORTA ENC2 equ 1 ; Encoder 2 on PORTA HZ2000T equ D'1' ; Number of clock ticks for Hz2000 HZ10T equ D'200' ; Number of clock ticks for Hz10 cblock H'20' Input ; Store the debounced input Output ; Store the outputs ThisRead ; Current reading LastRead ; Remember previous reading Hz2000cnt ; Counter for 2000x/sec Hz10Cnt ; Counter for 10x/sec endc goto Start ;--------------------------------------------------------------------- ; 2000 times per second code here ;--------------------------------------------------------------------- ; In order to debounce the input, we won't accept a reading ; until we have seen the same input on two successive ; reads of the encoder spaced 1/2 ms apart. This is probably ; not as much time as we would like, but the encoders shiped ; with newer PIC-ELs generate their transitions in a very short ; space, so a slower read would likely miss transitions. Hz2000 ; Read the encoder bits movf PORTA,W ; Pick up the input word andlw H'03' ; Mask off all but encoder movwf ThisRead ; And save into current reading ; See if the same as last time movf ThisRead,W ; Pick up current xorwf LastRead,W ; Will be zero if same btfsc STATUS,Z ; Zero? goto NewReading ; Yes, will use reading movf ThisRead,W ; No, remember for movwf LastRead ; next time return ; Exit Hz2000 ; We now have two successive readings that are identical. ; Or them into the input word after shifting the existing ; contents left two bits and masking off any excess. NewReading movf ThisRead,W ; Remember for movwf LastRead ; next time ; Move last reading over 2 and mask other bits rlf Input,F ; Rotate the input storage rlf Input,F ; over two bits movlw B'00001100' ; Keep 2 bits from last time andwf Input,F ; but clear all others ; Move current status into input word movf ThisRead,W ; Pick up current reading iorwf Input,F ; And OR it into the input ; Set LEDs movf Input,W ; Pick up the input word addwf PCL,F ; Jump depending on value goto SetNo ; 0000 Same goto SetUp ; 0001 Up goto SetDn ; 0010 Down goto SetErr ; 0011 Error goto SetDn ; 0100 Down goto SetNo ; 0101 Same goto SetErr ; 0110 Error goto SetUp ; 0111 Up goto SetUp ; 1000 Up goto SetErr ; 1001 Error goto SetNo ; 1010 Same goto SetDn ; 1011 Down goto SetErr ; 1100 Error goto SetDn ; 1101 Down goto SetUp ; 1110 Up goto SetNo ; 1111 Same ; Movement is clockwise, turn on LED3 SetUp movlw B'00001100' ; Set LED3 (bit 1) on movwf Output ; (FALSE=LED on) return ; Movement is counterclockwise, turn on LED1 SetDn movlw B'00000110' ; Set LED1 (bit 3) on movwf Output ; (FALSE=LED on) return ; Got a bad combination, turn on LED2 SetErr movlw B'00001010' ; Set LED2 (bit 2) on movwf Output ; (FALSE=LED on) return ; No change, leave LEDs alone SetNo return ; Exit HZ10 ;--------------------------------------------------------------------- ; 10 times per second code here ;--------------------------------------------------------------------- ; Send the outputs Hz10 movf Output,W ; Pick up the output word movwf PORTB ; and send it to PORTB return ; Exit HZ10 ;--------------------------------------------------------------------- ; Mainline begins here ;--------------------------------------------------------------------- Start ; Initialize GP register locations clrf Input ; Clear the input storage clrf Output ; and the output storage movlw HZ2000T ; Initialize the Hz2000 movwf Hz2000cnt ; counter movlw HZ10T ; and the HZ10 counter movwf Hz10Cnt ; ; Set up timer errorlevel -302 ; Yes, we know! banksel INTCON bcf INTCON,T0IE ; Mask timer interrupt banksel OPTION_REG bcf OPTION_REG,T0CS ; Select timer bcf OPTION_REG,PSA ; Prescaler to timer bcf OPTION_REG,PS2 ; \ bcf OPTION_REG,PS1 ; >- 1:2 prescale bcf OPTION_REG,PS0 ; / ; Set the LEDs to be outputs banksel TRISB ; Select bank 1 bcf TRISB,LED1 ; Clear the TRIS bits bcf TRISB,LED2 ; for each of the LEDs bcf TRISB,LED3 ; making them outputs errorlevel +302 ; Back on just in case banksel PORTB ; Back to bank 0 ;--------------------------------------------------------------------- ; Main program loop here ;--------------------------------------------------------------------- main btfss INTCON,T0IF ; Did timer overflow? goto main ; No, hang around some more bcf INTCON,T0IF ; reset overflow flag ;--------------------------------------------------------------------- ; Check for 2000 times per second ;--------------------------------------------------------------------- decfsz Hz2000cnt,F ; Count down until Hz2000 goto $+4 ; Not time yet movlw HZ2000T ; Reset the counter so movwf Hz2000cnt ; it's available next time call Hz2000 ; Go do 2000X per second code ;--------------------------------------------------------------------- ; Check for 10 times per second ;--------------------------------------------------------------------- decfsz Hz10Cnt,F ; Count down until Hz10 goto $+4 ; Not time yet movlw HZ10T ; Reset the counter so movwf Hz10Cnt ; it's available next time call Hz10 ; Go do 10X per second code goto main end