0

I'm making a clock using an arduino uno and a compatible freetronics screen. So far it can count the time in a 24 hour loop after which it repeats and counts again. The screen had a number of buttons built onto it and I want to get it so that when one of the buttons on the screen is pressed it prints the time that it was pressed on the top line of the screen while continuing to count and print the time on the second line of the screen.

How can I edit my code below to do this when a button is pressed? What sort of command do I need to add?

#include <Wire.h>
#include <LiquidCrystal.h>
#define MILLIS_OVERFLOW 34359738
/**
* Clock Variables
*/
unsigned long currentMillis, previousMillis, elapsedMillis;
int seconds = 0, minutes = 0, hours = 8;
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
void setup()
{
 Serial.begin(9600);
 lcd.begin( 16, 2 ); 
}
void loop()
{
setClock();
/**
 * After set clock now you have 3 int variables with the current time
 */
 //seconds
 //minutes
 //hours
 lcd.setCursor ( 0, 1);
 lcd.print(hours);
 lcd.print(":");
 lcd.print(minutes);
 lcd.print(":");
 lcd.print(seconds);
 lcd.print(":");
 lcd.print(elapsedMillis);
}
void setClock()
{
currentMillis = millis();
/**
 * The only moment when currentMillis will be smaller than previousMillis
 * will be when millis() oveflows
 */
if (currentMillis < previousMillis){
 elapsedMillis += MILLIS_OVERFLOW - previousMillis + currentMillis;
} else {
 elapsedMillis += currentMillis - previousMillis;
}
/**
 * If we use equals 1000 its possible that because of the mentioned loop limitation
 * you check the difference when its value is (999) and on the next loop its value is (1001)
 */
if (elapsedMillis > 999){
 seconds++;
 elapsedMillis = elapsedMillis - 1000;
}
if (seconds == 60){
 minutes++;
 seconds = 0;
}
if (minutes == 60){
 hours++;
 minutes = 0;
}
if (hours == 24){
 hours = 0;
}
previousMillis = currentMillis;
}

Any help will be greatly appreciated, thanks

asked May 11, 2015 at 2:25
2
  • 1
    What is your question? Commented May 11, 2015 at 3:08
  • How do I programme it so the button will print the time on the top line of the screen when pressed? Commented May 13, 2015 at 2:53

3 Answers 3

1

Since you will have to deal with two different times, I suggest writing a small class for representing those times in broken-down form. This is a reduced version of the classical strcut tm. Times are made Printable so you can just print() them to the LCD. I included an increment() method to add one second to this time.

class BrokenDownTime : public Printable {
 uint8_t hours;
 uint8_t minutes;
 uint8_t seconds;
public:
 void increment();
 size_t printTo(Print &p) const;
};
/* Increment the time by one second. */
void BrokenDownTime::increment()
{
 if (++seconds >= 60) {
 seconds = 0;
 if (++minutes >= 60) {
 minutes = 0;
 if (++hours >= 24)
 hours = 0;
 }
 }
}
/*
 * Print to anything that inherits from the Print class (Serial,
 * LiquidCrystal, etc.). This makes times `Printable'.
 */
size_t BrokenDownTime::printTo(Print &p) const
{
 p.print(hours/10);
 p.print(hours%10);
 p.write(':');
 p.print(minutes/10);
 p.print(minutes%10);
 p.write(':');
 p.print(seconds/10);
 p.print(seconds%10);
 return 8; // 8 bytes written
}

The main program checks in loop() for the button being pressed. When this happens, it saves the current time as lastPress. If the button was ever pressed (variable button_was_pressed), the recorded time is displayed on the first line:

#include <LiquidCrystal.h>
#define BUTTON_ADC_PIN A0
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);
BrokenDownTime now;
/* Detect a press on `left', change the thresholds for other buttons. */
bool buttonPressed()
{
 int reading = analogRead(BUTTON_ADC_PIN);
 return reading > 405 && reading < 605;
}
/* Update `now'. */
void updateTime()
{
 static unsigned long last;
 if (millis() - last >= 1000) {
 now.increment();
 last += 1000;
 }
}
void setup()
{
 lcd.begin(16, 2);
}
void loop()
{
 static BrokenDownTime lastPress;
 static bool button_was_pressed;
 updateTime();
 /* Record the time of the button press. */
 if (buttonPressed()) {
 lastPress = now;
 button_was_pressed = true;
 }
 /* Display the recorded time on the first line. */
 if (button_was_pressed) {
 lcd.setCursor(0, 0);
 lcd.print(lastPress);
 }
 /* Display the current time on the second line. */
 lcd.setCursor(0, 1);
 lcd.print(now);
}

I did not test the program, but I hope you get the idea.

answered May 13, 2015 at 10:15
0

use a second variable called TNow and when the button is pressed pass it the value of currentMillis. parse and use this as the value to display. or have misunderstood your question? wondering why you aren't using a time library. such as this if you look on the site here use the time library you can then use variable name = now();

answered May 11, 2015 at 6:27
2
  • I do not understand what you mean by this. Commented May 13, 2015 at 2:52
  • The Time library is probably a good choice if this grows into a "real" clock. For the OP’s toy program, however, it looks a bit overkill: Whenever you ask it to break a time value into hours, minutes and seconds, it also computes the year, month, day-of-week and day-of-month, just in case you may need it later. That's a lot more expensive than incrementing an (hours, minutes, seconds) triplet. And it's times are not Printable, so you still have to write your own print routine. Commented May 13, 2015 at 10:46
0

You probably want to read the button press on LCD using "read_LCD_buttons" function. See an example at: Arduino LCD KeyPad Shield.

So your part of your code would probably be:

#define btnRIGHT 0
#define btnUP 1
#define btnDOWN 2
#define btnLEFT 3
#define btnSELECT 4
#define btnNONE 5
int lcd_key = 0;
void loop()
{
 setClock();
 /**
 * After set clock now you have 3 int variables with the current time
 */
 //seconds
 //minutes
 //hours
 printValueAtLine(0);
 lcd_key = read_LCD_buttons(); // read the buttons
 switch (lcd_key)
 {
 case btnSELECT:
 {
 printValueAtLine(1);
 break;
 }
 case btnRIGHT:
 {
 // code in case other buttons like btnRIGHT, etc are pressed
 break;
 }
 case btnNONE:
 {
 //do nothing
 break;
 }
 }
}
void printValueAtLine(int line)
{
 lcd.setCursor (1, line);
 lcd.print(hours);
 lcd.print(":");
 lcd.print(minutes);
 lcd.print(":");
 lcd.print(seconds);
 lcd.print(":");
 lcd.print(elapsedMillis);
}

The code is untested and you may have to make minor corrections to it.

Also, rather than saving values in global variables, you might want to use local ones using libraries suggested by wobbler.

answered May 13, 2015 at 8:21

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.