Rotary Encoder Programming Code for Fast and Robust Usage
by RuiMonteiro in Circuits > Arduino
949 Views, 4 Favorites, 0 Comments
Rotary Encoder Programming Code for Fast and Robust Usage
The typical Arduino sketches out there are prone to failure due to not considering the full cycle to count as a rotation. To solve the problem of stability and also to allow faster speeds here are two variations of a Fast and Robust code for the typical Rotary Encoder.
As you can see, there is a cycle of 5 steps for an entire movement, those steps are:
CLK(A) and DT(B) bit pairs for CCW (Moving Left):
- 11
- 01
- 00
- 10
- 11
CLK(A) and DT(B) bit pairs for CW (Moving Right):
- 11
- 10
- 00
- 01
- 11
This means we can reduce the entire cycle into a single byte (char) like so:
- 01001011 for CCW
- 10000111 for CW
You may visualize these A/B cycles in the picture above.
Supplies
One Arduino Rotary Encoder.
Wire the Rotary Encoder accordingly to the picture, like this:
- CLK to Arduino pin 2
- DT to Arduino pin 3
- SW to Arduino pin 4
Robust and Simple Programming
For the Robust and Simple programming code use this one:
// Rotary Encoder Inputs
#define CLK 2
#define DT 3
#define SW 4
#define DPR 50 // Debounce timer for press and release
#define LPR 3000 // Long press/release in milliseconds
unsigned char readBits = 0b111; // 8 bits
unsigned char rotationBits = 0b011; // 8 bits
unsigned char buttonBits = 0b111; // 8 bits
int counter = 0;
String currentDir = "";
unsigned long lastActionButton = 0;
void setup() {
// Set encoder pins as inputs
pinMode(CLK,INPUT);
pinMode(DT,INPUT);
pinMode(SW, INPUT_PULLUP);
Serial.begin(9600); // opens serial port, sets data rate to 9600 bps
}
void loop() {
readBits = digitalRead(SW) << 2 | digitalRead(CLK) << 1 | digitalRead(DT);
if ((rotationBits & 0b11) != (readBits & 0b11)) {
rotationBits = rotationBits << 2 | readBits & 0b11;
// Bit Pairs Cyclic Sequence (CLK DT Pair Bits):
// 1. 2. 3. 4. 5.
// 11 | 01 | 00 | 10 | 11 for CCW
// 11 | 10 | 00 | 01 | 11 for CW
if (rotationBits == 0b01001011 || rotationBits == 0b10000111) {
if (rotationBits == 0b01001011) {
currentDir = "CCW";
counter--;
} else {
currentDir = "CW";
counter++;
}
Serial.print("Direction: ");
Serial.print(currentDir);
Serial.print(" | Counter: ");
Serial.println(counter);
}
}
if ((buttonBits & 0b001) != (readBits >> 2 & 0b001)) {
// Bit Pairs Press Release Cyclic Sequence (OFF ON Pair Bits):
// 1. 2. 3. 4. (long press/release)
// 000 | 001 | 011 | 111 for OFF
// 111 | 110 | 100 | 000 for ON
if ((buttonBits & 0b001) == 0b000) {
buttonBits = 0b001;
} else {
buttonBits = 0b110;
}
// Starts counting time since button physically operated
lastActionButton = millis();
// LONG Press/Release Actions
} else if (abs(millis() - lastActionButton) > (unsigned long)LPR) {
if (buttonBits == 0b011) {
buttonBits = 0b111;
Serial.println("LONG released!");
} else if (buttonBits == 0b100) {
buttonBits = 0b000;
Serial.println("LONG pressed!");
}
// SIMPLE Press/Release Actions
} else if (abs(millis() - lastActionButton) > (unsigned long)DPR) {
if (buttonBits == 0b001) {
buttonBits = 0b011;
Serial.println("Button released!");
} else if (buttonBits == 0b110) {
buttonBits = 0b100;
Serial.println("Button pressed!");
}
}
// Put in a slight delay to help debounce the reading
delay(1);
}
Robust and Fast Speeds Programming
For extremely high speeds you have to use bit operators and port registers. In this case use the following code for the Rotary Encoder:
int counter = 0;
String currentDir = "";
unsigned char currentPairBit = 0b11; // 8 bits
unsigned char lastPairBit = 0b11; // 8 bits
void setup() {
Serial.begin(9600); // opens serial port, sets data rate to 9600 bps
DDRD = 0b00000000; // Sets all PD Arduino pins as inputs
}
void loop() {
while(true) { // while cycle is faster than loop!
// reads the PD digital pins for states!
// PD2 >> 1 jumps to bit 0b0010 and PD3 >> 3 jumps to bit 0b0001
currentPairBit = PIND >> 1 & 0b10 | PIND >> 3 & 0b01; // CLK(PD2) and DT(PD3) bits
if ((lastPairBit & 0b11) != currentPairBit) {
lastPairBit = lastPairBit << 2 | currentPairBit;
// Bit Pairs Cyclic Sequence:
// 1. 2. 3. 4. 5.
// 11 | 01 | 00 | 10 | 11 for CCW
// 11 | 10 | 00 | 01 | 11 for CW
if (lastPairBit == 0b01001011 || lastPairBit == 0b10000111) {
if (lastPairBit == 0b01001011) {
currentDir = "CCW";
counter--;
} else {
currentDir = "CW";
counter++;
}
Serial.print("Direction: ");
Serial.print(currentDir);
Serial.print(" | Counter: ");
Serial.println(counter);
}
}
}
}