0

I have little to no experience in programming and i'm very slowly and gradually getting the hang of it. My next project is that i'm making a clock, and wanted to use multiple functions for the hour:minute:seconds instead of just using one for everything. But after reading some i came to the conclusion that the arduino can only run one function at a time. So my question is how can i make the illusion of multiple functions running simultaneously on a LCD screen.

My code:

#include <LiquidCrystal.h>


LiquidCrystal lcd(8, 9, 4, 5, 6, 7);


int lcd_key     = 0;
int adc_key_in  = 0;
#define btnRIGHT  0
#define btnUP     144
#define btnDOWN   329
#define btnLEFT   504
#define btnSELECT 741
#define btnNONE   5


int read_LCD_buttons()
{
 adc_key_in = analogRead(0);    

 if (adc_key_in > 1000) return btnNONE; 
 if (adc_key_in < 50)   return btnRIGHT; 
 if (adc_key_in < 195)  return btnUP;
 if (adc_key_in < 380)  return btnDOWN;
 if (adc_key_in < 555)  return btnLEFT;
 if (adc_key_in < 790)  return btnSELECT;  
 return btnNONE;


}
unsigned long minInterval = 60000UL; // Interval for minutes in milliseconds
unsigned long secInterval = 1000UL;  // Interval for seconds in milliseconds
unsigned long prevMinMillis = 0UL;   // Holds the timestamp of the last time Minute() was called
unsigned long prevSecMillis = 0UL;   // Holds the timestamp of the last time Second() was called

void setup()
{
 lcd.begin(16, 2);
}

void loop()
{
  unsigned long currentMillis = millis();

  if (currentMillis - prevMinMillis > minInterval)
  {
    prevMinMillis = currentMillis;
    Minute();
  }

  if (currentMillis - prevSecMillis > secInterval)
  {
    prevSecMillis = currentMillis;
    Second();
  }

}

void Second(){
  int First_Digit = 0;
  int Second_Digit = 0;


  for(Second_Digit; Second_Digit<10; Second_Digit++){
    if(Second_Digit==10){
      First_Digit = First_Digit + 1;
      }

    lcd.setCursor(0, 0);
    lcd.print(First_Digit);
    lcd.setCursor(1, 0);
    lcd.print(Second_Digit);
    lcd.clear();

    if(First_Digit==5 && Second_Digit==9){
      First_Digit = First_Digit - 5;
      Second_Digit = Second_Digit -10;

      }
    if(Second_Digit==9){
      First_Digit = First_Digit + 1;
      Second_Digit = Second_Digit - 10;
      }

  }
}
void Minute(){
  int First_Digit = 0;
  int Second_Digit = 0;
  for(Second_Digit; Second_Digit<10; Second_Digit++){
    if(Second_Digit==10){
      First_Digit = First_Digit + 1;
      lcd.print(First_Digit);
      }

    lcd.setCursor(3, 0);
    lcd.print(First_Digit);
    lcd.setCursor(4, 0);
    lcd.print(Second_Digit);
    lcd.clear();


    if(First_Digit==5 && Second_Digit==9){
      First_Digit = First_Digit - 5;
      Second_Digit = Second_Digit -10;
      lcd.print(First_Digit);

      }
    if(Second_Digit==9){
      First_Digit = First_Digit + 1;
      lcd.print(First_Digit);
      Second_Digit = Second_Digit - 10;
      }

  }
}
  • You ought to be able to write to specific positions on the LCD by specifing setCursor() as you have. Is this not working? If not, please describe what it displays, and what you want to see it display? – jose can u c Jan 24 '18 at 19:35
  • imagine that you are cooking a pot of stew and a pot of soup. you have to stir the stew every 10 minutes and you have to stir the soup every 15 minutes. you have a clock that displays time and beeps every minute. what process do you use for that scenario if you have other things to do? (your LCD program will do something very similar) – jsotola Jan 24 '18 at 19:40
  • @josecanuc It's only showing the Second() function on the first line and nothing else, i want to see the Minute() function beneath that on the second line. – Marten Jan 24 '18 at 19:43
  • @jsotola i think you're referring to the millis() command which shows the amount of milliseconds that have passed after you start a program. But how could i integrate that in my code so that it seems like they're both shown on the lcd simultaneously. – Marten Jan 24 '18 at 19:50
  • Examine closely the non-popular-enough Arduino example called BlinkWithoutDelay arduino.cc/en/Tutorial/BlinkWithoutDelay Your problem is that the use of delay() as you guessed. You need to think about your program flow as though loop() runs millions of times per second, but you only want to execute a particular function less frequently. Expand to running multiple functions at different frequencies. – jose can u c Jan 24 '18 at 19:57
0

Use the state machine model shown in BlinkWithoutDelay

unsigned long minInterval = 60000UL; // Interval for minutes in milliseconds
unsigned long secInterval = 1000UL;  // Interval for seconds in milliseconds
unsigned long prevMinMillis = 0UL;   // Holds the timestamp of the last time Minute() was called
unsigned long prevSecMillis = 0UL;   // Holds the timestamp of the last time Second() was called

void setup()
{
 lcd.begin(16, 2);
}

void loop()
{
  unsigned long currentMillis = millis();

  if (currentMillis - prevMinMillis > minInterval)
  {
    prevMinMillis = currentMillis;
    Minute();
  }

  if (currentMillis - prevSecMillis > secInterval)
  {
    prevSecMillis = currentMillis;
    Second();
  }

}

With this example, Second() is called only when the difference between "now" and the last time it was called is greater than secInterval. Likewise for Minute().

[Note, the code above will not run as-is, but I assume you have initialized the LiquidCrystal library and assigned the pins as per your schematic.]

EDIT BASED ON UPDATED CODE SAMPLE

Issue 1:

In both your Minute() and Second() functions you have a sequence like:

lcd.setCursor(0, 0);
lcd.print(First_Digit);
lcd.setCursor(1, 0);
lcd.print(Second_Digit);
lcd.clear();

After writing the characters, you immediately clear the LCD screen. Don't do this, it erases all the output on your LCD.

Issue 2:

At the start of the Minute() function, you have the following:

int First_Digit = 0; int Second_Digit = 0;

This means the variables First_Digit and Second_Digit are initalized to zero every time the function is called. This means you won't get an increment of the value, it will start at zero every time you try to update the LCD. You can declare those variables as static so that the value remains the same between calls of the function. Static variables are automatically initialized to zero. Thus:

static int First_Digit;
static int Second_Digit;

and similarly in the Second() function.

You're correct that digitalWrite() is not needed in your function as it is described. digitalWrite() is for changing a physical pin on the Arduino to a LOW or HIGH value (that is, a 0V or 5V voltage.) In the Blink without Delay example, ledPin and ledState are just variables to hold the pin identifier for the blinking LED, and the current state (LOW or HIGH) of that pin. Again, not necessary for your code, as you have described it.

SECOND UPDATE

Having tackled the issue of how to run multiple functions "simultaneously", now move on to fixing the overly complicated code for writing the minute and second values to the LCD... I'm not sure why you put the for loop in the Minute() and Second() functions, but it's unnecessary.

You also are treating each digit way too complicated. If your value for the seconds counter is 0 to 59, why not keep track of it that way, and then display each digit as necessary:

void Second() {
  static int second;

  second++;
  if (second>59) {
    second = 0;
  }
  lcd.setCursor(0, 0);
  lcd.print(second/10);   // Prints the 10s digit
                          // Note, lcd.print automatically moves to the next column
  lcd.print(second % 10); // Prints the remainder after dividing by 10
}

void Minute() {
  static int minute;

  minute++;
  if (minute>59) {
    minute = 0;
    // Probably want to increment an Hour counter here?
  }
  lcd.setCursor(3, 0);
  lcd.print(minute/10);   // Prints the 10s digit
                          // Note, lcd.print automatically moves to the next column
  lcd.print(minute % 10); // Prints the remainder after dividing by 10
}
  • After updating my code i only get what it seems like the function Second, furthermore it's unreadable untill i reset it so that it stops for a moment, and then it shows the correct seconds. So it works but it's unreadable until you stop it. Any solutions to this? – Marten Jan 25 '18 at 20:25
  • Added another part of this answer to deal with the other functions, which are not strictly related to how to run multiple functions simultaneously... – jose can u c Jan 25 '18 at 21:16
  • It works properly for each individual part but the hour only shows after an hour and the minute only shows after a minute, how can i display this instantly? – Marten Jan 29 '18 at 16:21
  • Write the hour and minute in setup() so they run at least at startup – jose can u c Jan 29 '18 at 16:26

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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