Make Magazin 5/2016
S. 96
Baubericht
Aufmacherbild

Der springende Punkt

Die ausrangierte Fahrtzielanzeige aus einem Linienbus kann nach einem kleinen Umbau eigene Texte und Grafiken anzeigen. Ein effektvoller Hingucker für Messen und das FabLab, aber auch gut geeignet für Sportvereine zur Spielstandsanzeige.

Eine Frage, die man in der Make-Redaktion nur mit Bedacht stellen sollte, lautet: „Was ist das, was macht man damit?“ Die Antwort könnte lauten: „Mach mal! Hast drei Tage Zeit.“ So geschehen, als ich in einer Ecke die Flipdot-Anzeige entdeckte, die dort stand, seitdem sie ein Kollege bei einer günstigen Gelegenheit erworben hatte. Ausgebaut wurde das etwa 150 cm × 30 cm × 10 cm große Display irgendwann vermutlich einmal aus einem Fahrzeug des öffentlichen Personen-Nahverkehrs in Mannheim. Hersteller war die Firma InfoSystems beziehungsweise Brose. Nachdem die Anzeige ihren Weg in die Redaktion gefunden hatte, blieb sie lange Zeit unbeachtet, sollte jetzt aber zur diesjährigen Maker Faire in Hannover den Messestand ergänzen.

Flipdots

Aufbau eines Flipdots
ASCII-Textzeichen mit dem internen Zeichensatz

Flipdot-Displays nutzen ein elektrisch induziertes Magnetfeld, um kleine Plättchen (die eigentlichen Punkte, im englischen „dots“) um knapp 180 Grad zu drehen und so zwischen einer farbigen und einer schwarzen Fläche umzuschalten. Unser Display besteht aus einer Matrix von 140 × 24 solcher Pixel (im Englischen auch als „flip-disc“ bezeichnet). Jedes Pixelplättchen ist drehbar gelagert und besitzt einen kleinen magnetischen Pol im Material. Unterhalb und seitlich des Plättchens befinden sich zwei magnetisierbare Stäbchen (Stator) in einem Viertelkreissegment angeordnet. Diese Stäbchen sind von unten mit lackiertem Draht umwickelt und bilden zwei Elektromagnete. Die Wicklung ist gegenläufig ausgeführt, sodass die magnetische Ausrichtung stets entgegensetzt ist.

Das Display wurde geöffnet und einer ersten Analyse unterzogen. Vorne befindet sich der Industriestecker, hinten das Netzteil. Rechts vorne ist die Steuerplatine für die LEDs. Im vorderen Drittel befindet sich der Kartenleser, gefolgt von den zwei Platinen zur Ansteuerung. Die notwendigen ICs für die Flipdots befinden sich links unter den Flachbandkabeln.

Fließt ein Strom von wenigen Milliampere für ein paar Millisekunden durch die beiden Spulen, baut sich ein Magnetfeld in den Stäbchen auf. Je nach Ausrichtung wird von diesem der magnetische Pol im Plättchen angezogen oder abgestoßen und es dreht sich in die eine oder andere Richtung und kippt (engl. „flip“) mit der farbigen oder der dunklen Seite nach oben. Die magnetisierten Spulenkerne (Stäbchen) behalten ihre Feldausrichtung bei (Remanenz), so dass sich die Ausrichtung des Plättchens auch ohne Stromfluss nicht ändert. Selbst wenn man das Plättchen von Hand vorsichtig dreht, springt es stets in den letzten Zustand zurück. Um den Pixel umzuschalten, wird erneut ein Strom an die zwei Spulen angelegt, diesmal mit umgekehrter Polung, sodass sich das Magnetfeld umdreht. Andere Ausführungen benutzen nur eine einzelne Magnetspule an einem U-förmigen Stator. Auch die Dicke und die technischen Daten der Spule variieren je nach Modell. Weil es nur ein bewegliches Teil gibt, sind nach Herstellerangaben weit über 100 Millionen Drehungen gewährleistet.

Zusätzlich besitzt unser Modell auch noch eine grüne LED neben jedem Pixel. Diese kann unabhängig vom Flipdot angesteuert werden und ermöglicht eine Anzeige von Informationen auch bei Dunkelheit, wenn die mechanischen Punkte extra beleuchtet werden müssten.

Anschluss des Laptop-Netzteils an die interne Spannungsregelung

Integriertes Bordinformationssystem

In den öffentlichen Verkehrsmitteln werden die Fahrtzielanzeigen an der Fahrzeugfront, die Liniennummern an der Seite und die Haltestellennamen ebenso wie die Entwerter oft über das Integrierte Bordinformationssystem (IBIS) nach VDV 300 miteinander verbunden. Ein zentrales Steuergerät (der Master) befindet sich meistens beim Fahrer und steuert von dort die einzelnen Geräte (die Slaves) über einen Datenbus. Dabei handelt es sich um einen einfachen seriellen Bus, der mit Pegeln zwischen 0 und 12 V arbeitet. Mit einem einfachen Pegelwandler ist es dann möglich, über eine serielle Schnittstelle mit einem Terminalprogramm vom PC aus Texte an das Display zu senden.

  1 const uint8_t ANZ_SPALTEN = 28;     
  2 const uint8_t ANZ_PANEL = 5;     
  3 const uint8_t PANEL_LEFT = 0xFE;
  4 const uint8_t ZEICHEN_ZEILE = 23;
  5 
  6 /*
  7  * @brief   dreht die Reihenfolge der Bits in einem Byte um
  8  * @param   Byte
  9  * @return  Byte in LITTLE Endian
 10  */
 11 uint8_t rev_bits(uint8_t input)
 12 {
 13     uint8_t output = 0;
 14     uint8_t n = sizeof(input) << 3;
 15     uint8_t i = 0;
 16 
 17     for (i = 0; i < n; i++)
 18         if ((input > i) & 0x1)
 19             output |=  (0x1 << (n - 1 - i));
 20 
 21     return output;
 22 }
 23 
 24 /*
 25  * @brief   schreibt einen Pixel auf das Display.
 26  *          Ursprung oben/links = 0/0
 27  * @param   Spalte, Zeile, set = farbe: 0=schwarz, 1=gelb
 28  * @return  none
 29  */
 30 void flipdot_pixel (uint8_t spalte, uint8_t reihe, uint8_t set)
 31 {
 32   uint8_t panel, spalte_offset, offset8=0;
 33 
 34   panel = uint8_t(spalte / ANZ_SPALTEN); // welches Panel
 35   spalte = (spalte - (ANZ_SPALTEN * panel)) + 1; // Spalte
 36   panel = PANEL_LEFT - panel; // Paneladresse
 37 
 38   switch (reihe)    // physische Adresse ermitteln
 39   {
 40     case (0)  : reihe = 0x32; spalte_offset = 0x00; break;
 41     case (1)  : reihe = 0x31; spalte_offset = 0x00; break;
 42     case (2)  : reihe = 0x33; spalte_offset = 0x00; break;
 43     case (3)  : reihe = 0x30; spalte_offset = 0x80; break;
 44     case (4)  : reihe = 0x32; spalte_offset = 0x80; break;
 45     case (5)  : reihe = 0x31; spalte_offset = 0x80; break;
 46     case (6)  : reihe = 0x33; spalte_offset = 0x80; break;
 47     case (7)  : reihe = 0x36; spalte_offset = 0x00; break;
 48     case (8)  : reihe = 0x35; spalte_offset = 0x00; break;
 49     case (9)  : reihe = 0x37; spalte_offset = 0x00; break;
 50     case (10) : reihe = 0x34; spalte_offset = 0x80; break;
 51     case (11) : reihe = 0x36; spalte_offset = 0x80; break;
 52     case (12) : reihe = 0x35; spalte_offset = 0x80; break;
 53     case (13) : reihe = 0x37; spalte_offset = 0x80; break;
 54     case (14) : reihe = 0xC2; spalte_offset = 0x00; break;
 55     case (15) : reihe = 0xC1; spalte_offset = 0x00; break;
 56     case (16) : reihe = 0xC3; spalte_offset = 0x00; break;
 57     case (17) : reihe = 0xC0; spalte_offset = 0x80; break;
 58     case (18) : reihe = 0xC2; spalte_offset = 0x80; break;
 59     case (19) : reihe = 0xC1; spalte_offset = 0x80; break;
 60     case (20) : reihe = 0xC3; spalte_offset = 0x80; break;
 61     case (21) : reihe = 0xC6; spalte_offset = 0x00; break;
 62     case (22) : reihe = 0xC5; spalte_offset = 0x00; break;
 63     case (23) : reihe = 0xC7; spalte_offset = 0x00; break;
 64   }
 65 
 66   if (!set) // Pixel schwarz (loeschen) => Adresse korrigieren
 67   {
 68     reihe -= 8;
 69     spalte_offset = spalte_offset | 0x40;
 70   }
 71 
 72   // alle x Pixel eine Adresse überspringen (weil EP2800A 7-Segment-Treiber):
 73   if ((spalte >= 8) && (spalte <= 14))
 74     offset8=1;    
 75   if ((spalte >= 15) && (spalte <= 21)) 
 76     offset8=2;   
 77   if ((spalte >= 22)) 
 78     offset8=3;   
 79 
 80   spalte += offset8;
 81 
 82   // Bits umsortieren
 83   spalte = rev_bits (spalte);       // Spalte rückwärts
 84   spalte = spalte >> 2;             // zwei nach rechts schiften
 85   spalte = spalte | spalte_offset;  // mit physischer Spaltenadresse verodern
 86 
 87   flipdot_writepixel (spalte, reihe, panel);
 88 }
 89 
 90 /*
 91  * @brief   Daten per I2C senden
 92  * @param   I2C Adresse, Daten-Byte
 93  * @return  none
 94  */
 95 void send_data (uint8_t address, uint8_t value)
 96 {
 97   const uint16_t pause_us = 800;    // 800 bei LED, 15 nur Dots (200 besser) aber man kann einfach —      2 x schreiben
 98 
 99   Wire.beginTransmission (address);   
100   Wire.write (value);          
101   Wire.endTransmission ();     
102   delayMicroseconds (pause_us);
103 }
104 
105 /*
106  * @brief   Daten fuer einen Dot senden
107  * @param   Spalte, Zeile, Panel
108  * @return  none
109  */
110 void flipdot_writepixel (uint8_t spalte, uint8_t reihe, uint8_t panel)
111 {
112     
113   send_data (0x21, spalte);   // Column
114   send_data (0x38, panel);    // Panel
115   send_data (0x22, reihe);    // Row
116   send_data (0x22, 0x0F);     // END?
117   send_data (0x38, 0xFF);     // LED follows?
118 } 
Diese Anweisungen übernehmen die Umrechnung der Pixelkoordinaten in die entsprechenden Adressen auf dem Display und senden die Daten per I²C.

Ein gravierender Nachteil bei IBIS ist, dass sowohl der Master als auch die Slaves keine ausgefeilten Funktionen zur Darstellung von Inhalten auf den Displays besitzen. Der Verkehrsbetrieb programmiert mit einem speziellen Gerät die benötigten Symbole fest in die EPROMS der Geräte. Vom Master wird dann lediglich ein Befehl an den Slave gesendet, welches Symbol anzuzeigen ist. Texte und Zahlen können zwar frei erzeugt werden, allerdings unterliegt die Darstellung den Möglichkeiten, die durch die ebenfalls fest im EPROM abgelegte Schrifttype (Font) gegeben sind.

Das Innenleben

Der Arduino Uno wurde modifiziert, damit nicht aus Versehen Spannung über das Board ans Display oder den PC eingespeist wird.

Um einen ersten Eindruck vom Display zu bekommen, habe ich kurzerhand die Rückwand abgeschraubt. Darunter befinden sich zahlreiche Platinen und fünf große Module mit jeweils 28 Spalten à 24 Zeilen Flipdots, alles verbunden mit breiten Flachbandkabeln. Die Anschlüsse des massigen Industrieverbinders auf der Außenseite führen zu einem kleinen Schaltnetzteil, von welchem aus die LED-Matrix und die Flipdot-Steuerung versorgt werden. Ins Auge sprang auch sofort der PCMCIA-Kartenleser, der wohl dazu da ist, die vordefinierten Zeichen und Schriften umzuprogrammieren. Die zwei Datenleitungen führen dann zu einem Board, von wo aus die Daten offenbar aufbereitet und weitergeleitet werden, bis sie an der letzten Platine anlangen. Von dort führen die Flachbandkabel zu den Modulen. Jedes Modul verfügt über ein paar DIP-Schalter, mit denen sich anscheinend die Adressen der Module einstellen lassen. Aufkleber am Rand legen diesen Schluss zumindest nahe. Für die LEDs gibt es eine eigene Steuerplatine mit Mikrocontroller. Wie auch für die Flipdots gibt es für die LEDs massenweise ICs, deren Anordnung und Verdrahtung sehr nach Schieberegistern aussieht. Mangels frei verfügbarer Dokumentation müsste die Funktionsweise noch näher untersucht werden, will man die LED mit einem eigenen Controller ansteuern. An der Front befindet sich links noch ein Lichtsensor, der automatisch die Helligkeit der LEDs reduziert, wenn es dunkel ist.

Umbau der VM-IIC-Compact-Platine
Tabelle
Tabelle: Zweckentfremdung der Sockel für die Bustreiber-ICs

Die Versorgung des Displays mit Spannung soll zukünftig über ein 230-V-Netzteil erfolgen. Aus dem Fundus unserer Werkstatt suche ich mir dazu ein altes Laptopnetzteil mit 24 V und 2,5 A Leistung. Zuvor hatte ich mit einem Labornetzgerät überprüft, wie weit der Strombedarf ansteigt. Ohne LEDs sind es maximal etwa 0,7 A. Wenn alle 3360 LEDs gleichzeitig leuchten, werden etwa 2,2 A benötigt. Bei fehlender Leistung fangen die LEDs ansonsten an zu blinken. Auf der Netzteilplatine im Display gibt es für die Flipdots und die LEDs zwei getrennte Versorgungsanschlüsse, die mit dem Industriestecker am Gehäuse verbunden sind. Die Zuleitungen zum externen Stecker werden gekappt und die Klemmanschlüsse werden beide gemeinsam mit dem Laptop-Netzteil verbunden.

Moderner I2C-Datenbus

Am I²C-Bus können mehrere Slave-Bausteine von einem Master angesprochen werden. Die Pull-Up-Widerstände sind zwingend einmal notwendig.

Von besonderem Interesse war die letzte der drei Platinen: Auf diese führten neben der Versorgungsspannung nur vier Leitungen von der vorherigen. Zudem prangte ein Aufkleber mit der Bezeichnung „VM-IIC Compact Venus“ auf der Platine. „Venus“ steht für die Modellvariante, bei der Flipdots mit LEDs verbaut sind. IIC sieht wie die alternative Schreibweise von I2C aus.

Gleich in der Nähe des Kabelsteckers befinden sich zwei ICs vom Typ SN75176B. Diese dienen als Signalkonverter zwischen 5-V-TTL-Signalpegeln und RS-422/RS-485. An dieser Stelle werden also die ungewohnt hohen Signalpegel auf die bei Mikrocontroller-Anwendungen üblichen umgesetzt. Für jede Datenleitung wird ein IC benötigt. Direkt daneben befinden sich dann die nächsten interessanten ICs: PCF8574. Dabei handelt es sich um Port-Expander für I2C. Über den I2C-Zweidrahtbus können damit acht Pins als Ein- oder Ausgänge benutzt werden. Von hier aus führen die Leiterbahnen weiter zu den 40-poligen Treiber-Chips von Alcatel Brose. Um das Display anzusteuern, sind also lediglich die passenden I2C-Befehle zu ermitteln. Die Ansteuerung der einzelnen Spulen und LEDs kann dann der vorhandenen Elektronik überlassen werden.

I2C ist ein gängiger Datenbus, um Sensoren und Aktoren anzusteuern und auch der Atmel Prozessor auf einem Arduino kann von Hause aus die passenden Signale generieren. I2C benötigt neben den zwei Versorgungsleitungen zwei Datenleitungen: Takt (SCL) und Daten (SDA). Diese beiden Leitungen werden über je einen Pull-Up-Widerstand mit der Versorgungsspannung verbunden. Sämtliche angeschlossenen Geräte haben Open-Collector-Ausgänge, was zusammen mit den Pull-Up-Widerständen eine Wired-AND-Schaltung ergibt. Weil auf dem Arduino-Board keine Widerstände hierfür verbaut sind, müssen diese an einer beliebigen Stelle des Datenbusses eingebaut werden.

Tabelle
Tabelle: Steuersequenz für ein Flipdot

Da wir die zwei RS-485-Bustreiber-ICs nicht benötigen, können wir sie entfernen und in die freigewordenen Sockel zwei weitere IC-Sockel einstecken und an denen die Anschlüsse für Masse, den I2C-Bus sowie die zwei 4,7 kOhm-Widerstände anlöten. Den runden Verbindungsstecker zur rechten Platine lösen wir, so dass keine Datenverbindung besteht und nur die Versorgungsspannung die I2C-Platine erreicht. Anhand des Datenblatts des SN75176B wissen wir, wie die ursprünglichen Pins belegt waren. Die Verbindungen von dort zu den Pins 14 (SCL) und 15 (SDA) der PCF8574P gibt Auskunft über die Zuordnung der zwei Datenleitungen. Die Leitungen werden mit einem Arduino verbunden. Je nach Modell sind die Datenleitungen dort an unterschiedlichen Pins zu finden. Die Spannungsversorgung für den Arduino greife ich auch hier ab, da das Display uns bereits stabilisierte 5 V bereitstellt. Masse muss auf jeden Fall verbunden werden. Wichtig ist, dass man nicht über die USB-Buchse oder den Arduino-Stromstecker das ganze Display versorgt. Damit dies nicht passieren kann, löte ich die Poly-Fuse auf dem Uno-Board aus und überziehe auch die Buchse für die Stromversorgung mit Schrumpfschlauch.

Adressierung der Elemente

Tabelle
Tabelle: ODER-Verknüpfung

Nachdem sich die Hardwareseite recht einfach gestaltete, bleibt die Frage, wie die Ansteuerung per Software aussieht. Da unser Display beim Einschalten keinerlei Text von sich aus anzeigt, ist eine Analyse des Datenverkehrs nicht möglich. Im Internet finden sich recht wenige Informationen zum Thema. Meistens liest man nur, dass es ganz einfach geklappt haben soll. Auf der Webseite von „TeddyDesTodes“ (siehe Weblinks) sind immerhin ein paar Informationen zur Adressierung aufgeführt. Mit diesen Daten ist es dann recht schnell möglich, ein einzelnes Plättchen auf Gelb umzuschalten.

Die Kommunikation bei I2C läuft in zwei Schritten ab: Zuerst sendet der Master die Adresse des Empfängers und anschließend die Daten. Für das Display werden offenbar fünf Nachrichten gesendet. wobei jeder Adresse nur ein einzelnes Byte folgt.

#include <avr/pgmspace.h>  // PROGMEM um Variable im —Flash abzulegen
const uint8_t font[256][8] PROGMEM = {
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
{0x70,0x88,0xD8,0x88,0xA8,0x88,0x70,0x00},
{0x70,0xF8,0xA8,0xF8,0x88,0xF8,0x70,0x00},
{0x00,0x50,0xF8,0xF8,0xF8,0x70,0x20,0x00},
 // …
{0x48,0x00,0x48,0x48,0x48,0x68,0x50,0x00},  // ü / u Umlaut
{0x18,0x20,0x10,0x38,0x00,0x00,0x00,0x00},
{0x00,0x00,0x78,0x78,0x78,0x78,0x00,0x00},
{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00} }; 
Auszug aus der Datei 6x8_horizontal_lsb_iso8859-1.h in welcher der Pixel-Font definiert wird. Die Daten werden nicht im RAM, sondern im Flash gespeichert.
Mit 140 × 24 Pixeln sind auch Grafiken möglich.

Nach jedem Datenpaket wird eine kurze Pause von wenigen Mikrosekunden eingelegt. Über die Adressierung wird dem Display mitgeteilt, ob die LED, ein Flipdot oder beides angesteuert werden soll. Es ist also durchaus möglich, dass die mechanischen Dots einen anderen Inhalt anzeigen als die LEDs. Interessant ist auch, dass sich die Pause zwischen den einzelnen Daten ebenfalls auf die Darstellung auswirkt. Die Flipdots schalten schon bei einer sehr schnellen Datenrate mit kurzen Pausen von etwa 15 µs um. Eine so schnelle Ansteuerung führt aber zu schlechten Ergebnissen, weil dann zu oft einzelne Plättchen nicht kippen, da die Zeit für die Magnetisierung offenbar nicht ausreicht. Ab etwa 200 µs bleiben nur noch selten Plättchen hängen. Damit auch die LEDs (bei entsprechender Adressierung) schalten, sind aber mindestens Pausen von 800 µs notwendig. Somit kann man die LEDs und die Dots unabhängig voneinander über die gleichen Adressen ansteuern, indem man einfach nur die Verzögerung variiert.

Mit der Freeware MikroElektronika GLCD Font Creator lassen sich Systemschriften in Pixelfonts konvertieren.
Die Wertigkeit der Bytes (binäre und hexadezimale Darstellung) kann horizontal oder vertikal bestimmt werden. Eventuell werden führende Nullen zum Auffüllen eingefügt.

Die Spaltenangaben beziehen sich immer auf ein bestimmtes der fünf verbauten Panele, die durch die bereits genannten Adressen bestimmt werden. Ob ein Punkt gesetzt (gelb) oder gelöscht (schwarz) werden soll, wird nicht durch ein Daten-Byte, sondern durch die jeweils genutzte Spalten- und Zeilenadresse festgelegt. Mit dieser Erkenntnis begann die schwerste Aufgabe: herauszufinden, wie die Adressen strukturiert sind. Im Grunde lief es auf mehrere Stunden langweiliges Ausprobieren hinaus. Die Erkenntnisse wurden in einer Tabelle festgehalten, um sie besser analysieren zu können. Dabei zeigte sich, dass einzelne Bytes Big–Endian kodiert sind und einzelne Bits eines Bytes für die Spalte und andere für die Zeilenangabe genutzt werden. Zusätzlich gibt es Sprünge bei den Adressen, so dass auch die Spaltenangaben nicht fortlaufend sind. Die Ambitionen eines Kollegen, das System dahinter genau zu durchleuchten, verliefen dann doch im Sande. Sicherlich würde ein Blick auf einen zu erstellenden Schaltplan der Schieberegister und Treiber-ICs weiterhelfen. Letztendlich wurde der pragmatische Ansatz genommen und die Adressierung in der Software mit Vergleichstabellen realisiert. Das ist zwar nicht ganz so elegant, aber im Endeffekt sieht es keiner und sowohl Speicher als auch Rechenzeit ist ausreichend vorhanden. Über den Link am Ende des Artikels können Sie ein Tabellenkalkulationsblatt öffnen, in dem Sie studieren können, wie die Adressen ausprobiert wurden und sie verteilt sind. Der Nullpunkt/Ursprung für alle Angaben ist die linke obere Ecke eines jeden Panels. Zwei Beispiele für die Adressierung von LED und Flipdot gleichzeitig sollen die Thematik veranschaulichen:

Um einen Pixel in der ersten (oberen) Reihe anzusteuern, lautet die Adresse für die Zeile 32Hex. Für die erste Zeile (und andere) ist kein Versatz bei den Spaltenadressen erforderlich. Soll nun der 4. Pixel gesetzt werden, ist zudem keine weitere Korrektur der Spaltenadresse notwendig, die Spaltenadresse lautet demnach 04 (es wird bei 1 begonnen zu zählen).

  1 /*
  2  * @brief   Gibt ein Textzeichen an Position x, y auf dem Display aus
  3  * @param   Zeichen, Spalte, Zeile
  4  * @return  none
  5  */
  6 void writechar (unsigned char c, uint8_t xpos, uint8_t ypos)
  7 {   
  8   unsigned char x, y, w;
  9 
 10   // Bitweise durch das Byte laufen fuer Pixelfont 
 11   for (y = 0; y < 8; y++)
 12   {   
 13     w = pgm_read_byte (&font[c][y]);          // Daten sind im FLASH mit PROGMEM!
 14     w = w > 2;                                // weil nachfolgend bei 2 angefangen wird: shiften
 15     for (x = 2; x < 8; x++)                       // nur 6 Spalten pro Zeichen
 16     {   
 17       if (w&1)                                // wenn Pixel zu setzen ist (Bit im Byte High):
 18         flipdot_pixel (x+xpos-2, y+ypos, 1);  // Pixel gelb setzen
 19       else                                    // kein Pixel: 
 20         flipdot_pixel (x+xpos-2, y+ypos, 0);  // Pixel schwarz setzen
 21       w = w > 1;                              // shiften
 22     }   
 23   }
 24 }
 25 
Funktion zu Ausgabe eines Buchstabens aus der Font-Datei. Die Daten-Bytes werden mit einem Makro aus dem Flash gelesen.

Jetzt soll der Pixel in Zeile 12, Spalte 17 gelöscht werden. Als Adresse für die Reihe wurde 2EHex ermittelt. Für diese Spaltenangaben muss aber ein Versatz (Offset) von 128 (80Hex)berücksichtigt werden, da die Basisadresse für jede Reihe immer zweimal benutzt wird. Weil ein Pixel schwarz werden soll, muss nun diesmal von der Adresse für die Reihe noch 8 subtrahiert werden. Zudem wird der Offset C für Set mit 40Hex Oder-Verknüpft. Dadurch wird das siebte Bit im Adressbyte gesetzt.

Alle 8 Spalten wird zudem eine Spaltenadresse übersprungen. Dies liegt an den EP2800A ICs, die ursprünglich für 7-Segment-Anzeigen konzipiert wurden. Diesmal liegt die gewünschte Spalte zwischen der 15. und der 21. Aus diesem Grund muss die Spaltenangabe noch um 2 erhöht werden. Somit lautet die Adresse für die Spalte D3Hex und für die Zeile 2E.

Weil die Adressen Mix-Endian codiert sind, ist immer ein Umsortieren der Bits erforderlich. Üblicherweise wird das niederwertige Bit in einem Byte rechts geschrieben. Für das Display muss die Reihenfolge der Spalten aber umgedreht werden: das niederwertige Bit steht links. Aus beispielsweise 13Hex (0001 0011Bin) wird C8Hex (1100 1000Bin). Dann folgt noch ein Rechtsshift der Bits um zwei Stellen (ergibt beispielsweise 32Hex/0011 0010Bin). Dieses Verschieben ist notwendig, weil abschließend noch eine Oder-Verknüpfung mit dem oben ermittelten Offset erfolgt, bei der eventuell die zwei linken Bits gesetzt werden. Für die Spalte aus dem Beispiel bedeutet dies: 32Hex ODER C0Hex = F2Hex.

Mit diesem Wissen ist die schwierigste Aufgabe erledigt. Eine entsprechende Funktion kann sich nun darum kümmern, die Adressen zu berechnen und dann einen einzelnen Pixel auf Schwarz oder Gelb umzudrehen.

ASCII-Zeichensatz

Um variablen Text anzuzeigen, ist ein Zeichensatz (englisch font) notwendig, bei dem für jedes Zeichen angegeben wird, welche Pixel sichtbar sein sollen. Häufig wird ein solcher Font für eine feste Zeichengröße als Abfolge von Bytes in einem Array abgelegt. Die Beispielgrafik für ein 5 × 7 großes Zeichen rechts zeigt, wie sich die Bytes zusammensetzen. Zuerst wird in den Kästchen festgehalten, welche Pixel zu sehen sein sollen (entspricht einer Eins). Dann wird die Wertigkeit der einzelnen Stellen binär notiert und als hexadezimale Zahl in einem Array gespeichert.

Für das Beispiel ergibt sich, dass die Notation der Spalten lediglich fünf Bytes benötigt, anstatt sieben bei einer zeilenweisen Schreibweise. Bei anderen Schriftgrößen kann dies natürlich anders ausfallen. Es gibt auch keine einheitliche Regelung, ob im Array dann zuerst das linke (obere) oder das rechte (untere) Byte abgelegt wird. Ebenso könnte die Reihenfolge der einzelnen Bits von rechts nach links (beziehungsweise von unten nach oben) vertauscht sein. Wird ein fertiger Font benutzt, sind diese Punkte bei der Programmierung zu berücksichtigen. Der Beispielcode nutzt einen Zeichensatz aus dem Internet, bei dem das niederwertige Bit zuerst steht und die Bytes horizontal angeordnet sind. Im Web finden sich auch einige Tools, um mit wenigen Klicks aus einer auf dem PC installierten Schrifttype einen Pixelfont zu generieren. In der Linksammlung zum Artikel haben wir einige interessante Seiten zusammengetragen. Bei der Verwendung von Schriften Dritter darf nicht außer Acht gelassen werden, dass Schriften oft einen Gebrauchsmusterschutz besitzen.

Der American Standard Code for Information Interchange (ASCII) legt seit Langem fest, welches Zeichen wo im Zeichensatz liegt. Aus den historischen Begebenheiten ergibt sich, dass es nur 128 Zeichen gab, weil die mit 7 Bit darstellbar sind. Der Zeichensatz umfasst ein paar Steuer-, Satz- und Sonderzeichen, Zahlen sowie die Buchstaben in Groß- und Kleinschreibung. Eine Erweiterung auf 8 Bit ermöglichte insgesamt 256 Zeichen. Ursprünglich waren dabei deutsche Umlaute und Betonungszeichen anderer Nationalitäten nicht enthalten. Später wurden dann verschiedene Untermengen umgesetzt. Nach ISO 8859-1 sind in der ASCII-Tabelle auch westeuropäische Sonderzeichen enthalten. Inzwischen werden Zeichensätze mit Unicode kodiert, womit die vielen nationalen Besonderheiten berücksichtigt werden können. Weil der benutzte Zeichensatz aus dem Internet nicht alle deutschen Umlaute enthielt und diese auch nicht an der Position nach ISO 8859-1 lagen, wurde die Datei etwas überarbeitet.

Ein Hauptproblem beim Einsatz von Schriften auf einem Mikrocontroller ist der benötigte Speicherplatz. Sollen mehrere verschiedene Schrifttypen gleichzeitig verfügbar sein, kann der Speicher im Mikrocontroller knapp werden. Wie das Beispiel zeigt, werden für einen schlichten Font mit 5 × 7 Pixeln schon 5 Bytes pro Zeichen benötigt. Bei 255 Zeichen sind das 1275 Bytes. Der gewählte Zeichensatz belegt mit 8 Bytes pro Zeichen 2048 Byte. Bei einem ATmega328, wie er auf dem Arduino Uno verbaut ist, stehen aber nur genau 2 kBytes SRAM für alle Variablen zur Verfügung, sodass neben dem Font keine weiteren Variablen möglich wären. Flash-Speicher ist aber genügend vorhanden (32 kBytes) und mit dem AVR-spezifischen GCC-Attribut progmem kann eine Variablendeklaration im static storage markiert werden. Mit dem Makro pgm_read_byte (&font[c][y]) wird dann ein Byte aus dem zweidimensionalen Font-Array im Flash ausgelesen. So bleibt das knappe SRAM frei und wir können den ganzen Zeichensatz nutzen.

Nutzungsvarianten und Montage des Displays

Seitenansicht der Displayhalterung

Wie das Display angesteuert wird, bleibt jedem selbst überlassen. Zum einen ist es möglich, dass der Arduino selbstständig Texte ausgibt. Auch primitive Grafiken sind auf der Fläche selbstverständlich umsetzbar. Die Daten könnten von einer anzuschließenden SD-Speicherkarte ausgelesen werden. In einem anderen Szenario werden die Daten von einem PC über USB oder ein zusätzliches Bluetooth-Modul wie das preiswerte HC-06 an den Arduino gesendet, der dann nur noch die Steuerung des Displays übernimmt. Für die Maker Faire Hannover haben wir uns aufgrund der kurzen verfügbaren Zeit für die USB-Variante entschieden. Eine mit heißer Nadel gestrickte Software für Arduino und Windows ermöglichte es, vorgegebene Texte anzuzeigen. Zudem konnten die Messestandbesucher an einem Laptop selber kreativ werden. Später wurde die Software noch um die Möglichkeit erweitert, Grafiken zu übertragen. Ein einfaches Spiel, welches mit einem WII-Nunchuck gesteuert werden soll, ist bereits in Arbeit und kann vielleicht schon auf der nächsten Maker Faire ausprobiert werden. Für den autarken Einsatz ist noch eine WLAN-Erweiterung geplant. Der Arduino soll sich über ein ESP8266 mit einem WLAN-Router verbinden können und dann Daten aus dem Internet abrufen, aufbereiten und präsentieren. Wie wäre es mit Wetterdaten, der aktuellen Uhrzeit und vielleicht noch den Abfahrtzeiten der öffentlichen Verkehrsmittel vor Ort? Wenn die Daten wie beispielsweise von OpenWeatherMap bereits mit XML ausgezeichnet sind, ist die Abfrage sehr einfach. Mit etwas programmiertechnischem Geschick lassen sich interessante Infos aber eigentlich aus den meisten Webseiten extrahieren.

Messen, bohren, schrauben – wir bauen die Displayhalterung in unserer Werkstatt.

Schlussendlich fehlte unserem Display nur noch eine repräsentative und stilechte Ständerkonstruktion. Zum Transport sollten die Ständer möglichst Platz sparend auseinander genommen werden können, während der Aufbau stabil genug sein muss, auch einen Einsatz auf einer Messe mit Besuchern standzuhalten. Mit grob geschätzten 25 kg ist das Display nicht gerade ein Leichtgewicht. Nach mehreren Entwürfen brachte der ausgiebige Aufenthalt im Baumarkt eine gute Lösung. Aus der Gartenbauabteilung wurden zwei aufschraubbare Bodenhülsen und 90er-Kanthölzer (teuer, aber stabiler: Zeder anstatt Fichte) mitgenommen. Dazu zwei Bodenplatten aus 18 mm Siebdruckplatte, unter die je vier Gummifüße geschraubt sind. Mit passenden Gewindeschrauben wurden dann die Hülsen auf den Platten befestigt und das Display am vorhandenen Winkel an die Kanthölzer geschraubt. Zum Transport kann alles zerlegt werden und der Aufbau dauert nur etwa 15 Minuten. fls