Debounced single button interrupt for LCD page handling

Hi all,

I’ve been working for a while on an in-car OBD readout \ clock \ temperature gauge to replace the factory-fitted clock. I’ve got all the various inputs connected up and working well, just having a bit of trouble getting my input button to work reliably.

It’s a basic momentary push button that I want to switch between two display “pages”. The first has time, date, temperature and the second has various OBD data displays from the car’s diagnostics.

The button is wired up as per this guidance (using internal resistor on the Arduino)

Originally I had the button handling inside the “loop” code but now all my inputs are sending data that makes the button response too slow so my aim is to use interrupts instead

However the problem I’m having is that the response to input is still unreliable and at some point spews random characters onto the LCD. If I go back to the previous version of my code (before adding interrupts) the issue goes away so it looks to be down to how I’ve implemented the debounce \ interrupt.

  • Physically it’s connected one side to pin D2, the other to ground.
  • I was using an Arduino Uno, now move to a Nano but same results with both.
  • Other hardware includes an LCD, DS18B20 temperature sensor and DS3234 RTC module.

if I watch the serial monitor I can see the counter increasing but not always in time with me pressing the button. Code is in my next post below, put together from various snippets I’ve found so probably won’t win any awards for efficiency.

Code attached (too long to put inside post with code tags and then had to wait 10 minutes to be able to reply!)

Just also noticed someone here http://forum.arduino.cc/index.php?topic=46201.0 saying that the internal pull-up resistor can’t be used when the pin is set as an interrupt - is this definitely the case?

MG_ZR_Clock_button4_int.ino (9.75 KB)

There's no reason to use an interrupt to read a button that a human is going to push. Humans are way slow. If your other code was blocking and making your button unresponsive, then fix that code instead of kludging your human interface into an interrupt.

gshaw: Code attached (too long to put inside post with code tags and then had to wait 10 minutes to be able to reply!)

Just also noticed someone here http://forum.arduino.cc/index.php?topic=46201.0 saying that the internal pull-up resistor can't be used when the pin is set as an interrupt - is this definitely the case?

Definitely NOT the case. You can set the pin to INPUT_PULLUP and use an interrupt just fine.

move the button back into the loop and it should work fine.

made notes in this section of the problem with the code

 buttonState = digitalRead(buttonPin);
      
        // compare the buttonState to its previous state
        if (buttonState != lastButtonState) {
          //add timer for debounce here 40-50ms
          lcd.clear();
          // if the state has changed, increment the counter
          if (buttonState == HIGH) {//pull_up is other way round use LOW for pushed
          //add timer for debounce here 40-50ms .even delay(40); would work for testing
          
            // if the current state is HIGH then the button
            // wend from off to on: // no it went the other way
            buttonPushCounter++; 
            Serial.println("on");

Delta_G: Definitely NOT the case. You can set the pin to INPUT_PULLUP and use an interrupt just fine.

Good to know that's OK, one less component to fit on the PCB :)

Delta_G: There's no reason to use an interrupt to read a button that a human is going to push. Humans are way slow. If your other code was blocking and making your button unresponsive, then fix that code instead of kludging your human interface into an interrupt.

Just tried the other version of the code where the button handling is in the loop; it works OK with the basic temperature and clock inputs but lags badly when the OBD reader is brought into play. I haven't got much control over how quickly the data is returned from the car's ECU so have to tackle the button from another angle.

gpop1: move the button back into the loop and it should work fine.

made notes in this section of the problem with the code

Thanks, will give it a try. Was wondering whether it should be HIGH or LOW after seeing some other examples. Might explain the odd behaviour of the button picking up a delayed response.

You could try out my debounce library - https://github.com/PaulMurrayCbr/DebounceInput/wiki

PaulMurrayCbr:
You could try out my debounce library - Home · PaulMurrayCbr/DebounceInput Wiki · GitHub

Thanks for this, just gave it a try and your library has given the best button response so far in terms of speed and reliability of responding to a press. I’ve removed the interrupt now and put the code back in the loop.

Also tried to make some additional logic changes to only invoke screen handling code when the input state changes. It seems to be working but in a way I’m unsure why…

…in theory my code attached only changes screen when the button value changes. However what keeps updating the sensor values even though nothing else is changing? If I warm up the temperature sensor for instance the value changes as I’d want but the way I read the code it shouldn’t actually be happening?!

Maybe there’s a subtlety in how the programming language works when calling functions I’ve missed? I’m a network and server guy by trade rather than programmer so any further advice to tidy up the code would be much appreciated :slight_smile:

MG_ZR_Clock_button5_debounced.ino (11 KB)