Wir haben bei uns im Büro einen Spruch, der immer zur Anwendung kommt, nachdem man ca. eine halbe Stunde betriebsblind auf eine Konfiguration oder eine Stelle im Quelltext eines Programms gestarrt hat und sich fragt, warum in aller Welt das Ganze nicht funktioniert. Meist kommt dann ein Kollege vorbei, schaut für zwei Sekunden auf den Bildschirm und meint sowas wie: „Du, das kann doch nicht klappen, guck mal da.“
In solchen Situationen fällt dann der Spruch: „Kaum macht man’s richtig, schon funktioniert’s.“ Wir wollten das schon lange als Schild, als Brandmalerei auf Holz oder als Buzzer haben, um das bei Bedarf hochhalten oder auslösen zu können, aber es kam nie dazu – bis jetzt. Bei Ebay entdeckten wir eine LED-Laufschrift für kleines Geld, und da der besagte Satz kurz vorher mal wieder gefallen war, wollten wir endlich ernst machen. Gesagt, getan, Artikel geschossen. BTW: Die gibt es auch neu bei Pearl. 😉
Der Verkäufer meinte zwar dazu, er hätte das Ding nicht an’s Laufen bekommen, aber wir sind ja fähige Techniker (*hust*) und waren voller Vertrauen, dass das irgendwie hinzukriegen sei. 🙂
Als dann endlich das Päckchen ankam, war die Enttäuschung aber eher groß: Trotz aller Versuche, der heruntergeladenen Anleitung (die wir sogar gelesen haben!) und aller möglichen Treiber für den seriellen Port war mit dem Ding keinerlei Kontakt aufzunehmen. Das Einzige, was es von sich gab, war eine Folge wahlloser Blitze beim Einschalten. Na toll.
Also passierte das, was wir immer machen, wenn wir nicht weiter wissen: Aufschrauben und nachgucken. Stutzig machte uns ein Hinweis in einem Forum, dass das Gerät mit einer 5V Stromversorgung läuft und daher in einem PKW nicht an die Batterie angeschlossen werden könne. Nach einem kurzen Blick auf das vom Verkäufer mitgelieferte Netzteil hatten wir dann eine spontane Ahnung, warum er das Gerät nicht an’s Laufen bringen konnte: Genau. Er hat ein 12V-Netzteil benutzt. Also „adé, TTL-IC’s.“ 🙂
Die Frage war dann nur noch, ob wir jetzt einen sehr teuren und unhandlichen Briefbeschwerer ersteigert hatten oder ob sich mit dem Ding noch was machen ließe. Grundsätzlich konnte es ja noch was (blitzen), also konnte es auch nicht völlig kaputt sein. Da es nun schon mal offen war, konnten wir ja mal schauen, wie das Ganze so funktioniert. Eigentlich waren nur drei verschiedene Typen von IC’s zu entdecken. Einmal ein Atmel ATmega8/L, der als klassischer µC wohl die Steuerung des Lauflichts zu erledigen hatte und mit Sicherheit das erste Opfer der 12V-Spannung war (die externe Stromversorgung ging per Leiterbahn direkt auf den Pin7 – *fump*). Ansonsten waren da nur eine Handvoll SN74HC164 (das sind 8-Bit Schieberegister ohne Latch) und vier APM4953 (MOSFET Treiber). Die Beschaltung der insgesamt 10 5×7-LED-Elemente legte dann nahe, dass diese spaltenweise durch die Schieberegister und zeilenweise durch die Stromtreiber gesteuert wurden. Man muss sich das Ganze wie das zeilenweise Darstellen von Bildern auf einer alten Fernseh-Röhre vorstellen. Jede Zeile wird nacheinander aktiviert und durch den Status der 6 Schieberegister leuchten dann die entsprechenden LED’s in diesen Spalten. Wenn man das schnell genug hintereinander macht, hat man den Eindruck eines stehenden Bildes. Die Schieberegister waren dabei über die Pins QH und B hintereinander geschaltet und ergaben so ein einziges Schieberegister von 48 Bit Länge (die fehlenden zwei Spalten kommen nachher :-)). Der Eingang B des ersten Registers und das für alle Register gleiche CLK-Signal kam direkt vom ATmega. Alsoooooo….. DAS kann man doch nachbauen. 🙂
Womit wir dann wieder beim Thema Arduino wären. Nicht nur, weil da natürlich auch ein ATmega drauf ist (wenn auch ein 328er), sondern weil man damit genau solche Steuerungen umsetzen kann. Es fehlt da nur an zwei Dingen:
- Einer physikalischen Verbindung zum Lauflicht
- Einer passenden Firmware.
„Kirk an Enterprise“ – Die Verbindung mit der Platine
Als erstes musste mal der arme, alte und gebratene ATmega8 raus. DIP-Sockel sind scheinbar völlig überbewertet, daher war dieser natürlich auch fest mit der Platine verlötet. So etwas auszulöten ist bei 28 Beinchen schon eine Herausforderung, an der ich auch komplett gescheitert bin. 🙂
So schnell bekommt man die Lötpunkte selbst mit Auslötpumpe und Entlöt-Litze nicht alle gleichzeitig heiß, um den diesen starren, unflexiblen und hartnäckigen kleinen Sch… äh, Chip auch nur ansatzweise lose zu bekommen. Nach einer halben Stunde Fluchen und etlichen Brandblasen gab ich’s dann auf, bevor die Platine komplett ruiniert war und holte schweres Werkzeug: Einen ganz kleinen Dremel mit einer ganz winzig kleinen Trennscheibe. Mit einem wahrscheinlich ziemlich unanständigem und schadenfrohen Grinsen bekam der ATmega dann nacheinander alle 28 Beine amputiert. Die verbleibenden „Stümpfe“ waren dann einzeln und mit einer kleinen Zange beim Auslöten kein Problem mehr.
Damit mir das nicht noch mal passiert, habe ich dann an die Stelle des ATmega auf der Rückseite der Platine einen passenden DIP-Sockel eingelötet und mit Hilfe zweier weiterer Sockel ein Flachband-Kabel gebastelt. Das lässt sich lösen und auch wieder einstecken, ohne den Lötkolben anwerfen zu müssen. Das Ganze wurde dann nach Außen geführt und endete auf einer kleinen Platine, wo dann, wieder von einem DIP-Sockel aus, die entsprechenden Verbindungen zum Einen auf eine Headerleiste, zum Anderen auf einen passenden 32-Pol-Sockel verlötet wurden. Da der Arduino keinen Akku hat, kann er sich leider auch die Uhrzeit nicht merken. Daher haben wir ihm noch eine kleine batteriegepufferte Echtzeituhr spendiert, die einen über I2C angesprochenen DS1307 an Bord hat. Dafür brauchten wir allerdings Geduld; die Laufzeit dieser Bestellung (per Ebay in China geordert) war 11 Wochen. 🙂
Das sieht zwar alles nicht wirklich so aus, als könne man damit seine Elektroniker-Lehre bestehen, aber es funktioniert und zeugt von Hartnäckigkeit beim Löten (und der Verwendung einer Lupe). Man beachte den 1a Lego-Gerätehalter. 🙂
Lustig war, dass man bei Berührung der richtigen Pins schon Zeilen und Spalten ansprechen konnte – das hab‘ ich beim Durchmessen mit dem Multimeter entdeckt. Prima, es war scheinbar nicht alles gebraten durch den 12V-Schock. Allerdings ließen sich die ersten 7 Spalten von links durch nichts zu etwas Sinnvollem verleiten. Das liegt an dem, vom Stromanschluss aus gesehen, ersten Schieberegister, welches offensichtlich auch einen tödlichen Stromschlag erhalten hatte und auf allen 8 Ausgängen ein Dauer-HIGH hat. Gnädigerweise hat es das wenigstens nur mit ca. 7V, so dass es durch seinen frühen Tod seine nachgeschalteten Kollegen vor dem Hirnschlag bewahrt hat. Beinahe rührend, das erinnert doch an diese Kriegsgeschichten, wo sich der Held auf die Handgranate wirft, um seine Kameraden zu retten. Nun, zumindest hier hat es funktioniert. 🙂
Es gibt tatsächlich in der Kölner Innenstadt noch einen Laden, wo man einen solchen SN74HC164 kaufen kann. Ok, für € 2,- statt für 10 Cent wie bei Ebay, dafür aber zum Mitnehmen und nicht erst in 11 Wochen. Am gleichen Nachmittag war also das defekte Schieberegister durch ein neues ersetzt, jetzt ließen sich alle Spalten reproduzierbar ansprechen. Damit war der elektronische Part fertig.
Scotty: „Computer… Computer… Hallo, Computer.“
Eigentlich wäre hier auch ein Zitat aus Frankensteins Monster passend gewesen, immerhin geht es darum, dem lobotomisierten Lunartec-Lauflicht ein neues Hirn zu verpassen. Natürlich hätte man auch überlegen können, wieder einen ATmega8 einzusetzen, aber eine Firmaware hätte man sowieso schreiben müssen und einen Hardware-Programmer habe ich nicht. Also lieber einen Arduino Nano nehmen, der eine USB-Schnittstelle zur späteren Ansteuerung gleich mitbringt und über diese auch programmiert wird. Der Nano hat die gleichen Möglichkeiten wie ein Uno, nur bei einer wesentlich kompakteren Bauform. Insgesamt braucht man 11 Ausgänge: 7 für die Ansteuerung der MOSFETS (Zeilen), einen für den Eingang des gekoppelten 48-Bit-Schieberegisters, einen für das Clock-Signal und zwei weitere, die die ersten beiden Spalten des Displays ansteuern. Das waren die beiden, die in der Rechnung oben noch fehlten: 50 Spalten bei 48 Bit-Schieberegister, da fehlen zwei. 🙂 Nachmessen mit dem Multimeter hatten ergeben, dass die auch im Original direkt vom ATmega8 kamen. Der Nano hat reichlich digitale Ausgänge (14) und darüber hinaus noch Pins für den I2C-Bus für die Kommunikation mit der Echtzeituhr.
Was die Firmware leisten muss, ist eigentlich auch überschaubar. Sie muss das Display ansteuern und einen Text darstellen können, und sie muss über die USB-Schnittstelle Texte und Befehle entgegen nehmen können.
Der Teufel steckt hier natürlich im Detail. Da die Schieberegister keinen Latch haben, muss man man permament in einer Schleife zeilenweise die Schieberegister komplett füllen (die beiden direkt vom µC gesteuerten Spalten rechne ich einfach hier hinzu) und dann den richtigen MOSFET-Ausgang einschalten. Bei diesem LED-Matrix-Typ bedeutet das übrigens sowohl für die Schieberegister als auch für die Zeilen-Treiber, den Ausgang auf LOW zu setzen. Das muss man dann schnell genug wiederholen, damit sich für das Auge ein stehendes Bild ergibt. Unglücklicherweise ist der RAM (Platz für Variablen und Laufzeitobjekte) bei diesem Arduino Nano recht knapp bemessen (2K), so dass man hier wirklich Platz sparen und mit jedem Bit haushalten muss. Daher sind die Charmaps (die man für die darzustellenden Zeichen und Ziffern auch selber hinterlegen muss) in 7×5-Kodierung hinterlegt, also 5 Byte pro Buchstabe. Damit hat man für ein Zeichen nur 5 Bit „Verschnitt.“ Sie liegen also sozusagen „auf der Seite“. Leider muss man daher bei jedem Zeichen, welches man darstellen möchte, eine Spalten-zu-Zeilen-Zuordnung vornehmen und sich ganz genau überlegen, wleches Bit einer Buchstaben-Spalte man in welcher Zeile an welche Stelle in das Schieberegister schiebt. Auf den Kern dieses Algorithmus, der tatsächlich funktioniert, bin ich auch mächtig stolz: 🙂
for (r=0; r<NUMROWS; r++) {
lbptr = (byte *)linebuf[r];
lbptr[0] = lbptr[0] << 1;
for (b=1; b<DISPLAYBYTES; b++) {
if (bitRead(lbptr[b], 7)) {
lbptr[b-1] += 1;
}
lbptr[b] = lbptr[b] << 1;
}
// Add last bit from cur char
bitWrite(lbptr[DISPLAYBYTES-1], dsp_lastbit, bitRead((byte)colmap, r));
}
Der nächste große Block war die Kommunikationsschnittstelle. Angebunden wird das Lauflicht über die gute alte „Serielle Schnittstelle“ oder auch „RS232.“
Ohne jetzt in’s Detail gehen zu wollen, versteht das Lauflicht Anweisungen vom Typ:
<C>Payload<E>
Dabei steht C für die Kommandos:
- D: Duration == Anzeigedauer einer Nachricht
- S: Speed == Geschwindigkeit, mit der ein Text zur Seite scrolled
- T: Setzen der Systemzeit
- M: Anzeigen einer Nachricht
- R: Rotieren (scrollen) einer Nachricht.
Je nach Kommando ist die „Payload“ die anzuzeigende Nachricht oder der zu setzende Wert. Um sicherzustellen, dass die Anweisung vollständig ist, erwartet der Arduino immer ein abschließendes <E> für „Ende“.
Alles in allem funktioniert die Firmware stabil. Insgesamt bin ich dabei mit 13192 Byte für das Programm und 1837 Bytes für Variablen und Puffer zurechtgekommen und kann damit 1K große Nachrichten darstellen. Das sind immerhin über 7 SMS. 🙂
Man kann jetzt also dem Lauflicht Nachrichten schicken, die es darstellt. Wenn es nichts zu tun hat, zeigt es einfach die Uhrzeit. Irgendwann füge ich noch einen Countdown bis zum Feierabend hinzu. 🙂
Wer sich für das Programm interessiert, kann es sich hier ansehen und auch herunterladen: Lunartec_Arduino.zip
„Mr. Spock, wie kann man dieses… DING kontrollieren?“
Der Arduino hat eine wirklich blöde Angewohnheit: Wenn man die serielle Schnittstelle öffnet und DSR auf HIGH geht, resettet sich der Arduino. Wenn man das Lauflicht also wirklich benutzen will und lustige Nachrichten darstellen möchte, braucht man auf dem Steuerrechner (z.B. einem Raspberry oder, wie bei uns, einem alten Mac Mini) einen Daemon, der auf Nachrichten aus dem Netzwerk wartet und diese an die permanent geöffnete serielle Schnittstelle und damit an das Lauflicht weitergibt. Das ist natürlich um Lichtjahre komfortabler als das, womit das eigentlich verkauft wird: Einer Handsteuerung mit vier Pfeil- und einer Enter-Taste, wo man die Nachrichten buchstabenweise mühsam zusammensetzen muss. 🙂
Da ich hier die Wahl hatte, musste ich natürlich nicht C++ wie bei der Arduino-Firmware nehmen sondern konnte auf meine aktuelle Lieblingssprache, Go, zurückgreifen. Go ist eine absolut gelungene Mischung aus Python und C, die das Beste beider Welten kombiniert. Einer der Erfinder dieser Sprache ist übrigens die beinahe-Gottheit der UNIX-Welt, Ken Thompson.
Auch hier möchte ich nicht unnötig ins Detail gehen. Der Daemon „lunartecd“ lauscht auf einem definierten Port auf Nachrichten von Client-Programmen (z.B. dem Kommandozeilen-Tool „lunartec“) aus dem Netzwerk. Der Datenaustausch passiert dabei über JSON und Webservices, so dass man genauso schnell einen Client für den Browser oder einen Client mit GUI für ein beliebiges Betriebssystem bauen kann. Die Komandos werden auf Korrektheit kontrolliert und dann an das Lauflicht weitergeleitet. Der Daemon selber funktioniert multithreaded, also mit eigenen, voneinander unabhängigen Prozessen für die Verwaltung der seriellen Schnittstelle und der Verbindungen auf dem netzwerk-Stack (bei Go „gorouties“ genannt). Er stellt dabei einen echten kleinen Webserver bereit, der seine Webservices mit GET und PUT bedienen lässt. Er implementiert somit das REST-Protokoll. Die Threads unterhalten sich intern über Message-Channels.
Der dazu gehörenden kleine Kommandozeilen-Client „lunartec“ nimmt Nachrichten als Parameter entgegen und verschickt sie an den Webservice. Auch hier gilt: Wen das Ganze interessiert, der kann es sich hier anschauen oder herunter laden: Lunartec_Go.zip
Naja, und um den Kreis zu schließen: Darum haben wir das alles gemacht!