Slow Analog Button Response

Hello All,

I am working on my first arduino project, which will eventually be a fully functioning alarm clock. I am trying to work my way up so it is nowhere near complete.

The hardware I am using for this project is a TM1637 7-segment LED, DS3231 RTC, 5 push buttons wired to a single analog input, and some test LEDs.

I am currently using the buttons to light up/turn off one of the LED’s when pressed while also displaying the time. This will be used to allow alarm functions later such as setting the time,setting alarm time, etc.

The problem I am running into is a slightly delayed response when a push button is pressed. While running the program below I have to hold the button to trigger the LED. A single button push does not always trigger the corresponding LED. I am debouncing the buttons. The issue only arises when the displayTime function is called. When I comment that out, the buttons work as expected. This leads me to the displayTime function as the source of the issue.

The displayTime function is used to “blink” the colon on the TM1637, with the colon illuminated for 500ms and off for 500 ms.

Any ideas on how I could improve the function or restructure the code to eliminate the button delay? I appreciate your help!

//Include Libraries:
#include "RTClib.h"
#include <TM1637Display.h>

//Define variables, pin numbers, buttons:
#define btnNONE   0
#define btnONE  1
#define btnTWO     2
#define btnTHREE   3
#define btnFOUR   4
#define btnFIVE 5

int ledONE = 8;
int ledTWO = 9;
int ledTHREE = 10;
int ledFOUR = 11;
int ledFIVE = 12;

bool ledONEflag;
bool ledTWOflag;
bool ledTHREEflag;
bool ledFOURflag;
bool ledFIVEflag;

unsigned long currentMillis = 0;    // stores the value of millis() in each iteration of loop()
const unsigned long clockBlinkInterval = 1000;
const unsigned long offInterval = 500;
unsigned long offTimer;
unsigned long clockBlinkTimer;

// Define 12 or 24 hour time:
#define TIME_24_HOUR      false

// Define TM1637 connection pins:
#define CLK 2
#define DIO 3

// Create rtc and display object:
RTC_DS3231 rtc;
TM1637Display display = TM1637Display(CLK, DIO);

void setup() {
// Setup RTC:
// Begin serial communication at a baud rate of 9600:
  Serial.begin(9600);
  // Wait for console opening:
  //delay(3000);
  // Check if RTC is connected correctly:
  if (! rtc.begin()) {
    Serial.println("Couldn't find RTC");
    while (1);
  }
  // Check if the RTC lost power and if so, set the time:
  if (rtc.lostPower()) {
    Serial.println("RTC lost power, lets set the time!");
    // The following line sets the RTC to the date & time this sketch was compiled:
    rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
    // This line sets the RTC with an explicit date & time, for example to set
    // January 21, 2014 at 3am you would call:
    //rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0));
  }
// Setup Display:
  // Set the display brightness (0-7):
  display.setBrightness(1);
  // Clear the display:
  display.clear();
  
//Setup Pin Modes:

  pinMode(ledONE, OUTPUT);   // declare LED as output
  pinMode(ledTWO, OUTPUT);   // declare LED as output
  pinMode(ledTHREE, OUTPUT);   // declare LED as output
  pinMode(ledFOUR, OUTPUT);   // declare LED as output
  pinMode(ledFIVE, OUTPUT);   // declare LED as output
  
  //Serial.println("Setup Complete");
}

void loop() {
  currentMillis = millis();
  //Get Current Time:
  DateTime now = rtc.now();
  // Create time format to display:
  int displaytime = (now.hour() * 100) + now.minute();
  //Serial.println(displaytime);
  
  // Do 24 hour to 12 hour format conversion when required.
  if (!TIME_24_HOUR) {
    // Handle when hours are past 12 by subtracting 12 hours (1200 value).
    if (now.hour() > 12) {
      displaytime -= 1200;
    }
    // Handle hour 0 (midnight) being shown as 12.
    else if (now.hour() == 0) {
      displaytime += 1200;
    }
  }

  // Check for Buttons
  button_input();
  displayTime(displaytime);
}
//////button functions///////////////////////////////////////////////////////
//  multiple buttons on 1 analog pin
byte read_LCD_buttons() {              // read the buttons
  int adc_key_in = analogRead(0);       // read the value from the sensor

  //value read to identify button (values tested using analogRead())
  if (adc_key_in > 1015){
    return btnFIVE;
  }
  if (adc_key_in >650 && adc_key_in< 700) {
    return btnTWO;
  }
  if (adc_key_in >825 && adc_key_in < 877) {
    return btnTHREE;
  }
  if (adc_key_in > 900 && adc_key_in < 950){
    return btnFOUR;
  }
  if (adc_key_in > 965 && adc_key_in< 1005){
    return btnONE;
  }
    return btnNONE;
}

// debounce a button//////////////////////////////////////////////////////////////////////////
int counter = 0;       // how many times we have seen new value
long previous_time = 0;    // the last time the output pin was sampled
byte debounce_count = 10; // number of millis/samples to consider before declaring a debounced input
byte current_state = 0;   // the debounced input value

byte  key_press(){
  // If we have gone on to the next millisecond
  if(millis() != previous_time)
  {
    byte this_button = read_LCD_buttons();

    if(this_button == current_state && counter > 0) counter--;

    if(this_button != current_state) counter++; 

    // If the Input has shown the same value for long enough let's switch it
    if(counter >= debounce_count) {
      counter = 0;
      current_state = this_button;
      return this_button;
      //Serial.println(this_button);
    }
    previous_time = millis();
  }
  return 0;
}
//Tie Actions to buttons//////////////////////////////////////////////
void button_input() {
  byte lcd_key = key_press();   // read the buttons
  switch (lcd_key) {
    case btnONE:
      ledONEflag =!ledONEflag;
      digitalWrite(ledONE, ledONEflag);
      break;
    case btnTWO:
      ledTWOflag =!ledTWOflag;
      digitalWrite(ledTWO, ledTWOflag);
      break;
    case btnTHREE:
      ledTHREEflag =!ledTHREEflag;
      digitalWrite(ledTHREE,ledTHREEflag);
      break;
    case btnFOUR:
      ledFOURflag =!ledFOURflag;
      digitalWrite(ledFOUR, ledFOURflag);
      break;
    case btnFIVE:
      ledFIVEflag =!ledFIVEflag;
      digitalWrite(ledFIVE, ledFIVEflag);
      break;
  }
}

// Show Time on TM1637///////////////////////////////////////////////////
void displayTime(int displaytime) {
    if (currentMillis- clockBlinkTimer >= clockBlinkInterval){
      clockBlinkTimer = millis();
    }
    else if (currentMillis - clockBlinkTimer >= offInterval){
      display.showNumberDec(displaytime, true);
      //Serial.println("No Colon");
    }
    else {
      display.showNumberDecEx(displaytime, 0b11100000, true);
      //Serial.println("Colon");
    }
}

Don't update the display in every loop (sending the data to the display driver needs several ms). Decrease the debounce_count.

Thanks, that fixed it!