Speed of reading 500 cpr Rotary Encoder less - gives inaccurate results

I'm using Pittman E30B rotary incremental encoder (datasheet attached) which has got 500 counts per revolution
The following code from Arduino Playground - RotaryEncoders does not gives accurate result

enum PinAssignments {
  encoderPinA = 2,   // rigth
  encoderPinB = 3,   // left
};

volatile unsigned int encoderPos = 0;  // a counter for the dial
unsigned int lastReportedPos = 1;   // change management
static boolean rotating=false;      // debounce management

// interrupt service routine vars
boolean A_set = false;              
boolean B_set = false;


void setup() {

  pinMode(encoderPinA, INPUT); 
  pinMode(encoderPinB, INPUT); 
 // turn on pullup resistors
  digitalWrite(encoderPinA, HIGH);
  digitalWrite(encoderPinB, HIGH);

// encoder pin on interrupt 0 (pin 2)
  attachInterrupt(0, doEncoderA, CHANGE);
// encoder pin on interrupt 1 (pin 3)
  attachInterrupt(1, doEncoderB, CHANGE);

  Serial.begin(9600);  // output
}

// main loop, work is done by interrupt service routines, this one only prints stuff
void loop() { 
  rotating = true;  // reset the debouncer

  if (lastReportedPos != encoderPos) {
    Serial.print("Index:");
    Serial.println(encoderPos, DEC);
    lastReportedPos = encoderPos;
  }
}

// Interrupt on A changing state
void doEncoderA(){
  // debounce
  if ( rotating ) delay (1);  // wait a little until the bouncing is done

  // Test transition, did things really change? 
  if( digitalRead(encoderPinA) != A_set ) {  // debounce once more
    A_set = !A_set;

    // adjust counter + if A leads B
    if ( A_set && !B_set ) 
      encoderPos += 1;

    rotating = false;  // no more debouncing until loop() hits again
  }
}

// Interrupt on B changing state, same as A above
void doEncoderB(){
  if ( rotating ) delay (1);
  if( digitalRead(encoderPinB) != B_set ) {
    B_set = !B_set;
    //  adjust counter - 1 if B leads A
    if( B_set && !A_set ) 
      encoderPos -= 1;

    rotating = false;
  }
}

In one revolution it should give 500 counts but it gives less. If I give one rotation in anti - clockwise direction, it is not giving the same result as previous case.

What should I do?

Circuit diagram of connection attached

E30_encoder.pdf (421 KB)

Untitled.gif

remove the delay(1) 's from your code.

as that is called 500 times per rotation that means half a second lost as delay() blocks.

  1. if you need to debounce that thing at that speed you should ask if it is the right sensor...

You specifically must never call delay() in an ISR, and also why would you want to? Interrupts
are for handling urgent events.

delay() can/will hang the system if called when interrupts are disabled, like they are in an ISR.

You don't need to do debouncing when handling a rotary encoder like this, the correct
approach is:

  1. Whenever either pin changes state, invoke an interrupt routine.

  2. The ISR must then read both pins A & B and compare with their previously read states
    to determine whether to increment or decrement the count. The ISR then updates the
    "previously read state".

  3. will automatically mean every edge is correctly accounted (assuming the mechanical
    speed of the encoder is within the worst-case latency of the ISR) This alone will
    cancel out the effects of contact bounce in a mechanical encoder.

  4. means the pin states read are consistent with each other for correct accounting
    even if the ISR got deferred because of another unrelated ISR.

For fast encoders you need to make the ISR lightweight and fast, which means using
direct port manipulation and perhaps disabling other sources of interrupts that
have a higher priority.

If that doesn't give enough performance a hardware encoder-counting chip is called for,
or a faster MCU (some have built-in quadrature encoder counters).

[ and one last point, you may need stiff pull-up resistors for a fast encoder, less than 10k,
to get fast enough rising edges - the built-in pullups are weak - most encoders are
open-collector output (although this one might not be according to datasheet if I
read it right) ]