Rotary Encoder Programming Code for Fast and Robust Usage
by RuiMonteiro in Circuits > Arduino
600 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); } } } }