Stabiel de tijd bijhouden tussen herstarten
Met baby steps, zo komen we er wel. Eerder had ik het erover dat de Arduino geen eigen RTC (Real Time Clock) heeft en daardoor ten eerste een vrij grote afwijking van enkele seconden per dag heeft en ten tweede de tijd-instelling steeds kwijtraakt bij herstarten.
Er zijn twee goed ondersteunde RTCs voor Arduino verkrijgbaar; de DS1307 en de DS3231. Qua prijs ontlopen ze elkaar niet
veel, maar qua precisie is de DS3231 absoluut superieur met een afwijking van maar ±2 minuten per jaar. Aansluiten op de
Arduino, het wordt langzaam een beetje voorspelbaar, is weer een fluitje van een cent. VCC
en GND
naar de plus en
min, SDA
direct op analoge poort A4
en SCL
direct naar analoge poort A5
.
DS3231 met batterijhouder en pins
Vervolgens kan je met de DS3231 library de boel besturen:
#include <DS3231.h>
#include <AceTime.h>
BasicZoneProcessor zoneProcessor;
TimeZone tz = TimeZone::forZoneInfo(&zonedb::kZoneEurope_Amsterdam, &zoneProcessor);
void setup() {
// Initialiseer de verbinding
Wire.begin();
Serial.begin(9600);
}
void loop() {
// Haal de huidige tijd op uit de RTC
DateTime rtcNow = RTClib::now();
ZonedDateTime now = ZonedDateTime::forUnixSeconds64(rtcNow.unixtime(), tz);
now.printTo(Serial);
delay(100);
}
De tijd instellen
De kans dat de RTC de juiste tijd geeft als je hem voor het eerst gebruikt is op zich vrij klein, dus moet je hem eerst instellen. Via de seriële poort van de Arduino kunnen we de module instellen:
void loop() {
// Als er iets op de seriële poort klaar staat...
if (Serial.available()) {
// ... dan lees het als een integer
long readLong = Serial.parseInt();
// ... en lees de rest van de buffer leeg, zoals een <enter> of spaties
while (Serial.available()) {
Serial.read();
}
// stel de RTC in op de integer die van de seriële poort is ingelezen
rtc.setEpoch(readLong);
}
ZonedDateTime now = ZonedDateTime::forUnixSeconds64(RTClib::now().unixtime(), tz);
now.printTo(Serial);
delay(100);
}
Vervolgens kunnen we de tijd instellen door de Unix epoch timestamp over de seriële poort naar de Arduino te sturen. De
huidige Unix epoch krijg je met het commando date +%s
. Je kan de uitvoer daarvan in de Arduino IDE naar de seriële
poort sturen (Tools | Serial monitor), maar het kan ook vanaf de command line met het cu
commando. Eerst moet je weten
welk device je seriële poort heeft; in de Arduino IDE zie je dat onderin het scherm als je Arduino verbonden is. Bij mij
is dat /dev/cu.usbmodem101
, vervolgens start je cu
met het commando:
$ sudo cu -l /dev/cu.usbmodem101
Nu zie je alles wat over de seriële poort binnenkomt, dus in dit geval elke 100 milliseconden de huidige tijd. Het cu
commando kan echter ook berichten terugsturen (zie man cu
), en heeft zelfs nog
functionaliteit om de invoer uit een ander programma te halen door middel van ~$<command>
. We krijgen de huidige epoch
met date +%s
(zie ook man date
).
Als je door de stroom aan timestamps heen het commando <enter>~$date +%s
invoert, zul je zien dat de timestamps opeens de
huidige tijd weergeven. Aangezien je dit maar af en toe hoeft te doen zou je kunnen overwegen dit in een apart programma
te doen, want dat scheelt weer in het geheugengebruik. Je sluit cu
netjes af met het commando <enter>~.
.
Andere tijdsignaal-bronnen
Een RTC is zeker niet de enige bron van tijdsignalen. Als je een WiFi module toevoegt aan de Arduino, kan de tijd opgehaald worden vanaf een NTP-server. Met een GPS-ontvanger kan je de tijd ophalen van satellieten. Een nog andere optie is om een tijdsignaal van de DCF77-zender in Mainflingen bij Frankfurt op te vangen. Ook de originele klok in de Rheinturm doet dit!
Ik wil daar in de toekomst nog wel eens naar kijken, maar op dit moment is de klok volledig zelfstandig operationeel! De volgende stap is eerst iets compleet anders: de lichtstrip moet worden ingebouwd in een meer permanente opstelling.
Webmentions
Heb je een reactie op dit artikel geschreven? Stuur me een webmention! Het kan een paar dagen duren voordat je reactie hier verschijnt.