DEV Community

Cover image for Arduino Mega - Rotary Encoder
Arduino ESP32 Raspberry Pi Tutorials
Arduino ESP32 Raspberry Pi Tutorials

Posted on Originally published at newbiely.com

Arduino Mega - Rotary Encoder

A rotary encoder lets you turn a knob and read both how far and in which direction it moved, plus it usually has a built-in push button. That makes it a nice input device for menus, volume controls, or any project where a potentiometer's limited rotation range won't do. Here's how to wire one to an Arduino Mega and read it in code.

The full tutorial, with every detail and the line-by-line code explanation, is on our site: Arduino Mega - Rotary Encoder

What you need

Wiring

Arduino Mega - Rotary Encoder wiring diagram

The encoder module has five pins. CLK and DT are the two signal outputs, SW is the built-in push button, and VCC/GND power it with 3.3 to 5 volts. In the sketch, CLK goes to pin 2, DT to pin 3, and SW to pin 4 on the Mega. The SW pin relies on a pull-up so it reads HIGH when the button is untouched and LOW when pressed, which is why no external pull-up resistor is needed here.

How it works

Inside the encoder, a slotted disc connects two pins, A and B, to a common ground pin as you turn the knob. Because A and B touch ground at slightly different times, the two output signals end up 90 degrees out of phase, a trick called quadrature encoding. If A rises before B, you're turning one way; if B rises first, you're turning the other. This is different from a potentiometer, which gives you an exact position but can only turn about three quarters of a circle, while an encoder spins forever and only tells you relative movement.

Code

The sketch watches the CLK pin and waits for it to go from low to high. At that moment it checks DT: if DT is high the knob moved counterclockwise and the counter decreases, if DT is low it moved clockwise and the counter increases. The button on SW is handled with the ezButton library, which takes care of debounce so a single press isn't read as several. This version uses polling, meaning the loop constantly checks pin states, which can waste cycles or miss counts if other code runs slowly; an interrupt-based version lets the Mega watch for the pulse while doing other work instead.

arduino-mega-rotary-encoder.ino

/*
 * This Arduino Mega code was developed by newbiely.com
 *
 * This Arduino Mega code is made available for public use without any restriction
 *
 * For comprehensive instructions and wiring diagrams, please visit:
 * https://newbiely.com/tutorials/arduino-mega/arduino-mega-rotary-encoder
 */

#include <ezButton.h>  // the library to use for SW pin

#define CLK_PIN 2 // The Arduino Mega pin connected to the CLK pin of encoder
#define DT_PIN 3 // The Arduino Mega pin connected to the DT pin of encoder
#define SW_PIN 4 // The Arduino Mega pin connected to the SW pin of encoder

#define DIRECTION_CW 0   // clockwise direction
#define DIRECTION_CCW 1  // counter-clockwise direction

int counter = 0;
int direction = DIRECTION_CW;
int CLK_state;
int prev_CLK_state;

ezButton button(SW_PIN);  // create ezButton object that attach to pin 4

void setup() {
  Serial.begin(9600);

  // configure encoder pins as inputs
  pinMode(CLK_PIN, INPUT);
  pinMode(DT_PIN, INPUT);
  button.setDebounceTime(50);  // set debounce time to 50 milliseconds

  // read the initial state of the rotary encoder's CLK pin
  prev_CLK_state = digitalRead(CLK_PIN);
}

void loop() {
  button.loop();  // MUST call the loop() function first

  // read the current state of the rotary encoder's CLK pin
  CLK_state = digitalRead(CLK_PIN);

  // If the state of CLK is changed, then pulse occurred
  // React to only the rising edge (from LOW to HIGH) to avoid double count
  if (CLK_state != prev_CLK_state && CLK_state == HIGH) {
    // if the DT state is HIGH
    // the encoder is rotating in counter-clockwise direction => decrease the counter
    if (digitalRead(DT_PIN) == HIGH) {
      counter--;
      direction = DIRECTION_CCW;
    } else {
      // the encoder is rotating in clockwise direction => increase the counter
      counter++;
      direction = DIRECTION_CW;
    }

    Serial.print("DIRECTION: ");
    if (direction == DIRECTION_CW)
      Serial.print("Clockwise");
    else
      Serial.print("Counter-clockwise");

    Serial.print(" | COUNTER: ");
    Serial.println(counter);
  }

  // save last CLK state
  prev_CLK_state = CLK_state;

  if (button.isPressed()) {
    Serial.println("The button is pressed");
  }
}
Enter fullscreen mode Exit fullscreen mode

Full tutorial

The complete tutorial - wiring diagram, code explanation and troubleshooting - is here: https://newbiely.com/tutorials/arduino-mega/arduino-mega-rotary-encoder

Top comments (0)