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

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?
    – Fern
    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.

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();

2
  • I do not understand what you mean by this.
    – Fern
    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.

Your Answer

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

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