Postat: 10 augusti 2006, 13:02:35
Annars kan man koppla t.ex. A till en interrupt-pinne och sen vid interrupt kolla läget på B för att besluta upp- eller ner-räkning.
Svenskt forum för elektroniksnack.
https://elektronikforumet.com/forum/
Kod: Markera allt
cblock H'20'
ROT_TMP ; Temporary byte for rotary encoder functions
ROT_INPUT ; Input of rotary encoder passed to ParseRotaryEncoder
ROT_STATE ; State of the rotary encoder, both passed and returned
ROT_VAL ; Value to be incremented or decremented each "complete
; turn" or the encoder. CW increments, CCW decrements.
endc
; *** ParseRotaryEncoder ***************************************************** ;
; ParseRotaryEncoder will compare input from ROT_INPUT and ROT_STATE, to see
; wheter the rotary encoder has moved in any (valid) direction since the last
; reading. It will update ROT_STATE to reflect the new state unless the input is
; the same as before.
;
; Explanation of bits ROT_INPUT and ROT_STATE
; ROT_INPUT: Contains nothing but 2 bit input of encoder in bits <0:1>. Period.
; ROT_STATE: Bits <0:1> contains old input of encoder (as compared to new in
; ROT_INPUT <0:1>. Bits<6:7> contains the moving direction of the
; encoder, where bit<6>=0 means CW and bit<6>=1 means CCW. Bit<7> is
; set if we are moving in any direction (usually ROT_INPUT != 0).
; **************************************************************************** ;
ParseRotaryEncoder:
; Test if new input is the same as old one, and if it is, return without
; doing anything else.
movf ROT_STATE, W
andlw H'3'
subwf ROT_INPUT, W
btfsc STATUS, Z
return ; Same input, return
; Calculate the moving direction, and at the same time we check
; wheter the "direction" is valid. We do this by putting the old input
; in W<2:3> and new input in W<0:1> and calling a lookup table.
movf ROT_STATE, W
andlw H'3'
movwf ROT_TMP
bcf STATUS, C ; Don't shift in unwanted carry flag
rlf ROT_TMP, F
rlf ROT_TMP, W
iorwf ROT_INPUT, W
call _ParseRotaryEncoder_DirectionTable
xorlw H'1' ; Change the direction since we did
; the lookup in "reverse" order
; Check wheter the moving direction is valid (make sure we didn't miss
; any inputs in between readings).
movwf ROT_TMP
btfss ROT_TMP, 1 ; Bit 1 will be set if rotation is valid
goto _ParseRotaryEncoder_ResetAndEnd
; Make sure we are moving in the same direction as before (just compare
; ROT_STATE<6:7> with newly returned direction).
bcf STATUS, C
rlf ROT_TMP, F
rlf ROT_TMP, F
swapf ROT_STATE, W
andlw H'C'
subwf ROT_TMP, W
btfss STATUS, Z
goto _ParseRotaryEncoder_TestFirstMove ; Direction not same...
call _ParseRotaryEncoder_SaveNewInput ; Same direction
; Test if new input is 00, which marks a "complete turn". Increment/
; decrement ROT_VAL every turn. Direction is determined by checking
; ROT_STATE<6>
movf ROT_INPUT, F
btfss STATUS, Z
return ; Still not a complete turn; return.
btfss ROT_STATE, 6
incf ROT_VAL ; CW direction, inc
btfsc ROT_STATE, 6
decf ROT_VAL ; CCW direction, dec
goto _ParseRotaryEncoder_ResetAndEnd
; === _ParseRotaryEncoder_SaveNewInput ======================================= ;
; Save new input from ROT_INPUT to ROT_STATE
; ============================================================================ ;
_ParseRotaryEncoder_SaveNewInput:
movlw H'FC'
andwf ROT_STATE
movf ROT_INPUT, W
iorwf ROT_STATE, F
return
; === _ParseRotaryEncoder_TestFirstMove ====================================== ;
; Test if ROT_STATE is uninitialized. If is is the movement is valid and we
; update it to reflect the new data. Otherwise reset ROT_STATE and return.
; ============================================================================ ;
_ParseRotaryEncoder_TestFirstMove:
movf ROT_STATE, W
andlw H'C0'
btfss STATUS, Z
goto _ParseRotaryEncoder_ResetAndEnd
; Save direction
swapf ROT_TMP, F
movlw H'3F'
andwf ROT_STATE, F
movf ROT_TMP, W
iorwf ROT_STATE, F
call _ParseRotaryEncoder_SaveNewInput ; Save input
goto _PortBInterrupt_End
; === _ParseRotaryEncoder_ResetAndEnd ======================================== ;
; Reset ROT_STATE and return
; ============================================================================ ;
_ParseRotaryEncoder_ResetAndEnd:
movlw H'0'
movwf ROT_STATE
return
; === _ParseRotaryEncoder_DirectionTable ===================================== ;
; W should contain old direction in bits<2:3> and new direction in bits<0:1>.
; We then return a value through W describing the direction, where 00 means no
; change or moving too fast. 01 and 11 for CW and CCW direction, respectively.
; ============================================================================ ;
_ParseRotaryEncoder_DirectionTable:
addwf PCL, 1
retlw B'00' ; 00 => 00, no change
retlw B'10' ; 00 => 01, CW
retlw B'11' ; 00 => 10, CCW
retlw B'00' ; 00 => 11, moving too fast
retlw B'11' ; 01 => 00, CCW
retlw B'00' ; 01 => 01, no change
retlw B'00' ; 01 => 10, moving too fast
retlw B'10' ; 01 => 11, CW
retlw B'10' ; 10 => 00, CW
retlw B'00' ; 10 => 01, moving too fast
retlw B'00' ; 10 => 10, no change
retlw B'11' ; 10 => 11, CCW
retlw B'00' ; 11 => 00, moving too fast
retlw B'11' ; 11 => 01, CCW
retlw B'10' ; 11 => 10, CW
retlw B'00' ; 11 => 11, no change
Kod: Markera allt
ISR(INT0_vect) //Channel A
{
if(bit_is_set(PIND, PD2)) //Rising edge
{
if(bit_is_set(PIND, PD3)) //If B is high decrement
{
ProcessVariable--;
} else { //Else increment
ProcessVariable++;
}
} else { //Falling edge
if(bit_is_set(PIND, PD3)) //If B is high increment
{
ProcessVariable++;
} else { //Else decrement
ProcessVariable--;
}
}
}
ISR(INT1_vect) //Channel B
{
if(bit_is_set(PIND, PD3)) //Rising edge
{
if(bit_is_set(PIND, PD2)) //If A is high increment
{
ProcessVariable++;
} else { //Else decrement
ProcessVariable--;
}
} else { //Falling edge
if(bit_is_set(PIND, PD2)) //If A is high decrement
{
ProcessVariable--;
} else { //Else increment
ProcessVariable++;
}
}
}