eggdweather describes the simplest and easiest solution which should work for any digital rotary encoder; interrupt or poll one pin and, when that activates, check the level of the other pin. That gives a step and a direction indicator.
For example, interrupting on the rising edge of A and then looking at B, we would get 0 when moving forward, 1 when moving backwards -
Code:
|<-- forward -->| stop |<-- backwards -->|
___ ___ ___ ___
A ___| |___| |___________| |___| |___
___ ___ ___ ___
B _____| |___| |_______| |___| |_____
: : : :
0 0 1 1
If there are 20 interrupts per revolution you have a maximum increase or decrease of 20 every revolution, a change every 18 degrees.
If you have a more complicated interrupt system which can interrupt on rising and falling edges of A you can double the maximum count per revolution halve the change angle to 9 degrees -
Code:
|<-- forward -->| stop |<-- backwards -->|
___ ___ ___ ___
A ___| |___| |___________| |___| |___
___ ___ ___ ___
B _____| |___| |_______| |___| |_____
: : : : : : : :
0 0 0 0 1 1 1 1
Getting more complicated still, interrupting on rising and falling edges of both A and B, you can double the maximum count per revolution again and halve the change angle to 4.5 degrees -
Code:
|<-- forward -->| stop |<-- backwards -->|
___ ___ ___ ___
A ___| |___| |___________| |___| |___
___ ___ ___ ___
B _____| |___| |_______| |___| |_____
: : : : : : : : : : : : : : : :
0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1
You can also apply 'computer mouse acceleration' so how quickly the count goes up increases the quicker the encoder is turned. That can be determined by how long ago the last change was, and if below a certain value add or subtract 2 instead of 1 and similar. Using 'fixed point numbers' which can be held as if integers you can have 1.5 multipliers which can make things smoother and more pleasing.
It's not easy to say what is needed for a particular project so it's probably best to start simple and then get more complicated if needed. The more you are doing, the more interrupts being handled, the faster the PICAXE will need to be to handle the interrupts themselves and the rest of the code.
Interrupting on rising and falling edge of A is usually a good starting point because interrupting on just a rising edge means having to wait for the A signal to disappear before returning to the main program, and one may end up stuck in the interrupt if you stop turning the sensor and it just happens to stop with that signal high.
The following simulates interrupting on both edges. The count increments every time C.4 (A) is set high or low, set C.3 (B) high to make that decrement -
Code:
#Picaxe 08M2
; 543210
Symbol IRQ_A = %010000 ; Signal A = pin C.4
Symbol PIN_B = pinC.3 ; Signal B = pin C.3
Symbol counter = w0 ; b1:b0
Symbol detect = b2
Symbol thisCount = w2 ; b5:b4
Symbol lastCount = w3 ; b7:b6
MainProgram:
Gosub Interrupt_Enable
Do
thisCount = counter
If thisCount <> lastCount Then
lastCount = thisCount
If thisCount >= $8000 Then ; Negative
thisCount = -thisCount
SerTxd( "-", #thisCount, " " )
Else
SerTxd( "+", #thisCount, " " )
End If
End If
Loop
Interrupt:
counter = PIN_B ^ 1 * 2 - 1 + counter
Interrupt_Enable:
detect = detect ^ IRQ_A
SetInt detect, IRQ_A
Return
Note the interrupt increments 'counter' and the main loop grabs 'counter' into 'thisCount'. This allows 'counter' to increment without messing up the values the main program is using.
In a real system it is not advisable to use a single SERTXD to output any display data because that takes considerable time and one can miss interrupts during that. It is best to use BINTOASCII and use SERTXD to output a character at a time as that allows interrupts to occur between each character output. Using HSEROUT is even better.
Ideally one wants to make the interrupt as fast as possible so one might allocate the B pin to fall on pinX.1, and swap A and B to alter direction indicated, to optimise the counting. Instead of -
counter = pinC.1 ^ 1 * 2 - 1 + counter
One can then use a faster -
counter = pinsC & %000010 - 1 + counter
Admittedly it's quite complicated and intricate but also quite straightforward once one has got to grips with it.
Added: Forgot to point out the demo only works with simulation, not a real rotary encoder. On a real rotary encoder B will be changing as A does and that needs to be catered for. It's a simple(ish) change in the interrupt counting knowing what 'detect' is at the time. Eg interrupting on a rising edge of A and B=0 is an increment, on falling edge of A then B=1 is the increment. I'll post a full example later.
More Added: Actually it's a simple change -
Code:
Interrupt:
counter = detect Max 1 ^ PIN_B * 2 - 1 + counter
Just remember to cycle through toggling pinC.4 then pinC.3, then pinC.4, and pinC.3 again, or vice versa to get it incrementing as a real quadrature encoder would give.