Bouncing encoder...

Hello everybody,

I have been working on this project for quite some time now. What I have is an Arduino Nano a 20PPR encoder and a 16x2 LCD. I have everything working as it should for the most part. When my encoder is turned somewhat slowly it behaves as it should (10 - 15RPM I am guessing) however much above that and the readout on my LCD becomes spastic and unstable. placed a .1uf cap on pins D2, and D3 both to gnd and I have set the pullup resistor to high on both pins (INPUT_PULLUP) with little or no improvement. I have spent a good amount of time reading about different methods of debouncing but I am struggling to understand how to implement software debounce in my sketch. Any help you guys might be able to offer would be greatly appreciated.

#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= 2; //the clk attach to pin2
const int dtPin= 3; //the dt attach to pin3
const int swPin= 4 ;//the number of the button
int encoderVal = 0;//raw counts from encoder
const float distancePerCount = .157; //adjust as required
float totalDistance = 0.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
}

void loop()
{
  int change = getEncoderTurn();
  encoderVal = encoderVal + change;
  totalDistance = encoderVal*distancePerCount;
  
  if(digitalRead(swPin) == LOW)//if button pull down
  {
    //encoderVal = 0.157;
    encoderVal = 0;
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print("Belt Length :");
  }
  Serial.println(encoderVal); //print the encoderVal on the serial monitor
  Serial.println(totalDistance,3);//print float with 3 dp
  lcd.setCursor(5,1);
  //lcd.print(encoderVal);
  lcd.print(totalDistance,3);
}

int getEncoderTurn(void)
{
  static int oldA = HIGH; //set the oldA as HIGH
  static int oldB = HIGH; //set the oldB as HIGH
  int result = 0.078;
  int newA = digitalRead(dtPin);//read the value of clkPin to newA
  int newB = digitalRead(clkPin);//read the value of dtPin to newB
  if (newA != oldA || newB != oldB) //if the value of clkPin or the dtPin has changed
  {
    // something has changed
    if (oldA == HIGH && newA == LOW)
    {
      result = (oldB * 2 - 1);
    }
  }
  oldA = newA;
  oldB = newB;
  return result;
}

Hi,

I'm not that good at code, but what I suspect is the time writing to the LCD is taking too long for your loop.

For a test:
I would suggest you disable the encoder code. Measure the time of the main loop "mostly the LCD write".

you could use millis() and a loop counter to get the time. Then compare that to the loop time needed to keep up with your encoder.

John

Use the encoder library. That will use interrupts when available. On most Arduinos, that means putting at least one of the encoder lines on pin 2 or 3 (which you already have.)

Under many circumstances, bouncing is not a problem. Bounces just look like flipping the knob back and forth really quickly and when the bounces settle, the position reported by the library is equal to the actual position. If it is a problem then a tiny capacitor like 10pF between each encoder line and ground may help.

Perhaps a video will clarify what I am experiencing, this sure looks like bouncing to me, admittedly however I would consider myself still rather green in the world of Arduino.

Arduino video

Maxxheadroom:
Perhaps a video will clarify what I am experiencing, this sure looks like bouncing to me, admittedly however I would consider myself still rather green in the world of Arduino.

Arduino video

That doesn't look like a 'bouncing' issue. Bouncing would be associated with getting more trigger pulses than desired. This issue here looks like it's just missing trigger pulses altogether when you're turning the shaft relatively quickly.

But better get things straight first ... what result is the readout supposed to be? Is it supposed to just count the number of pulses as you keep turning the shaft?

Also...should avoid statements like the following one ..... for good reasons.

Maxxheadroom:
becomes spastic and unstable.

I too, do not think it is bouncing. It looks like it is missing pulses. As Morgan S suggests switch to an interrupt based sketch. Use either a library or write your own routine.

Here is you last posted code, minimally revised to use interrupts. I have changed the display to only update on a change. You may be reading all four quadrature pulse with this code, and the distance per pulse may need revision.

#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 = 2; //the clk attach to pin2
const int dtPin = 3; //the dt attach to pin3
const int swPin = 4 ; //the number of the button
int encoderVal = 0;//raw counts from encoder
const float distancePerCount = .157; //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, 3); //print float with 3 dp
    lcd.setCursor(5, 1);
    //lcd.print(encoderVal);
    lcd.print(totalDistance, 3);
  }

  if (digitalRead(swPin) == LOW) //if button pull down
  {
    //encoderVal = 0.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 --;
  }
}

Debouncing is not needed for an encoder, bounces look exactly like a one-unit jitter in position, and that you
get anyway if the shaft is on the edge of one of the contacts - you have to live with this anyway.