rotary encoder: too many interrupts = freeze

Hi -
I posted a week or so back about issues I was having trying to work with a rotary encoder from an old HP plotter (HEDS-6300 attached to a DC motor). I was using the Boarduino and it was freezing up - possibly resetting - so I looked at my power sources, H-bridge controller, code, etc.

Everything seemed fine so it was pretty baffling (ok, frustrating :wink:

After some sweaty debugging, it turns out that the encoder is firing so many interrupt events that loop() is never called. At first I was trying to use both channels on the encoder with the interrupt CHANGE mode. Then one channel with CHANGE mode. I finally got things working (code below) using just one channel with the interrupt RISING mode. The interrupt routine is the one from the Arduino Playground - pretty barebones.

I couldn’t find a datasheet for this HEDS-6300 encoder so I don’t know what hardware I am dealing with. Has anyone encountered this before? Is there a way around it? I can live with less encoder resolution if I have to but I’d like to understand the issue better (and maybe help someone who runs into this and does a search in future).

Oh - I tried this with the Boarduino, an Arduino NG, and got it working with a Wiring board. Haven’t gone back to the other boards to see if the same code works on them.

Cheers,
‚ÄďRoy

int enablePin = 3;
int dir1Pin = 24;
int dir2Pin = 25;

int LEDpin = 48;
int encoder0PinA = 38;
int encoder0PinB = 39;
int theDirection = 1;
volatile long encoder0Pos = 0;
long lastEncoderPos = 0;

void setup(){
  pinMode(encoder0PinA, INPUT); 
  pinMode(encoder0PinB, INPUT);

  pinMode(dir1Pin, OUTPUT);
  pinMode(dir2Pin, OUTPUT);  
  pinMode(LEDpin, OUTPUT); 

  attachInterrupt(6, doEncoderA, RISING);

  Serial.begin(115200);
  Serial.println("reset");

  //CW
  digitalWrite(dir1Pin, LOW);
  digitalWrite(dir2Pin, HIGH);
  analogWrite(enablePin, 1000);

  encoder0Pos = 0;
  theDirection = 1;
}


void loop(){
  digitalWrite(LEDpin, HIGH);
  delay(50);


  if (encoder0Pos != lastEncoderPos){
    Serial.print(theDirection); 
    Serial.print(" "); 
    Serial.println(encoder0Pos);   
    lastEncoderPos = encoder0Pos;
  }

  if (encoder0Pos > 10000 && theDirection == 1){
    //CCW
    digitalWrite(dir1Pin, HIGH);
    digitalWrite(dir2Pin, LOW);
    analogWrite(enablePin, 500); 
    theDirection = 0;

  }  
  else  if (encoder0Pos < -10000 && theDirection == 0){
    //CW
    digitalWrite(dir1Pin, LOW);
    digitalWrite(dir2Pin, HIGH);
    analogWrite(enablePin, 500 ); 
    theDirection = 1;
  }

  digitalWrite(LEDpin, LOW);
  delay(50);
}



void doEncoderA(){

  // look for a low-to-high on channel A
  if (digitalRead(encoder0PinA) == HIGH) { 
    // check channel B to see which way encoder is turning
    if (digitalRead(encoder0PinB) == LOW) {  
      encoder0Pos--;         // CW
    } 
    else {
      encoder0Pos++;         // CCW
    }
  }

  else   // must be a high-to-low edge on channel A                                       
  { 
    // check channel B to see which way encoder is turning  
    if (digitalRead(encoder0PinB) == HIGH) {   
      encoder0Pos--;          // CW
    } 
    else {
      encoder0Pos++;          // CCW
    }
  }
}

I think you've already identified the source of your problem:

it turns out that the encoder is firing so many interrupt events that loop() is never called.

Those old HP encoders usually have discs with lots of holes, so you're getting scores, maybe hundreds, of interrupts for every revolution of the motor.

There are a couple of approaches you could take. If you don't need maximum precision, you could put a counter chip between the encoder and the Arduino, and use it to "pre-scale" the pulses, slowing down the interrupt rate.

If you do want maximum precision, you'll have design an up-down counter circuit, and read its value to get the position.

Ran

Thanks - yeah, and it occurred to me after the fact that I could easily determine the resolution just by powering the encoder but not the motor and turning the shaft by hand. doh!

There are at least hundreds of interrupts triggered each revolution.

I think by using RISING mode in the interrupt and only reading one channel, I am using 1/4 of the resolution. If I get the PID control part working and the precision isn't good "enough" - well, I guess I'll deal with that then.