Wer ein 5×7-Dot-Matrix-Display direkt von einer MCU aus ansteuern möchte, sollte sich die Arduino-Bibliothek DotMatrix5x7 anschauen. Sie ist flexibel, einfach zu benutzen, benötigt nur wenig Speicher und ermöglicht Low-Power-Maßnahmen.

Motivation

Wie ich vielleicht schon erwähnt habe, baue ich gerne Gadgets, die im Rahmen des Geocachings mit Menschen interagieren. Typischerweise muss der Geocacher eine Aufgabe ausführen, z. B. zum Gipfel eines Hügels gehen, bevor kritische Informationen wie ein numerischer Code preisgegeben werden. Diese Gadgets gibt es oft in Form eines PETlings. Die Interaktionsmöglichkeiten sind dabei sehr begrenzt. Oft gibt es eine Taste, die der Benutzer drücken kann. Manchmal besteht die einzige Form der Benutzereingabe darin, den PETling zu bewegen. Die Systemausgabe beschränkt sich auf blinkende LEDs und/oder Sieben-Segment-Anzeigen. Damit kann man einen Zahlencode oder Koordinaten anzeigen. Wie im obigen Beispiel zu sehen ist, kann man sogar einige Buchstaben anzeigen.

Und hier beginnt das Problem. Es gibt eine Empfehlung, wie Sieben-Segmentanzeigen verwendet werden sollen, um alle Buchstaben anzuzeigen. Einige der „Buchstaben“ sind jedoch nicht sehr offensichtlich und andere sind leicht mit Zahlen zu verwechseln.

In einem meiner Geocaches müssen sich die Leute drehen und dabei den PETling in der Hand halten. Wenn sie es schnell genug tun, erhalten sie den Code für ein Schloss. Andernfalls wird „Bye“ angezeigt. Die Leute wollen jedoch Zahlen sehen! Also halten sie die Röhre auf den Kopf und interpretieren die angezeigten Zeichen als 349. Das mittlere Zeichen ist definitiv keine Vier, aber vielleicht ist das ja ein Darstellungsfehler …

Displays, die sich besser für die Anzeige von Buchstaben eignen, sind Vierzehn-Segment-Displays oder Dot-Matrix-Displays. Leider gibt es keine Displays mit vierzehn Segmenten, die in einen PETling passen würden. Es gibt jedoch 5×7-Punktmatrix-Displays, die nur geringfügig größer sind als die von mir bisher verwendeten Sieben-Segment-Displays. Außerdem gibt es superhelle Typen, wie TA07-11SEKWA von Knightbright, die direkt über MCU-Pins angesteuert werden können.

LED-Punktmatrix-Anzeigen

Es gibt verschiedene Arten von LED-Dot-Matrix-Displays. Einige haben eine Größe von 8×8, andere 5×7, und manche verwenden sogar RGB-LEDs. Es gibt jedoch etwas, was sie alle gemeinsam haben. Es handelt sich um gemultiplexte Displays. Das bedeutet, dass man einen der Punkte nicht unabhängig von allen anderen ansteuern kann. Wenn man das tun wollte, würde man 36 Pins für ein 5×7-Display benötigen. Diese Displays haben jedoch nur 12 Pins. 5 Spaltenpins und 7 Zeilenpins. Unten sieht man ein Beispiel mit Spaltenanoden, d.h. alle LED-Anoden sind mit Spaltenpins verbunden.

Wenn man nun ein Zeichen mit dieser Anzeige anzeigen möchte, müssen die Zeilenpins nacheinander mit Masse verbunden werden. Während eine bestimmte Zeile aktiv ist (mit Masse verbunden), müssen die Spaltenpins, die den Punkten entsprechen, die in dieser Reihe aufleuchten sollen, mit Vcc verbunden werden (über einen Strom begrenzenden Vorwiderstand). Wenn man das schnell genug macht, indem man beispielsweise jeden Zeilenpin nur für 1 ms aktiviert, führt die Persistenz des Sehens zu dem Eindruck, dass ein Zeichen angezeigt wird, wie es im animierten GIF von Laserlicht demonstriert wird.

Man kann sich jetzt fragen, ob es möglich ist, Spaltenmultiplexing anstelle von Zeilenmultiplexing wie oben beschrieben zu verwenden. Ja, das kann man! Der Nachteil ist, dass man 7 statt 5 Widerständen benötigt und dass 7 LEDs gleichzeitig aktiv sein können, was einen potenziell größeren Strom für den aktiven Spaltenpin im Vergleich zum maximalen Strom für einen Zeilenpin beim Zeilenmultiplexen impliziert.

Ansteuern einer Punktmatrix

Die übliche Art, ein solches Display anzusteuern, ist die Verwendung eines Treiber-ICs wie MAX7921. Die MCU muss nur einige Befehle über den I2C-Bus an den IC senden und der IC übernimmt die gesamte Arbeit. Wenn man die Anzahl der ICs minimieren möchte und sowieso ungenutzte MCU-Pins hat, dann kann das Multiplexing auch von der MCU selbst durchgeführt werden. Ein Beispiel dafür ist Hacklace2. Leider ist dieses Kit nicht mehr erhältlich.

Die Verdrahtung einer MCU zur Ansteuerung eines 5×7-Punktmatrix-Displays ist unkompliziert. Man verbindet die 7 Zeilenpins direkt mit 7 MCU-Pins und die 5 Spaltenpins über Vorwiderstände mit MCU-Pins.

Was ist nun ein guter Wert für den Vorwiderstand? Es hängt alles davon ab, welche MCU verwendet wird, welche Versorgungsspannung man hat und wie hell das Display erscheinen soll.

Nehmen wir als Beispiel das superhelle Display TA07-11SEKWA und einen ATtiny1634 mit einer Versorgungsspannung von 3,6 Volt. 3 bis 4 mA für jede LED sollte ausreichend sein, auch wenn jede LED nur für 1/7 der Zeit mit Strom versorgt wird (wegen des Zeilenmultiplexen). Werfen wir einen Blick auf die Ausgangsspannung vs. Ausgangs- und Eingangsstromdiagramme bei 3 Volt Vcc.

Ausgangsspannung bei Vcc = 3 V

Es sieht also so aus, als ob man bis zu 2 mA Eingangs- und Ausgangsstrom einfach 100 mV von oder zur Ausgangsspannung subtrahieren bzw. addieren kann. Bei höheren Strömen sieht es so aus, als könne man die Kurve approximieren, indem man von einem Widerstand von jeweils etwa 50 Ω (für den Eingangspin und für den Ausgangspin) ausgeht. Der Durchlassstrom jeder LED beträgt 2 Volt und die Versorgungsspannung einer 3,6 Volt Batterie sinkt um 0,1 Volt, wenn etwa 10 mA gezogen werden. Wir benötigen also einen Spannungsabfall von 1,5 Volt über unserem Serienwiderstand (einschließlich der virtuellen Eingangs- und Ausgangswiderstände).

Nehmen wir einen Widerstand von 330 Ω an, der zusammen mit den virtuellen Widerständen sich zu 430 Ω aufaddiert. 1,5 V / 430 Ω = 3,5 mA pro LED. Man beachte, dass, wenn alle fünf LEDs einer Zeile leuchten, der Eingangsstrom 17,5 mA beträgt. Wie im Datenblatt angegeben, übertrifft dies die Testbedingungen (und kann aus diesem Grund niedriger sein), liegt aber deutlich unter dem maximal erlaubten Strom von 40 mA pro Pin.

Jetzt muss man einfach nur noch die richtigen Pins auf 1 oder 0 setzen, um ein Zeichen mit Zeilenmultiplexen anzuzeigen. Ein Beispiel dafür findet man auf dem Arduino-Spielplatz. Was man jedoch wirklich will, ist eine Bibliothek, die alle Details verbirgt und einem viel Flexibilität bietet. Dafür habe ich die DotMatrix5x7-Bibliothek erstellt, die man aus dem GitHub-Repository herunterladen oder mit dem Bibliotheksmanager von Arduino laden kann.

DotMatrix5x7-Bibliothek

Die DotMatrix5x7-Bibliothek implementiert das Multiplexing Interrupt-gesteuert, d.h. nach dem Aufruf einer Anzeigemethode wird die Auswahl von Zeilen und Spalten sowie das Timing durch Timer-Interrupts übernommen. Zu diesem Zweck wird standardmäßig Timer1 verwendet (der dann nicht für andere Zwecke wie PWM-Ausgang, Servosteuerung oder Tonerzeugung verwendet werden kann). Alternativ kann man die Kompilierzeitkonstante USETIMER0 in DotMatrix5x7.h definieren. In diesem Fall wird Timer0 (derjenige Timer, der für millis() und delay() zuständig ist) eingesetzt. Der Trick, den die Bibliothek hier verwendet, besteht darin, den TIMER0_COMPA-Interrupt zu nutzen, wie es in einem Adafruit-Tutorial zu Timer-Interrupts erläutert wird. Der einzige Nachteil ist, dass die Interruptfrequenz auf 1 kHz für 16 MHz Taktfrequenz, 500 Hz für 8 MHz, 250 Hz für 4 MHz usw. festgelegt ist. Da man mindestens einen Interrupt pro 2 ms benötigt, um ein flackerndes Display zu vermeiden, muss die MCU mit mindestens 8 MHz laufen.

Die Anzeige kann auf verschiedene Arten konfiguriert werden und es ist möglich, entweder einzelne Zeichen oder ganze Zeichenfolgen anzuzeigen. Dabei können die Zeichen gescrollt werden. Im ersten Fall, bei der Anzeige einzelner Zeichen, ruft man die Anzeigemethode auf und dann wird das entsprechende Zeichen angezeigt, bis der nächste Aufruf erfolgt. Im letzteren Fall werden eine Zeichenfolge und Verzögerungszeiten als Parameter angegeben, wenn die Anzeigemethode aufgerufen wird. Um beim Warten auf das Scrollen etwas Nützliches zu tun (oder um idledelay zu implementieren), kann der Benutzer eine eigene delay-Funktion bereitstellen. Übrigens kann die Zeichenfolge entweder ein gewöhnliches Zeichenarray, eine PROGMEM-Zeichenfolge oder eine Zeichenfolge sein, die in einem F(…) -Makroaufruf eingebettet ist.

Anwendungs-Beispiele

Wenn man ein einzelnes Zeichen c anzeigen möchte, ruft man Dot5x7.show(c) auf. Ein String kann wie folgt angezeigt werden: Dot5x7.showString("Hello World!", 500, 100). Dadurch wird die Zeichenfolge „Hello World!“ angezeigt, wobei jedes Zeichen für 500 ms und eine Pause von 100 ms zwischen den Zeichen angezeigt wird. Man kann auch die F(...)- Notation verwenden, um eine Zeichenfolge zu übergeben, die im Flash-Speicher gespeichert ist, d.h. Dot5x7.showString(F("Hello World!"), 500, 100). Darüber hinaus kann man einen in Flash gespeicherten String (der mit PROGMEM definiert wurde) mit der _P-Variante der Methode übergeben: Dot5x7.showString_P(str, 500, 100), vorausgesetzt, str wurde als const char PROGMEM str[] = "Hello World!"; definiert.

Darüber hinaus gibt es Methoden, die eine Zeichenfolge durch die Anzeige scrollen. Das Scrollen kann vertikal nach oben oder unten oder horizontal nach links oder rechts erfolgen. Zum Beispiel kann man die Zeichenfolge „Hello World“ scrollen, indem man Dot5x7.scrollLeftString("Hello World!", 300, 50, 1) aufruft. Dadurch wird die Zeichenfolge nach links gescrollt, wobei jedes Zeichen für 300 ms in der Mitte der Anzeige angezeigt wird und 50 ms für jeden Schaltschritt verwendet wird. Das letzte Argument von 1 bedeutet, dass eine leere Spalte zwischen zwei aufeinanderfolgenden Zeichen verwendet wird. Es gibt auch Methoden zum Scrollen nach rechts, oben oder unten. Weiterhin kann man natürlich die F()- Notation verwenden und es gibt auch die _P Varianten der Methoden.

Konfiguration

Die Zeilen- und Spaltenpins können beim Aufruf der begin-Methode angegeben werden. Darüber hinaus kann man die Polarität angeben, wann die Zeilen- bzw. Spaltenpins aktiv sind. Standardmäßig sind Zeilenpins aktiv LOW und Spaltenpins sind aktiv HIGH. Dies entspricht dem Ansteuern einer Spaltenanodenanzeige direkt von den MCU-Pins.

Darüber hinaus gibt es einige Methoden, die die Schnittstelle steuern:

  • setUpsideDown(bool enable) steuert, ob die Zeichen verkehrt herum angezeigt werden.
  • setFont(const byte *f) kann verwendet werden, um einen alternativen Font auszuwählen. Ohne Argument wird auf den Standardfont zurückgeschaltet.
  • setFramesPerSecond(int fps) wird verwendet, um zu steuern, wie oft eine vollständige Matrix angezeigt wird. Der Standardwert ist 50 und man sollte keine Werte unter 42 auswählen. Dies ist nur wirksam, wenn Timer1 verwendet wird.
  • setBlinkFrames(int blinkon, int blinkoff) steuert das Blinken, indem es die Anzahl der Frames angibt, in denen das Zeichen angezeigt wird, und die Anzahl der Frames, wenn die Anzeige ausgeschaltet ist. Wenn einer der Werte 0 ist, wird nicht geblinkt.
  • mit setDelayFunction(void (*f) (long unsigned int)) kann eine benutzerdefinierte delay-Funktion angegeben werden, die verwendet werden soll, wenn die Methoden showString und scrollXXXString verwendet werden. Dies kann verwendet werden, um den Stromverbrauch zu minimieren oder mit Peripheriegeräten zu kommunizieren.
  • sleep() deaktiviert den Timer-Interrupt und schaltet alle LEDs aus.
  • wakeup() startet Timer-Interrupts neu.

Schließlich gibt es die Kompilierzeitoption USETIMER0, die, wenn sie in DotMatrix5x7.h definiert ist, dazu führt, dass Timer0 (der Timer für millis() und delay(...)) anstelle von Timer1 verwendet wird, wie oben beschrieben.

Beispiel

Betrachten wir ein kleines Beispiel.

// Simple sketch to display a character and a string
#include <DotMatrix5x7.h>

void setup()
{
    Dot5x7.begin(0, 1, 2, 3, 4,         // column pins
	         5, 6, 7, 8, 9, 10, 11, // row pins
	         LOW,                   // value when row pin active
		 HIGH);                 // value when column pin active
    Dot5x7.setFramesPerSecond(50);      // display 50 frames per
                                        // second (default value)
}	 

void loop()
{

    Dot5x7.scrollLeftString(F("Hello World!"), 300, 50, 1);
                                          // scroll string to the left
                                          // 300 ms static display of char
                                          // 50 ms for one scroll step
                                          // 1 empty column between chars
    delay(2000);
}

Dies würde dann zu einer Ausgabe wie im folgenden Video führen.

Views: 12