maker/arduino/ RotaryEncoders


Rotary Encoders

I have a few of these – five for under a tenner.

Rotary Encoder

Wiring

Wiring diagram Rotary Encoder Wiring

From left to right, looking down the encoder from above, with the connections below:
GND   --> GND on Arduino
VCC   --> 5V on Arduino
SW    --> (switch) to digital in
DT=B  --> (rotary B) to digital in
CLK=A --> (rotary A) to digital in
So you need two digital inputs per rotary, and one per button.

Code

I started from https://lastminuteengineers.com/rotary-encoder-arduino-tutorial/ (See below)

Sample Code

From https://lastminuteengineers.com/rotary-encoder-arduino-tutorial/

// Rotary Encoder Inputs
#define CLK 2
#define DT 3
#define SW 4

int counter = 0;
int currentStateCLK;
int lastStateCLK;
String currentDir ="";
unsigned long lastButtonPress = 0;

void setup() {

    // Set encoder pins as inputs
    pinMode(CLK,INPUT);
    pinMode(DT,INPUT);
    pinMode(SW, INPUT_PULLUP);

    // Setup Serial Monitor
    Serial.begin(9600);

    // Read the initial state of CLK
    lastStateCLK = digitalRead(CLK);
}

void loop() {

    // Read the current state of CLK
    currentStateCLK = digitalRead(CLK);

    // If last and current state of CLK are different, then pulse occurred
    // React to only 1 state change to avoid double count
    if (currentStateCLK != lastStateCLK  && currentStateCLK == 1){

        // If the DT state is different than the CLK state then
        // the encoder is rotating CCW so decrement
        if (digitalRead(DT) != currentStateCLK) {
            counter --;
            currentDir ="CCW";
        } else {
            // Encoder is rotating CW so increment
            counter ++;
            currentDir ="CW";
        }

        Serial.print("Direction: ");
        Serial.print(currentDir);
        Serial.print(" | Counter: ");
        Serial.println(counter);
    }

    // Remember last CLK state
    lastStateCLK = currentStateCLK;

    // Read the button state
    int btnState = digitalRead(SW);

    //If we detect LOW signal, button is pressed
    if (btnState == LOW) {
        //if 50ms have passed since last LOW pulse, it means that the
        //button has been pressed, released and pressed again
        if (millis() - lastButtonPress > 50) {
            Serial.println("Button pressed!");
        }

        // Remember last button press event
        lastButtonPress = millis();
    }

    // Put in a slight delay to help debounce the reading
    delay(1);
}

How Many?

My next experiment, when I have time, is to see how many rotaries an ArduinoUno, or an ArduinoMega can handle. So far as signalling the PC over USB, it needs to send two or three bytes. Three bytes is conceptually simpler: one byte for a command word indicating movement of a relative rotary encoder (other command words would be used for potentiometers and buttons), one for which encoder, and one to indicate which direction, and how much, it has turned by. Whether de-bouncing is better done on the Arduino or in software on the PC, or perhaps some hybrid, remains to be seen.