Rotary Encoder 2
Introduction
This page contains further details about rotary encoders and an alternative (and simpler) way to wire and use an encoder with an Arduino.
The cheaper rotary encoders have 3 pins, usually labelled A, B & C. In the last page we looked at the Sparkfun illuminated encoder - this code should work with any of the basic models that have this 3 pin setup.
A rotary encoder is used to detect rotation. It doesn't supply the position of the encoder, just the details of any change. The following diagram shows what happens to the 2 outputs, A and B as the encoder is rotated. The signals are shown as 'square waves', notice the abrupt changes from low to high - this is a digital output.
The two waves are out of phase by 90° (not quite right in my diagram, I know). The dotted red line shows us that, when turning clockwise, and the signal from A changes from high to low, the B signal will be a high. When turning anticlockwise, when A changes from high to low, there is a dotted blue line showing us that the B signal will be low.
So, what matters to us is the change in output on pin A. When that occurs, we read the signal on pin B and can use that to determine the direction in which the encoder was rotated.
You Will Need
- Rotary Encoder
- Jumper Wires
Like most digital inputs, we need pullup resistors for the A and B pins of the encoder. The Arduino's internal pullups will be used for this project.
Making The Circuit
The simplest bit of wiring you could do - pin C goes to GND. Pin A is connected to pin 12 and Pin B to pin 11 on the Arduino.
Programming The Arduino
The sketch takes readings from the rotary encoder and outputs the value to the Serial port when there is a change in the reading. Readings are taken every 5 milliseconds. This gives enough time to avoid any false readings. When I use this sketch, I can get all of the values in the range -12 to 12. In fact, this range was deliberately chosen because the rotary encoder I was using has 24 positions - it takes one 360° turn to cover the whole range of my counter.
// Setting up the counter
int reading = 0;
int lowest = -12;
int highest = 12;
int changeamnt = 1;
// Timing for polling the encoder
unsigned long currentTime;
unsigned long lastTime;
// Pin definitions
const int pinA = 12;
const int pinB = 11;
// Storing the readings
boolean encA;
boolean encB;
boolean lastA = false;
void setup() {
// set the two pins as inputs with internal pullups
pinMode(pinA, INPUT_PULLUP);
pinMode(pinB, INPUT_PULLUP);
// Set up the timing of the polling
currentTime = millis();
lastTime = currentTime;
// Start the serial monitor for debugging
Serial.begin(9600);
}
void loop()
{
// Read elapsed time
currentTime = millis();
// Check if it's time to read
if(currentTime >= (lastTime + 5))
{
// read the two pins
encA = digitalRead(pinA);
encB = digitalRead(pinB);
// check if A has gone from high to low
if ((!encA) && (lastA))
{
// check if B is high
if (encB)
{
// clockwise
if (reading + changeamnt <= highest)
{
reading = reading + changeamnt;
}
}
else
{
// anti-clockwise
if (reading - changeamnt >= lowest)
{
reading = reading - changeamnt;
}
}
// Output reading for debugging
Serial.println(reading);
}
// store reading of A and millis for next loop
lastA = encA;
lastTime = currentTime;
}
}
Challenges
Clearly, changing the counter is a good first step. If you can adapt this code to change the way the counter works, then you can use the value of the reading for some other purpose - like fading an LED.
A more interesting project might be to work only with the changes in value. Instead of keeping track of a counter, do something on each change. For example, you could send a left or right keystroke each time the encoder was turned.