Introduction
Definition (from Wikipedia): A rotary encoder, is an electro-mechanical device that converts the angular position of a shaft or axle to an analog or digital code.
I have been playing with a device like this for some time and thought I’d share what I learnt. I am not going to describe the theory of rotary encoders, there are plenty of places on the internet that have done an excellent job doing that. I will rather focus on its real life application complete with a working sample circuit with assembly code.
Having read a lot on the theory of its operation I was sure it was something easy and straightforward to implement. However, when I tried it I failed miserably. After hours and hours of experiments, research on the internet I found out out that my test circuit was working correctly, but my code was incomplete.
The test circuit
I created the circuit on a test board |
At the heart of it is a 16F628A microcontroller. I used this particular microcontroller, because I already had a few ones at hand. Also, I think, it’s an easy to use microcontroller with plenty of I/O ports and other peripherals for small projects. The 16P628A also has an internal oscillator (max. 4 MHz) which means it doesn’t really need any extra external components for normal operation.
The rotary encoder is connected to PORTB, which is configured to use its built-in pull-up resistors, further reducing the number of external components. To help debouncing a 100nF capacitor is used paralel to each pin of the rotary encoder. Further debouncing is done in code.
The feedback is built with a Serial-In-Parallel-Out shift register (74HC595) and an LED strip. I could have just used some LEDs directly connected to the microcontroller, since we have plenty of free I/O pins, but I used my own LED strip to make the test board simpler.
As always, I used an ICSP interface to program the PIC, greatly reducing the development time of a new application.
Code
The code was written in assembly, compiled with the MPLAB IDE 8.5 built in compiler.
All we need to do in the main loop is to poll the lines from the rotary encoder to see if they have changed:
;check rotary encoder – left
btfss Encoder_L
call Encoder_CheckNext_L;check rotary encoder – right
btfss Encoder_R
call Encoder_CheckNext_R
The following are the routines used for deciding if the rotary encoder was moved indeed (debouncing) and also to carry out any actions as necessary when the rotary encoder was indeed rotated:
; ——————————————
; rotary encoder routines
; ——————————————
Encoder_CheckNext_L
btfsc Encoder_R
goto Encoder_RightAction
returnEncoder_CheckNext_R
btfsc Encoder_L
goto Encoder_LeftAction
returnEncoder_RightAction
bcf STATUS, C
btfsc COUNT, 0
bsf STATUS, C
rrf COUNTgoto Encoder_RotationEnds
Encoder_LeftAction
rlf COUNT
goto Encoder_RotationEnds
Encoder_RotationEnds
btfss Encoder_L
goto Encoder_RotationEnds
btfss Encoder_R
goto Encoder_RotationEnds
return
This last part (Encoder_RotationEnds) is the one that I was missing from my code. Thanks to this excellent site now my test board works. I already used the above circuitry and code in actual projects and they work great: the rotary encoder never skips a step, and never gives extra steps.
Conclusion
Rotary encoders are simple to use user input devices that can simplify user interface significantly – think of menu systems, etc. I am sure I will use them in many projects to come.
it is strange you mention a debouncing circuit for the encoder. It seems that yours only sinks current.
What I've used, send quadrature pulses and either behave as a schimt trigger output or a TTL output.
Have never tried open collector outputs and have never use software or hardware debouncing.
http://www.youtube.com/watch?v=47px_6gVjBE
File mou, Thanks for sharing!