Raspberry-Pi-Projekt: LED-Anzeige mit MAX7219

Prof. Jürgen Plate

Raspberry Pi: LED-Anzeige (8x8-Matrix/7-Segment) mit MAX7219

Allgemeines

Nicht immer sind LCDs als Anzeige geeignet. Sei es, dass Zahlen bei schlechten Beleuchtungsverhältnissen dargestellt werden sollen, die Anzeige aus größerer Entfernung ablesbar sein soll oder einfach Geld gespart werden soll und der Kauf eines weiteren LC-Displays nicht lohnt. Es gibt noch viele andere Gründe, die für den Einsatz von LEDs in verschiedenen Formen sprechen. Typische Vertreter der LED-Displays sind 7-Segment-Anzeigenzur Darstellung von Ziffern. Zählt man den fast imme vorhandenen Dezimalpunkt (DP) mit dazu, sind es acht Segmente pro Stelle (Digit). Andere Anzeigen arbeiten mit einer LED-Punktmatrix. Typisch sind hier 8x8- oder 7x5-Anzeigen für alphanumerische oder grafische Symbole.

Hardwareseitig werden für soche Anzeigen in der Regel viele Anschlüsse (Ports) des Mikrocontrollers gebraucht, um die einzelnen Segmente überhaupt anzusteuern. Wenn man dann noch mehr Leistung braucht, als der Port liefern kann, geht es nicht ohne Verstärker für jedes Segment ab. Etwas besser als die Einzelansteuerung funktioniert das Multiplex-Verfahren, hier werden die einzelnen Displaystellen (Digits) nacheinander angesteuert und der jeweils zum Digit dazugehörige 7-Segment-Code ausgegeben. Wären im "Direktbetrieb" für z. B. acht Digits 64 Leitungen anzusteuern (8 Digits * 7 Segmente und DP), sind es im Multiplexbetrieb nur noch acht Segmente plus acht Digits, insgesamt 16 Leitungen. Oft hat man aber nicht einmal diese zur Verfügung. Auch ist der Softwareaufwand für das Multiplexen höher. Zudem steht für jedes Digit nur noch ein Achtel der Gesamtzeit zur Verfügung, was bei gleicher Helligkeit rein rechnerisch den achtfachen Strom bei den Segmenten gegenüber der Einzelansteuerung erfordert.

Hier kommt der integrierte Baustein MAX7219 ins Spiel, der alle diese Aufgaben allein bewältigt. Ihm reichen im Prinzip drei Portleitungen, über die er alle Informationen seriell vom Mikrocontroller erhält. Die Ansteuerung von LED-Displays aller Art, nicht nur Siebensegment-Displays, sondern auch Bargraf- oder Matrix-Displays werden problemlos bedient. Der MAX7219 von Maxim dient der Ansteuerung mehrerer Matrix- oder 7-Segment-Anzeigen. Er wird über eine serielle SPI-Schnittstelle angesteuert und kann bis zu 64 LED einzeln ansteuern. Dabei ist auch eine Einstellung der Helligkeit möglich. Durch Hintereinanderschalten (kaskadieren) mehrerer MAX7219 können auch größerer Anzeigen realisiert werden. Das folgende Bild zeigt die grundsätzliche Beschaltung (Quelle: Datenblatt), wobei anstelle der Digit- und Segmentauswahl auch eine 8x8-LED-Matrix angesteuert werden kann.


Bei Verwendung von 7-Segment-Anzeigen werden solche mit gemeinsamer Kathode verwendet. Wird eine LED-Matrix angeschlossen, so erfolgt die Auswahl der Zeile (LED-Kathoden) durch die Digit-Leitungen und die Auswahl der Spalte (LED-Anoden) durch die Segment-Leitungen. Der 10-kΩ-Widerstand (Rset) bestimmt die maximale Helligkeit der Anzeige.

Neben den Anschlussleitungen dor die LEDs finden Sie noch folgende Signale am IC:

Es werden jeweils 16 Bits übertragen, wobei die acht höchstwertigen Bits die Adresse des ausgewählten Registers und die acht niedrigwertigen Bits den Wert enthalten, der in das Register übertragen werden soll. Die Daten werden immer mit der steigenden Flanke des CLK-Signal in das Schieberegister übernommen. Am Ausgang Dout (Pin 24) kann der Eingang Din (Pin 1) eines weiteren MAX7219 angeschlossen werden. Auf diese Weise können mehrere MAX7219 kaskadiert (also hintereinander geschaltet) werden. Das folgende Bild zeigt das Funktionsschma des Bausteins.

Die Konfiguration des MAX7219 und die Ansteuerung der einzelnen Digits (wahlweise 7-Segmentanzeige oder die einzelnen Leuchtdioden einer 8x8-Dot-Matrix) erfolgt mit 16 Registern. Diese sind nach folgendem Schema aufgebaut. Jedes Register besteht aus einer 8-Bit-Adresse (wobei nur die Bits D8 bis D11 eine Rolle spielen) und aus einem 8-Bit-Datenwort. Die Adresse gibt an, welches Register angesprochen werden soll. Beim Einschalten werden alle Steuerregister zurückgesetzt, die Anzeige wird ausgeschaltet und der MAX7219 geht in die Shutdown-Modus. Danack sollte die Initialisierung des MAX7219 erfolgen, damit die anschließende Anzeige korrekt funktioniert.

Die folgende Tabelle zeigt die Bedeutung der einzelnen Register. Die Digitregister werden mit einem internen 8x8 Dual-Port-SRAM realisiert. Sie sind direkt ansprechbar, weshalb einzelnen Ziffern individuell aktualisiert werden können. Die Steuerregister legen Dekodiermodus, Anzeigeintensität, Anzahl der gescannten Ziffern, Shutdown und Anzeigetest (alle LEDs an) fest.

No-Op (Adresse 00h):
Dieses Register wird verwendet, wenn mehrere MAX7219 kaskadiert werden. Beim Hintereinanderschalten werden die Datenbits durch alle ICs hindurch geschoben. Werden nur einem MAX7219 innerhalb der Kette Daten gesendet, so muss dennoch das Protokoll eingehalten werden und Daten für alle ICs in der Kette gesendet werden. Den anderen MAX7219 werden in diesem Fall die Adresse 00h (= No Operation) gesendet, damit der Anzeige unverändert bleibt.

Digit 0 bis Digit 7 (Adressen 01h bis 08h):
Auswahl der Stelle des 7-Segment-Displays bzw. der Zeile einer 8x8-Matrix.

Decode Mode (Adresse: 09h):
Dies Register setzt den BCD-Code B (Anzeige: 0-9, E, H, L, P und -) oder keine Decodieroperation für jede Ziffer. Das jeweilige Bit im Register entspricht der entsprechenden Ziffernstelle. Eine '1' wählt die Decodierung entsprechend Code B aus, eine '0' schaltet die Decodierung aus. Wird der Decodiermodus verwendet, betrachtet der Decoder nur das untere Halbbyte der Daten der Ziffer (D3 - D0), die Bits D4 - D6 werden ignoriert. Bit D7 setzt den Dezimalpunkt (SEG DP) und ist unabhängig vom Decodierungsmodus. Wenn kein Decodieren ausgewählt ist, entsprechen die Datenbits D7 - D0 den Segmentleitungen des MAX7219. Für die Ansteuerung einer Dot-Matrix-Anzeige sind die Bits (D0 - D7) dieses Registers mit '0' zu laden. Im Datenblatt finden Sie eine Tabelle der Decodierungsmuster.

Intensity (Adresse 0Ah):
Dieses Register steuert die Helligkeit der Anzeige softwaremäßig in 16 Stufen über die Bits D3 - D0, die höherwertigen Bits D4 - D6 werden ignoriert. Eine Tabelle der Helligkeitsstufen finden Sie im Datenblatt. Die digitale Steuerung der Displayhelligkeit erfolgt über einen internen Pulsbreitenmodulator. Die Helligkeit (Grundhelligkeit) kann auch hardwaremäßig per Widerstand Rset am Eingangspin Iset (Pin 18) eingestellt werden (z. B. mittels eines Fotowiderstands für eine automatische Anpassung an die Umgebungshelligkeit). Der minimale Wert beträgt 10 kΩ, was den maximalen Strom durch die LEDs auf 40 mA begrenzt. Der Spitzenstrom durch die LEDs beträgt nominal das Hundertfache des Stroms, der durch Rset fließt.

Scan Limit (Adresse 0Bh):
Mit diesem Register wird dem MAX7219 mitgeteilt wie viele Spalten die angeschlossene Anzeige besitzt. So wird verhindert, dass der MAX7219 unnötig Daten an die nicht vorhandenen Spalten ausgibt. Es werden ur die drei Bits D2 - D0 ausgewertet, die höherwertigen Bits D3 - D6 werden ignoriert. Dabei gilt 000 = Spalte 1, 001 = Spalten 1 und 2, 010 = Spalten 1 - 3 ... 111 = Spalten 1 - 8. Eine falsche Einstellung beeinträchtigt auch die Helligkeit der Anzeige.

Shutdown (Adresse 0Ch):
Mit diesem Register kann der MAX7219 ausgeschaltet werden. Dass bedeutet natürlich auch, dass keine der LEDs leuchtet. Das Bit D0 im Register 0Ch legt den Modus fest: '0' = Shutdown, '1' = Normalbetrieb. Befindet sich der MAX7219 im Shutdown-Modus, wird der Scan-Oszillator angehalten und es werden alle LEDs ausgeschaltet. Die Daten in den Digit- und Kontrollregistern bleiben unverändert. Der Shutdown kann verwendet werden, um Strom zu sparen, aber auch um das Display blinken zu lassen (indem Shutdown regelmäßig umgeschaltet wird). Normalerweise dauert es ca 250 μs, um den Shutdownmodus zu verlassen. Der MAX7219 kann im Shutdownmodus programmiert werden.

Display Test (Adresse 0Fh):
Mit diesem Register kann ein Selbsttest des MAX7219 erfolgen, d. h. alle LEDs leuchten mit der maximalen Helligkeit. Dazu muss nur das Bit D0 auf '1' gesetzt werden (Normalbetrieb: D0 = '0').

Die Kommunikation eines Mikrocontrollers mit dem MAX7219 gestaltet sich sehr einfach:

Die Zykluszeiten des MAX7219 liegen im Bereich von 25 ns bis 50 ns, so dass keine Verzögerungsschleifen in der Software notwendig sind - die SPI-Schnittstelle kann mit maximaler Geschwindigkeit betrieben werden.

Hardware

Zur Minimierung der Stromversorgungswelligkeit aufgrund von Stromspitzen des Treibers sind Blockkondensatoren notwendig: Ein 10-μF-Elektrolytkondensator und parallel einen 0,1-μF-Keramikkondensator zwischen V+ und GND so nahe am Chip wie möglich. Der MAX7219 sollte zudem in unmittelbarer Nähe der LED-Anzeige platziert und die Verbindungen so kurz wie möglich gehalten werden, um die Auswirkungen der Schaltungs-Induktivitäten und elektromagnetischer Störungen zu minimieren. Es müssen auch beide GND-Pins mit Masse verbunden sein.

Bedenken Sie auch, dass beim Betrieb mehrere kaskadierter Displays der Strombedarf gegebenenfalls einige Ampere betragen kann. Daher ist eine Versorgung des Displays aus dem Raspberry Pi (z. B. über Pin 2 oder 4) nur möglich, wenn nicht mehr als ein MAX7219 angeschlossen ist. Sondt ist die Versorgung der Displays aus einer getrennten Stromversorgung zwingend notwendig. In diesem Fall nicht vergessen, den GND-Anschluß der externen Stromversorgung mit dem GND des Raspberry Pi zu verbinden.

Um Strom zu sparen kann man bei entsprechenden Anzeigen den Widerstand Rset auch problemlos auf 33 kΩ - 56 kΩ erhöhen. Für Versuche kann man Rset zeitweilig durch die Reihenschaltung eines 10-kΩ-Widerstandes mit einem 50-kΩ-Trimmpotenziometer ersetzen, um so eine brauchbare Grundhelligkeit auszuprobieren. Beachten Sie auch die Hinweise zur maximalen Leistungsaufnahme des MAX 7219 im Datenblatt.

Rein prinzipiell könnte man sich die Anzeige mit dem MAX7219 auf einer Lochrasterplatte selbst zusammenlöten (bei speziellem Design muss man das wahrscheinlich sogar), aber fertige Platinen sind überall erhältlich (z. B. Ebay, Amazon, Adafruit, Aliexpress) und kosten fertig oft weniger, als die Einzelkomponenten beim Elektronikhändler. Die Platinen mit Siebensegment-Display sind zwar nicht waagrecht, aber vertikal nahtlos anreihbar. Die folgenden Bilder zeigen die Oberseite mit Vierfach-LED-Anzeigen und die Unterseite mit dem MAX7219 im SMD-Gehäuse. Die Platine hat auf der einen Seite die Eingangs-Stiftleiste und auf der anderen Seite eine Stiftleiste für die Kaskadierung.

Für 8x8-Matrixdisplays gibt es die LED-Matrix fix und fertig, es wird also nur noch der MAX7219 benötigt. Hier liefert der Handel zwei verschiedene Bauformen. Die folgende Variante ist mit einem Chip im DIL-Gehäuse ausgestattet. Auch hier gibt es Stiftleiste für Ein- und Ausgang. Diese Variante kann waagrecht zu LED-Zeilen kaskadiert werden (der Chip weist dann nach unten), jedoch lassen sich keine zusätzliche Spalten bilden. indem man die Platinen nicht nur horizontal, sondern auch vertikal anreiht.

Natürlich kann eine "Zeile" aus Matrix-Displays auch vertikal betrieben werden, was nur eine Frage der Sofware ist. Will man die Displays in beiden Richtungen anreihen, wählt man die Alternativ-Variante, ber der die Platine die gleichen Abmessungen hat wie die LED-Matrix. Hier kommt beim Chip auch wieder die SMD-Bauform zum Einsatz. Diese Platinen lassen sich horizontal und vertikal anreihen und auf der Rückseite verdrahten.

Im Bild oben ist ein Teilbausatz zu sehen, bei dem man die Stift- und Buchsenleisten selbst einlöten muss. Manchmal ist so etwas auch ein Trick und eine CE-Konformitätserklärung zu umgehen. Der Anbieter ist nur Bauteileliferant und der Bastler wird durch das Zusammenlöten dann zum Hersteller. Das folgende Bild zeigt, wie aus diesen Platinen eine Zeile gebildet wird. Solche fertigen Zeilen mit jeweis vier LED-Matrizen sind ebenfalls im Handel - wahlweise als Zeile (4x1) oder Quadrat (2x2). Ein Hersteller (Eckstein) bietet sogar eine 4x4-Matrix an, d. h. 32x32 LEDs.

Anstelle einer 8x8-LED-Matrix lassen sich natürlich auch andere LED-Anordnungen ansteuern, z. B. kleinere Matrizen (8x5), mehrere Bargraph-Anzeigen oder eigene LED-Anordnungen beliebigen Aussehens. Die Software erlaubt das Ein- und Ausschalten jeder eizelnen LED. Es muss lediglich bei der Verdrahtung das Prinzip einer 8x8-Matrix eingehalten werden.

Anschluss an den Raspberry Pi

Board-PinNameBemerkungRasPi-PinRasPi GPIO
1Vcc+5 V Power25 V
2GNDGround6GND
3DinData In19GPIO 10 (MOSI)
4CSChip Select24GPIO 8 (SPI CE0)
5ClkClock23GPIO 11 (SPI CLK)

Da die für SPI verwendeten GPIO-Ports mit 3,3 V arbeiten, der MAX7219 jedoch mit 5 V, sollte ein einfacher Pegelumsetzer (level shifter) an den zwischen RasPi und die DIN-, CS- und CLK-Eingänge des MAX7219 geschaltet werden, um die Pegel auf 5 V zu erhöhen. Bei meinen Versuchen, sie direkt an den 3,3-V-GPIO-Pins zu betreiben, zeigte sich aber keine negativen Effekte. Nach CMOS-Standard für 5-V-Betrieb beginnt eine logische '1' bei 3,5 V. Der Maximale Ausgangspegel des Raspberry Pi liegt mit ca. 3,2 V gerade außerhalb der Toleranz und kann eventuell zu Störungen führen. Bei auftretenden Problemen hat sich auch gezeigt, dass man gegebenefalls alle CLK-Eingänge der Displays direkt mit dem CLK-Ausgang des Raspberry Pi verbinden kann um Störungen und Laufzeiteffekte zu minimieren.

Vorbereitende Installationen

Es wird an dieser Stelle davon ausgegangen, dass SPI freigeschaltet ist (siehe auch Raspberry Pi: SPI-Schnittstelle). Standardmäßig ist der SPI-Kernel-Treiber nicht aktiviert. Sie können mit den folgenden Shell-Befehlen nachsehen, ob das SPI-Modul aktiviert ist und ob die Gerätedateien in /dev existieren (Ausgabe kursiv):

$ lsmod | grep spi
spi_bcm2835    7074  0
$ ls -l /dev/spi*
crw-rw---- 1 root users 153, 0 Sep  6  2034 /dev/spidev0.0
crw-rw---- 1 root users 153, 1 Sep  6  2034 /dev/spidev0.1
Wird nichts angezeigt, bedeutet dies, dass der Kernel-SPI-Treiber nicht geladen ist. Dann muss wie in Raspberry Pi: SPI-Schnittstelle beschrieben, SPI aktiviert und der RasPi rebootet werden.

Danach stellen Sie sicher, dass die notwendigen Standard-Bibliotheken für Python installiert sind:

sudo apt-get install python-dev python-pip
sudo pip install spidev
Die MAX7219-Bibliothek funktioniert mit Python 2 und Python 3. Für Python 3 sind die obigen Kommandos zu ersetzen durch:
sudo apt-get install python3-dev python3-pip
sudo pip3 install spidev
Die Python-Bibliothek für den MAX7219 von Richard Hull kann direkt mit dem folgenden Kommando installiert werden:
sudo pip install max7219
(Bei Python 3 muss pip3 statt pip verwendet werden.) Alternativ kann man sich die Bibliothek auch von Github holen:
git clone https://github.com/rm-hull/max7219.git
cd max7219
sudo python setup.py install
(Bei Python 3 muss python3 statt python aufgerufen werden.) Damit wäre das System bereit für erste Versuche.

Software

Die Python-Bibliothek

Die Bibliothek besteht aus nur drei Dateien:

Entsprechend übersichtlich gestalten sich die Import-Befehle in Python, wobei der Import der Fonts nur bei Bedarf erfolgen muss und auch nicht immer alle Fonts benötigt werden:
import max7219.led as led
from max7219.font import proportional, SINCLAIR_FONT, TINY_FONT, CP437_FONT

Erste Schritte

Der Einstieg in die Ansteuerung der Displays ist recht einfach, Biblithek importieren und mal einen ersten Befehl probieren, zum Beispiel für das Matrix-Display:

#!/usr/bin/env python

import max7219.led as led

matrix = led.matrix(cascaded=1)
matrix.clear()

matrix.letter(deviceId = 0, ord("A"))
Schon erscheint ein großes 'A' auf der Matrix. Als Font ist per Default der Zeichensatz CP437_FONT eingestellt. Will man einen anderen Font, mus dieser entweder beim Methodenaufruf angegeben oder per Befehl DEFAULT_FONT = ... global eingestellt werden. Ähnlich bequem geht es auch bei der Siebensegmentanzeige:
#!/usr/bin/env python

import max7219.led as led

device = led.sevensegment(cascaded=1)
device.write_number(0, 3.14159, decimalPlaces=5)
Wie schon erwähnt, unterstützt der MAX7219-Chipsatz einen seriellen 16-Bit-Puffer für Registerinhalte, der bei jeder fallenden Taktflanke am Din-Pin eingetaktet wird und auf dem Dout-Pin 16,5 Taktzyklen später ausgetaktet wird. Dadurch lassen sich mehrere Devices miteinander verketten (kaskadieren).

Bei der Initialisierung von kaskadierten Displays muss ein cascaded = ...-Parameter angegeben werden, der mitteilt, wiefile Displays hintereinandergeschaltet sind. Im Allgemeinen wird bei Methoden, die bestimmte Displays gezielt ansprechen, ein Parameter der Form deviceId = N erwartet, der von 0 aus zählt (N: 0 .. cascaded-1), z. B.:

#!/usr/bin/env python

import max7219.led as led

device = led.matrix(cascaded = 3)
device.show_message("Hello")

Im Bibliotheks-Paket sind im Unterverzeichnis /examples zwei Programme enthalten, die so ziemlich alle Features als Demo "abspielen": matrix_test.py und sevensegment_test.py. Lassen Sie diese einfach mal laufen. Einige kleinere Beispiele finden Sie weiter unten.

Bibliotheks-Methoden

Wer alle Tricks und Finessen der Bibliothek durchschaen will, kommt leider nicht um das Studieren der Qelldateien herum. Bei meinen ersten Versuchen habe ich neben den oben genannten Beispielen auch immer wieder die Quelle led.py herangezogen. Einige häufig verwendetet Methoden werden im Folgenden kurz beschrieben.

Methoden der Klasse "matrix"

brightness()
Mit dieser Methode wird die Helligkeit der LEDs eingestellt. Als Parameter wird ein Wert zwischen 0 (dunkel) und 15 (hell) übergeben. Der Inhalt der Anzeige wird dabei nicht geändert.

clear()
Löscht die gesamten Displays, keine LED leuchtet mehr. Um eine einzelne Matrix innerhalb einer Kette zu löschen, kann der Parameter deviceId = N übergeben werden.

scroll_left()
Verschiebt alle Anzeigen um eine Spalte nach links.

rotate_left()
Verschiebt alle Anzeigen um eine Spalte nach links. Die nach links "herausgeschobene" Spalte wird rechts wieder angefügt.

scroll_right()
Verschiebt alle Anzeigen um eine Spalte nach rechts.

rotate_right()
Verschiebt alle Anzeigen um eine Spalte nach rechts. Die nach rechts "herausgeschobene" Spalte wird links wieder angefügt.

scroll_up()
Verschiebt alle Anzeigen um eine Zeile nach oben.

scroll_down()
Verschiebt alle Anzeigen um eine Zeile nach unten.

invert(X)
Der Wert von X legt fest, ob die Anzeigen invertiert werden sollen oder nicht ('0' oder 'False': normal, '1' oder 'True': invertiert).

orientation(X)
Dreht die Matrix um ein Vielfaches vom 90 Gad, mögliche Werte für X sind: 0, 90, 180 oder 270.

pixel(x, y, value)
Schaltet eine einzelne LED der Matrix ein oder aus. Als Parameter werden die X-Position und die Y-Position übergeben sowie, ob die LED leuchten soll oder nicht ('0' oder 'False': aus, '1' oder 'True': an).

show_message(text)
Gibt einen Text auf der Matrix wieder, welcher sich als Laufschrift nach links über den Bildschirm bewegt. Es gibt noch zusätzliche optionale Parameter: font=... legt den gewünschten Font fest (Voreinstellung: DEFAULT_FONT), delay=... bestimmt die Scroll-Geschwindigkeit (Voreinstellung: 0.05).

letter(deviceId, code)
Diese Methode hat zwei Parameter, zuerst die Nummer der Matrix und dann den ASCII-Wert des auszugebenden Zeichens. man kann also nicht direkt das Zeichen übergeben, sondern dessen ASCII-Repräsentation (für den '@' wäre das beispielsweise der Wert 64. Es wird einfach die Funktion ord() benutzt: letter(0, ord('@')).

Die Methoden scroll_left(), scroll_left(), scroll_up(), scroll_down(), rotate_left(), rotate_left(), invert(), orientation(), pixel() und letter() besiten noch einen optionalen Parameter redraw, der per Default auf 'True' gesetzt ist. In dieser Einstellung werden die aufgerufenen Methoden sofort im Display wirksam. Setzt man dagegen redraw = False, zeigt sich auf den Anzeigen keine Änderung, diese erfolgt nur in einem internen Puffer. Erst ein Aufruf der Methode flush() schreibt den Pufferinhalt in die Anzeigen. So kann man Displayinhalte in aller Ruhe berechnen (auch, wenn's mal länger dauert) und auf einen Schalg ausgeben.

Beispiel für die Methode pixel():

#!/usr/bin/env python

import time
from random import randrange
import max7219.led as led

# create matrix device
device = led.matrix(cascaded=1)
device.brightness(7)

try:
  while True:
    # zeilenweise von links nach rechts einschalten
    device.clear()
    for y in range(8):
      for x in range(8):
        device.pixel(x, y, 1, redraw=True)
        time.sleep(0.1)

    # und wieder ausknipsen
    for y in range(8):
      for x in range(8):
        device.pixel(x, y, 0, redraw=True)
        time.sleep(0.1)

    # Dreieck zeichen und in 90-Grad-Schritten drehen
    for ori in(0,90,180,270):
      device.clear()
      device.orientation(ori)
      dat = (0,1,3,7,15,31,63,127,255)
      for y in range(1,9):
        device.set_byte(0,y,dat[y])
        time.sleep(0.1)

    # Zufallsmuster  
    device.clear()
    for cnt in range(1000):
      x = randrange(8)
      y = randrange(8)
      z = randrange(2)
      device.pixel(x, y, z, redraw=True)
      time.sleep(0.1)

except KeyboardInterrupt:
  # Bei Strg-C dunkel machen
  device.clear()
Das folgende Beispiel wiederholt das Zufallsmuster, diesmal jedoch auf zwei kaskadieren Displays:
#!/usr/bin/env python

import time
from random import randrange
import max7219.led as led

# create matrix device
device = led.matrix(cascaded=2)
device.brightness(7)

try:
  while True:
    device.clear()

    # eine LED durch alle Zeilen laufen lassen
    for y in range(8):
      for x in range(16):
        device.pixel(x, y, 1, redraw=True)
        time.sleep(0.01)
        device.pixel(x, y, 0, redraw=True)
        time.sleep(0.01)

    # Zufallsmuste
    for cnt in range(1000):
      x = randrange(16)
      y = randrange(8)
      z = randrange(2)
      device.pixel(x, y, z, redraw=True)
      time.sleep(0.02)

except KeyboardInterrupt:
  device.clear()

Es gibt noch eine Lowlevel-Methode, mit der man eine komplette Spalte setzen kann: set_byte(deviceId, y-position, value, redraw=True). Für die normale Programmierung solle aber pixel() verwendet werden. Das folgende Beispiel zeigt eine Anwendung, die ein Smiley definiert bzw. eine Funktion definiert, die ein Smiley auf der ersten Matrix ausgibt. Für die Misantropen ist alternativ noch ein "Grumpy" programmiert:

#!/usr/bin/env python

import time
from random import randrange

import max7219.led as led
from max7219.font import proportional, SINCLAIR_FONT, TINY_FONT, CP437_FONT

def smily(device):
  dat = (0,0x3C,0x52,0xA5,0xA1,0xA1,0xA5,0x52,0x3C)
  for y in range(1,9):
    device.set_byte(0,y,dat[y])

def grumpy(device):
  dat = (0,0x3C,0x62,0x95,0x91,0x91,0x95,0x62,0x3C)
  for y in range(1,9):
    device.set_byte(0,y,dat[y])

# create matrix device
device = led.matrix(cascaded=1)
device.brightness(7)

try:
  while True:
    for ori in(0,90,180,270):
      device.clear()
      device.orientation(ori)
      smily(device)
      time.sleep(2)
      grumpy(device)
      time.sleep(2)

except KeyboardInterrupt:
  device.clear()

Methoden der Klasse "sevensegment"

Die Methoden brightness(), clear(), scroll_left(), scroll_left(), scroll_up(), scroll_down(), rotate_left(), rotate_left(), orientation() und flush() sind die gleichen wie bei der oben beschriebenen Klasse "matrix". Dazu kommen spezielle Methoden für die Siebensegmentanzeige. Die Klasse bietet eine praktische Methode zum Schreiben von Zahlen auf eine bestimmte Anzeige, wahlweise oktal, dezimal oder sedezimal (hex), links- oder rechtsbündig, mit oder ohne führende Nullen. Dezimalzahlen können entweder ganze Zahlen oder Fließkommazahlen sein, die Anzahl der Dezimalstellen ist einstellbar. Für die Textausgabe ist ein rudimentärer Zeichensatz definiert. Es lassen sich aber nicht alle Buchstaben und Sonderzeichen auf einer Siebensegment-Anzeige darstellen.

show_message(text)
Gibt einen Text auf der Anzege wieder, welcher sich als Laufschrift nach links über den Bildschirm bewegt. Es gibt noch einen zusätzlichen optionalen Parameter: delay=... bestimmt die Scroll-Geschwindigkeit (Voreinstellung: 0.04)

letter(deviceId, position, char, dot=False, redraw=True)
Diese Methode hat mindestens drei Parameter, zuerst die Nummer der Matrix, als Zweites die Position auf der Anzeige. Hier wird ausgehend von 1 von rechts nach links gezählt. Der dritte Parameter enthält den auszugebenden Wert. Dabei ist die Methode so schlau, sowohl ASCII-Zahlen ('0', '1', ...) auszugeben als auch Binärwerte (0, 1, ...). Der optionale Parameter dot schaltet den Dezimalpunkt ein oder aus. Auch hier kann wieder flush() verwendet werden, wenn redraw=False gesetzt ist.

write_text(deviceId, text)
Gibt einen Text auf der Anzeige wieder, ohne zu scrollen. Als erster Parameter wird die Nummer der Anzeige und als zweiter Parameter der Text übergeben. Der Text wird linksbündig angezeigt und darf maximal acht Zeichen lang sein.

write_number(deviceId, wert, base=10, decimalPlaces=0,
zeroPad=False, leftJustify=False)

Formatiert den Wert gemäß den angegebenen Parametern und zeigt die Zahl auf der angegebenen Anzeige angezeigt. Die formatierte Zahl darf nicht länger als acht Ziffern sein. Es gibt vier optionale Parameter: base legt die Zahlenbasis fest (oktal, dezimal oder sedezimal (hex)), decimalPlaces bestimmt bei Float-Werten die Anzahl der Nachkommastellen. Wird zeroPad=True gesetzt, wird links mit führenden Nullen aufgefüllt. Bei ganzen Zahlen kann mittels leftJustify=True die Zahl auch linksbündig dargestellt werden.

Auch dazu einige Beispiele. Das erste Programm erzeugt Zufallszahlen und zeigt diese dezimal mit drei Stellen auf einem Display an, auf dem zweiten Display wird der tausendfache Wert sedezimal angezeigt:

#!/usr/bin/env python

import time
from datetime import datetime
import random

import max7219.led as led

try:
  device = led.sevensegment(cascaded=2)
  device.clear()
  while True:
    x = random.random()*10
    y = x*1000
    device.write_number(0, x, decimalPlaces=3)
    time.sleep(0.5)
    device.write_number(1, int(y), base=16, leftJustify=True)
    time.sleep(0.5)
except KeyboardInterrupt:
  device.clear()
Das folgende Programm hat auch wieder zwei kaskadierte Siebensegmentdisplays. Auf einem wird das Datum und auf dem anderen die Uhrzeit ausgegeben:
#!/usr/bin/env python

import time
from datetime import datetime

import max7219.led as led

try:
  device = led.sevensegment(cascaded=2)
  device.clear()
  while True:
    now = datetime.now()
    datestr = "%02d-%02d-%02d" % (now.day, now.month, now.year - 2000)
    device.write_text(0, datestr)
    for _ in range(3600):
      now = datetime.now()
      timestr = "%02d.%02d.%02d" % (now.hour, now.minute, now.second)
      device.write_text(1, timestr)
      time.sleep(1)
except KeyboardInterrupt:
  device.clear()
Bei Beispielen zur Siebensegmentanzeige darf natürlich ein Programm nicht fehlen, das von einem vorgegebenen Zeitpunkt einen Countdown ausführt.
#!/usr/bin/env python

import time
import max7219.led as led

try:
  hour = 1
  min = 0
  sec = 0
  device = led.sevensegment(cascaded=1)
  device.clear()

  while True:
    timestr = "%02d.%02d.%02d" % (hour, min, sec)
    device.write_text(0, timestr)
    sec = sec - 1
    if sec < 0:
      sec = 59
      min = min - 1
      if min < 0:
        min = 59
        hour = hour - 1
    if hour < 0:
      break
    time.sleep(1)
  device.clear()
  device.show_message("-boing-")

except KeyboardInterrupt:
  device.clear()

Eigene Fonts für die Marix

Weitere Fonts für die Matrix zu erstellen ist kein Hexenwerk, sondern eher eine Fleissarbeit. Für jedes Zeichen muss ein 8x8-Bitmuster erstellt werden (im Prinzip so, wie oben beim Smiley). Der Font kann dann ebenso wie die mitgelieferten Fonts eingebunden werden. Als keines Sahnehäubchen finden Sie noch den Zeichensatz des guten alten Heimcomputers C64. Der war aber nur für den Standard-ASCII-Bereich von 0x20 bis 0x7F definiert. Alle übrigen Zeichen sind mit Null vorbesetzt. Zu Kontrollausgabe kann folgendes Programm dienen (zum Download des Fonts siehe Lins am Ende der Seite):

#!/usr/bin/env python

import time
import max7219.led as led
from C64_Font import C64_FONT


# create matrix device
device = led.matrix(cascaded=1)
device.brightness(7)
DEFAULT_FONT = C64_FONT

try:
  while True:
    device.clear()
    for x in range(32,127):
      device.letter(0, x)
      # wenn C64_FONT nicht, wie oben, als Standard-Font gesetzt ist:
      # device.letter(0, x, font=C64_FONT)
      time.sleep(0.4)
except KeyboardInterrupt:
  device.clear()

Links


Copyright © Hochschule München, FK 04, Prof. Jürgen Plate und die Autoren
Letzte Aktualisierung: