Button not being read during loop consistently

Is this a case for an interrupt, or is there a better way to handle this. Essentially my sketch allows a user to set a temperature between 60-90 degrees, and then activates a series of fans for cooling after a delay. I’ve noticed that the set point button seems to be slow in reacting (sometimes long hold, sometimes not), and I’m guessing it’s because of when I’m polling the button (at the very beginning of the code). I’m looking at adding a menu structure via the LCD to adjust the set point and the delays between the fans, but am worried with the slow responsiveness of the set point button these will all be an issue…any thoughts?

#include <LiquidCrystal.h>
#include <DallasTemperature.h>
#include <OneWire.h>
LiquidCrystal lcd(12, 11, 5, 4, 3, 2); 
float setpoint;
float faren;
unsigned long startTime=0;
unsigned long temper=0;
float high;
float low;


int inPin = 13;	   // the number of the input pin
int reading;	     // the current reading from the input pin
int previous = LOW;    // the previous reading from the input pin
int count=78; //number of times button was pressed
// the follow variables are long's because the time, measured in miliseconds,
// will quickly become a bigger number than can be stored in an int.
long time = 0;	   // the last time the output pin was toggled
long debounce = 200;   // the debounce time, increase if the output flickers


#define ONE_WIRE_BUS 7
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);

void setup()
{
   lcd.begin(20, 4); // set up the LCD's number of columns and rows..remember rows start at 0
  sensors.begin();

  pinMode (8, OUTPUT);
pinMode(9,OUTPUT);
pinMode (10,OUTPUT);
//pinMode (0,OUTPUT);
 pinMode(inPin, INPUT);
 high=75;
low=75;
}

void loop()
{

  reading = digitalRead(inPin);

  // if we just pressed the button (i.e. the input went from LOW to HIGH),
  // and we've waited long enough since the last press to ignore any noise...  
  if (reading == HIGH && previous == LOW && millis() - time > debounce) {
    //increment count
    count++;

    // ... and remember when the last button press was
    time = millis();    
  }
  previous = reading;

  if (count==91)
  {
    count=60; //reset count
  }
  
setpoint=count;

lcd.setCursor(0,0); //set cursor spot on the top left
    lcd.print("Cur:");
    lcd.setCursor(4,0);
    lcd.print(faren);
    lcd.setCursor(0,1);
    lcd.print("Set:");
lcd.setCursor(4,1);
lcd.print(count);
    lcd.setCursor(0,2);
    lcd.print("H:");
    lcd.setCursor(3,2);
    lcd.print(high);
    lcd.setCursor(0,3);
    lcd.print("L:");
    lcd.setCursor(3,3);
    lcd.print(low);
    
 sensors.requestTemperatures();
  
  
  faren=sensors.getTempCByIndex(0);
  faren=((1.8*faren)+32);
  
  if (faren<setpoint) {
    digitalWrite (8,LOW);
    digitalWrite (9,LOW);
    digitalWrite (10,LOW);
   // digitalWrite (0,LOW);
  }
  
  if ((faren>=setpoint) && (digitalRead (8)==LOW)) {
    digitalWrite(8,HIGH);
    startTime=millis();
  }
  
  if (faren>setpoint && digitalRead (9)==LOW && (millis()-startTime)>10000 ) {
    digitalWrite(9,HIGH);
    startTime=millis();  
  }
  
   if (faren>setpoint && digitalRead (10)==LOW && (millis()-startTime)>10000 ) {
    digitalWrite(10,HIGH);
    startTime=millis();  
  }
  // if (faren>setpoint && digitalRead (0)==LOW && (millis()-startTime)>5000 ) {
  //  digitalWrite(0,HIGH);
   // startTime=millis();
    
  //}  
  
  if (faren<low) {
    low=faren;
  }
  if (faren>high) {
    high=faren;
  }
  
}

How is the switch wired? You are not using the internal pull-up resistor, so, this implies that you have an external resistor. The test for HIGH implies a pull-down resistor? Do you have such a resistor?

Yes I have a pull up resistor installed at the switch. I'm assuming that since it's in the loop portion, it's only getting checked after everything else has been gone through (the IF statements). I'm really wanting to integrate a menu system with 4 buttons for various settings, but am scared I'm going to run into the same situation with those as it only gets checked at the beginning of the loop??

I'm assuming that since it's in the loop portion, it's only getting checked after everything else has been gone through (the IF statements).

That's true, but nothing in the loop actually delays, as far as I can see.

Try adding a Serial.print() statement whenever the button is read. There should be a steady stream of data sent to the serial monitor. If that is the case, move the print statement inside the if(reading == HIGH block. The message should print every time you press and release the switch. 200 milliseconds is a long debounce time.

Sparkinman:

void loop()

{

reading = digitalRead(inPin);

if (reading == HIGH && previous == LOW && millis() - time > debounce) {
   [...]
 }
 previous = reading;

The problem is with the line previous=reading. You should only set previous inside the if statement, otherwise depending on the switch bounces the condition of the if might never be true for the switch state and the time together. Try:

void loop()
{

  reading = digitalRead(inPin);

  if (reading == HIGH && previous == LOW && millis() - time > debounce) {
     count++;

    // ... and remember when the last button press was
    time = millis(); 
    previous = reading;
  }

Korman

Major time consuming code is right here.

lcd.setCursor(0,0); //set cursor spot on the top left
    lcd.print("Cur:");
    lcd.setCursor(4,0);
    lcd.print(faren);
    lcd.setCursor(0,1);
    lcd.print("Set:");
lcd.setCursor(4,1);
lcd.print(count);
    lcd.setCursor(0,2);
    lcd.print("H:");
    lcd.setCursor(3,2);
    lcd.print(high);
    lcd.setCursor(0,3);
    lcd.print("L:");
    lcd.setCursor(3,3);
    lcd.print(low);

Checking digital inputs and doing calculations and ifs will take you less than 1ms in your loop but the above is a lot of time. You can time just the above alone if you want but that is what you should cut down.

You don't need to update your lcd every time you sense your buttons, making no sense. You should update your lcd, only the content that are actually changing, when there is a change, the labels don't need reprint. Here is what you should do, if you pause and think about your project for a moment:

render lcd once

loop:

the button sensing and else
if say 0.2 seconds passed since last lcd render, render again, but only the values, leave the labels alone.

loop end:

Okay, So I moved the reading=precious up inside the IF statement, and am going to look at the LCD portion.
Would it be advisable to set my "labels" on the LCD screen in the setup portion of the code rather than the loop? The reason I ask is because I want to have more of an interactive menu in the next iteration....would it be best to put those in other functions and call them for certain events (rather than looping)?
I will upload later tonight and test to see if the switch responds faster than it is now!

For interactive menus, you can look at me work:

What I do is keep checking buttons and only update the lcd if there is a need. The menu is simply a select_list() function call and the call returns when the user has made a decision. You can decide what to run from which item the user selected.

On 16X2 display:

On 20X4 display: