BCD klok
Een BCD klok is een klok waarbij elk decimaal cijfer is vervangen door de bijbehorende binaire code. Dat is wat anders dan een binaire klok waarbij alle getallen binair worden weergegeven. Hoe je een binaire klok maakt vind je verderop! De BCD klok wordt meestal zo uitgevoerd dat er geen enkele aanwijzing is hoe deze werkt. De kijker moet dat dan zelf ontdekken. Mensen die "iets" hebben met informatica hebben daar geen moeite mee. Niets let je om wèl bij de klok te zetten hoe deze werkt of om ook de "gewone digitale" tijd weer te geven. Dat deze klokken ook heel mooi kunnen zijn zie je in mijn Javascript simulatie. Veel brugklassers op mijn school ontdekten al snel hoe de klok werkt.
Als je niet zelf wilt uitvinden hoe de klok werkt kun je op het plaatje hiernaast klikken. 
Lees als binaire getallen.
De klok loopt van 15:59:11 tot 15:59:22 u.
Je kunt een simpele BCD klok maken met met maar een paar onderdelen. Vanaf 1 een euro koop je al een RTC (real time klok) I²C module, met plaats voor een knoopcel batterij. Met zo'n batterij kan de klok tot meer dan een jaar zijn tijd bijhouden, zelfs als deze uitstaat. Zonder de batterij werkt de module ook, maar als de Arduino uitgaat dan moet je de tijd en datum opnieuw instellen. Ik heb de module getest met de DS3231 chip en met de minder nauwkeurige DS1307. Voor de software en voor de aansluitingen maakt het niet uit welke je gebruikt. Daarnaast heb je een 8x8 display nodig, gebaseerd op de MAX7219.
Het gebruikte display
De code hieronder werkt met het display dat je in het plaatje ziet en ook met vele andere uitvoeringen. Bedenk wel dat elke fabrikant zelf bepaalt hoe hij de pinnen nummert en daarom kan het zijn dat de getallen gedraaid of gespiegeld zijn. Verderop geef ik tips hoe je in zo'n geval te werk kunt gaan. Sluit van de real time clock en van het display VCC en GND aan op de corresponderende pinnen van de Arduino. Verbind van de real time clock CLK met A4 en DTA met A5 van de Arduino (bij sommige Arduino's moet je andere pinnen gebruiken). Andere pinnen sluit je niet aan. Van het display sluit je pinnen als volgt aan: CS naar pin 10, CLK naar pin 11 en DataIn naar pin 12. Andere pinnen sluit je niet aan. Zet de eerste keer de goede tijd in de klok, in de programmalisting zie je hoe. De rij ledjes die het snelst verandereen moeten aan je rechterhand zijn en alleen de onderste vier rijen ledjes moeten worden gebruikt. Draai het display eventueel zo dat dit klopt. Je kunt ook de instructie lc.setRow 6 keer vervangen door ls.setCol. Als de kolommen gespiegeld zijn dan moet je de kolomnummers in lc.setRow aanpassen (dat is het tweede getal in lc.setRow). Volgens mij moet op deze manier zo ongeveer elk type 8x8 display goed komen.

Masker

Masker
Nu is de klok weliswaar klaar, maar hij is moeilijk af te lezen. Daarom moet je een kartonnetje maken om de niet gebruikte ledjes af te dekken. Dit gaat bijzonder makkelijk door een masker te printen op glanzend fotopapier. Je maakt alles zwart, behalve op plaatsen waar de ledjes doorheen moeten schijnen. Het zal je verbazen hoeveel licht er door het fotopapier heen komt! Als je toch print, dan kun je net zo goed een patroon drukken, bijvoorbeeld een bloemetje. Zo krijg je een erg leuke en goed werkende klok. Ik heb dit gefilmd, maar ik laat dit (nog) niet zien want in werkelijkheid is het veel mooier. Op de foto hieronder kun je wel zien hoe het er ongeveer uitziet 's middags om 2:44:24 uur; deze klok gebruikt het 12-uurssysteem. Als je een BCD klok wilt maken kun je een van de maskers hiernaast gebruiken. Stel de afmetingen van de afdruk in op 33 bij 33 mm en knip het uit met wat ruimte boven en onder. Als je dit zo afdrukt dan moet hij al vrijwel precies passen, maar door verschillen in printers (en displays) moet je misschien enkele procenten aanpassen. Vouw het masker om het display heen.

Hier zie je dat alles mooi op een breadboard past
links: display met masker; rechts de RTC
Klik hier om de sketch te zien
// Simpele BCD klok. Kijk verderop bij setup() hoe je de tijd moet instellen
#include "Wire.h"
#include "LedControl.h"
#define klokAdres 0x68 // I2C adres van de DS3231 klokchip
#define DataIn 12 // Data In (DIN) van het display gaat naar pin 10
#define CLK 11 // De klok (CLK) van het display gaat naar pin 11
#define CS 10 // Chip Select van het display gaat naar pin 10
LedControl lc = LedControl(DataIn, CLK, CS);
byte decToBcd(byte dec) { // Zet om van decimaal naar "binary coded decimal"
return ( dec / 10 * 16 + dec % 10 );
}
void zetTijd(byte seconde, byte minuut, byte uur) { // Stel de tijd in
Wire.beginTransmission(klokAdres);
Wire.write(0); // Start vanaf het secondenregister
Wire.write(decToBcd(seconde));
Wire.write(decToBcd(minuut));
Wire.write(decToBcd(uur));
Wire.write(decToBcd(1)); // deze en de volgende gegevens
Wire.write(decToBcd(1)); // kunnen we op een willekeurige
Wire.write(decToBcd(1)); // (geldige) waarde instellen
Wire.write(decToBcd(17)); // jaartal
Wire.endTransmission(); // klaar met verzenden
}
void UploadTijd()
{
byte u = String(__TIME__).substring(0, 2).toInt(),
m = String(__TIME__).substring(3, 5).toInt(),
s = String(__TIME__).substring(7, 9).toInt();
zetTijd(s, m, u);
}
void setup()
{
Wire.begin();
/* haal // in EEN van de twee volgende regel weg als je de tijd wil instellen (o.a. bij de eerste keer) */
// zetTijd(30, 45, 13); /* Kies je eigen tijd: sec, minuut, uur. Zet // meteen terug en upload opnieuw */
// UploadTijd(); /* Gebruik de tijd van het uploaden. Zet // meteen weer terug en upload opnieuw !! */
lc.shutdown(0, false); lc.setIntensity(0, 7); lc.clearDisplay(0);
}
void leesTijd(byte *second, byte *minute, byte *hour)
{
Wire.beginTransmission(klokAdres);
Wire.write(0); // zet de DS3231 register pointer op 0
Wire.endTransmission();
Wire.requestFrom(klokAdres, 3); // vraag 3 bytes data van de DS3231 vanaf register 0
*second = Wire.read() & 0x7f;
*minute = Wire.read();
*hour = Wire.read() & 0x3f;
}
void toonTijd()
{
byte seconde, minuut, uur;
leesTijd(&seconde, &minuut, &uur); // haal de klokstand op
lc.setRow(0, 0, seconde & 0xF); lc.setRow(0, 1, seconde >> 4);
lc.setRow(0, 3, minuut & 0xF); lc.setRow(0, 4, minuut >> 4);
lc.setRow(0, 6, uur & 0xF); lc.setRow(0, 7, uur >> 4);
}
void loop()
{
toonTijd();
delay(1000); // lees de chip elke seconde uit
}

Masker voor de 12-uurs uitvoering
12-uurs systeem
De klok hierboven gebruikt het 24-uurssysteem Als je liever het 12-uurssysteem gebruikt dan heb je voor de eerste kolom maar één ledje nodig. Als je wilt aangeven of het voor- of na de middag is dan kun je hiervoor twee extra ledjes gebruiken. Ik geef alleen een voorbeeld zonder verdere uitleg.
Klik hier om de sketch te zien
// Simpele 12-uurs BCD klok met AM/PM aanduiding. Kijk bij setup() hoe je de tijd moet instellen
#include "Wire.h"
#include "LedControl.h"
#define klokAdres 0x68 // I2C adres van de DS3231 klokchip
#define DataIn 12 // Data In (DIN) van het display gaat naar pin 10
#define CLK 11 // De klok (CLK) van het display gaat naar pin 11
#define CS 10 // Chip Select van het display gaat naar pin 10
LedControl lc = LedControl(DataIn, CLK, CS);
byte decToBcd(byte dec) { // Zet om van decimaal naar "binary coded decimal"
return ( dec / 10 * 16 + dec % 10 );
}
byte bcdToDec(byte bcd)
{
return ( bcd / 16 * 10 + bcd % 16 );
}
void zetTijd(byte seconde, byte minuut, byte uur) { // Stel de tijd in
Wire.beginTransmission(klokAdres);
Wire.write(0); // Start vanaf het secondenregister
Wire.write(decToBcd(seconde));
Wire.write(decToBcd(minuut));
Wire.write(decToBcd(uur));
Wire.write(decToBcd(1)); // deze en de volgende gegevens
Wire.write(decToBcd(1)); // kunnen we op een willekeurige
Wire.write(decToBcd(1)); // (geldige) waarde instellen
Wire.write(decToBcd(17)); // jaartal
Wire.endTransmission(); // klaar met verzenden
}
void UploadTijd()
{
byte u = String(__TIME__).substring(0, 2).toInt(),
m = String(__TIME__).substring(3, 5).toInt(),
s = String(__TIME__).substring(7, 9).toInt();
zetTijd(s, m, u);
}
void setup()
{
Wire.begin();
/* haal // in EEN van de twee volgende regel weg als je de tijd wil instellen (o.a. bij de eerste keer) */
// zetTijd(30, 45, 13); /* Kies je eigen tijd: sec, minuut, uur. Zet // meteen terug en upload opnieuw */
// UploadTijd(); /* Gebruik de tijd van het uploaden. Zet // meteen weer terug en upload opnieuw !! */
lc.shutdown(0, false); lc.setIntensity(0, 7); lc.clearDisplay(0);
}
void leesTijd(byte *second, byte *minute, byte *hour)
{
Wire.beginTransmission(klokAdres);
Wire.write(0); // zet de DS3231 register pointer op 0
Wire.endTransmission();
Wire.requestFrom(klokAdres, 3); // vraag 3 bytes data van de DS3231 vanaf register 0
*second = Wire.read() & 0x7f;
*minute = Wire.read();
*hour = Wire.read() & 0x3f;
}
void toonTijd()
{ // Ik maak geen gebruik van de 12-uurs stand van het RTC IC
byte seconde, minuut, uur, decUur; boolean PM;
leesTijd(&seconde, &minuut, &uur); // haal de klokstand op
decUur = bcdToDec(uur);
PM = decUur >= 12;
if (decUur > 12) decUur -= 12; // 12.15 is 's middags (dus NIET 0.15)
uur = decToBcd(decUur);
lc.setRow(0, 0, seconde & 0xF); lc.setRow(0, 1, seconde >> 4);
lc.setRow(0, 3, minuut & 0xF); lc.setRow(0, 4, minuut >> 4);
lc.setRow(0, 6, uur & 0xF);
if (PM) lc.setRow(0, 7, (uur >> 4) + 64); else lc.setRow(0, 7, (uur >> 4) + 128);
}
void loop()
{
toonTijd();
delay(1000); // lees de chip elke seconde uit
}
Een binaire klok
Een binaire klok is veel moeilijker uit te lezen dan een BCD klok, maar misschien vind je dat juist leuk. Op het 8 bij 8 display is het mogelijk de binaire tijd en datum weer te geven. Ik geef hier een voorbeeld van. Er is zelfs nog plaats over om de dag van de week weer te geven, allemaal op dat ene display! Ik heb in dit geval de bibliotheek RTClib gebruikt. De code wordt hierdoor veel eenvoudiger en korter. In het voorbeeldprogramma laat ik de dag van de week niet zien. Zou je dat wel doen, dan heb je daar maar 3 ledjes voor nodig (001 = zondag of maandag, 111 = zaterdag of zondag al naar gelang welke definitie je gebruikt). Handiger is het om 7 ledjes te gebruiken, voor elke dag een. Je kunt op het masker de (tranparante) letters Zo, M, D, W, D, V, Za printen.
Klik hier om de sketch te zien
// Simpele Binaire klok. Stelt de tijd in op het moment van uploaden
#include <Wire.h>
#include <RTClib.h>
#include "LedControl.h"
#define DataIn 12 // Data In (DIN) van het display gaat naar pin 10
#define CLK 11 // De klok (CLK) van het display gaat naar pin 11
#define CS 10 // Chip Select van het display gaat naar pin 10
LedControl lc = LedControl(DataIn, CLK, CS);
RTC_DS1307 rtc;
void setup()
{
Wire.begin(); Serial.begin(9600);
rtc.begin();
// maak meteen na uploaden commentaar van de volgende regel en upload dan de schets opnieuw!
rtc.adjust(DateTime(__DATE__, __TIME__));
lc.shutdown(0, false); lc.setIntensity(0, 7); lc.clearDisplay(0);
}
void loop()
{
DateTime nu = rtc.now();
lc.setColumn(0, 7, nu.hour());
lc.setColumn(0, 6, nu.minute());
lc.setColumn(0, 5, nu.second());
// lc.setColumn(0, 3, nu.dayOfWeek() + 1); // Zo kun je de dag van de week binair weergeven
// lc.setColumn(0, 3, 1 << nu.dayOfWeek()); rechter led: zondag; links daarvan maandag enz.
lc.setColumn(0, 2, nu.day());
lc.setColumn(0, 1, nu.month());
lc.setColumn(0, 0, nu.year() - 2000);
delay(1000); // lees de chip elke seconde uit
}
BCD klok en kalender
Het maken van een BCD kalender gaat op dezelfde manier als de BCD klok, met een ledje minder. Omdat de klok maar een keer per dag verandert is dat een minder interessant project. Maar het is natuurlijk ook heel goed mogelijk om zowel de datum als de tijd weer te geven. Ook hiervan alleen de code.
Klik hier om de sketch te zien Moet ik nog maken
Komt nog
Mooie uitvoeringen
Je kunt ook mooie uitvoeringen maken die je aan de muur kunt hangen of op je bureau kunt zetten.
Maar dat is ingewikkelder en ik heb het nog (lang) niet af. Komt later.