Digital wall clock (v4, March 2021)
Sorry, translation to English still to be done!
Inhoud
Wandklok project
De wandklok is ca 40cm breed, 25cm hoog en 6cm diep. De cijfers zijn 10cm hoog, dus heel duidelijk leesbaar. Behuizing is van hout en afwerking is met grijze metaallak (hammerite). Het glas is 5mm dik rood getint plexiglas. Het energie verbruik is ca 0,008 KVA. Met een KWH prijs van €0,25 komt dit neer op verbruikskosten van ca €15/jaar. De helderheid van het display wordt automatisch geschakeld tussen dag en nacht mode. Dit omschakelpunt is afhankelijk van de maand. Bv in Maart wordt om 20:00 geschakeld naar nachtmode en om 08:00 terug naar dagmode. In de basis loopt de klok op een interne timer. De interne timer loopt op 10 sec per dag nauwkeurig, dus op zich al aardig maar zal na verloop van tijd een merkbare afwijking vertonen. De klok wordt daarom elk uur met de 'time server' gesynchroniseerd. Als de time server niet bereikbaar is loopt de klok door op een interne timer en probeert na een uur weer verbinding te maken met de time server. De klok kan eventueel ook volledig off-line werken. Als er dus helemaal geen verbinding mogelijk is met een lokaal netwerk dan kunnen de uren en minuten door middel van 2 drukknoppen worden ingesteld waarna de klok alleen op de interne timer loopt. De software voorziet in een fijnafstelling voor de interne timer. De cijfers voor de minuten zijn omgekeerd gemonteerd. Hierdoor kan de decimale punt gebruikt worden als ':' scheidingsteken tussen de uren en minuten.
De hardware
De belangrijkste onderdelen in dit project zijn:
De controller is dezelfde als bij mijn eerste project. Hier was ik dus al een beetje mee vertrouwd.
Het 7 segment display is 4" (100mm) hoog. Elk segment bestaat daardoor uit meerdere (rode) leds. Ik vermoed dat er wel 6 per segment in serie zijn geschakeld. Hierdoor is de spanningsval over een segment ca 10v. Er is dus een hogere voedingsspanning nodig dan de 5v waar de ESP8266 en de MAX7221 op werken. Omdat een omvorming nodig is tussen de 5v signalen van de MAX7221 en de displays heb ik gekozen voor een common anode variant. Dit omdat de omvormer de signalen inverteert.
De led configuratie lijkt me niet helemaal juist. Naar mijn idee zijn er dus meerdere leds in serie, ca 6. De decimale punt heeft een spanningsval van bijna 4v dus min 2 leds.
Het MAX7221 IC is speciaal bedoeld voor aansturen van max 8 7segment displays incl de punt óf één 8x8 ledmatrix. Dit IC communiceert dmv een zogenaamde SPI interface met de ESP8266 controller. De SPI interface bestaat uit een nul (GND), klok (CLK) en datalijn (MOSI = Master Out Slave In). Gelukkig zijn hiervoor bibliotheken beschikbaar die het moeilijkste werk doen. Omdat in theorie meerdere gebruikers van dezelfde SPI bus gebruik kunnen maken is er een een zogenaamde 'chip select' nodig. Dit is een signaal waarmee de master (ESP8266) kan aangeven welke slave aangesproken wordt over de SPI bus. Elke slave heeft dus een eigen chip select, meestal afgekort met CS. De MAX7221 kan rechtstreeks een zg gemeenschappelijke kathode display aansturen. Bij een gemeenschappelijke kathode display zijn alle kathodes van de verschillende segmenten dus met elkaar verbonden. Zoals gezegd maak ik gebruik van een gemeenschappelijke anode display.
De aansluitingen 1 (DIN), 12 (CS) en 13 (CLK) zijn voor de SPI interface met de controller. De DIGx aansluitingen zijn voor elk 7 segments display. Hiervan gebruik ik dus alleen DIG0 t/m DIG3. Waarbij DIG0 de kleinste minuten cijfer is. De SEG x en DP aansluitingen zijn voor de 7+1 segmenten van elk display. De ISET is bedoeld om de stroom door de SEG x en DP uitgangen te reguleren. Hierdoor is een voorschakelweerstand niet nodig bij aansturen van een gemiddeld display. Dit is ook te zien in het getoonde voorbeeld.
DOUT kan gebruikt worden om meerdere MAX7221 IC's in series te zetten voor grotere aantallen display. Aangezien de MAX7221 er al max 8 kan aansturen is dit vooral nodig bij LED dot matrix display waarbij elke MAX7221 slechts 1 matrix aanstuurt voor 1 symbool. Voor dit project is de DOUT niet nodig.
Alle segmenten x van de displays worden met elkaar en met één SEG x uitgang verbonden. Om toch meerdere displays aan te sturen gebruikt de MAX7221 de DIGx uitgangen. Deze worden om beurt geactiveerd en daarbij de juiste segmenten gezet voor het desbetreffende display. Het schakelen tussen de displays gaat zo snel (ca 800x per seconde) dat het menselijk oog alle 4 displays gelijktijdig ziet oplichten.
Via de SPI interface worden steeds 2 bytes gestuurd door de controller. Eén byte bevat een opdracht en de andere de data voor de MAX7221. De volgende opdrachten zijn beschikbaar:
- No-Op
Initieel moet de MAX7221 in de operational mode gezet worden met deze opdracht. - Digit x
Om een cijfer op het display weer te geven. - Decode Mode
Hiermee zet je de MAX7221 in voor gebruik als 7 segments display (=BCD mode) of 8x8 matrix. - Intensity
De lichtintensiteit kan hiermee worden ingesteld. De waarde van de data bepaald dan hoe groot deel van de cyclus de segment uitgang aan blijft staat. Dit kan worden ingesteld tussen een minimale waarde van 1/16 en maximaal 15/16. Ik gebruik dit voor dag- en nacht-mode. - Scan Limit
Hiermee stel je in hoeveel displays er zijn aangesloten. In mijn geval dus 4. - Shutdown
Hiermee zet je de MAX7221 in een low power mode. Dit wordt niet gebruikt in mijn project. - Display test
Alle segmenten lichten hiermee op. Dit wordt gebruikt in mijn project bij opstarten van het programma om te laten zien dat alle segmenten kunnen branden.
Voor de opdracht 'Digit x' is deze data van toepassing:
De data waarde 'blank' gebruik ik om de eerste nul te onderdrukken, dus 9:00 i.p.v. 09:00. De decimale punt wordt aangestuurd door het hoogste bit aan te zetten.
Hoe het allemaal met elkaar verbonden is.
De grootste uitdaging zat eigenlijk in de omvormer. Deze moet de signalen van de MAX7221 omzetten naar signalen geschikt om de display aan te sturen. De uitgangen van de MAX7221 mogen hierbij niet boven de 5v komen. Ook kan een SEG x uitgang wel stroom leveren maar niet opnemen en een DIGx uitgang wel opnemen maar niet leveren.
Voor de voeding heb ik gekozen voor 15v. Hiermee blijft er genoeg maar niet te veel spanning over na aftrek van de LED segment waarde en de spanningsval over de transistoren. Voor de ESP8266 en MAX7221 maak ik een 5v voeding. De ESP8266 werkt intern eigenlijk op 3.3v. De microcontroller print heeft hiervoor een 5v -> 3.3v omzetter aan boord. Deze wordt ook gebruikt als je de ESP8266 aansluit via USB. De ESP8266 uitgangen zijn dus 3.3v waar de MAX7221 ingangen op 5v werken. Strikt genomen zou hier ook een omvormer nodig zijn maar de schakeldrempels van de MAX7221 ingangen zijn blijkbaar voldoende laag dat dit ook met 3.3v aangestuurd kan worden. Ik heb in ieder geval geen problemen hiermee ondervonden.
Let op, voor de duidelijkheid heb ik de omvormers getekend voor 1 segment en 1 display. In werkelijkheid zijn er 4 omvormers voor het display en 8 voor de segmenten.
R5, R7 en de BCY59 zetten het SEG x signaal om voor het display. De BCY59 kan de 15v voeding verdragen. Ik heb een BCY59 genomen omdat ik die toevallig had liggen. Een andere multi purpose NPN transistor zal ook voldoen. R8 en R9 heb ik samengesteld van meerdere weerstanden omdat ik de benodigde waarden niet had. Dit mag natuurlijk gewoon 1 weerstand zijn. Vermogen van 1/4 watt is voldoende.
De omvormer voor de DIGx uitgangen is iets lastiger. Hierbij gebruik gemaakt van een 10v zener diode om de stap van 15v naar 5v te maken. R2 en R3 zorgen er voor dat de spanning op de DIGx uitgang niet boven de 5v komt. Als de DIGx uitgang laag is zal de BC160 gaan geleiden en kan er stroom lopen door de segmenten van het display. Hier de BC160 gebruikt omdat ik die had liggen. Een andere PNP transistor kan ook voldoen. Let er wel op dat deze een redelijke stroom kan verwerken, één segment gebruikt maximaal 300mA. Ook moet deze een versterking (hfe) van min 100 hebben om de spanningsval over de transistor klein te houden.
Voor de voeding en voor de ESP8266+MAX7221 heb ik 2 printplaatjes gebruikt van 5x7cm. Reden is dat ik die had liggen en deze ook in de klok passen.
De C1 uit het schema is een 470uF exemplaar. De C2 heb ik opgebouwd uit meerdere exemplaren (100uF + 0.1uF + 1nF) om hoge frequenties te onderdrukken. Het koelplaatje is wel nodig. De 78xx bereikt een temperatuur van zo'n 20 graden boven de omgeving. Zonder koelplaat loopt dat op tot 50 graden boven omgeving.
Dit is het print plaatje voor de controller en de MAX7221. Deze laatste is niet zichtbaar. Omdat er ruimte was onder de ESP8266 en om de aansluitingen tussen beide kort te houden heb ik de MAX7221 er dus onder gemonteerd.
De omvormers voor de segmenten en display zijn samen met de LED displays op 2 grote print experimenteerplaten aangebracht. De componenten bevinden zich onder de displays aan de andere kant van de print plaat. Dit omdat deze 12x18cm printplaten maar aan 1 kant soldeer aansluitingen had. Beter zou zijn om dubbelzijdige printplaten te gebruiken (wel iets duurder). Als ik dit project nogmaals zou mogen maken dan zou ik kiezen voor 4 dubbelzijdige printplaatjes van 9x15cm. De displays zijn 9x12cm. Hierdoor kan elk display op zijn eigen printplaat en blijft er aan de boven en onderkant ruimte om deze aan elkaar te verbinden met bv een smalle aluminium strip of hoekprofiel. Hiermee kan het geheel ook aan de behuizing worden gemonteerd.
De internet time server
De sketch software gebruikt deze website host als time server. Zie ook mijn eerste project voor een uitleg hierover.
Voor de wandklok heb ik de tijd nodig in uren, minuten en ook seconden. Hoewel de klok geen seconden weergeeft wil ik wel de minuut overgang op het juiste moment doen. Echter de website gaf nog niet de tijd in sekonden. Dus deze heb ik toegevoegd, zie regel 5 en 9 ...
<?php
// timeserver
$currentDate = date("Y-m-d"); // e.g. 2020-05-16
$localTime = date("H:i"); // e.g. 08:34
$localTimeSec = date("H:i:s"); // e.g. 08:34:12
echo <<<_END
yyyy-mm-dd=$currentDate
hh:mm=$localTime
hh:mm:ss=$localTimeSec
_END;
?>
De software
Gebruik gemaakt van de gratie beschikbare Arduino IDE v1.8.13 voor de software.
Zorg er voor dat je het juiste bord/controller selecteerd in Arduino. Voor het weerstation was dit dus de "NodeMCU 1.0 ESP-12E". De maker van de controller die ik heb gekocht was Geekcreit, deze is compatibel met de NodeMCU. Zorg er voor dat je versie 1.0 van de NodeMCU selecteert en niet per ongeluk de 0.9. Deze laatste is een heel andere controller. Zorg ook dat je de beschikbare standaard software voor de ESP8266 download (via de board manager: Tools -> Board: NodeMCU 1.0 (ESP-12E module) -> Board manager). Voor mijn project heb ik versie 2.7.4. van de ESP8266 bibliotheek gebruikt.
Ook voor dit project de sketch weer opgedeeld in kleinere stukken. In het screenshot hieronder kun je zien dat ik uiteindelijk 6 sketches heb die gezamelijk aan elkaar geknoopt het programma vormen:
- ron-clockv4. Dit is de hoofdsketch
- 0_private. Hier staan prive gegevens in die ik niet zichtbaar wil maken in de download, oa WiFi SSID and password. Deze waarden beginnen allemaal met PRIVATE_
- 1_definition. Dit is het deel waar variabelen en generieke constanten worden gedefinieerd.
- 2_setup. Deze code wordt door de controller 1x uitgevoerd bij het opstarten van het programma. Hier wordt bv de WiFi verbinding geinitialiseerd.
- 3_loop. Deze code wordt continue in een loop uitgewerkt door de controller.
- 4_functions. Hier zitten stukjes code die meerdere keren worden gebruikt en stukken code die de 3_loop sketch wat compacter maken.
Sketch: ron-clockv4
Deze sketch is erg klein. Het beschrijft het project en laadt bibliotheken die nodig zijn voor mijn project.
De ESP8266WiFi bibliotheek bevat weer meerdere bibliotheken die nodig zijn om de controller te verbinden met de WiFi en om verbinding te maken met de internet servers.
Verder definieert deze sketch of debug mode aan of uit staat. In debug mode worden bepaalde regels geschreven naar de seriele uitgang die met de Arduino bekeken kunnen worden.
// debugging macros
//#define DEBUG // Remove comment for DEBUG mode!
#ifdef DEBUG
#define DPRINT(...) Serial.print(__VA_ARGS__)
#define DPRINTLN(...) Serial.println(__VA_ARGS__)
#else
#define DPRINT(...) //now defines a blank line i.e. no print output
#define DPRINTLN(...) //now defines a blank line i.e. no print output
#endif
Met deze constructie kun je door het weglaten van de // bij de define DEBUG regel de mode activeren.
Sketch: 0_private
// define private constants
const char* PRIVATE_WIFI_SSID = "";
const char* PRIVATE_WIFI_PASSWORD = "";
const char* PRIVATE_URLT = "your time page";
In deze sketch staan prive gegevens. In de download zit een bestandje met bovenstaande regels and niet die van mijn sketch.
Sketch: 1_definition
Hier worden de constanten, variabelen en ojecten gedefinieerd die verder in het programma gebruikt worden. Ondere andere constanten voor de MAX7221 aansturing:
// MAX7221 address bytes / modes of operation
const byte MAX7221_NOOP = 0x00;
const byte MAX7221_DIGIT0 = 0x01;
const byte MAX7221_DIGIT1 = 0x02;
const byte MAX7221_DIGIT2 = 0x03;
const byte MAX7221_DIGIT3 = 0x04;
const byte MAX7221_DIGIT4 = 0x05;
const byte MAX7221_DIGIT5 = 0x06;
const byte MAX7221_DIGIT6 = 0x07;
const byte MAX7221_DIGIT7 = 0x08;
const byte MAX7221_DECODEMODE = 0x09;
const byte MAX7221_INTENSITY = 0x0a;
const byte MAX7221_SCANLIMIT = 0x0b;
const byte MAX7221_SHUTDOWN = 0x0c;
const byte MAX7221_DISPLAYTEST = 0x0f;
// MAX7221 values for mode MAX7221_DECODEMODE:
const byte MAX7221_NO_DECODE = 0x00;
const byte MAX7221_CODEB_DIG0 = 0x01;
const byte MAX7221_CODEB_DIG03 = 0x0F;
const byte MAX7221_CODEB_DIG07 = 0xFF;
// MAX7221 values for mode MAX7221_INTENSITY:
const byte MAX7221_INTENSITY_MIN = 0x00;
const byte MAX7221_INTENSITY_MAX = 0x0F;
// MAX7221 values for mode MAX7221_SCANLIMIT:
const byte MAX7221_SCAN_DIG0 = 0x00;
const byte MAX7221_SCAN_DIG01 = 0x01;
const byte MAX7221_SCAN_DIG02 = 0x02;
const byte MAX7221_SCAN_DIG03 = 0x03;
const byte MAX7221_SCAN_DIG04 = 0x04;
const byte MAX7221_SCAN_DIG05 = 0x05;
const byte MAX7221_SCAN_DIG06 = 0x06;
const byte MAX7221_SCAN_DIG07 = 0x07;
// MAX7221 values for mode MAX7221_SHUTDOWN:
const byte MAX7221_SHUTDOWN_ON = 0x00;
const byte MAX7221_NORMAL_OPER = 0x01;
// MAX7221 values for mode MAX7221_DISPLAYTEST:
const byte MAX7221_DISPLAY_NORMAL = 0x00;
const byte MAX7221_DISPLAY_ON = 0x01;
// MAX7221 mask value for digits in normal operation:
const byte MAX7221_DP_OFF = 0x00;
const byte MAX7221_DP_ON = 0x80;
Zo wordt ook TCP client aangemaakt voor een server met een beveiligde verbinding (URL die begint met HTTPS:). 443 is de standaard voor HTTPS.
WiFiClientSecure clientS; // to connect to a secure (HTTPS) internet server
const int httpsPort = 443;
// constants for time server
const char* hostT = "rjut.nl";
Sketch: 2_setup
De in- en uitgangen voor de SPI communicatie worden gezet door de SPI bibliotheek. Behalve het CS (of SS Slave Select signaal. Dit moet door de sketch zelf worden gedefinieerd en aangestuurd:
// the spi library sets the MOSI and CLK outputs
// set pin for slave select output (not used by SPI library)
pinMode(SS, OUTPUT);
Hier worden ook de pinnen van de ESP8266 gedefinieerd voor input of output. In dit geval de input voor de drukknoppen:
// input for hour + button
pinMode(ButtonHour, INPUT_PULLUP);
// input for minute + button
pinMode(ButtonMinute, INPUT_PULLUP);
De SPI interface wordt ingesteld. Voor de MAX7221 moet dit MSBFIRST en SPI_MODE0 zijn. En de MAX7221 wordt ge-initialiseerd.:
SPI.begin();
SPI.beginTransaction(SPISettings(1000000, MSBFIRST, SPI_MODE0)); // All LED segments should light up
maxTransfer(MAX7221_DISPLAYTEST, MAX7221_DISPLAY_ON);
delay(1000);
maxTransfer(MAX7221_DISPLAYTEST, MAX7221_DISPLAY_NORMAL);
// Set decode mode B for digits 0-3
maxTransfer(MAX7221_DECODEMODE, MAX7221_CODEB_DIG03);
// Set intensity
maxTransfer(MAX7221_INTENSITY, MAX7221_INTENSITY_MAX);
// Only use digits 0-3
maxTransfer(MAX7221_SCANLIMIT, MAX7221_SCAN_DIG03);
// Turn on chip
maxTransfer(MAX7221_SHUTDOWN, MAX7221_NORMAL_OPER);
// Blank the clock
maxTransfer(MAX7221_DIGIT3,0x0F);
maxTransfer(MAX7221_DIGIT2,0x0F);
maxTransfer(MAX7221_DIGIT1,0x0F);
maxTransfer(MAX7221_DIGIT0,0x0F);
De seriele poort voor debug messages wordt geinitialiseerd en ingesteld op de maximale snelheid (zogenaamde baud rate).
// activate debug monitor
Serial.begin(115200);
Sketch: 3_loop
In deze sketch wordt het repeterende werk gedaan. De sketch kan worden opgesplitst in:
- Verkrijg de datum en tijd van de tijd server
- Set de variabelen die bepalen wanneer klok wordt aangepast en wanneer opnieuw datum en tijd moet worden opgevraagd. Het opvragen van de datum en tijd gebeurd op 30 seconden in een minuut om geen last te hebben van internet vertragingen in het updaten van de klok.
- Controleer of er een minuut gepasseerd is en update de klok
- Controleer of er een uur voorbij is en de datum en tijd opnieuw moet worden opgehaald
- Lees de drukknoppen en verhoog eventueel de uur of minuut waarde (off-line mode)
Sketch: 4_functions
- connectLocalWiFi()
Dit is dezelfde software als gebruikt in mijn eerste project. - getLocalDateTime()
Ook dit is grotendeels gelijk aan mijn eerste project. Alleen dus de seconden toegevoegd. - maxTransfer()
Deze functie stuurt een opdracht met bijbehorende data naar de MAX7221. Deze functie stuurt ook de CS/SS aan. - updateDisplay()
Deze functie geeft de tijd weer op het display. Het onderdrukt een eerste nul. Het geeft door middel van de decimale punten ook een soort van status aan. Als er geen WiFi verbinding is en dus ook geen geldige tijd dan zijn beide decimale punten uit. Als er wel WiFi verbinding is maar de website geen response geeft dan gaat alleen de decimale punt van DIG2 aan. - CalcIntensity()
Deze functie berekent de intensiteits waarde voor het display. Voor de dag- en nacht-mode dus. Het schakelpunt is afhankelijk gemaakt van de huidige maand. De berekening is niet exact correct. Bv zomers wordt pas later op de avond terug geschakeld naar nacht mode.
De behuizing
Zoals gezegd is de behuizing gemaakt van 18mm hout. Voor de exacte maten van elk onderdeel verwijs ik naar de SketchUp file in de download. Hieronder een impressie:
In de volgende afbeelding zijn de onderdelen wat uit elkaar getrokken om deze beter afzonderlijk te zien. Ook dit is opgenomen in dezelfde SketchUp file in de download.
Voor het plexiglas heb ik een 6mm brede en 6mm diepe gleuf gefreesd in het hout.
Download
De Arduino IDE en de bordbibliotheken moet u zelf van internet downloaden.
Download het ZIP bestand met alle bestanden. De download bevat ook het SketchUp 2017 bestand voor de behuizing. Ook in de download de datasheets van de BCY59, BC160 en MAX7221.
Download alleen het Fritzing bestand. De Fritzing-software moet je ook zelf downloaden van de fritzing.org site.
Download alleen het SketchUp bestand voor 3d printing.