Is it possible to count time in Arduino?

Hello everybody!

Vanessa Schauer developed a good clock and alarm for Arduino. I don´t know if she logs in at present.

Anyway, I wonder if we can have a reasonable exact measure of time based on Arduino hardware. Something simple, but necessary to many applications.

Is anyone in possession of this knowledge?

Thank you in advance,

OldBeaver
:sunglasses:

There is a Date and Time library in the playgound that makes it easy to keep time using no extra hardware and is accurate to a few seconds per day.

see: Arduino Playground - DateTime

Dear Mem,

I tried to make a little time counter, but don´t work.

Well, my idea is to use the time counter in minutes and seconds only.

Anyway, the compiler says: "LiquidCrstal does not name a type In function void loop(); in function "void lcdPrintFloat(float, byte)"

Something is wrong. Here´s the code:


#include <LiquidCrystal.h>

//create object to control an LCD.
LiquidCristal lcd(12, 11, 2, 7, 8, 9, 10);

void setup(){
}

void loop(){

static float sec;
static float min;
static float hour;
float value;

value = millis();
lcd.clear();

if value == 1000;{
sec=sec + 1;
value = 0;
}
if(sec==60);{
min=min+1;
sec=0;
}
if(min==60) {
hour=hour+1;
min=0;
}
//if(hour==24) {
// hour=0;
// }

lcd.setCursor(0,0);
lcd.print("Min=");
lcd.setCursor(1,6);
x = min;
lcdPrintFloat(x,1);

lcd.setCursor(0,1);
lcd.print("Sec=");
lcd.setCursor(2,6);
x = sec;
lcdPrintFloat(x,2);

digitalWrite(13,LOW);
delay (1000);
digitalWrite(13,HIGH);
}

void lcdPrintFloat(float x, byte precision){
lcd.print((long)x);
}


Will take a look to the solution you mention.

OldBeaver

The compiler is giving you good advice. LiquidCristal is not a valid name for a type it know about. It's a typo, you meant write LiquidCrystal.

I expect there are other syntax errors in that code. If you study the compiler messages you should be able to fix them.

p.s. watch out for semicolons:
this:
if(sec==60);{
min=min+1;
sec=0;
}

I think should be this:
if(sec==60){
min=min+1;
sec=0;
}

Ha, ha, ha !!! Yes, you are right.

Thank you!

I got the DateTime library, loaded the clock example it comes with. The example was made to be seen on a serial display. I don´t know how to do that, but anyway, that is not what I need. I tried to modify it, to make it capable of printing in the LCD display.

Below is what I made. It passes the compiler scrutiny, but nothing is shown on the LCD. Here's the code:


#include <LiquidCrystal.h>
#include <DateTime.h>
#include <DateTimeStrings.h>
LiquidCrystal lcd(12, 11, 2, 7, 8,9, 10);

void setup(){
pinMode(13,OUTPUT); // we flash the LED each second
}

void loop(){
unsigned long prevtime;

if( getPCtime()) { // try to get time sync from pc
lcd.setCursor(0,0);
lcd.print("PCClock:");
lcd.setCursor(7,0);
lcdPrintFloat(DateTime.now(),DEC);
}
if(DateTime.available()) { // update clocks if time has been synced
digitalWrite(13,LOW); // first flash the LED
prevtime = DateTime.now();
while( prevtime == DateTime.now() ) // wait for the second to rollover
;
DateTime.available(); //refresh the Date and time properties
lcdPrintFloat(DateTime.now(),DEC);
digitalWrite(13,HIGH);
}
delay(100);
}

boolean getPCtime() {
// if time sync available from serial port, update time and return true
//while(Serial.available(); >= TIME_MSG_LEN ){ // time message consists of a header and ten ascii digits
char TIME_HEADER;
char TIME_MSG_LEN;
if( Serial.read() == TIME_HEADER ) {
time_t pctime = 0;
for(int i=0; i < TIME_MSG_LEN -1; i++){
char c= Serial.read();
if( c >= '0' && c <= '9'){
pctime = (10 * pctime) + (c - '0') ; // convert digits to a number
}
}
DateTime.sync(pctime); // Sync Arduino clock to the time received on the serial port
return true; // return true if time message received on the serial port
}

return false; //if no message return false
}

// digital clock display of current date and time
void lcdPrintFloat(float x, byte digits){
lcd.print(DateTime.Hour,DEC);
lcd.print(DateTime.Minute);
lcd.print(DateTime.Second);
lcd.print(" ");
lcd.print(DateTimeStrings.dayStr(DateTime.DayofWeek));
lcd.print(" ");
lcd.print(DateTimeStrings.monthStr(DateTime.Month));
lcd.print(" ");
lcd.print(DateTime.Day,DEC);
}

void printDigits(byte digits){
// utility function for digital clock display: prints preceding colon and leading 0
lcd.print(":");
if(digits < 10)
lcd.print('0');
lcd.print(digits,DEC);
}


Any ideas?

Jose

You need to set the time. try this setup code to start the clock at 11pm today:

void setup(){
pinMode(13,OUTPUT); // we flash the LED each second
time_t t = DateTime.makeTime( 23, 0, 03, 23, 11, 2008 );
DateTime.sync( t );
}

Well, hello, here is my own program for counting time. The only problem is it doesn't work out.

Here is the code:

#include <LiquidCrystal.h>

//create object to control an LCD.
LiquidCrystal lcd(12, 11, 2, 7, 8, 9, 10);

void setup(){
}

void loop(){
float x;
static float sec;
static float min;
static float hour;
unsigned long value;

lcd.clear();
value = millis();

if (value==1000){
sec=sec + 1;
}

if(sec==60){
min=min+1;
sec=0;
}

//if(min==60) {
// hour=hour+1;
// min=0;
// }
//if(hour==24) {
// hour=0;
// }

lcd.setCursor(0,0);
lcd.print("Sec=");
lcd.setCursor(6,0);
x = sec;
lcdPrintFloat(x,1);

lcd.setCursor(0,1);
lcd.print("Min=");
lcd.setCursor(6,1);
x = min;
lcdPrintFloat(x,2);

digitalWrite(13,LOW);
delay (1000);
digitalWrite(13,HIGH);
}

void lcdPrintFloat(float x, byte precision){
lcd.print(long(x));
}

Actually, it is working partially, but in displaying time.

I will make a check to see if time is actually calculated but not displayed, or none of them.

Any ideas?

Old Beaver

Ok Mem, tks for the suggestion. I will try to test that sketch.

What I actually need, is count the time in minutes, since I start a test trip, or a long trip. By the way, how can I reset the program?

I have this sketch, where the if cicles do not work, I don´t know why.

However, the counting of time by assignment of value = millis() is working, cause I have made some test divisions later in the program.

This is my present code:


#include <LiquidCrystal.h>

//create object to control an LCD.
LiquidCrystal lcd(12, 11, 2, 7, 8, 9, 10);

void setup(){
}

void loop(){
float tank;
tank = analogRead(1);
float spend;
float x;
int sec;
int min;
int hour;
unsigned long value; // value states for time in milliseconds

lcd.clear();
value = millis();
if (value == 1000){
sec = sec++; //this doesn´t work
value = 0 ;
}

if(sec==60){
min=min++; // and this either
sec=0;

}
if(min==60) {
hour=hour++; // neither do this
min=0;
}

/* ---------- Prints seconds ------------ */
lcd.setCursor(0,0);
lcd.print("Sec");
lcd.setCursor(5,0);
x = sec;
lcdPrintFloat(x,1);

/* --------- Prints minutes ----------- */
lcd.setCursor(0,1);
lcd.print("Min");
lcd.setCursor(5,1);
x = min;
lcdPrintFloat(x,2);

/* ------- Print Tank values ------- */
lcd.setCursor(8,0);
lcd.print("Tank");
lcd.setCursor(14,0);
x = tank;
lcdPrintFloat(x,1);

/* ------- Print Spend values ------- */
spend = (55-tank)/min;
lcd.setCursor(8,1);
lcd.print("Spend");
lcd.setCursor(14,1);
x = spend;
lcdPrintFloat(x,1);

digitalWrite(13,LOW);
delay (1000); // this is flashing
digitalWrite(13,HIGH);
}

void lcdPrintFloat(float x, byte precision){
lcd.print(long(x));
}

I made a short sketch trying to test your adviced variables, unsuccessfully.

I assumed time_t is a string, and t is a floating number. Couldn´t find any reference about this new library.

Here is my sketch:


#include <DateTime.h>
#include <LiquidCrystal.h>

//create object to control an LCD.
LiquidCrystal lcd(12, 11, 2, 7, 8, 9, 10);

void setup(){
pinMode(13,OUTPUT); // we flash the LED each second
time_t t = DateTime.makeTime( 23, 0, 03, 23, 11, 2008 );
DateTime.sync( t );
}

void loop(){
char time_t[10];
float t;

/* --------- Prints time string ----------- */
lcd.setCursor(0,0);
lcd.print(time_t);
lcd.setCursor(0,1);
lcd.print(t,3);

digitalWrite(13, LOW); //light the LED
delay (1000);
digitalWrite(13, HIGH); //
}


The led blinks shortly, and some characters show for time_t and a zero for t.

That is it so far.

Greetings, Jose

There are no floats used in the DateTime library. Time is maintained as a count in seconds from a particular point in time. The type used to hold the count is defined as a time_t and is an unsigned long value.

Here is a sketch that uses the library to display elapsed minutes on one line and elapsed hours and minutes on the second line:

#include <DateTime.h>
#include <LiquidCrystal.h>

int resetPin = 3; // pin 3 resets the time

//create object to control an LCD.  
LiquidCrystal lcd(12, 11, 2, 7, 8, 9, 10);

void setup(){
  pinMode(13,OUTPUT); // we flash the LED each second
  pinMode(resetPin, INPUT); // a button on this pin resets the time
  DateTime.sync( 0 );  // set time to zero
}

void loop(){
  if(digitalRead(resetPin) == LOW)
      DateTime.sync( 0 );  // reset time to zero if button pressed


  /* --------- Prints time in minutes and hours ----------- */
  DateTime.available(); // needed to refresh the clock time
  time_t timeNow = DateTime.now();
  lcd.setCursor(0,0);
  lcd.print(timeNow/60);  // this is total elapsed minutes
  
  
  lcd.setCursor(0,1);  
  lcd.print(DateTime.Hour,DEC);  // this is the total hours (up to 24)
  lcd.print(":");
  lcd.print(DateTime.Minute,DEC); // and minutes since reset


  digitalWrite(13, LOW); //light the LED
  delay (1000);
  digitalWrite(13, HIGH);  //
}

Its not tested but I hope gets you going in the right direction.

Dear Mem,

Received and many thanks to you.

Will test it today.

I will post the results.

Greetings,

Oldbeaver

Dear Mem and all,

I tested the sketch in the following format:

#include <DateTime.h>
#include <LiquidCrystal.h>

int resetPin = 3; // pin 3 resets the time

//create object to control an LCD GMD1602K.
LiquidCrystal lcd(12, 11, 2, 7, 8, 9, 10);

void setup(){
pinMode(13,OUTPUT); // we flash the LED each second
pinMode(resetPin, INPUT); // a button on this pin resets the time
DateTime.sync( 0 ); // set time to zero
}

void loop(){
if(digitalRead(resetPin) == LOW)
DateTime.sync( 0 ); // reset time to zero if button pressed

/* --------- Prints time in hours, minutes and seconds ----------- */
DateTime.available(); // needed to refresh the clock time
time_t timeNow = DateTime.now();
lcd.setCursor(0,0);
lcd.print(timeNow/60); // this is total elapsed minutes
lcd.setCursor(0,8);
lcd.print(timeNow/360); // checking total elapsed seconds

lcd.setCursor(0,0);
lcd.print("Hour:min");
lcd.setCursor(10,0);
lcd.print(DateTime.Hour,DEC); // this is the total hours (up to 24)
lcd.print(":");
lcd.print(DateTime.Minute,DEC); // and minutes since reset
lcd.setCursor(0,1);
lcd.print("Sec");
lcd.setCursor(10,1);
lcd.print(DateTime.Second,DEC); // and seconds since reset

digitalWrite(13, LOW); //light the LED
delay (1000);
digitalWrite(13, HIGH); //
}

The code compiles ok, and run. But only the flashing debug led is got as output. The titles print ok on the lcd screen, the numbers print, but as zeros only.

I added seconds as a way of debug.

Test it yourself, maybe you discover the problem.

I also tested the sketch as you sent it, and it printed only zeros.

Greetings,

Oldbeaver. :frowning:

Perhaps you don't have the reset pin wired up, it needs to have a pull-up so its value is high except when a button is pressed.

You could use an internal pull-up. Add the following line to setup
pinMode(resetPin, INPUT); // a button on this pin resets the time
digitalWrite(resetPin,HIGH); // add this line to enable pull-up

also, you may want to look at the example sketch for the DateTime library to see how you can format the time so that minutes is always displayed using two digits

Hi Mem and all,

The sketch is working fine now.

Here it is:


#include <DateTime.h>
#include <LiquidCrystal.h>

int resetPin = 3; // pin 3 resets the time

//create object to control an LCD GMD1602K.
LiquidCrystal lcd(12, 11, 2, 7, 8, 9, 10);

void setup(){
digitalWrite(resetPin,HIGH); // this line enables pull-up
pinMode(13,OUTPUT); // we flash the LED each second
pinMode(resetPin, INPUT); // a button on this pin resets the time
DateTime.sync( 0 ); // set time to zero
}

void loop(){
if(digitalRead(resetPin) == LOW)
DateTime.sync( 0 ); // reset time to zero if button pressed

/* --------- Prints time in hours, minutes and seconds ----------- */
DateTime.available(); // needed to refresh the clock time
time_t timeNow = DateTime.now();
lcd.setCursor(0,0);
lcd.print(timeNow/60); // total elapsed minutes
lcd.setCursor(0,8);
lcd.print(timeNow/3600); // total elapsed seconds

lcd.setCursor(0,0);
lcd.print("Hour:min");
lcd.setCursor(10,0);
lcd.print(DateTime.Hour,DEC); // prints total hours (up to 24)
lcd.print(":");
lcd.print(DateTime.Minute,DEC); // and minutes since reset
lcd.setCursor(0,1);
lcd.print("Sec");
lcd.setCursor(10,1);
lcd.print(DateTime.Second,DEC); // and seconds since reset
lcd.print(" "); // clears second digit every minute

digitalWrite(13, LOW); //light the LED every second
delay (1000);
digitalWrite(13, HIGH); //
}

Do you people know where can one get the documents of libraries? For example "Liquid Crystal.h" and "DateTime.h" ?

Is there any updated or more complete manual about programming Arduino than the Brian W. Evan's "Arduino Programming Notebook"?

Thanks much for the help got, specially to Mem.

Oldbeaver.
:slight_smile:

Good to hear its working.

You can find info on the Liquid Crystal library in the Arduino reference and info on DateTime in the arduino playground.

Massimo Banzi has published a book on getting started with the Arduino: Amazon.com

Ok, Mem, thank you very much.

As a matter of fact, I visited your city (London I suppose) once. Stayed in a hostel close to Picadilly Circus. I think I can find it on Google Earth. This was in 1985, though.

I had a very sympathetic experience on the transportation buses of london, (the red two floors ones) that I may tell later on a private email. I have a letter of the Queen related to that adventure.

Oldbeaver.

To fix the incremental statements mentioned earlier:

// sec = sec++; // not valid
sec++;  // increment sec value in place

Also, this kind of test is leaky:

if (millis == 1000)
{
   sec++;
   millis = 0;
}

Instead, assume that you might not see every single value of millis... it might tick twice before you get around to looking again. If millis somehow got up to 1001, you'd never increment the seconds again (until millis wrapped ALL THE WAY AROUND, and even then maybe not).

if (millis >= 1000)
{
    sec++;
    millis -= 1000;
}

Going even further, if your millis was bumped in an interrupt routine, and you had some other code do any significant delays, it could be off way more than one tick. If millis somehow got to the value of 2005, then this incrementing of the seconds would be off by over a whole second.

To protect against both possibilities, do this:

while (millis >= 1000)
{
    sec++;
    millis -= 1000;
}

or if this scenario is likely to happen often, and a division operation is not too expensive,

sec += (millis / 1000);
millis %= 1000;

Thank you for the post. Very useful.

OldBeaver

Hi halley, to compile that code you would need to change the variable named millis to something else because it conflicts with the function millis();

BTW, the code in the DateTime library works similar to one of the example above, with the additional functionality to set the system time to a given value :

unsigned long prevMillis = 0;
unsigned long sysTime = 0;

void setTime(unsigned long time)
{
// set the system time to the given time value (as seconds since Jan 1 1970)
sysTime = time;
prevMillis = millis();
}

// return the number of seconds since the time was last set
unsigned long now()
{
while( millis() - prevMillis >= 1000){
sysTime++;
prevMillis += 1000;
}
return sysTime;
}

mem:
Hi halley, to compile that code you would need to change the variable named millis to something else because it conflicts with the function millis();

Yeah, I see that now. I just typed from memory when I saw that general kind of problem on the first post of the thread. The value variable was what should have been used where I said millis. A good standard is to use verbs for function names (unlike millis()), and specific nouns for variable names (unlike value). Oh well.