; rotary.asm ; Program to demonstrate the use of the rotary encoder. ; The rotary encoder is a mechanical device with two switches that are normally closed. ; When the encoder is turned, the switches open and then close as each detent is passed. ; The encoder on the Raven board has 24 positions, so it can encode with a resolution of ; 360/24 = 15 degrees. The key thing is that the phase difference between the two outputs ; is different depending on the direction. For the encoder on the Raven board, turning ; clockwise, causes the RB2 output to go low first, and then the RB0/RB1 output. When ; turning counterclockwise, it is reversed. ; When turning clockwise, pins RB2 and RB1/RB0 go through a sequence ; 11 -> 01 -> 00 -> 10 -> 11 ; and when turning counter-clockwise, ; 11 -> 10 -> 00 -> 01 -> 11 ; When note is that this program takes a very simplistic approach to this, so it is ; possible to miss some transitions, particularly if you turn the encoder rapidly. ; What happens is that the polling routine misses a transition and then you can get a ; false reading. For example, you turn clockwise but miss a couple of transitions ; and it appears that the transition is from 11 to 10, which looks like a counter- ; clockwise rotation. This can be eliminated by polling more frequently, using ; interrupts or by keeping track of more information so that false readings can be ; detected. LIST P=16F877, R=DEC INCLUDE "P16F877.inc" ; Definitions ; __CONFIG _CP_OFF & _DEBUG_OFF & _WRT_ENABLE_OFF & _CPD_OFF & _LVP_OFF & _BODEN_OFF & _PWRTE_ON & _WDT_OFF & _HS_OSC20 ; Define start of vars RAM EQU 0x20 ; Variables Temp EQU RAM+0 OldPort EQU RAM+1 Direction EQU RAM+2 DTemp1 EQU RAM+3 DTemp2 EQU RAM+4 Counter EQU RAM+5 ; Start of the Program ORG 3 goto Start ORG 4 ; This loop polls port B and output the current direction. You can determine the speed ; by including a timer so that the number of "clicks" per unit time can be determined. ; After getting the port, determine the state of things. Since you could easily sample ; several times during a single move between detents, you have to consider that ; possibility. So Start bsf STATUS, RP0 clrf TRISB ; Set up the port B bits for input. In this case, we are not using RB0 and ; interrupts, so leave it as an output. ; bsf TRISB,0 bsf TRISB,1 bsf TRISB,2 clrf TRISA ; for led bank display clrf TRISD bcf STATUS, RP0 clrw clrf Direction main_loop movlw 0x1C movwf PORTA fill (nop),10 movf PORTB,W andlw 0x06 ; cleanup bits (change for using RB0) movwf Temp movlw 0x12 ; reenable ledbar movwf PORTA ; Debugging stuff - will display actual value of port B in the direction register when ; next updated. If you turn the encoder slowly, you can see the actual transitions ; on the pins for port B. ; movf Temp,W ; movwf Counter ; bcf STATUS,C ; rlf Counter,F ; rlf Counter,F ; rlf Counter,F ; rlf Counter,F ; movlw 0x0F ; andwf Direction,F ; movf Counter,W ; iorwf Direction,F ; Check to see if old value was b'00000110'. If not, do nothing here. movlw 0x06 xorwf OldPort,W btfss STATUS,Z goto rotary_out ; Last state was b'00000110' so check current state and see what to do. ; If still b'00000110', do nothing. If b'00000100', we are going counter ; clockwise; if b'00000010' clockwise; if b'00000000', ignore. btfsc Temp,1 goto bit1_set btfss Temp,2 goto rotary_out ; both are zero ; If we get here, bit 2 is high and bit 1 is low - counter-clockwise movement bsf Direction,0 goto rotary_out ; If we get here, bit 1 is set bit1_set btfsc Temp,2 goto rotary_out ; both are one ; If we get here, bit 2 is low and bit 1 is high - clockwise movement bcf Direction,0 goto rotary_out ; Output the current direction rotary_out movf Temp,W movwf OldPort movf Direction,W call DispLedBar goto main_loop ; ----------------------------------------------- ; Output a value to the LED bar DispLedBar ; Enable the led bar and put the value in W there. movwf Temp ; save W movlw 0x12 movwf PORTA comf Temp,W movwf PORTD return ; ------------------------- ; Delay milliseconds Delay_ms bsf STATUS,RP0 bsf STATUS,RP1 movwf DTemp1 dloop_0 ; number of ms to delay movlw 250 movwf DTemp2 dloop_1 ; 1 ms delay (approximately) fill (nop), 17 decfsz DTemp2,F goto dloop_1 decfsz DTemp1,F goto dloop_0 bcf STATUS,RP1 bcf STATUS,RP0 return END