Dealing with time

I'm just getting started with Arduino. I'm trying to make a dual clock for my ham shack with an RTC and 2 line display. I downloaded this code and tweaked it to try to get the clock working. I figured out most of it but there's something weird going on with the math.

If I set the local time to 11:00:00 and the offset (line 51) to +12, the time shows 23:00:00 as it should. However, if I set the offset to +13 (Just to pass the 24 hour mark), the time jumps to 02:00:00. It should show 00:00:00 (midnight the next morning). If I change it to +14 it jumps to 12:00:00. +15 = 22:00:00, etc.

Thanks for any help.

#include "Wire.h"
#define DS1307_ADDRESS 0x68
#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x27,16,2);


void setup(){
  Wire.begin();
  
  Serial.begin(9600);

    lcd.init();                      // initialize the lcd 
    lcd.init();
     // Print a message to the LCD.
    lcd.backlight();
}

void loop(){
  printDate();
  delay(1000);
}

byte bcdToDec(byte val)  {
// Convert binary coded decimal to normal decimal numbers
  return ( (val/16*10) + (val%16) );
}

void printDate(){

  // Reset the register pointer
  Wire.beginTransmission(DS1307_ADDRESS);

  byte zero = 0x00;
  Wire.write(zero);
  Wire.endTransmission();

  Wire.requestFrom(DS1307_ADDRESS, 7);

  int second = bcdToDec(Wire.read());
  int minute = bcdToDec(Wire.read());
  int hour = bcdToDec(Wire.read() & 0b111111); //24 hour time
  int weekDay = bcdToDec(Wire.read()); //0-6 -> sunday - Saturday
  int monthDay = bcdToDec(Wire.read());
  int month = bcdToDec(Wire.read());
  int year = bcdToDec(Wire.read());

int Zulu=((hour)+13);  //CHANGE FOR DST


  //START SERIAL 
//  Serial.print(Local); THIS WORKS
  Serial.print(month);
  Serial.print("/");
  Serial.print(monthDay);
  Serial.print("/");
  Serial.print(year);
  Serial.print(" ");
  Serial.print(hour);
  Serial.print(":");
  if((minute) < 10)
  {
    Serial.print("0");
  }
  Serial.print(minute);
  Serial.print(":");
  if((second) < 10.0)
  {
    Serial.print("0");
  }
  Serial.println(second);

//PRINT LOCAL TO LCD
 //   lcd.setCursor(0,0);
 //   lcd.print("                 ");  This just makes the display flicker
    lcd.setCursor(0,0);
  if((hour) < 10)
  {
    lcd.print("0");
  }
  lcd.print(hour);
    lcd.setCursor(2,0);
    lcd.print(":");
    lcd.setCursor(3,0);
  if((minute) < 10)
  {
    lcd.print("0");
  }
  lcd.print(minute);
    lcd.setCursor(5,0);
    lcd.print(":");
    lcd.setCursor(6,0);
  if((second) < 10.0)
  {
    lcd.print("0");
  }
  lcd.print(second);
    lcd.setCursor(9,0);
    lcd.print("Phelan");
//END LOCAL   
//PRINT TO LCD ZULU SET IN VAR for CALC's
 //   lcd.setCursor(0,1);
 //   lcd.print("                 ");
    lcd.setCursor(1,1);
    if((Zulu) > 23.00)   // Adjusting for UTC 
    {
      lcd.print((Zulu)-24);
      }
      lcd.print(Zulu);
    lcd.setCursor(3,1);
    lcd.print(":");
    lcd.setCursor(4,1);
  if((minute) < 10)
  {
    lcd.print("0");
  }
  lcd.print(minute);
    lcd.setCursor(6,1);
    lcd.print(":");
    lcd.setCursor(7,1);
  if((second) < 10.0)
  {
    lcd.print("0");
  }
  lcd.print(second);
    lcd.setCursor(10,1);
    lcd.print("Zulu");
//END ZULU    
}

Another weird thing I just noticed. If I set the lcd.print((Zulu)-??) to different values it doesn't flow.

With Local @ 16:00 and the offset @ +9 (=25:00 and Zulu should be 01:00)

(Zulu)- 13 = 12:00 (OK. That's what it should be)

(Zulu)- 14 = 11:00 (OK)

(Zulu)- 15 = 10:00 (OK)

(Zulu)- 16 = 92:00 (WHAT???)

(Zulu)- 17 = 82:00

(Zulu)- 18 = 72:00

What's going on??

First, drop the decimal points and extra zeros in these comparisons. You are forcing floating point arithmetic.

if((second) < 10.0)

Second, using cursor control on LCD displays is very tricky. If you don't overwrite characters that were previously on the display, the results will be very confusing. The writing happens too fast for you to follow.

You are much better off learning to use the sprintf() function to format text strings, which you then write directly to the display. sprintf can automatically take care of adding leading zeros.

e.g.

char buf[25]; //space to fill a 24 character display, plus the zero terminator
int hour = 1;
int minute = 9;
sprintf(buf,"%02d:%02d",hour,minute);  //will place the characters 01:09 in "buf".
lcd.print(buf); //show it

BATMan_Phln:

    if((Zulu) > 23.00)   // Adjusting for UTC 

{
     lcd.print((Zulu)-24);
     }
     lcd.print(Zulu);

So when Zulu is 24 you print 0, then you print 24:
024
Then you move the cursor to column 3, which is where the 4 was just printed and print :
02:
Look familiar?

You should have written the code as:

    if ((Zulu) > 23.00)  // Adjusting for UTC
    {
      lcd.print((Zulu) - 24);
    }
    else {
      lcd.print(Zulu);
    }

You should always do Tools > Auto Format on your code. The automatic indentation will make things like this obvious, the random indentation of your current code will not.

Pert, that solved the weird math issue. Thank you!! Now it's just a formatting issue. It's showing up as 4 :01:05 instead of 04:01:05. I think that's going to be jremington's code. I just need to figure out how to use it without screwing up the rest. LOL

Glad to hear! You just need to add the leading zero code in, either by using the same system as in your minutes code or following jremington's advice.

jremington:
e.g.

char buf[25]; //space to fill a 24 character display, plus the zero terminator

int hour = 1;
int minute = 9;
sprintf(buf,"%02d:%02d",hour,minute);  //will place the characters 01:09 in "buf".
lcd.print(buf); //show it

If I'm looking at this correctly, it sets a static time of 01:09. Since I'm reading the RTC second by second, how would this work? I also need to have the day after the time for each zone so would I set the char buf to 9 just for the time and leave space for the day?

22:04:06 WED
02:04:06 THU

I haven't worked out how to do the day yet. That will probably be my next post. HAHA

if ((Zulu) > 23)  // Adjusting for UTC
  {
    lcd.print("0");
    lcd.print((Zulu) - 24);
  }
  else {
    lcd.print(Zulu);
  }

That was easy! I don't know if it's the best solution but it works!!

Thanks guys!

For your Phelan time you would just leave off the hour and minute definitions from that code, which was just added for demonstration purpose:

char buf[25]; //space to fill a 24 character display, plus the zero terminator
sprintf(buf,"%02d:%02d",hour,minute);  //will place the characters 01:09 in "buf".
lcd.print(buf); //show it

For your Zulu time you only need to change hour to Zulu.

As for the day thing, I'd use an array:

const char weekDayName[][4] = {
  {"SUN"},
  {"MON"},
  {"TUE"},
  {"WED"},
  {"THU"},
  {"FRI"},
  {"SAT"}
};

Then you can do

tft.print(weekDayName[weekDay]);

That array is using up 28 bytes of precious SRAM. Probably better to put it in the more plentiful flash by using progmem but that's an extra layer of complexity.

Actually, this is the correct code for the Zulu time.

  lcd.setCursor(0, 1);
  //TESTING FROM FORUM
  if ((Zulu) > 23)  // Adjusting for UTC
  {
    lcd.print("0");
    lcd.print((Zulu) - 24);
  }
  else {
  if((Zulu) < 10)
  {
    lcd.print("0");
  }
    lcd.print(Zulu);
  }

BATMan_Phln:
I'm just getting started with Arduino. I'm trying to make a dual clock for my ham shack with an RTC and 2 line display.
<...>

It has been my experience over the last few years, that the approx. $10 GPS units work fantastically for clocks! No need for RTC, always receive accurate time.

I have a few variations on my project page.

Ray

always receive accurate time.

Indoors too?

jremington:
Indoors too?

Yes, inside too! There are enough GPS and glonass satellites these days to always have 1 or 2 near apogee which is ideal for the patch antennas used on $10 GPS.

As long as 2 satellites can be received to get an initial 2D lock to init the gps hardware, only 1 satellite is necessary for the $GPRMC sentence I use.

For years, I have had 2 GPS clocks in the home with no receiver issues for time-date. Last year, I started a refresh on the GPS clocks. One GPS is now in the attic with an ESP8266 which does a UDP broadcast of the full GPRMC whuch can be received anywhere inside or outside.

If you have an Android tablet or cellphone, load a free GPS utility to view the satellite constellation ... things surely are better than in the mid 90's.

Ray

I have an Arduino Uno with a GPS shield. It works outdoors but not indoors in my one story house. Perhaps a better antenna would help.

You may want to look at using a timzone library.
It will do the proper timzone offsets which is more complicated than just adjusting the hour, particularly if you are interested in the date and/or daylight savings adjustments as well.

You can do anything/everything related to time zones and local DST adjustments by combining these libraries with a DS3231

--- bill

vaj4088:
I have an Arduino Uno with a GPS shield. It works outdoors but not indoors in my one story house. Perhaps a better antenna would help.

Patch antennas and active antenna options is discussed in PDF

I have only used 1 GPS module which was not a u-blox Neo, it was a Parallax branded but even it worked in my basement.

I did have a nightmare with the ESP8266 wifh the GPS not working... finally tracked it to the ESP8266 'swamping; the GPS. Finally had to separate them by 9" and shield them. I guess the Arduini may be generating some RF hash, but I cannot imagine it affecting the GPS frequencies. Maybe just a low-gain unit.

This is representative of what I have used...

Ray

Well, it worked yesterday.

Yesterday and last night it was working perfectly. The Zulu time had advanced and changed the day to SUN.

I turn it on today and the times are correct but the day shows an odd character. In one character space there's a stack of a long bar, two short bars, a long bar, two short bars and a long bar. I hope you understand that.


_ _


_ _


I don't remember changing anything in my sleep so I don't know what blew up.

I was playing with a face at the end of each line to fill the space (and to see if I could do it). :slight_smile: :open_mouth: (goofina) and (goofinb). Once I added those, that character went away all together. If I comment those lines out, that character is back.

#include "Wire.h"
#define DS1307_ADDRESS 0x68
#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x27, 16, 2);


void goofina(){
  //JUST GOOFIN' Leave 1 delay if you delete this
  lcd.setCursor(14, 0);
  lcd.print(":)");
  lcd.setCursor(14, 1);
  lcd.print("  ");
}

 void goofinb(){
  //JUST GOOFIN'
  lcd.setCursor(14, 1);
  lcd.print(":O");
  lcd.setCursor(14, 0);
  lcd.print("  ");
  }

void setup() {
  Wire.begin();

  Serial.begin(9600);

  lcd.init();                      // initialize the lcd
  lcd.init();
  // Print a message to the LCD.
  lcd.backlight();
}

void loop() {
  printDate();
  goofina();
  delay(1000);

  printDate();
  goofinb();
  delay(1000);
}

byte bcdToDec(byte val)  {
  // Convert binary coded decimal to normal decimal numbers
  return ( (val / 16 * 10) + (val % 16) );
}
void printDate() {

  // Reset the register pointer
  Wire.beginTransmission(DS1307_ADDRESS);

  byte zero = 0x00;
  Wire.write(zero);
  Wire.endTransmission();

  Wire.requestFrom(DS1307_ADDRESS, 7);

  int second = bcdToDec(Wire.read());
  int minute = bcdToDec(Wire.read());
  int hour = bcdToDec(Wire.read() & 0b111111); //24 hour time
  int weekDay = bcdToDec(Wire.read()); //0-6 -> sunday - Saturday
  int monthDay = bcdToDec(Wire.read());
  int month = bcdToDec(Wire.read());
  int year = bcdToDec(Wire.read());

  int Zulu = ((hour) + 7); //CHANGE FOR DST

  //DAY OF THE WEEK
  const char weekDayName[][4] = {
    {"SUN"},
    {"MON"},
    {"TUE"},
    {"WED"},
    {"THU"},
    {"FRI"},
    {"SAT"}
  };
  const char weekDayNamez[][4] = {

    {"MON"},
    {"TUE"},
    {"WED"},
    {"THU"},
    {"FRI"},
    {"SAT"},
    {"SUN"}
  };
  //START SERIAL
  //  Serial.print(Local); THIS WORKS
  Serial.print(month);
  Serial.print("/");
  Serial.print(monthDay);
  Serial.print("/");
  Serial.print(year);
  Serial.print(" ");
  Serial.print(hour);
  Serial.print(":");
  if ((minute) < 10)
  {
    Serial.print("0");
  }
  Serial.print(minute);
  Serial.print(":");
  if ((second) < 10)
  {
    Serial.print("0");
  }
  Serial.println(second);

  //PRINT LOCAL TO LCD
  lcd.setCursor(0, 0);
  if ((hour) < 10)
  {
    lcd.print("0");
  }
  lcd.print(hour);
  lcd.setCursor(2, 0);
  lcd.print(":");
  lcd.setCursor(3, 0);
  if ((minute) < 10)
  {
    lcd.print("0");
  }
  lcd.print(minute);
  lcd.setCursor(5, 0);
  lcd.print(":");
  lcd.setCursor(6, 0);
  if ((second) < 10)
  {
    lcd.print("0");
  }
  lcd.print(second);
  lcd.setCursor(9, 0);
  lcd.print(weekDayName[weekDay]);
  //END LOCAL
  //PRINT TO LCD ZULU

  lcd.setCursor(0, 1);
  //TESTING FROM FORUM
  if ((Zulu) > 23)  // Adjusting for UTC
  {
    lcd.print("0");
    lcd.print((Zulu) - 24);
  }
  else {
    if ((Zulu) < 10)
    {
      lcd.print("0");
    }
    lcd.print(Zulu);
  }

  lcd.setCursor(2, 1);
  lcd.print(":");
  lcd.setCursor(3, 1);
  if ((minute) < 10)
  {
    lcd.print("0");
  }
  lcd.print(minute);
  lcd.setCursor(5, 1);
  lcd.print(":");
  lcd.setCursor(6, 1);
  if ((second) < 9)
  {
    lcd.print("0");
  }
  lcd.print(second);
  lcd.setCursor(9, 1);
  if ((hour) > 17)  // Adjusting for DATELINE  
  {
    lcd.print(weekDayNamez[weekDay]);
  }
  else {
    lcd.print(weekDayName[weekDay]);
  }
  //END ZULU
}