TimeSerialDateStrings from Paul Stoffregen with arduino uno

Hello everyone,

I'm trying to use the TimeSerialDateString example of the Time-master library with and Arduino uno to set the current time manually and display it on a digital display.

I first just added the display code part and everything worked just well. Giving the input in the serial monitor (T follow by 10 digit), its was displaying the current time on the serial monitor and on the display.

I picked a look in the code and though I could just get rid of the serial monitor part, since the input is just store in a char variable and it uses an if statement to display the time if the entered variable is equal to 'T'.
I tried to replace the Syntax char c= Serial.read(); with c='T';

but I soon as I comment out the function serial.read(); the time is displayed on the display but will not be incremented. It just stays static.

Is the Function Serial.read() somehow reading the PC time?

Here is my code:

void time_serial(){
char c = 'T';// Serial.read();
if( c == TIME_HEADER) {
processSyncMessage();
}
if (timeStatus()!= timeNotSet) {
digitalClockDisplay();
int T= now();
lcd.setCursor(0,3);
lcd.print(T);
}
delay(1000);
}

My Loop just calls this function all the time.

I even looked at the Time.h and changed the timeStatut to always give back timeset as follow:

// indicates if time has been set and recently synchronized
timeStatus_t timeStatus() {
now(); // required to actually update the status
Status=timeSet;
return timeSet;
}

Can someone gives me an advise?

thanks in advance!

Tades

This line in the example, and which is missing from your sketch, sets the Arduino system time:
setTime(pctime) ; // Sync Arduino clock to the time received on the serial port

but I soon as I comment out the function serial.read(); the time is displayed on the display but will not be incremented. It just stays static.

The T is the first character in a 10 character message. If you no longer expect to read the T as the start of the packet, the processSyncMessage() function, which you didn't show, will unconditionally be called. What is that now going to do?

   int T= now();

Where is the implementation of now()? If you are using the standard implementation, now() does NOT return an int.

I took the original example "TimeSerialDateStrings" and first just added the LCD_display part as follow:

/*

  • TimeSerialDateStrings.pde

  • example code illustrating Time library date strings

  • This sketch adds date string functionality to TimeSerial sketch

  • Also shows how to handle different messages

  • A message starting with a time header sets the time

  • A Processing example sketch to automatically send the messages is inclided in the download

  • On Linux, you can use "date +T%s\n > /dev/ttyACM0" (UTC time zone)

  • A message starting with a format header sets the date format

  • send: Fs\n for short date format

  • send: Fl\n for long date format
    */

#include <TimeLib.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>

// single character message tags
#define TIME_HEADER 'T' // Header tag for serial time sync message
#define FORMAT_HEADER 'F' // Header tag indicating a date format message
#define FORMAT_SHORT 's' // short month and day strings
#define FORMAT_LONG 'l' // (lower case l) long month and day strings

#define TIME_REQUEST 7 // ASCII bell character requests a time sync message

LiquidCrystal_I2C lcd(0x27,16,4); // set the LCD address to 0x27 or 0x20

static boolean isLongFormat = false;

volatile int Start=0, Up=0, Down=0, Settup=0, OK=0;

void setup() {
Serial.begin(9600);
while (!Serial) ; // Needed for Leonardo only
setSyncProvider( requestSync); //set function to call when sync required
Serial.println("Waiting for sync message");
lcd.begin(); // Print a message to the LCD.
lcd.backlight();

// setSyncProvider( requestSync); //set function to call when sync required
lcd.setCursor(0,0);
lcd.print("set the Date");
}

void loop(){
if (Serial.available() > 1) { // wait for at least two characters
char c = Serial.read();
if( c == TIME_HEADER) {
processSyncMessage();
}
else if( c== FORMAT_HEADER) {
processFormatMessage();
}
}
if (timeStatus()!= timeNotSet) {
digitalClockDisplay();
}
delay(1000);
}

void digitalClockDisplay() {
// digital clock display of the time
lcd.setCursor(0,2);
Serial.print(hour());
lcd.print(hour());
printDigits(minute());

printDigits(second());
Serial.print(" ");
lcd.setCursor(0,1);

if(isLongFormat)
{
Serial.print(dayStr(weekday()));

lcd.print(dayStr(weekday()));
}

else
{
Serial.print(dayShortStr(weekday()));
Serial.print(" ");
Serial.print(day());
Serial.print(" ");

lcd.print(dayShortStr(weekday()));
lcd.print(" ");
lcd.print(day());
lcd.print(" ");
}

if(isLongFormat)
{
Serial.print(monthStr(month()));
lcd.print(monthStr(month()));
}

else
{
Serial.print(monthShortStr(month()));
Serial.print(" ");
Serial.print(year());
Serial.println();

lcd.print(monthShortStr(month()));
lcd.print(" ");
lcd.print(year());
//Serial.println();
}
}

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

void processFormatMessage() {
char c = Serial.read();
if( c == FORMAT_LONG){
isLongFormat = true;
Serial.println(F("Setting long format"));
}
else if( c == FORMAT_SHORT) {
isLongFormat = false;
Serial.println(F("Setting short format"));
}
}

void processSyncMessage() {
unsigned long pctime;
const unsigned long DEFAULT_TIME = 1546344000; // Jan 1 2019

pctime = Serial.parseInt();
if( pctime >= DEFAULT_TIME) { // check the integer is a valid time (greater than Jan 1 2013)
setTime(pctime); // Sync Arduino clock to the time received on the serial port
}
}

time_t requestSync() {
Serial.write(TIME_REQUEST);
return 0; // the time will be sent later in response to serial mesg
}

void setTime_HMS()
{
Serial.print("enter the current time in the following format Hour Minutes Seconde");

}

Since I didn't want to set the time via the Serial monitor but with two Up and Dawn Button, I began to comment out and deleted everything I didn't need. I was compiling it at each step and the time was still appearing on the LCD and counting up.

Here is my ProcessSyncMessage() function.

void processSyncMessage() {
unsigned long pctime;
const unsigned long DEFAULT_TIME = 1546344000; // Jan 1 2019

pctime = DEFAULT_TIME; //Serial.parseInt();
if( pctime >= DEFAULT_TIME) { // check the integer is a valid time (greater than Jan 1 2013)
setTime(pctime); // Sync Arduino clock to the time received on the serial port
}
}

I set pctime to a constant since I wanted to transform it in the given time later.

Here is the function with the issue:

void time_serial(){
/* char c = 'T';// Serial.read();
if( c == TIME_HEADER) {*/
processSyncMessage();
// }
if (timeStatus()!= timeNotSet) {
digitalClockDisplay();
time_t T= now();
lcd.setCursor(0,3);
lcd.print(T);
}
delay(1000);
}

This basically the main function in the original example that I transformed in a void function and call it in the my main function.

if I use the Serial.read() and just send the single character 'T', everything work fine. the set default time will appear and the time will be incremented every second. But if I comment out this line with Serial, the time will not count up anymore. it just stays static at the default time (which I set to 01 Jan 2019).

I knew that the function now() was given a time_t variable but just to see if the value of now will be update every second. this is the case when the serial.read command is there and it won't be update if I comment it out.

any advice?

Tades

What you started with updated the Arduino's concept of time whenever serial data arrived that contained a T followed by a bunch of digits.

The function that did that, processSyncMessage(), read the serial data, and compared the value to DEFAULT_TIME. If received value was greater, then the baseline time was updated.

Time keeping happened with respect to the baseline time.

Now, you call processSyncMessage() on every pass through loop(), and your version of processSyncMessage() pretends that the PC time is years ago. Since you set the PC time to the same value as the comparison value, setTime() is never called. In other words, processSyncMessage() is never doing anything useful, and could be deleted.

I really would be surprised if the LiquidCrystal_I2C class knew how to properly handle a time_t object.

This basically the main function in the original example that I transformed in a void function and call it in the my main function.

if I use the Serial.read() and just send the single character 'T', everything work fine. the set default time will appear and the time will be incremented every second. But if I comment out this line with Serial, the time will not count up anymore. it just stays static at the default time (which I set to 01 Jan 2019).

void time_serial(){ 
   /* char c = 'T';// Serial.read();
    if( c == TIME_HEADER) {*/
      processSyncMessage();
  //  }
  if (timeStatus()!= timeNotSet) {
    digitalClockDisplay();  
   time_t T= now();
   lcd.setCursor(0,3);
  lcd.print(T);
  }
  delay(1000); 
}

When you call the time_serial() function every pass through loop without the conditional requirement or reading a TIME_HEADER it executes the processSyncMessage() every time and keeps resetting to the default time.

Try this to do it once

EDIT: You could put the call to the function in setup() instead of loop() and don't use the "do it once" control variable.

void time_serial() {
  /* char c = 'T';// Serial.read();
    if( c == TIME_HEADER) {*/
    static boolean timeSet = false;
    if(!timeSet)
    {
     processSyncMessage();
     timeSet = true;
    }
  if (timeStatus() != timeNotSet) {
    digitalClockDisplay();
    time_t T = now();
    lcd.setCursor(0, 3);
    lcd.print(T);
    Serial.println(T);
  }
  delay(1000);
}

hi,

but even if I set the pctime=12, which is just non sense, the displayed time will be the baseline time (Thu 1 Jan 1970) and won't change. but if give the same constant through the serial monitor (T12) the time will be update after each second on my display.
I just don't get why because I even peaked a look in the Time.h and TimeLib.h where everything should be implemented and I'm not seeing the time Update and the serial COM port!

Here are some important function out of the time.h:

time_t now() {
// calculate number of seconds passed since last call to now()
while (millis() - prevMillis >= 1000) {
// millis() and prevMillis are both unsigned ints thus the subtraction will always be the absolute value of the difference
sysTime++;
prevMillis += 1000;
#ifdef TIME_DRIFT_INFO
sysUnsyncedTime++; // this can be compared to the synced time to measure long term drift
#endif
}
if (nextSyncTime <= sysTime) {
if (getTimePtr != 0) {
time_t t = getTimePtr();
if (t != 0) {
setTime(t);
} else {
nextSyncTime = sysTime + syncInterval;
Status = (Status == timeNotSet) ? timeNotSet : timeNeedsSync;
}
}
}
return (time_t)sysTime;
}

void setTime(time_t t) {
#ifdef TIME_DRIFT_INFO
if(sysUnsyncedTime == 0)
sysUnsyncedTime = t; // store the time of the first call to set a valid Time
#endif

sysTime = (uint32_t)t;
nextSyncTime = (uint32_t)t + syncInterval;
Status = timeSet;
prevMillis = millis(); // restart counting from now (thanks to Korman for this fix)
}

timeStatus_t timeStatus() {
now(); // required to actually update the status
Status=timeSet; // timeNotSet
return Status; //
}

void setSyncProvider( getExternalTime getTimeFunction){
getTimePtr = getTimeFunction;
nextSyncTime = sysTime;
now(); // this will sync the clock
}

void setSyncInterval(time_t interval){ // set the number of seconds between re-sync
syncInterval = (uint32_t)interval;
nextSyncTime = sysTime + syncInterval;
}

Hi Cattledog,

thanks a lot for your advise, it solves the issue!

the function were called every time in the loop. putting it in the setup to be called just ones solve the problem.

thanks again to you all

Sincerely

Tades