0

Program reads rotary encoder correctly without bouncing in this code:

int val = 0;
byte clkPin = 3;
byte dtPin = 2;
bool lastClk;
bool lastDt;
void setup() {
  pinMode(clkPin,INPUT);
  pinMode(dtPin,INPUT);
  lastClk = digitalRead(3);
  lastDt = digitalRead(2);
  val = 0;
  attachInterrupt(digitalPinToInterrupt(clkPin), clkRise, RISING);
  Serial.begin(9600);
}

void loop() {
}

void clkRise(){
      lastClk = HIGH;
      lastDt = digitalRead(dtPin);
      if(lastDt == LOW){
        val--;
        Serial.println(val);
        }  else{val++; Serial.println(val);}
        }

but when i use lcd to show the result, i get massive bounces (i think) in this code:

#include <LiquidCrystal_I2C.h>

#include <Wire.h>

LiquidCrystal_I2C lcd(0x27,20,4);
int val = 0;
byte clkPin = 3;
byte dtPin = 2;
bool lastClk;
bool lastDt;
void setup() {
  lcd.begin();
  pinMode(clkPin,INPUT);
  pinMode(dtPin,INPUT);
  lastClk = digitalRead(3);
  lastDt = digitalRead(2);
  val = 0;
  attachInterrupt(digitalPinToInterrupt(clkPin), clkRise, RISING);
  Serial.begin(9600);
  lcd.home();
}

void loop() {
  lcd.print(val);
}

void clkRise(){
      lastClk = HIGH;
      lastDt = digitalRead(dtPin);
      if(lastDt == LOW){
        val--;
        Serial.println(val);
        }  else{val++;}
        }

it increases and decreases by random numbers between 0-5.I use KY-040 R.E. it has built-in 10k pull up resistors.

This is what i use to debounce:

A or B pin of R.E--10k R----------------------------------Arduino INPUT PIN
                         |
                         |
                         =0.1uF C
                         |
                         ---------------------GND
  • Try adding a slight delay after lcd.print(val);. Something like delay(50);. Also, if the R.E. has in internal pull-up of 10k, the series resistor between the A/B pin should be lower than 10k. Otherwise the maximum voltage is only 2.5V (Vcc/2). – Gerben Mar 19 '16 at 15:27
  • @Gerben i tried delaying, it works better but there are still big jumps like 3-4+ – Çay Öncesi Mar 19 '16 at 16:04
  • Either increase the delay, or only do the lcd.print if the value of val has changed. – Gerben Mar 19 '16 at 16:13
  • @Gerben it work way better now, but there are still rare jumps. would a schmitt trigger fix this? I took off the 10k resistor that i placed. – Çay Öncesi Mar 19 '16 at 16:24
  • I don't know. That's not my area of expertise. – Gerben Mar 19 '16 at 16:36
0

I suspect the problem is that your hardware-debounce capacitive circuit isn't working well enough to accurately debounce the contacts, and that invalid transitions are occurring on the quadrature lines as read by the program.

Note that use of Serial.println() within your clkRise() interrupt handler is problematic, because Serial.println() uses interrupts itself. As far as I know, println() is not reentrant, ie cannot be used correctly from the multiple interrupts that may start before previous println() calls finish their background processing. The bits of extra delay introduced by LCD code may merely be exposing a problem.

There is no need for either hardware or software debouncing on quadrature inputs. A correctly-implemented state machine will reject invalid conditions that arise during bounce, or will immediately follow any extra up-tick by a corresponding down-tick, or vice versa.

For some state machine code, see for example answer 16420/3917 and also see answer 18221/3917. Also see answer 19109/3917.

  • Çay Öncesi should definitely not be doing Serial.println inside an ISR. – Nick Gammon Mar 20 '16 at 3:15
  • @NickGammon alright. I finished my project. just curious, what is the outcome of placing Serial.println inside an ISR? – Çay Öncesi Mar 21 '16 at 15:21
  • Serial.print puts whatever-it-is you want to print into a buffer. It then waits for interrupts to empty the buffer. If the buffer is full already, it waits before putting data into the buffer. Since the buffer won't be emptied inside an ISR, if the serial buffer is full, the program will then block indefinitely. – Nick Gammon Mar 21 '16 at 19:39
  • What I've been doing in my decoder interrupt routines is to set a "valueChanged" flag. Then in the app's main loop, if value changed is true, I use Serial.println() to print it and set valueChanged=false. That way I'm not trying to do serial.print inside an ISR. When I needed more info than that. I created a large (char logBuffer[100]) C string to contain my logged data, and used strcat() to append to that. Then in the app's loop() I print the logBuffer and set it back to empty. – Duncan C Feb 24 at 22:52
  • @DuncanC, the general idea of using a buffer like that is ok, but there are several races that can occur -- eg if the ISR adds to the buffer between loop()'s "print the logBuffer" and its "set it back to empty" operations, the added data gets lost. One can fix the problems using semaphores, or switching between two buffers atomically, etc – James Waldby - jwpat7 Mar 5 at 4:43

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.