I am working on a GPS clock with TimeZone and DST off set using World Clock sketches. I have found that if I reset the Arduino or power it off for any period of time, the displayed time does not match the GPS time. It acts as if the sketch is reading a default time from memory.
Here is the sketch file: I know it's not clean, it's still a work in process.
#include <Wire.h>
#include "Adafruit_LEDBackpack.h"
#include <Adafruit_GPS.h>
#include <Adafruit_GFX.h>
#include <SoftwareSerial.h>
#include <idDHT11.h> // Tempature & Humidity Sensor
#include <Time.h> //http://www.arduino.cc/playground/Code/Time
#include <Timezone.h> //https://github.com/JChristensen/Timezone
int light;
int gpsTime;
int cgpsTime;
int idDHT11pin = 2; //Digital pin for comunications
int idDHT11intNumber = 0; //interrupt number (must be the one that use the previus defined pin (see table above)
//declaration
void dht11_wrapper(); // must be declared before the lib initialization
// Lib instantiate
idDHT11 DHT11(idDHT11pin,idDHT11intNumber,dht11_wrapper);
#define LIGHTPIN 0
Adafruit_7segment matrix1 = Adafruit_7segment(); // Main display
Adafruit_7segment matrix2 = Adafruit_7segment(); // Speed display
Adafruit_7segment matrix3 = Adafruit_7segment(); // Tempature display
Adafruit_7segment matrix4 = Adafruit_7segment(); // Humidity display
SoftwareSerial mySerial(6, 7);
Adafruit_GPS GPS(&mySerial);
#define GPSECHO false
boolean usingInterrupt = false;
void useInterrupt(boolean); // Func prototype keeps Arduino 0023 happy
// World Clock Settings
//US Eastern Time Zone (New York, Detroit)
TimeChangeRule usEDT = {"EDT", Second, Sun, Mar, 2, -240}; //Eastern Daylight Time = UTC - 4 hours
TimeChangeRule usEST = {"EST", First, Sun, Nov, 2, -300}; //Eastern Standard Time = UTC - 5 hours
Timezone usET(usEDT, usEST);
TimeChangeRule *tcr; //pointer to the time change rule, use to get the TZ abbrev
time_t utc;
// These constants are for the LED Dim Function and won't change:
const int sensorPin = A0; // pin that the sensor is attached to
// variables:
int sensorValue = 0; // the sensor value
int sensorMin = 1023; // minimum sensor value
int sensorMax = 0; // maximum sensor value
unsigned long previousMillis = 0; //This stores the last time DimDisplay was updated
const long interval = 30000; // interval at which DimDisplay will be updated
const unsigned long TaskAtime = 500UL; //Runs TaskA every 500 milli seconds
const unsigned long TaskBtime = 15000UL; //Runs TaskB every 60 seconds
const unsigned long TaskCtime = 30000UL; //Runa TaskC every 60 seconds
unsigned long TimeA; //Times up, Task A time
unsigned long TimeB; //Times up, Task B time
unsigned long TimeC; //Times up, Task C time
void setup()
{
matrix1.begin(0x70); // Clock Display
matrix2.begin(0x72); // Speed Display
matrix3.begin(0x71); // Tempature Display
matrix4.begin(0x74); // Humidity Display
Serial.begin(115200);
Serial.println("Steve's UTC GPS Seven Segment Clock with AutoDim, Speed, Tempature & Humidity");
setTime(usET.toUTC(compileTime())); // World Clock Setting
GPS.begin(9600);
GPS.sendCommand(PMTK_SET_NMEA_OUTPUT_RMCGGA);
GPS.sendCommand(PMTK_SET_NMEA_UPDATE_1HZ); // 1 Hz update rate
useInterrupt(true);
delay(1000);
mySerial.println(PMTK_Q_RELEASE);
}
// Interrupt is called once a millisecond, looks for any new GPS data, and stores it
SIGNAL(TIMER0_COMPA_vect) {
char c = GPS.read();
if (GPSECHO)
if (c) UDR0 = c;
}
void useInterrupt(boolean v) {
if (v) {
OCR0A = 0xAF;
TIMSK0 |= _BV(OCIE0A);
usingInterrupt = true;
} else {
// do not call the interrupt function COMPA anymore
TIMSK0 &= ~_BV(OCIE0A);
usingInterrupt = false;
}
{ //This is for the LED Dim Function
TimeA = millis(); //Initailize
TimeB = TimeA; //Initialize
TimeC = TimeA; // Initialize
}
}
void dht11_wrapper() {
DHT11.isrCallback();
}
uint32_t timer = millis();
void loop() // run over and over again
{
unsigned long millisNow = millis();
//==================
if (millisNow - TimeA >= TaskAtime) //Is it time to run Task A?
{
TimeA = millis(); //Re-initialize
TaskA();
}
//==================
if (millisNow - TimeB >= TaskBtime) //Is it time to run Task B?
{
TimeB = millis(); //Re-initialize
TaskB();
}
//==================
if (millisNow - TimeC >= TaskCtime) //Is it time to run Task B?
{
TimeC = millis(); //Re-initialize
TaskC();
}
// calibrate during the first five seconds
while (millis() < 5000)
sensorValue = analogRead(sensorPin);
// record the maximum sensor value
if (sensorValue > sensorMax)
sensorMax = sensorValue;
// record the minimum sensor value
if (sensorValue < sensorMin)
sensorMin = sensorValue;
}
// FUNCTIONS
void TaskA()
{
// in case you are not using the interrupt above, you'll
// need to 'hand query' the GPS, not suggested :(
if (! usingInterrupt) {
// read data from the GPS in the 'main loop'
char c = GPS.read();
// if you want to debug, this is a good time to do it!
if (GPSECHO)
if (c) UDR0 = c;
// writing direct to UDR0 is much much faster than Serial.print
// but only one character can be written at a time.
}
if (GPS.newNMEAreceived()) {
GPS.parse(GPS.lastNMEA()); // this also sets the newNMEAreceived() flag to false
if (GPS.hour)
{
gpsTime = (((GPS.hour) *100)+ GPS.minute);
if (gpsTime < 10, '0');
}
}
Serial.println();
utc = now();
printTime(usET.toLocal(utc, &tcr), tcr -> abbrev, " New York");
}
//Function to return the compile date and time as a time_t value
time_t compileTime(void)
{
#define FUDGE 25 //fudge factor to allow for compile time (seconds, YMMV)
char *compDate = __DATE__, *compTime = __TIME__, *months = "JanFebMarAprMayJunJulAugSepOctNovDec";
char chMon[3], *m;
int d, y;
tmElements_t tm;
time_t t;
strncpy(chMon, compDate, 3);
chMon[3] = '\0';
m = strstr(months, chMon);
tm.Month = ((m - months) / 3 + 1);
tm.Day = atoi(compDate + 4);
tm.Year = atoi(compDate + 7) - 1970;
tm.Hour = atoi(compTime);
tm.Minute = atoi(compTime + 3);
tm.Second = atoi(compTime + 6);
t = makeTime(tm);
return t + FUDGE; //add fudge factor to allow for compile time
}
//Function to print time with time zone
void printTime(time_t t, char *tz, char *loc)
{
Serial.print(" GPS Time: ");
Serial.print(GPS.hour, DEC); Serial.print(':');
Serial.print(GPS.minute, DEC); Serial.print(':');
Serial.print(GPS.seconds, DEC); Serial.print('.');
Serial.println();
matrix1.print((hour(t) *100)+ minute(t));
if(hour(t) *100 < 10)
matrix1.writeDigitNum(0, 0);
if(hour(t) *100 < 1)
matrix1.writeDigitNum(1, 0);
if(minute(t) < 10)
matrix1.writeDigitNum(3, 0);
matrix1.writeDigitNum(0x02, true);
matrix1.writeDisplay();
matrix2.print((GPS.speed),1);
sPrintI00(hour(t));
sPrintDigits(minute(t));
sPrintDigits(second(t));
Serial.print(' ');
Serial.print(weekday(t));
Serial.print(' ');
sPrintI00(day(t));
Serial.print(' ');
Serial.print(month(t));
Serial.print(' ');
Serial.print(year(t));
Serial.print(' ');
Serial.print(tz);
Serial.print(' ');
Serial.print(loc);
Serial.println();
}
void sPrintI00(int val)
{
if (val < 10) Serial.print('0');
Serial.print(val, DEC);
return;
}
void sPrintDigits(int val)
{
Serial.print(':');
if(val < 10) Serial.print('0');
Serial.print(val, DEC);
}
//==================
void TaskB()
{
unsigned long currentMillis = millis();
// read the sensor:
sensorValue = analogRead(sensorPin);
// apply the calibration to the sensor reading
sensorValue = map(sensorValue, sensorMin, sensorMax, 0, 255);
// in case the sensor value is outside the range seen during calibration
sensorValue = constrain(sensorValue, 0, 255);
if(currentMillis >= interval);
// save the last time you udated LED setBgightness command
previousMillis = currentMillis;
if (previousMillis > interval)
previousMillis = 0;
matrix1.setBrightness((sensorValue) / 16);
matrix2.setBrightness((sensorValue) / 16);
matrix3.setBrightness((sensorValue) / 16);
matrix4.setBrightness((sensorValue) / 16);
}
//==================
void TaskC()
{
light = analogRead(LIGHTPIN);
matrix3.print(DHT11.getFahrenheit(), 1);
matrix3.writeDisplay();
matrix4.print(DHT11.getHumidity(), 1);
matrix4.writeDisplay();
delay(500);
}