2

Beginner here.

I´ve been trying to implement a button function timer working with millis() instead of delay as I want the button to be responsive while the timer is running.

So far I´ve managed to start the counter on the button´s state change and let it time out. Unfortunately all kind of strange behavior is coming out of my sketch and I am yet to understand why.

Help is appreciated.

This is the desired behaviour of the timer:

  1. On startup the Arduino is ready to recieve a button push. The relay is off (HIGH).
  2. Once the button is pushed:
    • The relay state is changed to LOW in order to turn it on
    • A green LED switches on.
    • A millis() based timer is switched on.
  3. If the user presses the button while the switch is on, the timer is reset to 0 and continues counting.
  4. If the on-time is going to end, a red LED starts blinking. Say in the last minute.
  5. As soon as the timer reaches the specified on-time:
    • The green LED switches off
    • The relay switches off • The system returns to step 1. and is awaiting a push.

In my code example the red blinking Led is not implemented yet. The following code switches the switch and the green LED on but does not switch them off anymore.

//CONSTANTS

#define BUTTON_PIN        2  // Button
int in1 = 7;
int greenLED = 4;
int redLED = 9;


//VARIABLES

int buttonPushCounter = 0;   // counter for the number of button presses
int buttonState = 0;         // current state of the button
int lastButtonState = 0;     // previous state of the button

//MILLIS
unsigned long previousMillis = 0;
const long interval = 10000;


void setup()
{
  pinMode(BUTTON_PIN, INPUT);
  digitalWrite(BUTTON_PIN, HIGH); // pull-up
  Serial.begin(9600);

  pinMode(greenLED, OUTPUT);
  pinMode(redLED, OUTPUT);

  //SWITCH HANDLERS
  pinMode(in1, OUTPUT);
  digitalWrite(in1, HIGH);

}


void loop(){

    // read the pushbutton input pin:
    buttonState = digitalRead(BUTTON_PIN);
    unsigned long currentMillis = millis();

    // compare the buttonState to its previous state
    if (buttonState != lastButtonState) {

        buttonState = digitalRead(BUTTON_PIN);

        if (currentMillis - previousMillis < interval){
        //SWITCH ON, LED ON
          digitalWrite(in1, LOW);
          digitalWrite(greenLED, HIGH);
        }

        if (currentMillis - previousMillis >= interval) {
            previousMillis = currentMillis;
            digitalWrite(in1, HIGH);
            digitalWrite(greenLED, LOW);
        } 


        // Delay a little bit to avoid bouncing
        delay(50);


        // Reset buttonState:
        lastButtonState = buttonState;
   }
}
1
  • For one, you are running code when the button is being pressed, but also when the button is being released (though I don't think that effects anything here). Secondly, the code that checks if enough time has passed only runs when the button is pressed (or released). Thirdly the previousMillis isn't updated when the button is pressed.
    – Gerben
    Commented Nov 28, 2017 at 15:40

1 Answer 1

3

Written and tested. I also included the red blinking led.

//CONSTANTS

const int BUTTON_PIN = 2; // Button
const int in1 = 7;
const int greenLED = 4;
const int redLED = 9;


//VARIABLES

int buttonPushCounter = 0;   // counter for the number of button presses
int buttonState = 0;         // current state of the button
int lastButtonState = 0;     // previous state of the button
bool relayOn = false;

//MILLIS
unsigned long previousMillis = 0;
const unsigned long interval = 10000;
const unsigned long redLedInterval = 2000;


void setup()
{
  pinMode(BUTTON_PIN, INPUT);
  digitalWrite(BUTTON_PIN, HIGH); // pull-up
  Serial.begin(9600);

  pinMode(greenLED, OUTPUT);
  pinMode(redLED, OUTPUT);

  //SWITCH HANDLERS
  pinMode(in1, OUTPUT);
  digitalWrite(in1, HIGH);

}


void loop(){

    // read the pushbutton input pin:
    buttonState = digitalRead(BUTTON_PIN);
    unsigned long currentMillis = millis();

    // if button is pressed, turn relay on (if it wasn't already on), and reset the timer
    if( buttonState==LOW ) // no need to check for previous state, in this specific case
    {
        previousMillis = currentMillis;
        digitalWrite(in1, LOW);
        digitalWrite(greenLED, HIGH);
        digitalWrite(redLED, LOW);
        relayOn = true;
    }

    // if relay is currently on...
    if( relayOn )
    {
        // turn red led on, if close to turning off the relay
        if (currentMillis - previousMillis >= interval-redLedInterval )
            digitalWrite(redLED, (millis()/300)%2);//blink red led; 300ms on; 300ms off

        // if enough time has elapsed, turn of the relay
        if (currentMillis - previousMillis >= interval) 
        {
            // .. turn of relay
            digitalWrite(in1, HIGH);
            digitalWrite(greenLED, LOW);
            digitalWrite(redLED, LOW);
            relayOn = false;
        }
    } 
}

Added advantage here is that the timer will never run out if the button is keep being pressed down.

17
  • Thanks. This is very nice from you. Unfortunately all it seems to do is switch both, the greenLED and the relay on as soon as the Arduino is powered. Pushing the button does not sem to have any effect. Could this be a hardware problem? I was working on a very similar approach to your bool relayOn but with an integer changing between 0 and 1. While this partially worked, I was stuck at the timer reset implementation. I will try and include your solution in my approach and post the results. Commented Nov 28, 2017 at 16:27
  • Then I think you have your button connected the other way around. Is the button connected to 5v or GND when pressed?
    – Gerben
    Commented Nov 28, 2017 at 16:30
  • Try changing buttonState==LOW to buttonState==HIGH.
    – Gerben
    Commented Nov 28, 2017 at 16:31
  • Halleluja! It works! For some reason the idea that a button state change was important was stuck in my head. I thought that the buttonState==LOW and HIGH states are only working while this state is in fact present, meaning while the button is held pressed and not after that. I have no way to express the amout of gratitude. Commented Nov 28, 2017 at 16:41
  • I also find this expression very interesting. Why does this work? digitalWrite(redLED, (millis()/300)%2); Commented Nov 28, 2017 at 16:43

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