2015
HOME

Rheinturmuhr all over the world - Zeitsteuerung
GPS-Uhrzeit
Die aWatch: arduino-TFT-Watch mit Satellitensynchronisation
aWatch - model Sweden
Rechtzeitig zum Launch der Apple-Watch: Die aWatch, eine GPS-Uhr mit Arduino und NEO-6M-Modul von eblox. Hier die schwedische Variante. Weiter unten: weitere WatchFaces.
Im Gegensatz zu DCF77 ist GPS weltweit verfügbar. Somit wäre es nicht mehr schwierig weltweit funktionierende Funkwecker anzubieten. Das Angebot ist jedoch mager.

Neben Positionsdaten senden die GPS-Satelliten auch die Weltzeit sehr genau in Richtung Erde. Die Empfänger werden kleiner und preiswerter, wodurch der Einsatz für eigene Projekte möglich wird. Hier soll eine Uhr - auch die Rheinturmuhr - per Satellit synchronisiert werden.

Ein CRIUS NEO-6 GPS-Modul enthält Antenne, Empfänger und vier Anschlüsse: Versorgungsspannung und Masse, sowie die beiden seriellen Leitungen TX/RX. Das Modul arbeitet mit 9600 Baud und sendet einmal in der Sekunde unaufgefordert GPS-Daten in Textform. Eine blaue LED ist die Poweranzeige, eine grüne LED blinkt im Sekundentakt, wenn mehr als 3 Satelliten empfangen werden und ein so genannter FIX vorherrscht.

Im Auslieferungszustand sind das 8 oder 9 Zeilen mit bis zu 80 Zeichen pro Zeile. Jede Zeile beginnt mit dem Zeichen '$' und endet mit einem Zeilenvorschub (13). Je nach Phrase nach dem '$'-Zeichen folgen verschiedene CSV-Werte (durch Kommata getrennte Werte). Das Datenformat ist unter "NMEA 0183" bekannt und alle Datensätze findet man hier. Das CRIUS NEO-6 GPS-Modul liefert im Auslieferungszustand die Sätze: GPRMC, GPVTG, GPGGA, GPGSA, GPGLL sowie GPGSV mit 3 oder 4 Zeilen. Die für dieses Projekt verwendeten Zeilen lauten zum Beispiel (geändert, falsche Prüfsumme):

$GPRMC,072158.00,A,5100.12345,N,00645.12345,E,0.048,,210415,,,D*74
$GPGGA,072158.00,5100.12345,N,00645.12345,E,2,08,1.29,69.4,M,46.5,M,,0000*6D
...

GPS-Modul
Im ersten Datensatz findet man die Zeit (UTC) im ersten Parameter 7:21:58, sowie das Datum 21.04.2015 im 9. Parameter. Der zweite Datensatz enthält ebenfalls die Zeit und die Position, aber auch den FIX (6. Parameter) als 2 und die Anzahl der Satelliten (7. Parameter) mit 08, weiterhin die Höhe in Metern usw. Jeder Datensatz bzw. Zeile wird mit einer zweistelligen hexadezimalen Prüfsumme der Daten abgeschlossen, die nach dem Zeichen '*' steht. Mit dem 'u-center' von ublox können unter Windows viele Änderungen am GPS-Modul vorgenommen werden.


Ziele Randbedingungen

Die Realisierung der Arduino-GPS-Uhr soll einigen Bedingungen unterliegen:

  • Keine Veränderung am GPS-Modul (Datensätze, Baudrate)
  • Automatische Sommer-/Winterzeit für eine Zeitzone
  • Darstellung auf einem 1.8 TFT-Display
  • Anzeige von Uhrzeit, Datum mit Wochentag und Anzahl der Satelliten
  • Keine Softserial-Routinen - Datenzufuhr über Pin 0 (RX)
  • Verwendung des Arduino UNO mit 32K/16MHz

Im Laufe des Projekts stellte sich heraus, dass der Arduino mit TFT-Display und den entsprechenden Bibliotheken in Zeit- und Speichernot kam und die Datenmenge eigentlich reduziert werden sollte. Bei 9600 bps ergeben sich bei maximal 9x80 Zeichen 720 Bytes pro Sekunde. Mit Start- und Stoppbit sind das 7200 bps. Falls kein Denkfehler vorliegt, bliebe dann noch 250 ms zur Ansteuerung des TFT-Displays und für andere Dinge. Durch die asynchrone serielle Datenübertragung und dem 64 Byte großen Empfangspuffer im Arduino ist es nicht ganz einfach die Randbedingungen einzuhalten. Mit der Software 'u-center' von ublox können unter Windows viele Änderungen am GPS-Modul vorgenommen werden, was für noch zeitkritischere Anwendungen wohl unumgänglich erscheint. Nach verschiedenen gescheiterten Ansätzen konnten die gesetzten Bedingungen doch noch gerade eingehalten werden.


GPS-Routinen Zeile, Prüfsumme, Parameter

Die Verwendung einer GPS-Bibliothek (TinyGPS) wurde verworfen, da die Ziele hier so nicht erreicht werden konnten. Um die seriellen GPS-Daten zu verarbeiten wird eine Hand voll Routinen benötigt:

  • getline - Empfang einer kompletten Zeile über die serielle Schnittstelle
  • checksum - Überprüfung der Integrität der Datenzeile
  • getparam - Auslesen des gewünschten Parameters
//----------------------------------------------
//--------------GPS-ROUTINEN--------------------
//----------------------------------------------
//String Line="";

boolean getline(char *phrase) //HARD POLLING
{char s[100];byte b,n;unsigned long t=millis();
 for(int i=0; i<sizeof(s);i++)s[i]=0;
 Line="";
 do 
 {b=Serial.read();
  if(millis()>(t+100))return false;
 }while(b!='$');
 s[0]=b;
 n=Serial.readBytesUntil('\n', &s[1], 90);
 s[n]=0;
 if(strstr(s,phrase)==s)
 {for(int i=0;i<n;i++)Line+=s[i];
  return true; 
 }
 return false;
}

#define hex(i)  ((i<=9) ? ('0'+i): ('A'- 10 + i))

boolean checksum()
{byte b=0;int e;
 e=Line.indexOf('*');
 if(e>10)
 {for(int i=1;i<e;i++)b^=Line[i]; 
  if((hex((b&15))==Line[e+2]) && 
     (hex(b/16)==Line[e+1]))return true;
 }
 return false;
}

String getparam(int ix)
{int c,cc=0;
 if(checksum())
 {do
  {c=Line.indexOf(',',cc);
   if(c>=0)cc=c+1; else break;
  }while (--ix);
  return(Line.substring(c+1,Line.indexOf(',',c+1))); 
 }
 return "xx"; //debug
}

Die Routine getline löscht zunächst alle Zeichen der lokalen Zeichenkette und setzt den globalen String Line auf "". Nun wird maximal 0,1 s auf ein Zeilenanfang ($) gewartet und bei Erfolg die ganze Zeile bis zum Zeilenende '\n' eingelesen (readBytesUntil) und das Resultat in die globale Variable Line kopiert.

Checksum überprüft, ob die Zeile fehlerfrei vorliegt. Dazu werden alle Zeichen zwischen dem Anfang '$' und dem Ende '*' exklusiv-oder addiert. Das Ergebnis sollte dann mit den beiden Zeichen nach dem '*'-Zeichen übereinstimmen.

Mit getparam wird schließlich der Parameter ix als Zeichenkette geliefert. Das Datum erhält man demnach im 9. Parameter der Zeile, wenn sie mit $GPRMC beginnt.


Testlauf 'Ohne Alles'

Der folgende Sketch dient dazu die obigen Routinen zu überprüfen und ohne jedes Beiwerk die gewünschten Daten anzuzeigen.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
String Line = ""; // a string to hold incoming data

void setup()  
{Line.reserve(100);
 Serial.begin(9600);
 Serial.println("u-blox NEO-6M GPS at PIN 0 ...");
}

void loop() 
{if(getline("$GPGGA"))GGA();
 if(getline("$GPRMC"))RMC();
 while(Serial.available())Serial.read();
}//loop

void GGA()//FIX SAT ect.
{Serial.print  (getparam(7));
 Serial.print(" Sat:");
 Serial.println(getparam(6));
}//GPGGA

void RMC()//TIME DATE 
{Serial.print(getparam(1));
 Serial.print("  ");
 Serial.print(getparam(9));
 Serial.print("  ");
}//GPRMC

//----------------------------------------------
//--------------GPS-ROUTINEN--------------------
//----------------------------------------------

Nach der Zeile 27 müssen nun die drei weiter oben angegebenen GPS-Routinen eingefügt werden. Bei der Übertragung des Sketches muss der PIN 0 vom Arduino unbelegt sein, sonst erscheint ein Fehler: avrdude: stk500_getsync(): not in sync: resp=0x00. Danach wird die TX-Leitung vom GPS-Modul an PIN 0 angeschlossen. Im SerialMonitor könnten folgende Zeilen erscheinen:

u-blox NEO-6M GPS at PIN 0 ...
173507.00 140415 07 Sat:1
173508.00 140415 07 Sat:1
173509.00 140415 07 Sat:1
173510.00 140415 07 Sat:1
....

Solche Ergebnisse sind auch mit Bibliotheken oder SerialEvent-Routinen möglich. Hier sollen aber genau die obigen Routinen getestet werden.


Testlauf mit Zeitzone und Sommer-/Winterzeit

Um die entsprechende Lokalzeit und die Sommer-/und Winterzeit zu erhalten, kommen nun die Bibliotheken "Time" und "Timezone" dazu.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
//------- DATE TIME --------------------------
#include <Time.h> 
#include <Timezone.h>    
TimeChangeRule CEST = {"", Last, Sun, Mar, 2, 120};     
TimeChangeRule CET = {"", Last, Sun, Oct, 3, 60}; 
Timezone CE(CEST, CET);
TimeChangeRule *tcr; 
char *Tag[7] = {"SONNTAG","MONTAG","DIENSTAG","MITTWOCH",
                "DONNERSTAG","FREITAG","SONNABEND"};

String Line = "";    // a string to hold incoming data

void setup()  
{Line.reserve(100);
 Serial.begin(9600);
}

void loop() 
{static int os=-1;

 if(!(os%3))if(getline("$GPGGA"))GGA();
 if(!(os%4))if(getline("$GPRMC"))RMC();
 SerialClear(); 

 if(second()!=os)//every second
 {char s[80];
  sprintf(s,"%s der %02d.%02d.%04d um %02d:%02d:%02d",
  Tag[weekday()-1],day(),month(),year(),
  hour(),minute(),second());
  Serial.println(s);
  os=second();
 }//second
}//loop

void GGA()//FIX SAT ect.
{Serial.print (getparam(7));Serial.println(" Sat");
}//GPGGA

void RMC()//TIME DATE 
{setTime(getparam(1).substring(0,0+2).toInt(),
         getparam(1).substring(2,2+2).toInt(),
         getparam(1).substring(4,4+2).toInt(),
         getparam(9).substring(0,0+2).toInt(),
         getparam(9).substring(2,2+2).toInt(),
         getparam(9).substring(4,4+2).toInt());
 time_t cet=CE.toLocal(now(),&tcr);
 setTime(cet);
 Serial.println("sync");
}//GPRMC

void SerialClear()
{while(Serial.available())Serial.read();
}

//----------------------------------------------
//--------------GPS-ROUTINEN--------------------
//----------------------------------------------

Nach Zeile 54 müssen wieder die GPS-Routinen eingefügt werden. In der Hauptschleife wird nun jede 3. bzw. 4. Sekunde versucht GPS-Zeilen auszuwerten. Im SerialMonitor erscheinen zunächst die Daten der ungestellten Uhr, die laut Unix im Jahr 1970 beginnt. Nach einer Weile wird die korrekte Sommerzeit für Mitteleuropa dargestellt. Ein "sync" sagt, wann die GPS-Uhr gestellt wurde. Beispiel:

DONNERSTAG der 01.01.1970 um 00:00:13
DONNERSTAG der 01.01.1970 um 00:00:14
DONNERSTAG der 01.01.1970 um 00:00:15
06 Sat
DONNERSTAG der 01.01.1970 um 00:00:16
sync
DIENSTAG der 14.04.2015 um 20:04:44
sync
DIENSTAG der 14.04.2015 um 20:04:45
05 Sat


Uhrenkabinett Watchfaces
Studio
Sweden
Canvas
TowerArt
Wenn alles funktioniert, kann nun eine Uhr mit Zifferblatt oder Ähnlichem auf einem TFT-Display dargestellt werden. Im Laufe dieses Projekts entstanden vier Watchfaces, die alle in vier beliebigen Orientierungen (Porträt/Landschaft) funktionieren. Sie wurden für ein 1.8" TFT-Display ST7735 kodiert mit einer Auflösung von 128x160 Pixel. Die Pegel an PIN A0 und PIN A1 legen beim Start die Orientierung fest. Quellenangaben zur Analoguhr unter Zeitserver-Referenz.

Die Anschlussbelegung des Displays ist im Projekt Rheinturmuhr und TFT erläutert. Alle dortigen Hinweise gelten auch hier. Die vier Sketche funktionieren nur unverändert unter folgenden Bedingungen (IDE 1.0):

  • SainSmart 1.8-Zoll-TFT-Display - schnelle Ansteuerung
  • Arduino Uno
  • CRIUS NEO-6 GPS-Modul

Studio Sweden Canvas TowerArt

Ticks und Pips Zeitzeichen - Tonsignal
Alle Uhrenvarianten verfügen über einen Sekunden-Tick. Das Tonsignal der Frequenz 1000 Hz während einer Millisekunde ist an PIN 3 (TICKPIN) für einen Piezo-Beeper verfügbar. Zur halben und zur vollen Stunde erfolgt ein Tonsignal, wie man es aus dem Radio kannte oder kennt. In einem 'aufwendigen Prozess' wurden die Pip-Zeiten des Deutschlandfunks ausgemessen und in die Uhren integriert. Einziger Unterschied ist, dass diese Uhren 5x kurz und 1x lang zur vollen Stunde geben, während zurzeit beim DLF nur 3x kurz ertönt. Zu diesem Thema findet man mit den Suchbegriffen "radioforen Uhrzeit Tonsignal" überaus unterhaltsame 'Diskussionen'.

Wissenswertes über Uhren
Vom Werkzeug in der Luftfahrt zum Luxusartikel: Die Fliegeruhr

Die Fliegeruhr (bzw. oft auch "Pilotenuhr") ist heute vor allem eine Beschreibung für luxuriöse Chronometer. Früher grundsätzlich Männern vorbehalten, bietet sie beispielsweise Rolex auch für Damen an. Die Fachseite www.uhrenmeister.com listet einige der Qualitäten auf, für welche die Zeitmesser in der Gegenwart stehen: Funktionalität, Präzision, Zuverlässigkeit und spektakuläre Designs. Diese Stärken erzählen die spannende Geschichte der Fliegeruhren, die schon im Jahr 1906 begann. Fliegeruhren waren ursprünglich Messinstrumente 1906 entwickelte der Uhrenmacher Carl Zeiss die erste richtige Armbanduhr für den Brasilianer Alberto Santos Dumont. Sie funktionierte wesentlich präziser als alle bisherigen mobilen Zeitmesser. Das mechanische Uhrenwerk wurde zur Grundlage für die späteren Pilotenuhren. In der Luft mussten die Flieger ständig Berechnungen durchführen. Ermittelt werden musste beispielsweise der Treibstoffverbrauch oder die Fluggeschwindigkeit. Hierfür wurden zuverlässige Uhren benötigt, die mit den speziellen Anforderungen in der Luft umgehen könnten. Fliegeruhren sind deshalb relativ groß, damit sie gut gelesen werden können. Sie sind außerdem schlagfest und widerstandsfähig. Charakteristisch waren auch sehr große Armbänder, damit die Piloten sind über der Uniform tragen konnten. Längst müssen Piloten diese Berechnungen nicht mehr selbst durchführen, werden sie doch vom Bordcomputer übernommen. Als Werkzeug in der Luftfahrt sind Fliegeruhren deshalb überflüssig geworden. Doch ihre spektakuläre Optik sprach die breite Masse an, weshalb sie sich zur Luxusuhr entwickelt hat. Ganz tot ist die Fliegeruhr in der Luftfahrt nicht Komplett aufgeben möchte die Luftfahrt die Fliegeruhr aber noch nicht. So kam beispielsweise 2012 dazu, dass die FH Aachen gemeinsam mit einem Uhrenhersteller sogar einen eigenen technischen Standard entwickelte. Dieser regelt bestimmte funktionale Anforderungen, die Einfachheit der Benutzung und die Widerstandsfähigkeit. Er ist in der verbindlich für den Einsatz von Fliegeruhren in der Luftfahrt geworden.

Paul Lehrer von www.uhrenmeister.com 2018


HTML und der Canvas
Rheinturmuhr und TFT
Rheinturmuhr und DCF
Netzzeit/Timeserver

Weitere Software
.
Startseite Bücher Software Digital RTV Musik Kontakt

Für Inhalt und weitere Verzweigung externer Links sind die Betreiber der dortigen Seiten verantwortlich - H.-J. Berndt