Trouble with programming logic

Hello. I tried to do a basic countdown timer, that shows output on LCD. This is the code

#include <LiquidCrystal.h>

LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
const int SSB = 6;// StartStop button
const int RB = 7;// Reset button
const int PB= 8;//Setup button
int StartStop=0;
int Reset=0;
int Setup=0;
int htime=0, mtime=0, stime=0; // variables for hours, minutes and seconds

void setup() 
{
  lcd.begin(20, 4);
  lcd.print("Countdown timer");
  lcd.setCursor(2,1);
  lcd.print(":");//printing separation marks
  lcd.setCursor(5,1);
  lcd.print(":");  //printing separation marks
  pinMode(SSB, INPUT); 
  pinMode(RB, INPUT); 
  pinMode(PB, INPUT);  
}

void loop() 
{
  Reset=digitalRead(RB);
  delay(50);
  if (Reset == HIGH){htime=0; mtime=0; stime=0;}//if reset is pressed all time variables go to 0
  lcd.setCursor(6, 1);//used to print all zeros on LCD
  lcd.print(stime);//used to print all zeros on LCD
  lcd.setCursor(3, 1);//used to print all zeros on LCD
  lcd.print(mtime);//used to print all zeros on LCD
  lcd.setCursor(3, 1);//used to print all zeros on LCD
  lcd.print(htime);//used to print all zeros on LCD
  StartStop=digitalRead(SSB);//if start is presed program goes to count function
  delay(50);
  if(StartStop == HIGH){count;}//if start is presed program goes to count function
  Setup=digitalRead(PB);
  delay(50);
  if (Setup==HIGH)//if setup is pressed stime is incremented. 
  { 
    lcd.setCursor(6, 1);
    stime++;
    lcd.print(stime);
    if (stime>=60) //after stime reaches 60 seconds it should increment mtime, reset stime to 0 and start counting again.
    {
      stime==0;
      lcd.setCursor(3, 1);
      mtime++;
      lcd.print(mtime);
      if (mtime>=60)
      {
        mtime=0;
        lcd.setCursor(3, 1);
        htime++;
        lcd.print(htime);
      }
    }
  }
}
void count()// count function
{
  do
  {
    do
      {
        do
          {
            lcd.setCursor(6, 1);
            stime--;//program enters this do-while loop and decrement stime to 0 and then mtime, and htime
            lcd.print(stime);
            delayMicroseconds(16667);//specific delay because I need it to go faster then seconds
            if(StartStop == HIGH) {loop;}//if startstop button is pressed program jumps to loop -> changed "loop" to "return"
            if (Reset == HIGH){htime=0; mtime=0; stime=0; loop;};//resets time variables and jumps to loop-> changed "loop" to "return"
          }while(stime>=0);
        lcd.setCursor(3, 1);
        mtime--;
if (mtime>0){stime=60;}// added this line. count shoud be countdown timer with specific time
        lcd.print(mtime);
      }while(mtime>=0);
      lcd.setCursor(3, 1);
      //lcd.print(htime);
      htime--;
if (htime>0){mtime=60;}// added this line. count shoud be countdown timer with specific time
      lcd.print(htime);
  }while(htime<=0);
}

My problem is in loop, where stime should be reseted it keeps counting to 61, 62, and further. Also reset and startstop doesn't work. I tested button they are connected properly, and LCD works.

Also reset and startstop doesn't work.

I tested button they are connected properly

One of these two statements is wrong. If the switches are wired correctly, the they should work. That they don't means that the switches are not wired correctly.

It is far easier to connect one side of the switch to ground, and the other side to a digital pin, and turn on the pullup resistor, than it is to deal with external pullup or pulldown resistors.

(deleted)

Thanks for the quick reply. Buttons work, i tested it in different code, where i count every time i press it. They are not disconnected or anything. I just realized that reset works, but because of LCD i thought it doesn't work(LCD resets first number, and when coundown reaches next digit it overwrite the previous.) There is still problem with StartStop

stime==0;

should be stime = 0;

i would never see that :slight_smile:

After further testing, i thing that the problem is with the function, because after clicking startstop button program doesn't enter count subroutine

That count() function is atrocious.

            if(StartStop == HIGH) {loop;}//if startstop button is pressed program jumps to loop

This isn't how to call a function. Even if it were, you should NEVER call loop() from another function. Learn to use return or break statements.

A do/while loop is executed at least once. In some cases, that is one too many times. A while statement is executed at least zero times. In most cases, that is a better minimum number of times.

// Comments are a good thing. There is nothing to explain what the oddball count() function is doing. Or, is supposed to do.

I'm new at this so some mistakes are expected :slight_smile: I changed the count so it doesn't use loop, but return. Count function should count backward to 0, from the previusly set variables htime, mtime and stime. I will edit my first post to comment that. thx

  if(StartStop == HIGH){count;}//if start is presed program goes to count function

The comment is wrong. This is not how to call count().

if(StartStop == HIGH) {loop;}//if startstop button is pressed program jumps to loop

No it doesn't, nor should you even attempt to.

i would never see that

even with many years experience these kind or typos slip through.

Furthermore your code is not structured in layout. Good layout helps creating readable code.
Good variable names help too.

Here a partially code that is more structured to get started.
Not all details are filled in, but you should be able to fix those

#include <LiquidCrystal.h>

LiquidCrystal lcd(12, 11, 5, 4, 3, 2);

const int SSB = 6;    // StartStop button
const int RB = 7;     // Reset button
const int PB = 8;      //Setup button
int StartStop = 0;
int Reset = 0;
int Setup = 0;

int hours = 1;
int minutes = 2;
int seconds = 20; 

unsigned long lastSecond;
int running = 0;             // state of the timer  0 = idle    1 = running   ...

void setup() 
{
  lcd.begin(20, 4);
  lcd.print("Countdown timer");
  lcd.setCursor(2,1);
  lcd.print(":"); //printing separation marks
  lcd.setCursor(5,1);
  lcd.print(":");  //printing separation marks
  pinMode(SSB, INPUT); 
  pinMode(RB, INPUT); 
  pinMode(PB, INPUT);  
  
  lastSecond = millis();
} 

void loop()
{
  // MAKE THE MEASUREMENTS
  int startstop = digitalRead(SSB);
  int reset = digitalRead(RB);
  int setup = digitalRead(PB);
  unsigned long now = millis();

  // DO THE MATH 
  if (reset == HIGH)
  {
    hours = 0; 
    minutes = 0; 
    seconds = 0;
    return;               // loop will automatically be called again after return
  };
  if ( startstop == HIGH )
  {
    // fix the start stop state here
    running = 1;
  }
  if (running == 1)
  {
    // adjust the seconds minutes and hours here when a second has passed.
    // tip: look at blink without delay for timing  
     // tip use the var lastsecond
  }


   // DISPLAY THE RESULTS
   lcd.setCursor(0, 1);
   lcd.print(hours);
   lcd.setCursor(3, 1);
   lcd.print(minutes);
   lcd.setCursor(6, 1);
   lcd.print(seconds);
}

Your turn to :

  • implement the seconds minutes and hours math
  • implement the start stop behaviour
  • fix the errors in the display
  • maybe some other issues I forgot

Thank allot, this is a great reference. Trouble is that this is my school assingment, and is very specific. Time must be fastened. I real second my timer must count 60 seconds. Thats why i tried using delaymicros.

thats only a small delta. and yes then you need micros.

After 8 hours of working i was able to make my program work. There were many mistakes, mostly in coding. Every thing works great except when counting startstop button won't go to loop: If anybody have some sugestions would be most appreciated. The problematic part is commented, its in "count" function.

#include <LiquidCrystal.h>

LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
const int SSB = 6;
const int RB = 7;
const int PB= 8;
int StartStop=0;
int Reset=0;
int Setup=0;
int htime=1, mtime=58, stime=54;

void setup() 
{
  Serial.begin(9600);
  lcd.begin(20, 4);
  lcd.print("Count");
  lcd.setCursor(3,1);
  lcd.print(":");
  lcd.setCursor(7,1);
  lcd.print(":");  
  pinMode(SSB, INPUT); 
  pinMode(RB, INPUT); 
  pinMode(PB, INPUT);  
}
void loop() 
{
  delay(100);
  Reset=digitalRead(RB);
  delay(50);
  if (Reset == HIGH){htime=0; mtime=0; stime=0;}
  lcd.setCursor(9, 1);
  lcd.print(stime);
  lcd.setCursor(5, 1);
  lcd.print(mtime);
  lcd.setCursor(1, 1);
  lcd.print(htime);
  StartStop=digitalRead(SSB);
  delay(50);
  if(StartStop == HIGH){count();}
  Setup=digitalRead(PB);
  delay(50);
  if (Setup==HIGH)
  { 
    lcd.setCursor(9, 1);
    stime++;
    lcd.print(stime);
    Serial.print(stime);
    if (stime>=60)
    {
      stime=0;
      lcd.setCursor(5, 1);
      mtime++;
      lcd.print(mtime);
      Serial.print(mtime);
      if (mtime>=60)
      {
        mtime=0;
        lcd.setCursor(1, 1);
        htime++;
        lcd.print(htime);
        Serial.print(htime);
      }
    }
  }
}
void count()
{
  do
  {
    do
      {
        do
          {
            StartStop=digitalRead(SSB);
            delay(10);
            if(StartStop == HIGH) {loop();}                                                     //this thing here for some reason won't work
            Reset=digitalRead(RB);
            if (Reset == HIGH){ htime=0; mtime=0; stime=0; loop();};               //reset works, but jump to loop won't
            delay(10);
            lcd.setCursor(9, 1);
            stime--;
            lcd.print(stime);
            Serial.print(stime);
            //delay(16);
           }while(stime>0);
        lcd.setCursor(5, 1);
        mtime--;
        lcd.print(mtime);
         Serial.print(mtime);
        if (mtime>0){stime=60;}
      }while(mtime>0);
      lcd.setCursor(1, 1);
      htime--;
      lcd.print(htime);
      Serial.print(htime);
      if (htime>0){mtime=60;}
  }while(htime>=0);
}

You (still) should not be calling loop(). If you want count() to end at that point, return.

You are still using do/while statements, where while statements are more appropriate.

I have tried to use return but it stops the program for a moment then continues. Like i said i'm new to this. I could rewrite it to while loops but, if you could write specific line to exit count() it would be helpfull. I have tried return, break, even goto but nothing seems to work

Well, you need return. You also could use more Serial.print() statements to determine what is going on.

Finally, you need to comment the count() function better (after changing to while statements), and explain what you want the function to do, when.

You have to count down from what maximum?

Well, in the interest of indirect help see if this makes any sense to you.
TIme has been scaled per your earlier statement of 1 second equals 1 minute (or so I interpreted it as - if not change the value of 'ONE_SECOND').

const unsigned long ONE_SECOND  = 16UL;
const unsigned long ONE_MINUTE  = 60 * ONE_SECOND;
const unsigned long ONE_HOUR    = 60 * ONE_MINUTE;

unsigned long msTarget;

unsigned long hms2millisecs(uint8_t const hours, uint8_t const minutes, uint8_t const seconds)
{
    return ((hours * ONE_HOUR) + (minutes * ONE_MINUTE) + (seconds * ONE_SECOND));
}

void millisecs2hms(unsigned long milliseconds, uint8_t* hours, uint8_t* minutes, uint8_t* seconds)
{
    uint8_t h = milliseconds / ONE_HOUR;        milliseconds -= h * ONE_HOUR;       *hours      = h;
    uint8_t m = milliseconds / ONE_MINUTE;      milliseconds -= m * ONE_MINUTE;     *minutes    = m;
    uint8_t s = milliseconds / ONE_SECOND;      milliseconds -= s * ONE_SECOND;     *seconds    = s;
}

void loop()
{
    uint8_t     hours;
    uint8_t     minutes;
    uint8_t     seconds;
    long        remaining = msTarget - millis();
    millisecs2hms(remaining, &hours, &minutes, &seconds);

    Serial.print((short)hours);
    Serial.print(":");
    Serial.print((short)minutes);
    Serial.print(":");
    Serial.println((short)seconds);

    if ( remaining <= 0 )
    {
        // we've reached zero time
        while (true)
        {    }
    }
}

void setup()
{
    Serial.begin(9600);
    
    msTarget = millis() + hms2millisecs(1, 50, 54); // hours, minutes, seconds
}