Debouncing problem in a rotary encoder

Hi guys, I want to use a rotary encoder (ec11) in an LCD menu for my final project year, but the problem is debunking, when I turn the knob I get the result in the image below, I have put a low pass filter but it doesn't work, I have found a software solution that uses register but I haven't understood it.

I use this code, when I turn the knob to the right, I need to see 1, and to the left I need to see 0, but I got a 1 between 0 instead I turn it to the left

#define clk 2
#define dt 3
volatile boolean TurnDetected;
volatile boolean up;

void isr0 ()  {
  TurnDetected = true;
  up = (digitalRead(clk) == digitalRead(dt));
}



void setup() {
  // put your setup code here, to run once:
  pinMode(clk, INPUT);
  pinMode(dt, INPUT);
  attachInterrupt (0, isr0, RISING);
  Serial.begin (9600);
  Serial.println("start"); 
}

void loop() {
  // put your main code here, to run repeatedly:
  if (TurnDetected) {
    TurnDetected = false;
    Serial.println(up);
  }

}

Give this library a try, works for me.

I'm not sure if it works because I don't have rotary encoder. But you can try this code if you want
If output still contains noise, adjust debounceDelay

What code do is giving some time margin for vibrating(bouncing) signal to be stabilized. Though it seems that encoder makes only one rising edge at a time, but actually it generates noisy rising edges in short moment.

#define clk 2
#define dt 3
volatile boolean TurnDetected;
volatile boolean up;

// the following variables are unsigned longs because the time, measured in
// milliseconds, will quickly become a bigger number than can be stored in an int.
volatile unsigned long riseDetectTime = 0;  // the last time the rising capture ISR executed
unsigned long debounceDelay = 50;    // the debounce time; increase if the output still vibrates

volatile bool isChanged = false;

void isr0 ()  {
  riseDetectTime = millis();
  isChanged = true;
}

void setup() {
  // put your setup code here, to run once:
  pinMode(clk, INPUT);
  pinMode(dt, INPUT);
  attachInterrupt (0, isr0, RISING);
  Serial.begin (9600);
  Serial.println("start"); 
}

void loop() {
  // put your main code here, to run repeatedly:
  if ((millis() - riseDetectTime) > debounceDelay) {
    if(isChanged) {
      isChanged = false;
      TurnDetected = true;
      up = (digitalRead(clk) == digitalRead(dt));
    }
  }
  if (TurnDetected) {
    TurnDetected = false;
    Serial.println(up);
  }

}

Things like encoders -- at least optically switched variants -- don't suffer from bounce. Bounce is an electromechanical action that happens inside mechanical switches and relays etc. The digital output of something like an encoder doesn't suffer a zillion make/break cycles during switching like a push button might.

I suspect there are issue elsewhere.

OP, do you have a scope with which you check the signal levels, phase timing and signal quality etc of the encoder?

Blackfin:
Things like encoders -- at least optically switched variants -- don't suffer from bounce. Bounce is an electromechanical action that happens inside mechanical switches and relays etc. The digital output of something like an encoder doesn't suffer a zillion make/break cycles during switching like a push button might.

I suspect there are issue elsewhere.

OP, do you have a scope with which you check the signal levels, phase timing and signal quality etc of the encoder?

I haven't used ec-11 encoder but I searched it and found that output can bounces within 2ms. Ec-11 seems to have some mechanical parts to generate pulses.

You can see it searching 'bounce' in the page below
https://www.alps.com/prod/info/E/HTML/Encoder/Incremental/EC11/EC11B15242AF.html

hyunsung:
I haven't used ec-11 encoder but I searched it and found that output can bounces within 2ms. Ec-11 seems to have some mechanical parts to generate pulses.

You can see it searching 'bounce' in the page below
https://www.alps.com/prod/info/E/HTML/Encoder/Incremental/EC11/EC11B15242AF.html

Ah, okay, that makes sense then. Mechanically switched == bounce potential.

OP looks to be checking the state of the sensed phase well within that range. Might be possible to try this:

void isr0 ()  
{
    TurnDetected = true;
    up = digitalRead(dt) ? true:false;

}

Stipulate to the rising edge because you're in the ISR; examine only the phase of the 2nd channel (which should be stable) to deduce direction.

If the chatter/noise is really bad, this won't work reliably either.

This library provides inherent debouncing. It works well.

It seems that encoder solutions are like opinions -- everyone has one :wink:

You might try this library: GitHub - gfvalvo/NewEncoder: Rotary Encoder Library.

I wrote it for a PEC11 Encoder that has horrible contact bounce coming through using the standard encoder library. This encoder has 24 detents and outputs a complete quadrature pulse for every detent-to-detent transition. This caused a double count with the standard library (even without a contact bounce).

It looks like the EC11 encoders have half the number of pulses as detents (i.e. 18 / 36). So a full quadrature transition requires traveling over 2 detents.

So, I think my version will solve your bounce problem but will only show a change in output on every other detent. I might update it someday to support the encoder type that must travel two detents per quadrature pulse.

BTW, my library is based on the technique used in the one that @dougp links above -- I credit that at the bottom of the README. However, mine uses interrupts (rather than polling) and direct port read (rather than digitalRead()), so it's very fast and requires no tending in your loop() function.

EDIT:
My bad. I see that the buxtronix library can also work with interrupts. But, you have to supply the ISR yourself.

Looking at it some more, I think this output characteristic shown in the EC11 datasheet is going to make things a little more difficult:
EC11.JPG

It says that you can't know the state (ON or OFF) of the B-signal at the detent positions. However, the B-signal is stable at the point of A-signal transition. So you're going to have to watch for transitions on the A-signal and immediately read the B-signal to determine the direction of rotation. I think this will cause issues with the state table-based libraries. Also it seems that the only way to debounce (in code) will be a timed technique. So, it will be slow -- probably not a problem for a control turned by a person.

Something like the code below should be close. It compiles, but is untested. It will be important to connect the encoder's A-output to the Arduino's aPin input (2 in code below).

#include "Arduino.h"
#include "Bounce2.h"

int16_t readEncoder();

const uint8_t aPin = 2;
const uint8_t bPin = 3;
const uint8_t debounceTime = 5;

Bounce aInput;
Bounce bInput;

void setup() {
  aInput.attach(aPin, INPUT_PULLUP);
  aInput.interval(debounceTime);
  bInput.attach(bPin, INPUT_PULLUP);
  bInput.interval(debounceTime);
}

void loop() {
  static int16_t lastEncoderValue = 0;

  int16_t encoderValue = readEncoder();
  if (encoderValue != lastEncoderValue) {
    Serial.print(F("New Encoder Value = "));
    Serial.println(encoderValue);
    lastEncoderValue = encoderValue;
  }
}

int16_t readEncoder() {
  static int16_t encoderPosition = 0;

  aInput.update();
  bInput.update();

  if (aInput.rose()) {
    if (bInput.read()) {
      encoderPosition--;
    } else {
      encoderPosition++;
    }
  } else if (aInput.fell()) {
    if (bInput.read()) {
      encoderPosition++;
    } else {
      encoderPosition--;
    }
  }
  return encoderPosition;
}

EC11.JPG

@gfvalvo, I don't think that type of encoder is at all typical. In fact, the ALPS info on their EC11 says it comes in two versions, one of which has the typical pattern where both switches are at known values at every detent. See attachment. I've never seen the other type used in any video or web page on rotary encoders, and I don't know where you would buy one. If the OP has an EC11, odds are he has the more typical version.

But there can be an issue even with normal encoders as to the number of pulses and detents. A "pulse" is considered to be a full cycle of both switches, which consists of four transitions. Some encoders have the same number of pulses as detents per revolution, which means four transitions between detents. Both switches are typically both open at every detent, although they do make encoders with both switches closed at detents.

The other type has half as many pulses as detents. Those encoders have two transitions between detents, and can come to rest at a detent with both switches open, or with both switches closed.

The software has to match the encoder type. If it doesn't, you will get two ticks between detents, or one tick every other detent. The datasheets for encoders like the PEC11L show the part numbers that apply to the various pulses/detents options, and an output table showing where the detents occur.

In general, I would agree with the recommendation of the state-machine lookup-table method of servicing encoders. It provides very good performance even without any hardware debouncing.

ShermanP:
I don't know where you would buy one.

You need look no further than different models of EC11 on the Alps web site:

On EC11E15244G1, both outputs are stable and defined at the detents.

On EC11E18244A5, only the A output is defined at the detents.

But there can be an issue even with normal encoders as to the number of pulses and detents. A "pulse" is considered to be a full cycle of both switches, which consists of four transitions. Some encoders have the same number of pulses as detents per revolution, which means four transitions between detents. Both switches are typically both open at every detent, although they do make encoders with both switches closed at detents.

The other type has half as many pulses as detents. Those encoders have two transitions between detents, and can come to rest at a detent with both switches open, or with both switches closed.

The software has to match the encoder type. If it doesn't, you will get two ticks between detents, or one tick every other detent. The datasheets for encoders like the PEC11L show the part numbers that apply to the various pulses/detents options, and an output table showing where the detents occur.

As pointed out in Reply #7. BTW, from what I can see from the web site, all of the EC11 models are of the type that output half as many (complete quadrature) pulses as they have detents.