When I was stationed overseas back in the early 1970’s there were two things cheaply available that most military guys really liked: stereo equipment and booze. No, this post is not about a PIC-powered home distillery. Sorry. The stereo equipment was pretty good stuff at the time and, in fact, I still have a great set of Sansui speakers from those days. The electronics was all solid state so it held up pretty well but one nagging issue was the manual potentiometers that used a metal wiper on a resistive substrate. They would tend to get dirty or worn and then become intermittent. Not a good thing in any case but a real pain if it happened to be the volume control. Nowadays, with the availability of cheap microcontrollers, we can use digital rotary encoders to perform analog potentiometer functions. A bonus is that one size fits all in the digital world whereas the analog world might require different resistance values for different functions or even more expensive dual potentiometers for stereo applications. In this post we will see how to make a simple interface to a cheap rotary encoder module.
Rotary Encoders use a simple method for determining both the distance and the direction that the shaft is rotated. If you do some research on the coding method you may get confused by terms like “gray code” or “quadrature phase encoding”. Really, that is just tech-speak for saying that the two outputs of our rotary encoder will change from 0 to 1 or 1 to 0 at different times. In order to determine when to check for a change all we have to do is to trigger a read on either the rising edges or the falling edges of one of the outputs. You can see in the waveform that for every edge the opposite output is already at a steady state logic level. In order to determine the direction the shaft is turning we simply look at the logic level of the opposite output. For example, if we are triggering on the falling edges of output A in the waveform above and we read output B as a high logic level, then we are moving clockwise. If we read output B as a low logic level, then we are moving counter-clockwise. Exactly the opposite would be true if we chose to trigger on the rising edges of output A instead.
Rotary Encoder Module
You have a couple of options when picking a rotary encoder. You can buy the encoder unit by itself or, as shown in the pictures, you can buy it mounted on a board. You will also find that some encoders come with a built in switch and different encoders have a different number of clicks per full revolution. For this project I bought an encoder module like the one shown in the pictures. The module includes 10k pull up resistors for the DT and CLK lines and has a spot (R1) for another 10k resistor for the switch output. That resistor spot is open when you get the module. The switch itself is activated by pushing down on the encoder shaft and it provides a momentary contact to ground.
The hardware connections for the module are shown in the diagram above. The pins are labeled on the board so if you buy one that is different than what was pictured earlier the equivalent functions should be obvious. The interface to the 1602 LCD display is based on the hardware and software detailed in the 3-wire, 8-bit LCD Interface post so that detail is not shown here. The only difference is that the PIC pins used to interface to the LCD and the shift register were moved so that the External Interrupt pin can be used for this application.
Some rotary encoders are optical so the only mechanical part is the rotating shaft. The cheap ones, like the one used here, are basically mechanical switches so they need some contact debouncing. The debouncing can be done in hardware or software but the schematic shown here includes simple RC hardware debouncing. The line for the encoder module switch includes a 10k pull up resistor because the R1 spot on the bottom of the module board was left blank. You could solder a normal ¼ watt resistor to the R1 pads or just add it external to the board. The debounce circuit on the CLK line does not include an additional 10k resistor because that pull up is already provided on the module. Some folks also add debounce on the DT line but that is not needed for our application because we expect the DT line to already be at a steady state logic level when the CLK line triggers our software. That might not be the case if the shaft of the encoder is attached to something like a motor that generates a much higher rate of rotation than our fingers will. In any case, it wouldn’t hurt to add the same debounce circuit to the DT line.
The software link is listed below. While it is targeted for the 12F683, it is easily ported to bigger versions of the PIC. Mostly it requires changing names like TRISIO to TRISA, and GPIO to PORTA. You will also need to change the line that identifies the PIC version (LIST=) and the INCLUDE file but those are intuitive changes. The __CONFIG line may also need tweaking just because one or two of the labels used are spelled differently in some of the INCLUDE files. Just make sure that the PIC you use has a pin that allows an External Interrupt input (usually labeled EXT or INT). As we’ve seen before, the 16F688 (14-pin PIC) could be used with the same physical pin connections as the 12F683 if you want more I/O pins.
The sample software is pretty straightforward and is set up to interrupt on the falling edges of the CLK line. The interrupt handler checks the state of the DT line to determine the direction of shaft rotation and updates a simple counter accordingly. Given that the example software is using just one 8-bit memory location for the counter, the range is from +127 to -128. The counter is not saved in EEPROM so it will always reset to zero when power is turned on. The switch will toggle its state each time it is pressed. It is initialized to “off”. The status of the counter and the status of the switch are displayed on the LCD.
The rotary switch allows you to feel each click as it’s turned so you might expect to see the display count change with each click. In reality, because the software is only interrupted on the falling edge of the CLK line, the count will change every second click. The in between click is the rising edge of the CLK line when rotating in the clockwise direction. When going counter-clockwise that same edge becomes the falling edge. You can see that effect by just moving the shaft back and forth through a single click point.
Here is a picture that shows typical results. That’s it for this post. Check out my other electronics projects.