Zeitabgleich der internen Arduino-Uhr mit GPS-Daten. In diesen Thema beschreibe ich den Aufbau und die Programmierung.
Inspiriert wurde ich durch ein Thema unseres Mitgliedes @Quiddje , der bereits mit seinem Projekt Arduino GPS-Uhr mit TM1637 vorgelegt hat. Danke dafür!
Ins Rollen ist die Sache durch unsere Uhren-Projekte mit DCF77 Empfängermodule gekommen: DCF77 Empfang mit Arduino und Arduino mit DCF77-Modul und RTC Echtzeituhr DS3231
Auch da hat @Quiddje den Initialimpuls gebracht. So kann man als Holzwurm und Strippenzieher gemeinsam sehr kreativ und effizient arbeiten.
Basis für dieses Projekt ist ein Arduino Nano-Clone, ein GPS-Modul GY-NEO6MV2 (Achtung, der Link ist keine bezahlte Werbung!), eine 16x2 LCD-Anzeige und eine LED nebst Vorwiderstand.
Das verlinkte GPS-Modul arbeitet mit 5V, sodass man das direkt an den Nano anschließen kann. Die LED dient nur der Anzeige, dass auf Sommerzeit eingestellt ist.
Der Anschluß / Hardware:
Das GPS-Modul wird an +5V, GND und der TX-Pin an Pin D8 des Nanos angesteckt.
Für die Erkennung der Sommerzeitumstellung wird Pin D7 des Nanos an +5V (Sommerzeit) oder GND (Normalzeit) gelegt.
Parallel zum Pin D7 schließe ich eine LED über einen Vorwiderstand an. Sobald die LED leuchtet, liegt ein High-Pegel an D7 und der Nano wertet das programmtechnisch als Sommerzeit.
Mein Display mit I2C-Interface wird an die Nano-Pins A4(SDA) und A5(SCL) sowie an +5V und GND angeschlossen.
Das Programm:
Für das Programm benötigt man diverse Libraries.
Für das GPS-Modul braucht man die TinyGPS++.h und die SoftwareSerial.h, sowie die SPI.h. Die beiden letztgenannten sind normalerweise Bestandteil der Arduino IDE.
Für ein angeschlossenes Display muß man ggf. eine Lib verwenden, die mit dem eigenen Display funktioniert, mein LCD-Display läuft mit der LiquidCrystal_I2C.h, weil ich das Display mit einem I2C-Adapter betreibe.
Zum Programmablauf:
Basis für mein Programm ist ein Programm von simple-circuits.com, dass ich auf meine Hardware und meine speziellen Wünsche angepasst habe.
Die wesentlichen Modifikationen sind die 16x2 LCD-Anzeige (im Urprogramm 20x4), die mit einem I2C-Interface läuft. Natürlich musste ich dafür noch die Ausgabe des Datums, der Zeit und des Wochentages anpassen.
Bezüglich der Programmfunktionen setze ich nicht einen festen Korrekturwert zur UTC (Zeit am nullten Breitengrad, ehemals GMT), sondern bestimme die Zeitzone über den Längengrad, den ich aus dem GPS-Modul beim ersten Schleifendurchlauf der Hauptfunktion abfrage.
Deutschland liegt ungefähr zwischen dem 6. und 15. Längengrad. Um auch in den östlichen und westlichen Randgebieten des Landes auf Nummer sicher zu gehen, erweitere ich den Bereich der Abfrage auf den 5. bis zum 16. Längengrad.
Die Umstellung zwischen Sommer- und Normalzeit erfolgt über die Abfrage des Digitalports D7, den ich in meinen Projekten üblicherweise immer für derartige Zwecke verwende. Ich hatte kurzzeitig über eine automatische Umstellung nachgedacht, mich aber aus folgenden Gründen dagegen entschieden:
Die Umstellung zwischen Sommer- und Normalzeit könnte ich eigentlich auch nur einmal beim ersten Hauptschleifendurchlauf abfragen, nur müsste die "Uhr" dann resettet werden wenn man umschaltet, das gefiel mir aber nicht.
Also Frage ich bei jedem Schleifendurchlauf den Port D7 ab und vergleiche, ob vorher die jeweils andere Zeit aktiv war und berechne die Zeitkorrektur ggf. neu. Die parallel zum Pin D7 angeschlossene LED gibt Auskunft darüber, welche der beiden Zeiten aktiv ist. Ich könnte das auch auf dem Display anzeigen, habe das aber (noch) nicht gemacht.
Die Anzeige:
Auf dem Display erscheint in der ersten Zeile die Uhrzeit im Format HH:MM:SS, in der zweiten Zeile steht der Wochentag mit den zwei ersten Buchstaben und dahinter das komplette Datum inkl. Jahreszahl.
Die Uhrzeit wir bei jedem Schleifendurchlauf aktualisiert.
Das nun folgende Programmlisting enthält noch Programmzeilen zur Ausgabe über den seriellen Monitor am PC-Bildschirm, die ich für die Fehlersuche gebraucht habe, sowie auskommentierte Zeilen des Ur-Programms.
Aber es funktioniert auf jeden Fall.
Erkenntnisse:
Beim ersten Start der Schaltung (nach längerer Spannungslosigkeit) dauert es u.U. ca. 1 Minute, bis eine Zeit angezeigt wird, dabei ist es sogar möglich, dass kurzzeitig ein total unsinniges Datum (2099) und eine falsche Zeit angezeigt wird. Nach ein paar Sekunden hat man aber dann die korrekte Zeit. Nach einem Reset oder nur kurzer Trennung von der Betriebsspannung, erfolgt die richtige Datums- und Zeitanzeige bereits nach wenigen Augenblicken. Das GPS-Modul liegt bei mir nur in der Nähe des Fensters, also nicht direkt im Freien, da hat mich die relativ schnelle Reaktion sehr erstaunt. Mal sehen was sich aus dem Rohprojekt machen lässt. Im Moment läuft die "Uhr" erstmal nur auf meinem Schreibtisch zusammen mit der DCF77-Uhr aus dem Thema: Arduino mit DCF77-Modul und RTC Echtzeituhr DS3231
Inspiriert wurde ich durch ein Thema unseres Mitgliedes @Quiddje , der bereits mit seinem Projekt Arduino GPS-Uhr mit TM1637 vorgelegt hat. Danke dafür!
Ins Rollen ist die Sache durch unsere Uhren-Projekte mit DCF77 Empfängermodule gekommen: DCF77 Empfang mit Arduino und Arduino mit DCF77-Modul und RTC Echtzeituhr DS3231
Auch da hat @Quiddje den Initialimpuls gebracht. So kann man als Holzwurm und Strippenzieher gemeinsam sehr kreativ und effizient arbeiten.
Basis für dieses Projekt ist ein Arduino Nano-Clone, ein GPS-Modul GY-NEO6MV2 (Achtung, der Link ist keine bezahlte Werbung!), eine 16x2 LCD-Anzeige und eine LED nebst Vorwiderstand.
Das verlinkte GPS-Modul arbeitet mit 5V, sodass man das direkt an den Nano anschließen kann. Die LED dient nur der Anzeige, dass auf Sommerzeit eingestellt ist.
Der Anschluß / Hardware:
Das GPS-Modul wird an +5V, GND und der TX-Pin an Pin D8 des Nanos angesteckt.
Für die Erkennung der Sommerzeitumstellung wird Pin D7 des Nanos an +5V (Sommerzeit) oder GND (Normalzeit) gelegt.
Parallel zum Pin D7 schließe ich eine LED über einen Vorwiderstand an. Sobald die LED leuchtet, liegt ein High-Pegel an D7 und der Nano wertet das programmtechnisch als Sommerzeit.
Mein Display mit I2C-Interface wird an die Nano-Pins A4(SDA) und A5(SCL) sowie an +5V und GND angeschlossen.
Das Programm:
Für das Programm benötigt man diverse Libraries.
Für das GPS-Modul braucht man die TinyGPS++.h und die SoftwareSerial.h, sowie die SPI.h. Die beiden letztgenannten sind normalerweise Bestandteil der Arduino IDE.
Für ein angeschlossenes Display muß man ggf. eine Lib verwenden, die mit dem eigenen Display funktioniert, mein LCD-Display läuft mit der LiquidCrystal_I2C.h, weil ich das Display mit einem I2C-Adapter betreibe.
Zum Programmablauf:
Basis für mein Programm ist ein Programm von simple-circuits.com, dass ich auf meine Hardware und meine speziellen Wünsche angepasst habe.
Die wesentlichen Modifikationen sind die 16x2 LCD-Anzeige (im Urprogramm 20x4), die mit einem I2C-Interface läuft. Natürlich musste ich dafür noch die Ausgabe des Datums, der Zeit und des Wochentages anpassen.
Bezüglich der Programmfunktionen setze ich nicht einen festen Korrekturwert zur UTC (Zeit am nullten Breitengrad, ehemals GMT), sondern bestimme die Zeitzone über den Längengrad, den ich aus dem GPS-Modul beim ersten Schleifendurchlauf der Hauptfunktion abfrage.
Deutschland liegt ungefähr zwischen dem 6. und 15. Längengrad. Um auch in den östlichen und westlichen Randgebieten des Landes auf Nummer sicher zu gehen, erweitere ich den Bereich der Abfrage auf den 5. bis zum 16. Längengrad.
Die Umstellung zwischen Sommer- und Normalzeit erfolgt über die Abfrage des Digitalports D7, den ich in meinen Projekten üblicherweise immer für derartige Zwecke verwende. Ich hatte kurzzeitig über eine automatische Umstellung nachgedacht, mich aber aus folgenden Gründen dagegen entschieden:
- Die Zeitumstellung erfolgt nicht immer am selben Datum, sondern am letzten Sontag im März(SZ) und letzten Sonntag im Oktober(NZ). Die Berechnung des tatsächlichen Datums wäre dann etwas umfangreicher.
- Es könnte durchaus sein, dass die Umstellung der Zeit abgeschafft wird, dann wäre eine fest programmierte Zeitumstellung unbrauchbar und die geleistete Programmierarbeit für die Katz.
Die Umstellung zwischen Sommer- und Normalzeit könnte ich eigentlich auch nur einmal beim ersten Hauptschleifendurchlauf abfragen, nur müsste die "Uhr" dann resettet werden wenn man umschaltet, das gefiel mir aber nicht.
Also Frage ich bei jedem Schleifendurchlauf den Port D7 ab und vergleiche, ob vorher die jeweils andere Zeit aktiv war und berechne die Zeitkorrektur ggf. neu. Die parallel zum Pin D7 angeschlossene LED gibt Auskunft darüber, welche der beiden Zeiten aktiv ist. Ich könnte das auch auf dem Display anzeigen, habe das aber (noch) nicht gemacht.
Die Anzeige:
Auf dem Display erscheint in der ersten Zeile die Uhrzeit im Format HH:MM:SS, in der zweiten Zeile steht der Wochentag mit den zwei ersten Buchstaben und dahinter das komplette Datum inkl. Jahreszahl.
Die Uhrzeit wir bei jedem Schleifendurchlauf aktualisiert.
Das nun folgende Programmlisting enthält noch Programmzeilen zur Ausgabe über den seriellen Monitor am PC-Bildschirm, die ich für die Fehlersuche gebraucht habe, sowie auskommentierte Zeilen des Ur-Programms.
Aber es funktioniert auf jeden Fall.
C++:
/*
* Arduino GPS clock with local time using NEO-6M module and 20x4 LCD.
* This is a free software with NO WARRANTY.
* https://simple-circuit.com/
* angepasst von BAXL RC-Modellbau-Portal.de an eigene Bedürfnisse
*/
#include <SPI.h>
#include <TinyGPS++.h> // include TinyGPS++ library
#include <TimeLib.h> // include Arduino time library
#include <SoftwareSerial.h> // include software serial library
//#include <LiquidCrystal.h> // include LCD library
TinyGPSPlus gps;
#define S_RX 9 // define software serial RX pin
#define S_TX 8 // define software serial TX pin
SoftwareSerial SoftSerial(S_RX, S_TX); // configure SoftSerial library
// LCD module connections (RS, E, D4, D5, D6, D7)
// LiquidCrystal lcd(2, 3, 4, 5, 6, 7);
#include <LiquidCrystal_I2C.h> // LiquidCrystal_I2C Bibliothek einbinden
LiquidCrystal_I2C lcd(0x27, 16, 2); //Hier wird festgelegt um was für einen Display es sich handelt.
// In diesem Fall eines mit 16 Zeichen in 2 Zeilen und der HEX-Adresse 0x27.
// Für ein vierzeiliges I2C-LCD verwendet man den Code "LiquidCrystal_I2C lcd(0x27, 20, 4)"
#define time_offset 7200 // define a clock offset of 7200 seconds (2 hour) ==> UTC + 2
int Zeitzuschlag;
int Sommerzeit = 0;
byte SommerzeitPin = 7;
byte ErstStart;
byte De;
byte Sommer = 0;
// variable definitions
char Time[] = "00:00:00";
char Date[] = "00.00.2000";
byte last_second, Second, Minute, Hour, Day, Month;
int Year;
void setup(void)
{
Serial.begin(9600);
SoftSerial.begin(9600); // initialize software serial at 9600 baud
lcd.init(); //Im Setup wird der LCD gestartet
lcd.backlight(); //Hintergrundbeleuchtung einschalten (lcd.noBacklight(); schaltet die Beleuchtung aus).
lcd.setCursor(0, 0); // move LCD cursor to column 1, row 0 [upper left position (0, 0)]
lcd.print("GPS DE");
Serial.println("gestartet");
// Variablen zur Zeitumstellung zwischen Normal- und Sommerzeit
pinMode(SommerzeitPin, INPUT); // Eingang zur Umstellung zwischen Sommer- und Normalzeit
Sommerzeit = (digitalRead(SommerzeitPin)); // Berechnung der Zeitkorrektur bei Sommerzeit wen HIGH-Pegel
Sommer = 0;
if (Sommerzeit == 1){Sommer = 1;} // Merker für die Sommerzeitumstellung
ErstStart = 1; // Merker für Längengradbestimmung bei Neustart des Programms
}
void loop()
{
while (SoftSerial.available() > 0)
{
if (gps.encode(SoftSerial.read()))
{
// get time from GPS module
if (gps.time.isValid())
{
Minute = gps.time.minute();
Second = gps.time.second();
Hour = gps.time.hour();
Serial.print(Hour);Serial.print(":");Serial.print(Minute);Serial.print(":");Serial.println(Second);
Serial.println(ErstStart);
if (ErstStart == 1)
{UTC_De(); ErstStart = 0;Serial.println("ErstStart");}
if (Sommer != digitalRead(SommerzeitPin)) {
// Umstellung der Zeit wenn SommerZeitpin seinen pegel verändert hat
// HIGH - Sommerzeit, LOW - Normalzeit
Sommerzeit = !Sommerzeit;
Sommer = !Sommer;
Zeitzuschlag = (De + Sommerzeit) *3600; // Berechnung Korrektur aus GPS-Position und Sommerzeitstatus
}
}
// get date drom GPS module
if (gps.date.isValid())
{
Day = gps.date.day();
Month = gps.date.month();
Year = gps.date.year();
}
if(last_second != gps.time.second()) // if time has changed
{
last_second = gps.time.second();
// set current UTC time
setTime(Hour, Minute, Second, Day, Month, Year);
// add the offset to get local time
//adjustTime(time_offset);
adjustTime(Zeitzuschlag);
// update time array
Time[6] = second() / 10 + '0';
Time[7] = second() % 10 + '0';
Time[3] = minute() / 10 + '0';
Time[4] = minute() % 10 + '0';
Time[0] = hour() / 10 + '0';
Time[1] = hour() % 10 + '0';
// update date array
Date[8] = (year() / 10) % 10 + '0';
Date[9] = year() % 10 + '0';
Date[3] = month() / 10 + '0';
Date[4] = month() % 10 + '0';
Date[0] = day() / 10 + '0';
Date[1] = day() % 10 + '0';
// print time & date
print_wday(weekday()); // print day of the week
lcd.setCursor(0, 0); // move cursor to column 0 row 2
lcd.print(Time); // print time (HH:MM:SS)
lcd.setCursor(3, 1); // move cursor to column 0 row 3
lcd.print(Date); // print date (DD-MM-YYYY)
//longi = gps.location.lng();
//Serial.print("Längengrad");Serial.println(gps.location.lng());
//getlongi;
}
}
}
}
// function for displaying day of the week
void print_wday(byte wday)
{
lcd.setCursor(0, 1); // move cursor to column 5, row 1
switch(wday)
{
case 1: lcd.print("So "); break;
case 2: lcd.print("Mo "); break;
case 3: lcd.print("Di "); break;
case 4: lcd.print("Mi "); break;
case 5: lcd.print("Do "); break;
case 6: lcd.print("Fr "); break;
default: lcd.print("Sa ");
}
}
void UTC_De()
{
//double Longi;
//Longi = gps.location.lng();
if ((gps.location.lng()> 5) && (gps.location.lng() < 16)){De = 1;}
Serial.print("Längengrad:");Serial.print(gps.location.lng());Serial.print(" Deutschland: ");Serial.println(De);
Zeitzuschlag = (De + Sommerzeit) *3600;
}
void SetSommerWinter()
{
//double Longi;
//Longi = gps.location.lng();
if ((gps.location.lng()> 5) && (gps.location.lng() < 16)){De = 1;}
Serial.print("Längengrad:");Serial.print(gps.location.lng());Serial.print(" Deutschland: ");Serial.println(De);
Zeitzuschlag = (3600 * De) + Sommerzeit;
}
// end of code.
Beim ersten Start der Schaltung (nach längerer Spannungslosigkeit) dauert es u.U. ca. 1 Minute, bis eine Zeit angezeigt wird, dabei ist es sogar möglich, dass kurzzeitig ein total unsinniges Datum (2099) und eine falsche Zeit angezeigt wird. Nach ein paar Sekunden hat man aber dann die korrekte Zeit. Nach einem Reset oder nur kurzer Trennung von der Betriebsspannung, erfolgt die richtige Datums- und Zeitanzeige bereits nach wenigen Augenblicken. Das GPS-Modul liegt bei mir nur in der Nähe des Fensters, also nicht direkt im Freien, da hat mich die relativ schnelle Reaktion sehr erstaunt. Mal sehen was sich aus dem Rohprojekt machen lässt. Im Moment läuft die "Uhr" erstmal nur auf meinem Schreibtisch zusammen mit der DCF77-Uhr aus dem Thema: Arduino mit DCF77-Modul und RTC Echtzeituhr DS3231
Zuletzt bearbeitet: