Vor einigen Tagen habe ich auf der Instructables.com Seite von Marcelo Moraes alias BIGDOG1971 einen interessanten Sketch zur Ansteuerung mehrerer Dot Matrix LED Module via MAX7219 gefunden. Leider habe ich derzeit nur eines dieser MAX7219 Module verfügbar, weitere sind jedoch bereits bestellt.
Die Wortuhr Update 05.Okt.2013 Download
Viele kennen vermutlich bereits die verschiedensten Spielarten einer Wortuhr inspiriert durch die Qlocktwo. Per vorgegebenem Text wird hierbei die Uhrzeit im 5-Minutenbereich visuell über Textbausteine dargestellt. Das grundsätzliche Konzept habe ich nun auch für meine etwas ungewöhnliche Dot Matrix LED Uhr übernommen und lasse dabei die Uhrzeit in umgangssprachlicher Form als Text von rechts nach links auf dem LED Display durchlaufen.
Poor Men’s Word Clock
Um im ersten Schritt Aufbau und Sketch so einfach wie möglich zu gestalten, habe ich auf DCF77 synchrone Zeitsignale oder einer Echtzeituhr verzichtet und erzeugte anfangs einen Sekundentakt per delay() Funktion. Daraus lassen sich simpel Minuten- und Stundensignale ableiten. Die Genauigkeit ist dabei allerdings entsprechend unpräzise. Ich habe daher irgendwann angefangen nach anderen einfachen Lösungen zu suchen und bin dabei auf die Library TimerOne.h gestoßen, mit der sich recht komfortabel der interne Timer 1 des Atmega 328 meines Arduino Unos beeinflussen lässt. Da hier im Vergleich zu den üblichen Wortuhren alles absolut minimalistisch gestaltet ist, habe ich diese Uhr „Poor Men’s Word Clock“ getauft. Ich hoffe nur sehr, es fühlt sich jetzt niemand irgendwie diskriminiert . Ich möchte damit schließlich nur ausdrücken, dass sich mit minimalem Aufwand und der einen oder anderen Idee, relativ einfach tolle Projekte entwickeln lassen.
Die Hardware zur Anzeige von Texten
Solche oder ähnliche Modulbausätze können in verschiedenen Shops auch über Internet bestellt werden. Da hier bedrahtete und keine SMD Bauteile verwendet werden, gestaltet sich der Zusammenbau relativ einfach. Die Pins CLK, DIN und CS werden mit den entsprechenden Arduino Pins verbunden. Das von mir hier präferierte Modul läuft mit 5V Betriebsspanunng und ist kaskadierbar, es können also mehrere Module hintereinander geschaltet werden. Mehr zu diesem Dot Matrix LED Modul ist auch beim Arduino Stammtisch der Region Hannover zu finden.
5V = VCC
GND = GND
Arduino Digital Pin 10 = CLK
Arduino Digital Pin 8 = DIN
Arduino Digital Pin 9 = CS
Bei einer Kaskadierung werden die Pins der MAX7219 Module einfach durchverdrahtet, wobei DOUT des ersten Modules mit DIN des nächsten Moduls verbunden wird.
Die Einstellungen im Sketch
Wer den Sketch bereits heruntergeladen hat und testen möchte, hier vorab einige ggf. anzupassende Variablen.
- byte shiftSpeed = 60;
Über die Variable shiftSpeed wird die Durchlaufgeschwindigkeit bestimmt. Die sinnvollen Werte liegen etwa zwischen 50 und maximal 255.
- /*** Declare and initialize time variables here ***/
- byte seconds = 0; // Start value seconds
- byte minutes = 28; // Start value minutes
- byte hours = 6; // Start value hours
Hier muss jetzt die gerade aktuelle Uhrzeit im Zwölfstundenformat eingegeben werden bevor die Arduino IDE den Sketch kompiliert und in den ATmega programmiert.
Im Setup ganz unten gibt es noch m.setIntensity(0) zu finden, um die Helligkeit des Displays einzustellen. Erlaubt sind hier Werte von 0 bis 15, von dunkel bis hell.
- /*** Initialize MAX7219 matrix ***/
- m.init(); // Initialize module
- m.setIntensity(0); // Dot matrix intensity 0-15
Bei dem von mir eingesetzten Modul ist der unterste Helligkeitswert 0 völlig ausreichend gewesen.
Download des Sketches
Nun zum Download des Sketches. Nach Clicken des Download Links in dem sich separat öffnenden Github Browserfenster auf Raw clicken. Danach öffnet sich ein weiteres Downloadfenster. Mit der Auswahl von „Datei speichern“ kann die komprimierte Datei dann auf die eigene Festplatte heruntergeladen werden. Danach muss die Datei nur noch entpackt und der Ordner in das Projektverzeichnis kopiert werden. Sofern die Library TimerOne.h noch nicht installiert ist, diese bitte erst herunterladen und anschließend ins library Verzeichnis kopieren. Sollte die Arduino IDE noch geöffnet sein, diese schließen und neu starten. Anschließend kann in der IDE unter Datei|Sketchbook|MAX7219_DOT_MATRIX_CLOCK_II der Sketch geöffnet werden.
Es sind dort 3 Register zu finden. Fangen wir mit dem linken Register MAX7219_DOT_MATRIX_CLOCK_II an. Nach dem Einbinden der Libraries
- #include <MaxMatrix.h>
- #include <TimerOne.h>
und der nachfolgenden initialisierung der benötigten Variablen und Konstanten erfolgt die Definition der verschiedenen Character über ein Array. Das Array wird nicht wie sonst üblich im flüchtigen RAM sondern über PROGMEM prog_uchar im Flash des Programmspeichers abgelegt.
- /*** Table according ASCII chart 32..127 stored to Flash Memory ***/
- /*** Initialize Sprite starting with number of rows from total. ***/
- PROGMEM prog_uchar CH[] = {
- 3, 8, B00000000, B00000000, B00000000, B00000000, B00000000, // space
- 1, 8, B01011111, B00000000, B00000000, B00000000, B00000000, // !
- …usw.};
in dem nun folgenden Array werden anschließend die benötigten Worte abgelegt, um die Uhrzeit später umgangssprachlich darstellen zu können. Auf Umlaute habe ich vorerst noch verzichtet.
- /*** Create an array for the time depending words ***/
- char* stringTimeText[26]={
- “ „, „ein „, „zwei „, „drei „, „vier „, „fuenf „, „sechs „,
- „sieben „, „acht „, „neun „, „zehn „, „elf „, „zwoelf „, „zwanzig „, „vierzig „, „fuenfzig „,
- „Es ist „, „genau „, „gleich „, „kurz „, „vor „, „nach „, „viertel vor „, „viertel nach „, „halb „,
- „Uhr „
- };
Im Setup wird der serielle Monitor über eine if-Abfrage gestartet um optional Daten ausgeben zu können, sofern die Variable debug wahr ist. Im späteren fertigen Sketch kann die Zeile
- int debug = 1; // Debug counter; if set to 1, will write values via serial
auf
- int debug = 0;
gesetzt werden und alle serial.print Befehle auskommentiert werden. Anschließend wird die interne Kontroll-LED an Pin13 initialisiert .
- /*** Initialize LED to blink each second controlled via ISR and timer1 ***/
- pinMode(timerTickLED, OUTPUT);
- digitalWrite(timerTickLED, LOW);
Die ISR Routine wird mit dem Wert von 500.000 us entsprechend 0,5 Sekunden initialisiert. Jede Sekunde wird ein Interrupt erzeugt und die ISR timerTickIsr aufgerufen.
- /*** Intialize ISR ***/
- Timer1.initialize(500000); // Set a timer of length 500.000 microseconds / 0,5s
- Timer1.attachInterrupt( timerTickIsr ); // attach the service routine here
Ganz unten in diesem Register ist die ISR timerTickIsr zu finden. Hier wird nur die LED 13 im Sekundentakt getoggelt und eine Variable seconds hochgezählt. Über eine weitere if-Abfrage wird geprüft ob die Variable den Wert 60 erreicht hat. Falls ja, wird die Variable seconds wieder auf 0 gesetzt und ausserdem die Funktion clockGen() im Register Clockgen aufgerufen. Hier folgen 2 weitere if-Abfragen für die Minuten und Stunden der Wortuhr nachdem die Variable minutes um eins hochgezählt ist. Über serial.print wird die Uhrzeit für Debugzwecke im Klartext auf den seriellen Monitor ausgegeben. Die letzten beiden Zeilen im Setup dienen dazu die MAX7219 Matrix Module zu initialisieren.
- /*** Initialize MAX7219 matrix ***/
- m.init(); // Initialize module
- m.setIntensity(0); // Dot matrix intensity 0-15
Die Loop Schleife fällt recht kurz aus. Über die if(debug) Abfrage kann hier optional jeder xste Wert beliebiger Variablen auf dem seriellen Monitor ausgegeben werden. Der Wert in der if (debug > 100) Abfrage kann dazu auf jeden Wert einer Integer-Variable angepasst werden. In diesem Beispiel wird nur jeder 100ste Wert angezeigt. Am Ende der Loop wird die Funktion
- timeRange(minutes, hours); // Builds sentences based on hour and minute
im Register Time_Estimation aufgerufen. In dieser Funktion wird nur die übergebene Zeit über diverse if-Strukturen den Wort-Variablen aus dem Array char* stringTimeText[26] zugeordnet. Viele Dinge lassen sich hier sicherlich auch noch weiter verbessern und vereinfachen. Beispielsweise müssen die ausgegebenen Sätze nicht unbedingt aus einzelnen Worten zusammengesetzt werden, sondern es können auch zum Teil vorgefertigte Satzstrukturen in einem Array abgelegt werden. Über einen längeren Zeitraum betrachtet dürfte die Genauigkeit der Uhr nicht immer den Ansprüchen gerecht werden. Über eine Anpassung der Zeitdauer in der ISR
- Timer1.initialize(500000); // Set a timer of length 500.000 microseconds / 0,5s
könnte die Abweichung entsprechend angepasst werden. Der Funktionsumfang dieser Wortuhr kann gern noch deutlich erweitert werden. Tasten zum Einstellen der Uhrzeit, eine Echtzeituhr oder auch ein DCF77 Empfänger kann leicht noch integriert werden oder auch eine Alarmfunktion, Stundengong und vieles mehr. Das überlasse ich jedoch jedem selbst dieses zu umzusetzen. Ein Minivideo gibt es hier noch zu betrachten.
Heute habe ich ein weiteres Dot Matrix Modul zusammengelötet. Anschließend mal eben schnell auf dem Steckbrett mit dem ersten Modul verkabelt und….. Es funktioniert nicht! Zwar flackert das 2. Modul ab und zu oder leuchtet komplett in voller Helligkeit, etwas sinnvolles war dem Modul allerdings nicht abzuringen. Nach einigen Messungen, ist mir aufgefallen, dass die Bautiefe des neuen Modules etwas geringer ist als die vom ersten. Daraufhin schaute ich noch genauer auf Details, bis ich dann feststellte, dass bei diesem Modul die beiden Anschlüsse CS und CLK vertauscht sind. Nach vertauschen dieser beiden Leitungen funktionieren nun beide Anzeigen.
Ich habe das Projekt mit RTC erweitert. Jedoch gelingt es mir nicht Umlaute einzufügen. Kannst du mir helfen?
Hallo Helmut, das hört sich gut. Leider komme ich im Moment wegen andere Projekte hier nicht weiter. Ich wollte das Ganze hier beispielsweise noch um einen DCF77-Empfänger erweitern, es gibt allerdings noch einige andere Hürden dazu. Sobald ich hier wieder herangehe, schaue ich auch welche Möglichkeiten es gibt Umlaute einzusetzen. Spontan würde ich vorschlagen, einfach einige der nicht benötigten Sonderzeichen umzudefinieren.
Update folgt.
Gruß Olaf
Hey, hab grad das gleiche Prob. hast du da was rausgefunden??
Hallo Sammystorch, konnte mich bis jetzt leider nicht weiter mit beschäftigen 😦
Vieleicht hat aber sonst jemand eine noch eine Idee???
Gruß Olaf