The following code shows one way to read an incremental mechanical rotary enoder (the sort used for volume control in audio systems).  These rotary encoders have two switches A and B which return a quadrature output, i.e. they are 90 degrees out of phase.

SETUP

fritzing diagramThe common (centre) terminal should be connected to a Pi ground.

The A and B terminals may be connected to any spare gpios.

Here A to gpio18 (P1-12), common to ground (P1-20), B to gpio7 (P1-26).

photo of set-up

CODE

#include <stdio.h>

#include <pigpio.h>

/*
   Rotary encoder connections:

   Encoder A      - gpio 18   (pin P1-12)
   Encoder B      - gpio 7    (pin P1-26)
   Encoder Common - Pi ground (pin P1-20)
*/

#define ENCODER_A 18
#define ENCODER_B  7

static volatile int encoderPos;

/* forward declaration */

void encoderPulse(int gpio, int lev, uint32_t tick);

int main(int argc, char * argv[])
{
   int pos=0;

   if (gpioInitialise()<0) return 1;

   gpioSetMode(ENCODER_A, PI_INPUT);
   gpioSetMode(ENCODER_B, PI_INPUT);

   /* pull up is needed as encoder common is grounded */

   gpioSetPullUpDown(ENCODER_A, PI_PUD_UP);
   gpioSetPullUpDown(ENCODER_B, PI_PUD_UP);

   encoderPos = pos;

   /* monitor encoder level changes */

   gpioSetAlertFunc(ENCODER_A, encoderPulse);
   gpioSetAlertFunc(ENCODER_B, encoderPulse);

   while (1)
   {
      if (pos != encoderPos)
      {
         pos = encoderPos;
         printf("pos=%d\ ", pos);
      }
      gpioDelay(20000); /* check pos 50 times per second */
   }

   gpioTerminate();
}

void encoderPulse(int gpio, int level, uint32_t tick)
{
   /*

             +---------+         +---------+      0
             |         |         |         |
   A         |         |         |         |
             |         |         |         |
   +---------+         +---------+         +----- 1

       +---------+         +---------+            0
       |         |         |         |
   B   |         |         |         |
       |         |         |         |
   ----+         +---------+         +---------+  1

   */

   static int levA=0, levB=0, lastGpio = -1;

   if (gpio == ENCODER_A) levA = level; else levB = level;

   if (gpio != lastGpio) /* debounce */
   {
      lastGpio = gpio;

      if ((gpio == ENCODER_A) && (level == 0))
      {
         if (!levB) ++encoderPos;
      }
      else if ((gpio == ENCODER_B) && (level == 1))
      {
         if (levA) --encoderPos;
      }
   }
}

BUILD

cc -o rotary_encoder rotary_encoder.c -lpigpio -lrt -lpthread

RUN

sudo ./rotary_encoder

While the program is running you can capture the waveform using the notification feature built in to pigpio.  Issue the following commands on the Pi.

pigs no
pig2vcd  </dev/pigpio0 >re.vcd &
pigs nb 0 0x40080 # set bits for gpios 7 (0x80) and 18 (0x40000)

Twiddle the rotary encoder forwards and backwards for a few seconds.  Then enter

pigs nc 0

The file re.vcd will contain the captured waveform, which can be viewed using GTKWave.


Overview

rotary encoder waveform overview

Detail of switch bounce.  Contact A bounces for circa 700 us before completing the level transition

rotary encoder waveform detail