Needing help with buttoned timer

Hey guys im trying to make like a countdown where you can switch between hours minutes and seconds. Theres one button to switch between the three and another to change the value of the time they picked. Last to start the countdown and when the countdown ends the servos move. My problem is like the switching button only switches to Minutes and doesnt go to seconds or hours. The other problem is the increasing button only goes up to 1. Please help guys

#include <Servo.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>

Servo mainServo;
Servo servo1;
Servo servo2;

LiquidCrystal_I2C lcd(0x27, 16, 2);

const int selectButton = 2;
const int increaseButton = 3;
const int startButton = 4;

int selectedTime = 0; // 0 = hours, 1 = minutes, 2 = seconds
int countdownHours = 0;
int countdownMinutes = 0;
int countdownSeconds = 0;

bool lastSelectState = HIGH;
bool lastIncreaseState = HIGH;
bool lastStartState = HIGH;

void setup() {
    Serial.begin(9600);
    mainServo.attach(9);
    servo1.attach(10);
    servo2.attach(11);

    lcd.init();
    lcd.backlight();

    pinMode(selectButton, INPUT_PULLUP);
    pinMode(increaseButton, INPUT_PULLUP);
    pinMode(startButton, INPUT_PULLUP);

    displayTimeSelection();
}

void loop() {
    if (buttonPressed(selectButton, lastSelectState)) {
        selectedTime = (selectedTime + 1) % 3; // Cycles between 0, 1, 2
        displayTimeSelection();
    }

    if (buttonPressed(increaseButton, lastIncreaseState)) {
        increaseTime();
        displayTimeSelection();
    }

    if (buttonPressed(startButton, lastStartState)) {
        startCountdown();
    }
}

void increaseTime() {
    if (selectedTime == 0 && countdownHours < 23) {
        countdownHours++;
    } else if (selectedTime == 1 && countdownMinutes < 59) {
        countdownMinutes++;
    } else if (selectedTime == 2 && countdownSeconds < 59) {
        countdownSeconds++;
    }
}

void displayTimeSelection() {
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("Set Time:");
    lcd.setCursor(0, 1);
    
    lcd.print(selectedTime == 0 ? "[H] " : " H  ");
    lcd.print(countdownHours);
    lcd.print(" : ");
    lcd.print(selectedTime == 1 ? "[M] " : " M  ");
    lcd.print(countdownMinutes);
    lcd.print(" : ");
    lcd.print(selectedTime == 2 ? "[S] " : " S  ");
    lcd.print(countdownSeconds);
}

void startCountdown() {
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("Counting down...");
    
    while (countdownHours > 0 || countdownMinutes > 0 || countdownSeconds > 0) {
        lcd.setCursor(0, 1);
        lcd.print(countdownHours);
        lcd.print(" : ");
        lcd.print(countdownMinutes);
        lcd.print(" : ");
        lcd.print(countdownSeconds);
        delay(1000);

        if (countdownSeconds > 0) {
            countdownSeconds--;
        } else if (countdownMinutes > 0) {
            countdownMinutes--;
            countdownSeconds = 59;
        } else if (countdownHours > 0) {
            countdownHours--;
            countdownMinutes = 59;
            countdownSeconds = 59;
        }
    }
    triggerServo();
}

void triggerServo() {
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("Dispensing...");
    
    mainServo.write(45);
    delay(1000);
    mainServo.write(180);
    
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("Done!");
}

bool buttonPressed(int button, bool &lastState) {
    bool currentState = digitalRead(button);
    if (currentState == LOW && lastState == HIGH) {
        delay(50);
        while (digitalRead(button) == LOW);
        lastState = LOW;
        return true;
    }
    lastState = currentState;
    return false;
}

Here my tinkercad for the timer it a little messy right but ill tidy it up once i get to fix my problem

  • Where do you update your lastStatexxxx variables ?
    lastSelectState . . .

  • Avoid while( )

  • Don’t use delay( )

  • Study State Machines.

Have you tested buttonPressed() all by itself? I suspect It is not doing an adequate job of denouncing debouncing.

Use this pattern here in pseudocode: // edits to make it less unclear

    set button got pressed false
    if the button is different to last time (different!)
 
       if the button is now down
            the button just got pressed, set button got pressed true

       remember the button for next time
       delay a bit
  
    return button got pressed

You are currently only fixing one ragged edge of the button press. I bet.

a7

They are passed by reference and appear to be updated in the buttonPress() function.

I do not like the modern pass by reference. In C, things like that are impossible to not see.

a7

1 Like

:wink:

debouncing

1 Like

Hello plumlich

Divide the project into sub-projects:

For example:

  1. button manager with debouncing of the buttons
  2. LCD manager
  3. Servo handler
  4. I don't know at the moment

All in all, a timer is also required.

.

And one more comment on the project:

The coded hardware setup() does not match to the supplied circuit diagram.

grafik

grafik

1 Like

@plumlich I built your project.

I changed some printing and used a 20 character LCD, otherwise the logic is intact.

Even you inadequate button handling - the delay() you used masks the function's flaw, so you got lucky this time.

I may also have fixed the problem @paulpaulson points up. Wire you switches between the pin and ground, use INPUT_PULLUP for the pin mode and lose the resistors on the buttons.

It functions perfectly, with the exception of displaying some times incorrectly. It's because the old time digits are not fully erased. There are easy and better ways to code around this. Do it better than clearing the entire screen!

I also made the seconds tick past a bit faster. Life is short and it's too nice to sit around inside waiting for real time to go by. See it here:

HTH

a7

1 Like

The way I did it was connect a switch(in my case a range of dip switches) to serveral inputs and arrange code in a binary manner. I.e. sw1 =1 , sw2 =2, sw3 =4 etc. Then you can pick one (in your case) second at a time.
Mine was in minutes but it's same same really.
Don't currently have access to my workshop/office but will see in the coming week if you so require. Cheers

1 Like

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.