Introduction: Simple Rotary Decoder

About: 55+ years in electronics, computers, and teaching ... now retired.

This instructable describes a simple method of decoding a sequential rotary encoder using an Arduino Uno R3.

Compact software routines are used to to count the number of transitions, eliminate contact bounce, and determine the direction of rotation. Additional components and lookup tables are not required.

Interrupt and non-interrupt versions of the code are provided.

The interrupt version of the code only requires a single interrupt pin.

Images:

  • The opening photo shows the assembled encoder.
  • The screen shot shows the code for the interrupt version and the count when the encoder shaft is rotated clockwise and counter clockwise.
  • The video shows the count during rapid rotation.

Step 1: Circuit Diagram

The encoder wiring diagram is shown in fig.1.

The jumper wires are soldered directly to the encoder pins.

Interchange the two blue wires if the count direction is reversed.

Step 2: Parts List

The following parts were obtained from https://www.aliexpress.com/

  • 1 only Arduino UNO R3 with USB Cable.
  • 1 only sequential rotary encoder (EC11 or equivalent) with switch.
  • 1 only knob to suit shaft.
  • 3 only Arduino male-to-male jumper wires.

Step 3: Theory

Sequential rotary encoders generate two square-waves each of which are displaced by 90 degrees as shown in Fig.1.

The logic patterns at Contact A and Contact B are different when the shaft is rotated clockwise (CW) and counter clockwise (CCW) through positions 1 to 6.

Common methods of determining the direction of rotation include:

  • hardware
  • twin interrupts
  • pattern lookup tables

This project uses a software method that does not require lookup tables. [1]

Direction

Instead of looking at the output patterns from Contact A and Contact B let’s focus on Contact A.

If we sample Contact B after each Contact A transition we note that:

  • Contact A and Contact B have opposite logic states when the encoder is rotated CW
  • Contact A and Contact B have the same logic state when the encoder is rotated CCW

Actual code:

// ----- Count transitions
CurrentStateA = stateContactA();
if (CurrentStateA != LastStateA) 
{
  CurrentStateB = digitalRead(ContactB);
  if (CurrentStateA == CurrentStateB) Count++;
  if (CurrentStateA != CurrentStateB) Count--;
  LastStateA = CurrentStateA;
}

This method offers the following advantages:

  • lookup tables are not required
  • only a single interrupt line is required

Debounce

All mechanical encoders suffer from “contact bounce”.

If a switch contact does not make/break cleanly its logic state will oscillate rapidly from HIGH to LOW until the switch contact settles . This results in false counts.

One method for suppressing contact bounce is to add a small capacitor across each switch contact. The capacitor and associated pull-up resistor form an integrator which effectively shorts high frequencies and allows the switch voltage to rise/fall gracefully.

The downside to this approach is that transitions may be missed if the encoder shaft is rotated rapidly.

Software Debouncing

This method uses two counters (Open, Closed) that have been set to zero. [2]

Once a transition is detected on Contact A:

  • Continuously poll Contact A.
  • Increment the Open counter, and reset the Closed counter, whenever Contact A is HIGH.
  • Increment the Closed counter, and reset the Open counter, whenever Contact A is LOW.
  • Exit the loop when one of the counters reaches a predetermined count. We are effectively looking for the steady state period following any contact bounce.

Actual code:

// ----- Debounce Contact A
while (1) 
{
   if (digitalRead(ContactA)) 
   {
     // ----- ContactA is Open
     Closed = 0;	// Empty opposite integrator
     Open++; 		// Integrate
     if (Open > MaxCount) return HIGH;
   } 
   else 
   {
     // ----- ContactA is Closed
     Open = 0; 		// Empty opposite integrator
     Closed++; 		// Integrate
     if (Closed > MaxCount) return LOW;
   }
}

There is no need to debounce Contact B as the Contact A and Contact B transitions do not coincide.

Counting

A mechanical “detent” effectively doubles your count as two counts are registered between clicks (see fig 1).

The number of “detents” may be determined using modulo 2 arithmetic as shown below.

Actual code:

// ----- Count "detents"
if (Count % 2 == 0) 
{
   Serial.print("Count: ");
   Serial.println(Count / 2); 
}

References

Further information may be found at:

[1]

https://howtomechatronics.com/tutorials/arduino/ro...

[2]

https://newbiehack.com/ButtonorSwitchDebounceinSof...

Step 4: Software

This project requires a recent version of the Ardino Uno R3 IDE (integrated development environment) which is available from https://www.arduino.cc/en/main/software

Download each of the following two Arduino sketches (attached)

  • rotary_encoder_1.ino (polling version)
  • rotary_encoder_2.no (interrupt version)

Double-click on your preferred version and follow the on-screen instructions.

Enjoy ...

  Click here   to view my other instructables.