Real Time Clock

Als je bijvoorbeeld meetgegevens op een SD kaartje wil opslaan is het handig om de datum erbij te zetten. Een real time clock geeft je de tijd en datum. Er zijn diverse modules op de markt, te koop voor niet meer dan één euro. Kies voor modules met een I²C interface, zodat je maar twee signaaldraden nodig hebt. Je kunt een bibliotheek gebruiken, maar het kán ook zonder.
Zelfs als je een Real Time Clock gebruikt moet je er voor zorgen dat deze gelijk blijft lopen. Als je dat automatisch wil doen dan kun je overwegen de Duitse radiozender DCF77 te gebruiken. Hiervoor is wel een vrij dure ontvangsteenheid nodig.
Een alternatief voor een Real Time Clock is om het internet te gebruiken. Dat kan alleen als je toegang hebt tot internet op het moment dat je de tijd nodig hebt. Je kunt je Arduino hiertoe uitrusten met een internet module, maar veel makkelijker is het om een goedkoop Arduino alternatief zoals de nodeMCU te gebruiken. Zie verderop hoe dit werkt.

DS3231 of DS1307

model B
model A voorkant
model A achterkant
Deze chips worden in heel veel populaire klok-modules gebruikt. Ik heb er drie getest. Twee ervan gebruiken de zeer nauwkeurige DS3231 chip; de derde de DS1307.

De DS1307 chip is minder nauwkeurig. Ik heb hiervan een tiny RTC module getest, deze heeft als extra een temperatuursensor en een beetje geheugen aan board. Het schijnt dat deze vrij veel verloopt, maar een duurproef van langer dan een dag moet ik nog doen.

Ik noem het model dat links is afgebeeld model A en het andere model B (zie foto's). Model B is ook heel geschikt voor de Rasberry Pi. Zoals altijd bij I²C verbind je de SDA-pin met de analoge ingang A4 van de Arduino en de SCL-pin met A5. Bij model B staan nauwelijks labels: alleen een + teken bij de meest linkse pin en een D bij de pin daarnaast. Sluit VCC aan op de linkse pin met het + teken en GND op de meest rechtse pin; de tweede pin met de D is SDA en de derde pin is SCL. De vierde pin is niet aangesloten. Beide modules gebruiken adres 0x68.
Je moet eerst de tijd en datum erin zetten. Hiertoe moet je de sketch tijdelijk aanpassen. Zet in het setup() gedeelte command's om de tijd erin te zetten. Dat kan op vele manieren, het handigst is om de systeemtijd van je computer te gebruiken op het moment vlak voor uploaden via DateTime(__DATE__, __TIME__). Het is ook mogelijk om de tijd op te halen van Internet, of van de Duitse DCF77 zender, maar dat is allemaal meteen veel ingewikkelder. Meteen nadat de tijd er goed in staat, zet je code om in commentaar en laad je de sketch opnieuw in de Arduino. Zo voorkom je dat bij een nieuwe reset of opnieuw opstarten de verkeerde tijd erin wordt gezet. De back-up batterij zorgt ervoor dat de tijd bijgehouden wordt ook als je de module van de Arduino loskoppelt. Als de tijd echt belangrijk is dan is het slim om in de Arduino sketch te controleren of de datum bijvoorbeeld na 2018, maar voor 2099 ligt. Als dat niet zo is dan is de batterij leeg of is de module gereset. In ieder geval moet de tijd dan opnieuw worden ingesteld.
Ik heb module A gelijkgezet op 7 mei 2017 en daarna pas weer uitgelezen op 4 december 2017. Hij liep liep nog steeds binnen een minuut gelijk als je de weergegeven tijd omrekent naar wintertijd. Ook de tweede door mij geteste module voldoet goed.
Uitvoer van de sketch
Hieronder zie je de uitvoer als deze elke seconde een keer wordt uitgelezen. Het schijnt dat de klok wel minder nauwkeurig wordt als je hem vaak uitleest, maar dat heb ik niet kunnen testen.
Zie hieronder een simpel programma om de klok te testen
// Real Time Clock DS3231 of DS1307
#include <Wire.h>
#include <RTClib.h>
const String Maand[] = {"januari", "februari", "maart", "april", "mei", "juni", "juli", "augustus", "september", "oktober", "november", "december"};
const String Dag[] = {"zondag", "maandag", "dinsdag", "woensdag", "donderdag", "vrijdag", "zaterdag"};
RTC_DS3231 rtc; // Maak hier RTC_DS1307 van als je de DS1307 gebruikt

void setup()
{
  Wire.begin(); Serial.begin(9600);
  rtc.begin();
  // maak meteen na uploaden commentaar van de volgende regel en upload de schets daarna opnieuw!
  // rtc.adjust(DateTime(__DATE__, __TIME__));
  Serial.println("Tijd: ");
}

void loop()
{
  DateTime nu = rtc.now();
  String DagNaam = Dag[nu.dayOfTheWeek()]; // zondag = 0
  DagNaam[0] = DagNaam[0] + (byte('A') - byte('a')); // maak van beginletter hoofdletter
  Serial.print(DagNaam + " "); Serial.print(nu.day());
  Serial.print(" " + Maand[nu.month() - 1] + " "); // januari = 1
  Serial.print(nu.year()); Serial.print(" ");
  Serial.print(nu.hour());
  Serial.print(":"); byte minuut = nu.minute(); if (minuut < 10) Serial.print(0); Serial.print(minuut);
  Serial.print(":"); byte sec = nu.second(); if (sec < 10) Serial.print(0); Serial.println(sec);
  delay(1000); // lees de chip elke seconde uit
}
LET OP: deze sketch en ook de volgende, gebruiken geavanceerde String functies. Om een of andere redenen werkt dat niet bij Arduino's met een ATmega 168 chip! Je krijgt de meest vreemde resultaten. Alleen goedkope klonen en oudere types hebben soms nog deze beperkte processor erin zitten. De oplossing is om de datum anders te printen, bijvoorbeeld als 14-11-2019.
De klok geeft de tijd in BCD-code ("binary coded digital"): handig als je een bcd-klok wil maken. Zie hier een pagina over hoe je een simpele BCD klok kunt maken, inclusief sketch.

DS31302

Deze klok werkt met een seriële verbinding. Helaas geven de bibliotheken die je automatisch (via bibliotheek beheren) kunt installeren problemen. De bibliotheek DS1302.h die je op github kunt downloaden werkt wel probleemloos. Je moet in de sketch opgeven welke Arduino-pinnen je gebruikt. Bij veel modules komen de labels niet overeeen met de gebruikte namen in de bibliotheek, bijvoorbeeld RST ( = kCePin ), DAT ( = kIoPin) en CLK ( = kSclkPin ).

Losse chip

De PCF8563 in actie
Uiteraard kun je ook zelf een real time klok maken met het kale IC. Omdat je naast het IC een kristal nodig hebt is en eventueel een batterijhouder ben je meestal duurder uit dan met "breakout" module. Het aansluiten van het kristal is niet moeilijk en het werkt even goed als breakout modules. Ik heb dit getest met de Pcf8563 real time clock. Deze klok heeft een extern kristal van 32,768 kHz nodig. Ik heb diverse bibliotheken getest: de meeste waren erg buggy. Een bibliotheek voor een RTC mag je niet verplichten om de weekdag in te voeren, want dat kan de chip zelf uitrekenen. Als je de weekdag zelf invoert kan er een conflict ontstaan, maar erger het ontneemt je de mogelijkheid om de datum automatisch in te voeren via __DATE__. Uiteindelijk heb ik de bibliotheek PCF8563.h gbruikt. Dit is een bibliotheek, die goed in elkaar zit en goed gedocumenteerd is. Als je de tijd aanroept dan heb je meteen alle gewenste velden in een struct. Helaas wordt de weekdag niet correct bepaald. De chip kent nog meer functies dan het bijhouden van de tijd; deze kunnen ook via deze bibliotheek worden aangeroepen, maar dat valt buiten het kader van mijn RTC pagina.
#include <PCF8563.h>
const String Maand[] = {"januari", "februari", "maart", "april", "mei", "juni", "juli", "augustus", "september", "oktober", "november", "december"};
const String Dag[] = {"zondag", "maandag", "dinsdag", "woensdag", "donderdag", "vrijdag", "zaterdag"};

PCF8563 pcf;

void setup() {
  Serial.begin(9600);
  pcf.init(); // Als je de klok wilt gelijkzetten haal dan de commentaar aanduidingen /* en */ weg
  // en vul je de juiste gegevens in
  pcf.stopClock();
  /*
  pcf.setYear(19);  // dit jaar
  pcf.setMonth(11); // maand
  pcf.setDay(15);   // dag in de maand
  pcf.setHour(13);  // uur
  pcf.setMinut(38); // minuut
  pcf.setSecond(0); // seconde
  */
  pcf.startClock();
}

void loop() {
  Time nu = pcf.getTime();
  // Serial.print(Dag[nu.weekday]); Serial.print(" "); // Weekday wordt niet goed bepaald
  Serial.print(nu.day); Serial.print(" ");
  Serial.print(Maand[nu.month - 1]); Serial.print(" 20");
  Serial.print(nu.year); Serial.print(" ");
  Serial.print(nu.hour); Serial.print(":");
  if (nu.minute < 10) Serial.print(0); Serial.print(nu.minute); Serial.print(":");
  if (nu.second < 10) Serial.print(0); Serial.println(nu.second);
  delay(1000);
}

Echte datum en tijd via Internet

Het is niet moeilijk de datum en tijd via het internet te verkrijgen. Maar omdat het zoveel makkelijker is om dit met een module te doen die WiFi al ondersteunt, beschrijf ik bij uitzondering een programma dat niet werkt met een gewone Arduino Uno of nano. Voor enkele euro's kun je op eBay modules bestellen met de ESP8266 of ESP32 chip. Ik heb diverse uitvoeringen getest en ze werken eigenlijk allemaal probleemloos. Je moet in de bordenmanager de ESP borden installeren, maar dat gaat heel gemakkelijk. Ik vind zelf de WEMOS D2 mini PRO erg fijn: lekker compact, zeer snel en veel flash geheugen (4 MByte standaard, maximaal 16 MByte, voor deze toepassing meer dan genoeg). Ook de iets grotere nodeMCU's (in diverse uitvoeringen) voldoen erg goed. Als je een ESP8266 module hebt die niet in de lijst van borden staat, kies dan de generieke ESP8266 module, dat zal meestal probleemloos werken.
Er is een ding waar je goed op moet letten: elke internet klok geeft de "Universal Time" (UTC) terug. UTC is ongeveer hetzelfde als Greenwich Mean Time. Het is een goede gewoonte om bij data die je opslaat UTC te vermelden en niet de locale tijd. Dat is dan dus geen probleem. Maar als je een digitale klok wil maken, of als je naast de UTC tijd ook de lokale tijd wilt opstaan dan is er wel een probleem! Je moet namelijk weten hoeveel uur je moet optellen bij UTC. En dat is best lastig, want je moet dan uit de datum (in UTC) kunnen afleiden of je zomer- of winterijd hebt EN je moet op de juiste wijze 1 of 2 uur optellen bij UTC. Daarbij moet je rekening houden met het feit dat hierdoor de datum kan verspringen. Allemaal te lastig om zelf uit te zoeken en te testen. Gelukkig is er een bibliotheek die je kunt gebruiken. Dat wil zeggen zolang we in Europa hetzelfde systeem houden... Ik laat hieronder het programma zien, dat door mij is aangepast aan de West-Europese situatie. Als het systeem van de zomer- en wintertijd veranderd wordt, dan zul je dit programma moeten aanpassen. Programmalisting