How to read data from a rotary encoder with ATmega328
You will have to use interrupts or otherwise the encoder might be rotating but your Arduino is doing something else than reading the encoder. By using interrupts, the encoder counter is always updated when the encoder moves. This also means that the interrupt function has to be very short so that it only takes a few cycles to complete and thus leaves the majority of the Arduinos computing time for your sketch.

Here is a code that I've used in many applications from CNC handwheels to servos and for reading extremely accurate angle sensors. It is dead simple, uses two interrupts to read the quadrature signal (A &amp; B channel) and also makes use of Arduinos built in pull-up resistors to keep the channels held high for reliable readings.

Assuming that your encoder is an open-collector output and works with 5V, you only need to connect 5V and GND to it and then the A channel to the first interrupt pin #2 and channel B to #3. That's it for the hardware.

This code goes at the start of your sketch, right before setup() function:

const signed byte encoderDirections[] = {0, -1, 1, 0, 1, 0, 0, -1, -1, 0, 0, 1, 0, 1, -1, 0};
volatile long encCount = 0;


It defines a constant array that is used for finding the direction that the encoder has turned based on the previous value and the current value. It is defined as constant as it is never changed. Also a global variable calle encCount is defined as a long type variable so that the encoder can count in both directions. It is absolutelu imperative to declare it as volatile so that the compiler and the microprocessor never try to do any "shortcuts" when you use this variable, but instead always loads it from its respective memory address. This is done so because the interrupt can fire at any time and change the variables value without any other function knowing it.

Next, in your setup() function you will want to include these lines to make the Arduino pins as inputs with the internal pull-up resistors connected. The latter two lines attach the interrupts 0 &amp; 1 (hardware pins pins 2 &amp; 3) so that whenever the pin state changes (low to high or vice versa), it halts the microprocessors operation and jumps to the encoder_interrupt function immediately.

pinMode(2, INPUT_PULLUP);
pinMode(3, INPUT_PULLUP);
attachInterrupt(0, encoder_interrupt, CHANGE);
attachInterrupt(1, encoder_interrupt, CHANGE);


Last you will need the actual interrupt function that reads the encoder and updates the counter value.

void encoder_interrupt() {
  static unsigned int oldEncoderState = 0;
  oldEncoderState &lt;&lt;= 2;
  oldEncoderState |= ((PIND &gt;&gt; 2) &amp; 0x03);
  encCount += encoderDirections[(oldEncoderState &amp; 0x0F)];
}


First this defines a variable that holds the previous encoder value that was read from the pins 2 &amp; 3. This is declared as static, so the value is stored in memory even when this function exits so that it can be used the next time the interrupt routine is run.

The second line moves the previous interrupt channel values two bits to the left (multiply by 4) to make room for the new values.

The third line is an interesting one. It reads the PIND, meaning all the pins at D register, which holds many Arduino pin states, including the pins 2 &amp; 3 that we are interested in. Next it shifts this value 2 bits to the right (divide by 4) to "drop" the pin 2 &amp; 3 states to the lowest bits of this byte. Then it AND's this byte with 0x03 to zero everything else but the lowest two bits that now contain the interrupt channel states. Lastly these two bytes are OR'd with the previous encoder state values to obtain a 4 bit number.

On the forth line this 4 bit number is AND'd with a 0x0F to make sure the highest 4 bits are zero to make sure this number is truly a 4 bit number that stays between 0..15, as it is used as an index for the constant array we defined at the start of the program to get the encoders direction of rotation and this is then added to the counter variable.

And now you have an accurate and extremely fast way of reading a two channel encoder to keep track of its position.

If you want to calculate an angle from the encoders current position, you could do a function like this, but you have to know the line count of your encoder and multiply it by 4 so you know the encoder pulse count per revolution. For example, a 100 line rotary encoder gives out 400 pulses per revolution. I assume that there is a constant defined as follows at the start of program:

const int LINE_COUNT = 400;


Also, this function assumes that the encoder could have turned more than one revolution and you just want the angle from some reference spot in degrees. Do take in to account that the long type variable will overflow after +-2 147 483 648 pulses as it is a 32 bit signed variable.

float getAngle() {
  long curCount = encCount;  // Store the current count.
  while(curCount &lt; 0) {
    curCount += LINE_COUNT;
  }
  while(curCount &gt;= LINE_COUNT) {
    curCount -= LINE_COUNT;
  }
  return (curCount / LINE_COUNT * 360.0);
}


First the encoder count is copied to a one use variable. then two while statements make sure the values is positive from 0 to LINE_COUNT-1, so it basically reduces the count to what it would be with just under one revolution. Then it returns the number of degrees by calculating the current position as a fraction of a one revolution count and multiplies this with 360 to get the degrees.