Rotary Encoder giving glitchy results

I just purchased this rotary encoder from digikey http://search.digikey.com/scripts/DkSearch/dksus.dll?WT.z_header=search_go&lang=en&site=ca&keywords=P12336-ND&x=0&y=0 and have been using my own variation of the rotary encoder code in the playground

/*
 
  The circuit:
 * LCD RS pin to digital pin 12
 * LCD Enable pin to digital pin 11
 * LCD D4 pin to digital pin 10
 * LCD D5 pin to digital pin 9
 * LCD D6 pin to digital pin 8
 * LCD D7 pin to digital pin 7

 * Encoder A to digital pin 2
 * Encoder B to digital pin 3
 * Encoder Button to digital pin 4

 */

// include the library code:
#include <LiquidCrystal.h>

// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(12, 11, 10, 9, 8, 7);

// Encoder variables
int enc_a = 2;
int enc_b = 3;
int enc_button = 4;

int count = 0;

long prevMS = 0;
int interval = 200;

void setup() {
  pinMode(enc_a, INPUT);
  digitalWrite(enc_a, HIGH);
  pinMode(enc_b, INPUT);
  digitalWrite(enc_b, HIGH);
  
  pinMode(enc_button, INPUT);
  
  attachInterrupt(0, encoderPos, CHANGE);
  
  // set up the LCD's number of rows and columns: 
  lcd.begin(16, 2);
}

void loop() {
  if (digitalRead(enc_button) == LOW) {
    count = 0;
    lcd.clear();
  }
  // set the cursor to column 0, line 1
  // (note: line 1 is the second row, since counting begins with 0):
  lcd.setCursor(0, 0);

  lcd.print(count);
  
  //lcd.clear();
}

void encoderPos() {
  if (millis() - prevMS > interval) {
    prevMS = millis();
    
    if (digitalRead(enc_a) == digitalRead(enc_b)) {
      count++;
    } else {
      count--;
    }
  }
  // Sets range to 0-9  
  if (count < 0) {
    count = 9;
  } else if (count > 9) {
    count = 0;
  }
}

While it is technically working, I'm finding the rotary encoder to be rather glitchy. If I turn it really slow (and I mean really slow) it works as intended, but turning it at a natural speed I'm finding my count sometimes goes up, when it should go down and vice-versa - but only for one or two counts, so instead of outputting 1, 2, 3, 4, 5, I'll get 1, 2, 3, 2, 3, 4, 5, 3, 4, 5.

Is there a problem with my code, or is it simply because I bought a $2 rotary encoder?

You bought a 50 cent rotary encoder for $2. The results from that encoder are not going to be nearly as good as those from an optical rotary encoder.

it it's mechanical, maybe you'll have to debounce the switches

This isn't a robust way to get the encoder value.

There is an interrupt service routine which ignores inputs which are more frequent than 200 milli seconds. The value of interval cause the if test in encoderPos to skip inputs for 200 mSec before looking for another value, so you only have to turn at faster than one unit in 1/5th of second (which I think you can), and it will be lost

Try to find how fast the values change.
look at one encoder pin, and time changes to it. There is no need for an interrupt service routine, just a simple program that times, say 200 encoder pulses, and finds the fastest.

You might find that there is a lot of noise (extra, rapid pulses made by mechanicl noise). If this is the case, you should see a bunch of short duration pulses due to noise, then more believable pulse durations (estimated from the rate at which you are turning the encoder), a bunch of values which represent the actual rate the encoder pulses arrive.

I think the value of interval is intended to supress false readings from noise. I'd tend to make that about 10 mSec, as a guess, and the previous experiment will give you an idea about whether there is a lot of noise (the delay between encoder values will be stupidly fast compared to the rate of rotation). The previous experiment will also tell you if my guess is wildly wrong :slight_smile:

HTH

Take a look here -> http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1271116324

gbulmer: uh...I think I understood most of what you said. I actually put in the 200 millisecond interval to slow down the count rate, nothing to do with noise. Your suggestions at least look interesting, and I'll definitely try to wrap my brain around them in the morning. I've only done simple things with arduino, and it's probably been about a year since I've touched it, so it's taking me a bit to process everything.

felis: I'd actually come across that post earlier today and bookmarked it, but forgot about it - initial tests have it working just fine with the LCD...now for some tinkering

If you look in the encodes datasheet you will see it says:

Bouncing 5mS.

So you need to do at least 5mS debouncing for every "contact closure" to make sure you don't get false readings.

Well, after several tests with several different codes, I've concluded that it's just a crummy rotary encoder and I've opted to replace it with a much more reliable (though not quite as fun) pair of buttons to increase and decrease the number. Thanks all for the help!