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;
}
}
}
1 Answer 1
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– Marten2018年01月25日 20:25:16 +00:00Commented Jan 25, 2018 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– jose can u c2018年01月25日 21:16:51 +00:00Commented Jan 25, 2018 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– Marten2018年01月29日 16:21:10 +00:00Commented Jan 29, 2018 at 16:21
-
Write the hour and minute in
setup()
so they run at least at startupjose can u c– jose can u c2018年01月29日 16:26:17 +00:00Commented Jan 29, 2018 at 16:26
setCursor()
as you have. Is this not working? If not, please describe what it displays, and what you want to see it display?delay()
as you guessed. You need to think about your program flow as thoughloop()
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.