Rotary encoder missing pulses

Hello everybody,

I have been working on this project for a while now, I am getting quite close but I am having an issue with my encoder, it seems if I rotate my encode at anything other than quite slow it misses pulses. I thought initially this was bouncing however with my count remaining consistently low it would appear it is simply missing pulses. If I rotate the encoder slowly, say around 15 RPM there are no issues and I get a consistent number however much about that and my numbers begin to drop. I am hoping you guys can give me some insight as to what might be going on here... This is the encoder in question...

#include <Wire.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x3f, 20, 4); // set the LCD
//address to 0x3f for a 16 chars and 2 line display
const int clkPin = 3; //the clk attach to pin2
const int dtPin = 2; //the dt attach to pin3
const int swPin = 4 ; //the number of the button
int encoderVal = 0;//raw counts from encoder
const float distancePerCount = 1 ; //adjust as required
float totalDistance = 0.0;
//added variable for interrupt handler
volatile int count = 0;


void setup()
{
  lcd.init();  // initialize the lcd
  // Print a message to the LCD.
  lcd.backlight();
  lcd.setCursor(0, 0);
  lcd.print("Belt Length :");
  //set clkPin,dePin,swPin as INPUT
  pinMode(clkPin, INPUT_PULLUP);
  pinMode(dtPin, INPUT_PULLUP);
  pinMode(swPin, INPUT);
  digitalWrite(swPin, HIGH);
  Serial.begin(9600); // initialize serial communications at 9600 bps

  attachInterrupt(digitalPinToInterrupt(clkPin), isrA, CHANGE);
  attachInterrupt(digitalPinToInterrupt(dtPin), isrB, CHANGE);
}

void loop()
{
  int change = getEncoderTurn();
  if (change != 0)
  {
    encoderVal = encoderVal + change;
    totalDistance = encoderVal * distancePerCount;
    Serial.println(encoderVal); //print the encoderVal on the serial monitor
    Serial.println(totalDistance, 2); //print float with 2 dp
    lcd.setCursor(5, 1);
    //lcd.print(encoderVal);
    lcd.print(totalDistance, 2);
  }

  if (digitalRead(swPin) == LOW) //if button pull down
  {
    //encoderVal = .157;
    encoderVal = 0;
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("Belt Length :");
  }

}

int getEncoderTurn(void)
{
  noInterrupts();
  int result = count;
  count = 0;//reset count
  interrupts();
  return result;
}

void isrA() {
  if (digitalRead(dtPin) != digitalRead(clkPin)) {
    count ++;
  } else {
    count --;
  }
}
void isrB() {
  if (digitalRead(clkPin) == digitalRead(dtPin)) {
    count ++;
  } else {
    count --;
  }
}

Maybe you could start with trying the mode "FALLING" for the attachInterrupt .... for testing.

And whenever an interrupt occurs, you could add 1 count.

Do this with a new piece of code that contains bare minimum code..... just enough for testing. And you can use serial monitor to display the result of the counts.

Well...several things:

  • I see a couple of resistors in one of the photos. Presumably those are pull-ups [or even pull-downs?!?]. It would be great if you used a meter, or something, to find out.
  • If they are pull-ups, then use INPUT instead of INPUT_PULLUP on the CLK and DT pins BUT one of the pins [CLK/DT/SW] seems to be missing a resistor, so you will need to determine which ones are involved.
  • If they are pull-downs, then using INPUT_PULLUP could very well, be your problem, as the pull-down resistor will working with the MCU pull-up, to form a voltage divider, and since 10k [the apparent value of the resistors on the Encoder board] is around 1/2 or more [much more] of the value of the MCU internal pull-up, the voltage will never rise high enough to register a HIGH -- ever]
  • There should be a third resistor. But, based on the photo, only R2 & R3 are populated. R1 appears to be nothing more than an "air resistor".
  • A schematic of your setup would sure help. And, perhaps, a photo, or three.
  • If you have a scope, a two channel "printout" of the waveforms generated by a couple of turns, would be gold!

I suppose I can see how a quadrature output could be interpreted as a "Clock" and "Data" signal, but which one is which, is arbitrary, so it makes me wonder if something else is going on!?!

BTW: Here's a good article on how an encoder works, and how ot [at least, the typical encoder]: https://www.allaboutcircuits.com/projects/how-to-use-a-rotary-encoder-in-a-mcu-based-project

I can find nothing wrong with your code when used with an optical encoder turned quite fast. It does not appear to miss any counts.

I have one suggestion. Verify that there are indeed 10K pull up resistors to 5v on the back of your board.

If they are not there, then use a stronger external pullups to 10K or 4.7K or 2.2K in stead of the internal resistors used by the INPUT_PULLUP mode.

Even with the 10K resistors on the board, stronger pullups might help.

I would really question the use of Keyes 040 mechanical encoder for fast rotation. I am surprised that it wont go faster than 15 rpm, but they are cheaply made, and the internal switches may not work properly at higher speeds. They are best used for manual input of menu selection and things like that.

If you are really trying to monitor a motor at higher than 15 rpm I would consider an optical or magnetic encoder.

Thanks for the input guys, I have verified the 10k resistors are in fact in place, and pull up to 5v. I changed the INPUT_PULLUP to just INPUT with identicle results. The encoder is mounted in the center of a pulley, it does not need to spin extremely high RPM but certainly higher than 15. This machine will be used to measure out lengths of belt, the belt is pulled across the pulley and through a sheer by hand I would think 100 RPM would not be an unreasonable speed to see on this encoder. I've attached a few pictures of my setup. It is a bit of a mess as I have it torn apart at the moment trying to figure this out.

I agree with cattledog. That encoder is intended for manual operation only, and will wear out quickly if machine driven.

OK, some of you might have noticed that I removed a previous post. I did that because I wired up a test, using an algorithm that I had used decades ago. It was an algorithm that worked well, then, but was exhibiting the same issues as the OP was seeing, in my test setup.

So, I dug in and did a bunch of research, and tried various algorithms, watched the waveforms on my scope, and came up with the following (which I am sharing, even though it's not advised that the OP use the encoder eluded to, this code should work for the right kind of quadrature encoder [such as an optical encoder]):

This code works VERY well, even when I spin the encoder pretty fast. If I spin it as fast as I can, i.e. I flick it with my fingers, it tends to not update the count, but there are no other glitches -- in other words, it resumes the count where it was before the inactivity. It doesn't jump around at all. BTW: that was with the debounce delay active. If I turn the debounce delay off, it might be responding a little faster, but it also, increments when it should decrement, and vice versa.

The basic premise in decoding an encoder, is: Direction is determined by which switch changes first. CW or CCW depends on which encoder switch is defined as "A" and which is "B", so it's arbitrary, but to make the language easier, I will assume that when switch "A" changes first, that is CW and when switch "B" changes first, that's CCW. Then, a Full Action is determined by the other switch changing. To distinguish between these two "modes", one looks at whether the switches are in the same state, or in opposite states. At rest, the switches will be at the same state [i.e. either both open or both closed]. When rotating between the detents, there will be a point where the switches are at different states [i.e. one open and one closed]. When a rotation begins, the switch that first changes state, determines the direction of rotation. Then, when the other switch changes state, that indicates a full rotation and that it's time to increment or decrement the count [or whatever action is intended, when rotating the encoder].

Software debounce is achieved by catching unexpected states, as can be seen in the demo code, below.

BTW: the encoder I used may be different than the one the OP indicated.

I'll post the code in a new reply, since including it here exceeds the 9000 character limit!

UPDATE: I remembered that the delay() function doesn't function in an Interrupt Routine, so I changed it to delayMicroseconds().

Here's the altered code:

/***************************************************************************
 *                                Encoder Demo
 *                      
 * Demos a rotary encoder of the kind where it's two switches are at the same
 * state at rest [i.e. when shaft is not turning], and are at different states
 * when between detents. From one detent to another, one switch transitions, 
 * at which point the two switches are in opposite states, then the other 
 * switch transitions, and the two switches are at the same state.  For example:
 *          A  |  B
 * -----------------
 * Rest 1:  O  |  O
 * Trans 1: C  |  O
 * Rest 2:  C  |  C
 * Trans 2: O  |  C
 * Rest 3:  O  |  O
 * 
 * Where 'O' = Open  &  'C' = Closed
 * 
 * This demo increments in one direction, until a MAX_COUNT is reached,
 * then stays at that MAX_COUNT.  When rotated in the other direction, the count
 * decrements until it reaches zero, where it stays until rotated the other way.
 * Also, because it's hard to see glitchs in numbers [at least for some of us ;)]
 * I added a "graph".  Basically it's visual feedback, and makes glitches VERY
 * easy to see.  
 * 
 * Note: I watched the switch transitions on a scope, and saw no switch bounce
 *       until I turned the encoder shaft REALLY fast.  In all other cases,
 *       it was VERY clean (though there must be the occasional bounce, because 
 *       of the glitches that occur when the debounce delay is disabled)!  Not all 
 *       encoders may be that clean, and perhaps, as rotary encoders ages, this 
 *       might get worse -- stress testing might be prudent. 
 *                      
 * Version 04: Minimal code in the Interrupt Handlers.  Works Great!!  Only VERY 
 *             occasional glitches when the debounce delay is not activated, otherwise
 *             I was unable to get it to glitch, even with manic rotation!
 ***************************************************************************/

#define NO_EXT_PULLUPS          false
#define INCLUDE_DEBOUNCE_DELAY  true


// =========================================================
//                Pin Defines
// =========================================================
#define PIN_ENCODER_A 2
#define PIN_ENCODER_B 3
#define PIN_ENCODER_PB 4


// =========================================================
//                Constants
// =========================================================
const byte ENC_DIR_UNKNOWN   = 0;
const byte ENC_DIR_CW        = 1;
const byte ENC_DIR_CCW       = 2;
const int MAX_COUNT          = 60;
const int MIN_COUNT          = 0;
#if INCLUDE_DEBOUNCE_DELAY
const unsigned long DDELAY   = 200;   // Number of uS for Debounce Delay
#endif


// =========================================================
//                Parameters
// =========================================================
byte encoder_direction             = ENC_DIR_UNKNOWN;
volatile boolean encoder_changed_A = false;
volatile boolean encoder_changed_B = false;
boolean count_changed              = false;     // So the Serial port is not flooded with useless information
int da_count                       = MIN_COUNT;
String graph                       = String(MAX_COUNT+1);
String buf;

// =========================================================
//                Function Prototypes
// =========================================================
inline void update_count(int inc_or_dec);


// =========================================================
//                Interrupt Service Routines
// =========================================================
void ISR_Encoder_A()
{
#if INCLUDE_DEBOUNCE_DELAY  
  delayMicroseconds(DDELAY);        // Debounce delay [without this, there are [very] occasional glitches]
#endif  
  encoder_changed_B = false;        // Just in case things go wonky
  encoder_changed_A = true;  
}

void ISR_Encoder_B()
{
#if INCLUDE_DEBOUNCE_DELAY  
  delayMicroseconds(DDELAY);        // Debounce delay [without this, there are [very] occasional glitches]
#endif
  encoder_changed_A = false;        // Just in case things go wonky
  encoder_changed_B = true;  
}

// =========================================================
//                         SETUP
// =========================================================
void setup()
{
  Serial.begin(115200);      // Be sure to either change this to 9600, or change the setting on your terminal
#if NO_EXT_PULLUPS  
  pinMode(PIN_ENCODER_A, INPUT_PULLUP);
  pinMode(PIN_ENCODER_B, INPUT_PULLUP);
#endif  
  pinMode(PIN_ENCODER_PB, INPUT_PULLUP);

  attachInterrupt(digitalPinToInterrupt(PIN_ENCODER_A), ISR_Encoder_A, CHANGE);
  attachInterrupt(digitalPinToInterrupt(PIN_ENCODER_B), ISR_Encoder_B, CHANGE);

  Serial.println("Welcome to the Encoder Test Sketch!");

  // Fill graph string
  graph = "";
  for (int glen=0; glen<MAX_COUNT; ++glen)
  {
    graph += "*";
  }
}


// =========================================================
//                         LOOP
// =========================================================
void loop() 
{
  // Test the Encoder Push Button
  if (digitalRead(PIN_ENCODER_PB) == LOW)
  {
    // Your Push Button code here
  }

  if (encoder_changed_A)
  {
    encoder_changed_A = false;
  
    if (digitalRead(PIN_ENCODER_A) != digitalRead(PIN_ENCODER_B))     // A != B
    {
      // Then the rotation is in the first stage, and we now know that A changed first.
      // Thus this is a Clockwise rotation.
      if (encoder_direction != ENC_DIR_CW)
      {
        // This is where rotation direction is determined
        encoder_direction = ENC_DIR_CW;   
      }
      else if (encoder_direction == ENC_DIR_CW)
      {
        // This is either a bounce, OR the shaft rotation reversed before the B switched 
        // changed, so cancel any direction detection
        encoder_direction = ENC_DIR_UNKNOWN;
      }
      else     
      {
        // ERROR!!  Mark the direction as Unknown so we don't get a false action!
        encoder_direction = ENC_DIR_UNKNOWN;
      }
    }
    else    // A == B
    {
      if (encoder_direction == ENC_DIR_CCW)
      {
        // Then, this is the second half of a rotation.  Set the encoder direction to 
        // unknown to set this up for the next rotation action.
        encoder_direction = ENC_DIR_UNKNOWN;
        // And, because this is a CCW rotation, decrement the count.
        update_count(-1);
      }
      else
      {
        // ERROR!!
        encoder_direction = ENC_DIR_UNKNOWN;
      }
    }
  }
  else if (encoder_changed_B)
  {
    encoder_changed_B = false;

    if (digitalRead(PIN_ENCODER_B) != digitalRead(PIN_ENCODER_A))     // A != B
    {
      if (encoder_direction != ENC_DIR_CCW)
      {
        // This is where rotation direction is determined
        encoder_direction = ENC_DIR_CCW;   
      }
      else if (encoder_direction == ENC_DIR_CCW)
      {
        // This is either a bounce, OR the shaft rotation reversed before the
        // B switched changed, so cancel any direction detection
        encoder_direction = ENC_DIR_UNKNOWN;
      }
      else
      {
        // ERROR!!
        encoder_direction = ENC_DIR_UNKNOWN;
      }
    }
    else     // A == B
    {
      if (encoder_direction == ENC_DIR_CW)
      {
        encoder_direction = ENC_DIR_UNKNOWN;
        update_count(1);
      }
      else
      {
        // ERROR!!
        encoder_direction = ENC_DIR_UNKNOWN;
      }
    }   
  }

  // Provide feedback regarding the current encoder count and only update it
  // When the count has changed -- so there isn't a deluge of Serial data.
  if (count_changed)
  {
    count_changed = false;

    Serial.print("Count: ");
    // Force the number colum to a consistant width of 2, so the graph has
    // consistant positioning.
    if (String(da_count, DEC).length() == 1)
    {
      Serial.print(" " + String(da_count, DEC));
    }
    else
    {
      Serial.print(da_count);
    }
    
    Serial.print(" ");
    Serial.println(graph.substring(0, da_count));
  }
}

// =========================================================
//                 Function Defnintions
// =========================================================
inline void update_count(int inc_or_dec)
{
  da_count += inc_or_dec;

  if (da_count > MAX_COUNT)
  {
    // Pin the count at the Maximum Count
    da_count = MAX_COUNT;
  }

  if (da_count < MIN_COUNT)
  {
    // Pin the count at the Minimum Count
    da_count = MIN_COUNT;
  }

  // This is meant to be used to limit Serial output.
  count_changed = true;
}

I agree. Grab an optical quadrature rotary encoder for cases where the shaft is continually rotating.

BTW: Here's a link to a YouTube video that does a very good job of describing how an encoder works, and appears to feature the very encoder you are using:

Also, based on another video I watched [very tedious, full of superfluous information, and even misleading in places, thus the reason for not including it, here], I get the impression that your encoder [the one you purchased from Amazon] rotates through 4 switch changes between detents, whereas the encoder I experimented with, only does 2 switch changes per detent.

The code that I posted should still work, but it will, likely, generate two counts per "rotation" [i.e. between each detent]. If that's not in alignment with your needs, then you could count by 0.5 (using a float, instead of an int), or still count by 1, but divide the count by 2 [shift right by one], before using it, or count only when both switches are open, or vice versa [determined by what the rest state is -- i.e. if the rest state is, both switches open, then only count when a rotation brings the encoder back to the both-switches-open state.].

Southpark:
I agree. Grab an optical encoder for cases where the shaft is continually rotating.

Or magnetic, with a Hall Effect device [digital output being the, likely, best choice].

ReverseEMF:
Or magnetic, with a Hall Effect device [digital output being the, likely, best choice].

Agreed. That's a good variety to use.

Here's a rework of my Rotary Encoder Demo, but with most of the Encoder code in the Interrupt Routines (so the loop() func is cleaner). It still exhibits the occasional glitch [but only when the shaft is spun and released, like a top--so it's left to come to a stop on it's own, rather than being under muscle control the whole time--probably some vibration that isn't being dampened by finger mass], but only by +/- 1 count:

/***************************************************************************
 *                           Rotary Encoder Demo
 *                      
 * Demos a rotary encoder of the kind where it's two switches are at the same
 * state at rest [i.e. when shaft is not turning], and are at different states
 * when between detents. From one detent to another, one switch transitions, 
 * at which point the two switches are in opposite states, then the other 
 * switch transitions, and the two switches are at the same state.  For example:
 *          A  |  B
 * -----------------
 * Rest 1:  O  |  O
 * Trans 1: C  |  O
 * Rest 2:  C  |  C
 * Trans 2: O  |  C
 * Rest 3:  O  |  O
 * 
 * Where 'O' = Open  &  'C' = Closed
 * 
 * This demo increments in one direction, until a MAX_COUNT is reached,
 * then stays at that MAX_COUNT.  When rotated in the other direction, the count
 * decrements until it reaches zero, where it stays until rotated the other way.
 * Also, because it's hard to see glitchs in numbers [at least for some of us ;)]
 * I added a "graph".  Basically it's visual feedback, and makes glitches VERY
 * easy to see.  
 * 
 * Note: I watched the switch transitions on a scope, and saw no switch bounce
 *       until I turned the encoder shaft REALLY fast.  In all other cases,
 *       it was VERY clean (though there must be the occasional bounce, because 
 *       of the glitches that occur when the debounce delay is disabled)!  Not all 
 *       encoders may be that clean, and perhaps, as rotary encoders ages, this 
 *       might get worse -- stress testing might be prudent. 
 *                      
 * Version 06: Most code in the Interrupt Handlers, except the update_count() func  
 *             call.  Works Great when debounce delay is active [only 200uS]!  
 *             Almost as good as Version 04 with debounce delay.  Very occational 
 *             glitches, though.  But only +/- 1 count.
 *             But, if I rotate at a "resonable" rate, it's pretty clean.  
 *             This version is working much better than Version 05, 
 *             especially with the debounce delay activated.  But, Version 04 is 
 *             still the winner--by a slight margin!
 ***************************************************************************/

#define NO_EXT_PULLUPS          false
#define INCLUDE_DEBOUNCE_DELAY  true


// =========================================================
//                Pin Defines
// =========================================================
#define PIN_ENCODER_A 2
#define PIN_ENCODER_B 3
#define PIN_ENCODER_PB 4


// =========================================================
//                Constants
// =========================================================
const byte ENC_DIR_UNKNOWN   = 0;
const byte ENC_DIR_CW        = 1;
const byte ENC_DIR_CCW       = 2;
const int MAX_COUNT          = 60;
const int MIN_COUNT          = 0;
#if INCLUDE_DEBOUNCE_DELAY
const unsigned long DDELAY   = 200;   // Number of uS for Debounce Delay
#endif


// =========================================================
//                Parameters
// =========================================================
volatile byte encoder_direction    = ENC_DIR_UNKNOWN;
int da_count                       = MIN_COUNT;
volatile int inc_dec               = 0;              // This serves both to modify the count AND to serve as an indication of a count change
String graph                       = String(MAX_COUNT+1);


// =========================================================
//                Function Prototypes
// =========================================================
inline void update_count();


// =========================================================
//                Interrupt Service Routines
// =========================================================
void ISR_Encoder_A()
{
#if INCLUDE_DEBOUNCE_DELAY  
  delayMicroseconds(DDELAY);        // Debounce delay [without this, there is a slightly greater incidence of [very] infrequent, +/- 1 count glitches]
#endif  

  if (digitalRead(PIN_ENCODER_A) != digitalRead(PIN_ENCODER_B))     // A != B
  {
    // Then the rotation is in the first stage, and we now know that A changed first.
    // Thus this is a Clockwise rotation.
    if (encoder_direction != ENC_DIR_CW)
    {
      // This is where rotation direction is determined
      encoder_direction = ENC_DIR_CW;   
    }
    else if (encoder_direction == ENC_DIR_CW)
    {
      // This is either a bounce, OR the shaft rotation reversed before the B switch changed, so 
      // cancel any direction detection.
      encoder_direction = ENC_DIR_UNKNOWN;
    }
    else
    {
      // ERROR!!
      encoder_direction = ENC_DIR_UNKNOWN;
    }
  }
  else    // A == B
  {
    if (encoder_direction == ENC_DIR_CCW)
    {
      // Then, this is the second half of a rotation.  Set the encoder direction to 
      // unknown to set this up for the next rotation action.
      encoder_direction = ENC_DIR_UNKNOWN;
      // And, because this is a CCW rotation, decrement the count.
      inc_dec = -1;
    }
    else
    {
      // ERROR!!
      encoder_direction = ENC_DIR_UNKNOWN;
    }
  }
}

void ISR_Encoder_B()
{
#if INCLUDE_DEBOUNCE_DELAY  
  delayMicroseconds(DDELAY);          // Debounce delay [without this, there is a slightly greater incidence of [very] infrequent, +/- 1 count glitches]
#endif

  if (digitalRead(PIN_ENCODER_B) != digitalRead(PIN_ENCODER_A))     // A != B
  {
    if (encoder_direction != ENC_DIR_CCW)
    {
      // This is where rotation direction is determined
      encoder_direction = ENC_DIR_CCW;   
    }
    else if (encoder_direction == ENC_DIR_CCW)
    {
      // This is either a bounce, OR the shaft rotation reversed before the B switch 
      // changed, so cancel any direction detection.
      encoder_direction = ENC_DIR_UNKNOWN;
    }
    else
    {
      // ERROR!!
      encoder_direction = ENC_DIR_UNKNOWN;
    }
  }
  else    // A == B
  {
    if (encoder_direction == ENC_DIR_CW)
    {
      encoder_direction = ENC_DIR_UNKNOWN;
      inc_dec = 1;
    }
    else
    {
      // ERROR!!
      encoder_direction = ENC_DIR_UNKNOWN;
    }
  } 
}

// =========================================================
//                         SETUP
// =========================================================
void setup()
{
  Serial.begin(115200);         // Be sure to either change this to 9600, or change the setting on your terminal
#if NO_EXT_PULLUPS  
  pinMode(PIN_ENCODER_A, INPUT_PULLUP);
  pinMode(PIN_ENCODER_B, INPUT_PULLUP);
#endif  
  pinMode(PIN_ENCODER_PB, INPUT_PULLUP);

  attachInterrupt(digitalPinToInterrupt(PIN_ENCODER_A), ISR_Encoder_A, CHANGE);
  attachInterrupt(digitalPinToInterrupt(PIN_ENCODER_B), ISR_Encoder_B, CHANGE);

  Serial.println("Welcome to the Encoder Test Sketch!");

  // Fill graph string
  graph = "";
  for (int glen=0; glen<MAX_COUNT; ++glen)
  {
    graph += "*";
  }
}


// =========================================================
//                         LOOP
// =========================================================
void loop() 
{
  // Test the Encoder Push Button
  if (digitalRead(PIN_ENCODER_PB) == LOW)
  {
    
  }

  // Provide feedback regarding the current encoder count and only update it
  // When the count has changed [either 1 or -1 -- if 0, it's ignored] -- so 
  // there isn't a deluge of Serial data.
  if (inc_dec != 0)
  {
    update_count();
    
    Serial.print("Count: ");
    // Force the number colum to a consistant width of 2, so the graph has
    // consistant positioning.
    if (String(da_count, DEC).length() == 1)
    {
      Serial.print(" " + String(da_count, DEC));
    }
    else
    {
      Serial.print(da_count);
    }
    
    Serial.print(" ");
    Serial.println(graph.substring(0, da_count));
  }
}


// =========================================================
//                 Function Defnintions
// =========================================================
inline void update_count()
{
  da_count += inc_dec;
  inc_dec = 0;  // So no more counting will occur until this is changed to either 1 or -1

  if (da_count > MAX_COUNT)
  {
    da_count = MAX_COUNT;
  }

  if (da_count < MIN_COUNT)
  {
    da_count = MIN_COUNT;
  }
}

And, here's a bit of pseudo code that may make this a bit more clear:

MODULE 1
  if (A != B)
    result = 0
    if (A changed)
      direction = CW
    else if (B changed)
      direction = CCW
    else 
      Ignore this condition

  if (A == B)
    if (direction == CW  AND  B changed)
      direction = NONE  // So this triggers no more for this round
      result = 1
    else if (direction == CCW  AND  A changed)
      direction = NONE  // So this triggers no more for this round
      result = -1
    else
      We're probably at rest so ignore

MODULE 2
  Use _result_ in some way

I too had this problem .that when i was turning more fast .then arduino was droping the singnals and couldnt count correctly .i gave up that war and focus to lineer position resistance method :confused:

My apologies for telling you guys here are the pictures and not having any of them, ReverseEMF thank you so much for all your effort regarding this project I will be going over the information you provided this weekend. I will also be investigating different encoders this weekend. It's quite difficult for me to dedicate significant time to this project during the week I am quite busy. I am going to attempt to attach links to pictures again here...

Close up encoder

Further out encoder

The entire machine

The electronics

It's a bit of a mess still for that I apologize, the belt is pulled up over the top of the pulley through the guide and then through the sheer. The idea is the belt is pulled through the sheer until the desired length is reached and then it can be cut. This will all be done manually, no motors spinning anywhere on this particular device.

Based on the input I am receiving from you guys this seems like a good replacement for my current encoder however before I place the order I thought I'd run it by you guys and see what your thoughts were...

Optical encoder

emir22:
I too had this problem .that when i was turning more fast .then arduino was droping the singnals and couldnt count correctly .i gave up that war and focus to lineer position resistance method :confused:

Yeah, actually, come to think of it...this would be a job for discrete logic or perhaps some kind of array logic [GAL/CPLD/SPLD]. The external module would decode the encoder and maintain a count that would be available to the Arduino anytime it's needed. Or certain set points could trigger a more Arduino manageable signal, like every 100 counts and/or direction change and/or limit reached, etc.

I've never used one of these PLDs but clearly there are learning curves, the need for a programmer and possibly other support devices, and using such a device may be overkill, but if you care to explore:
Some helpful links:

You are headed in the right direction. I think this encoder might be a bit too high of resolution for your application. 600 pulses per revolution will give 2400 counts per revolution with your reading algorithm.

I see in the spec -Response frequency: 0-20KHz, even though it is mechanically spec'd for 5000 rpm.

I'm not exactly sure what this means, but its possible that at full resolution, you will be limited to about 500 rpm. (20k/2400)*60

If this is some sort of internal electronic limitation on switching time, then I don't think that alternative algorithms to read only 1200 counts or 600 counts per revolution will be a work around.

I would try to find something similar with higher response frequency. An encoder with fewer pulses per revolution might come with that. If you can't find anything in your price range then its worth giving this one a try.