Encoders for User Input

Encoders for User Input

Rotary encoders are commonly used for user input instead of potentiometers, because they can be used for multiple purposes and they don't get noisy, at least not in the same way as a potentiometer. Many have a momentary push switch on the shaft.

Fig. 1 - A rotary encoder with switch

This article is about the pot-like devices used for input, like volume controls. For position and speed type quadrature encoder use see An Arduino and a Quadrature Encoder. The design and intended use of these two types of encoders is completely different, but the way you interface to them is very similar.

Fig. 2 - Rotary encoder pinout

The devices are sold without documentation. A little messing around with it produced this pinout. The view is from the shaft end (the top of the device). Yours may be different, but if it is one of the many being sold on ebay as 20 pulse units, this is the pinout.

The switch is just a switch, a momentary pushbutton on the shaft, and we won't use it in this example, but INT1 or polling could be used to read it.

Fig. 3 - Rotary encoder timing

Phases A & B of the rotary encoder pictured above, and sold as having a grey code output, are different pulse lengths. And they really are pulses. They fire periodically as you turn the knob, and both go high when the device is at rest. You can see that the phase is different in that the edges that are aliigned change with direction. The key to decoding it is to look at the level of phase B on the rising edge of phase A. If B is low, you are turning clockwise, high and you are turning counterclockwise. This assumes you have grounded the common lead and are using pullups, internal or external, on the A and B phases.

The rotary encoder wired up to an ATtiny2313. The common lead is connected to ground. Phase A and phase B are filtered with 0.001µF capacitors to reduce false triggers. Phase A connects to an interrupt, in this case INT0, and phase B connects to any available pin on the same port (for convenience). The LED is just to show that it is actually doing something.

The following code is for an ATtiny2313, but could easily be modified for an ATmega328.

#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>

#define ENC_DDR  DDRD
#define ENC_A_MSK 0x04 
#define ENC_B_MSK 0x40 

#define PWM_DDR DDRB
#define PWM_MSK 0x04

volatile uint8_t volume = 127;

void init()
    // The encoder interface.
    ENC_DDR |= 0x00;                // Pins INT0 & PD6 are inputs.
    ENC_PORT |= ENC_A_MSK | ENC_B_MSK;  // Active pullups on INT0 (PD2) and PD6.
    MCUCR = (1<<ISC01) | (1<<ISC01);// Rising edge on INT0 pin     
    GIMSK = (1<<INT0);              // Enable INT0 interrupt.
    // PWM on an LED.
    PWM_DDR |= PWM_MSK;             // Set OC0A (PB2) to output.
    TCCR0A = (1<<WGM01) | (1<<WGM00) | (1<<COM0A1);   // Fast PWM on pin PB2.
    TCCR0B = (0<<CS02) | (0<<CS01) | (1<<CS00);     // Timer clock = sysclock/1.
    OCR0A = volume;
    sei();                          // Enable global interrupts.

int main()
    while (1)
        // Do other things.

    // Debounce phase A.
    if (ENC_PINS & ENC_A_MSK)
    // See which direction it was turned.
    if (ENC_PINS & ENC_B_MSK)
        if (volume > 15)
            volume -= 16;
        if (volume <240)
            volume += 16;
    OCR0A = volume;

The firmware to read the encoder is simple - it has a single interrupt on the rising edge of phase A, and in the interrupt service routine it looks at phase B to get the level, and then increments or decrements the position based on the result. A busy-wait delay in an ISR???. Sure. User interface things happen very slowly. And in the case of these little rotary encoders, very noisily. The delay is insignificant in terms of this application, and required because the switching is so noisy.

Arduino Board Logo


Arduino-Board is the go-to source for information on many available Arduino and Arduino-like boards, tutorials and projects.

Help and Support


Stay updated

Sign up if you would like to receive our once monthly newsletter.