HDSP-211x-Displays verwenden

Etwa 2013 habe ich mehrere Display-Module Avago HDSP-2112 gebraucht gekauft. Es hat allerdings bis 2021 gedauert, bis ich einen Prototyp für die Ansteuerung mit einem alten Raspberry Pi umgesetzt habe. Das besondere an diesen Modulen ist die Technologie: die Module sind für einen DIL-28-Sockel im Rastermaß von 2,54 mm geeignet und enthalten acht Zeichen mit einer Matrix aus je 5×7 LEDs, die insgesamt nur etwa 5 mm hoch ist. Mehrere Module können auch direkt nebeneinander montiert werden, um längere Textzeilen aufzubauen. Neben diesem Modell gibt es auch noch andere Farben:

  • HDSP-2110: Orange
  • HDSP-2111: Gelb
  • HDSP-2112: Rot (High Efficiency)
  • HDSP-2113: Grün

Etwas größere Zeichen mit etwa 7 mm Höhe bieten die Modulen der Serie HDSP-250x. Abgesehen von den Abmessungen sind diese Module ansonsten Pin-kompatibel und identisch in der Funktion. Daneben gibt es auch noch eine Variante HDSP-253x, die ein etwas kompakteres Gehäuse haben und eine ähnliche Pin-Belegung, passend zu einem schmaleren DIL-30-Layout. Die Ansteuerung ist bei HDSP-253x aber identisch zu den anderen Modellen.

Die nachfolgenden Informationen basieren auf den Angaben aus der Dokumentation, die ich als PDF bei RS Components gefunden habe. Nach dem Zusammenschluss von Avago und Broadcom werden die Module von Broadcom produziert, wo man auch eine Dokumentation findet: Produktinformation Broadcom HDSP-2112.

Technische Daten

Die Betriebsspannung beträgt +5 Volt und das Modul arbeitet mit TTL-Pegeln. Eingangsspannungen unter 0,8 Volt werden als „Low“ oder „0“ interpretiert, Pegel über 2,4 Volt als „High“ bzw. „1“. Damit ist auch die Ansteuerung mit den GPIO-Ausgängen eines Raspberry Pi oder Arduino bzw. Atmel AVR kein Problem.

Abhängig von der Anzahl der gleichzeitig leuchtenden LEDs liegt der Strombedarf in einer Größenordnung um 400 mA (430 mA bei 160 leuchtenden LEDs) was bei 5 Volt etwa 2 Watt entspricht.

Weitere Technische Angaben:

  • Taktfrequenz des Controllers: 57 kHz (minimal 28 kHz)
  • Aktualisierungsfrequenz des Displays: 256 Hz (minimal 128 Hz)
  • Blinkfrequenz für blinkende Zeichen: Controller-Takfrequenz geteilt durch 28672, normalerweise etwa 2 Hz (minimal 1 Hz)

Gehäuse und Anschlussbelegung

Das Modul kann in einen DIL-28-Sockel eingesetzt werden. Die Position von Pin 1 ist durch eine schräge Ecke gekennzeichnet. Zusätzlich fehlen zwei Pins in der oberen Reihe. Mehrere Displaymodule können auch direkt nebeneinander gesetzt werden, um eine längere Textzeile darzustellen.

HDSP-211x Layout

Pin Funktion Pin Funktion
1 RST 28 D7
2 FL 27 D6
3 A0 26 D5
4 A1 25 D4
5 A2 24 D3
6 A3 23 D2
7 N.C. 22
8 N.C. 21
9 N.C. 20 D1
10 A4 19 D0
11 CLS 18 RD
12 CLK 17 CE
13 WR 16 GND (logic)
14 VDD 15 GND (supply)

Beschreibung der Pins

In der nachfolgenden Beschreibung wird statt „Low“ und „High“ jeweils 0 und 1 verwendet.

Pin Funktion Beschreibung
1 RST
(Reset)
Ist dieser Eingang auf 0, wird das Modul zurückgesetzt.
11 CLS
(Clock Select)
Ist dieser Eingang  1, wird der Takt für den Controller intern erzeugt und am CLK ausgegeben.

Ist dieser Eingang 0, wird ein Taktsignal an CLK erwartet. Dies kann genutzt werden, um bei der Verwendung mehrerer Module gleichzeitig das Taktsignal von einem Hauptmodul zu übernehmen.

12 CLK
(Clock)
Abhhängig vom Signal an CLS dient dieser Anschluss entweder als Ausgang des Controller-Taktsignals oder als Eingang.
17 CE
(Chip Enable)
Dieser Eingang muss auf 0 sein, um das Modul generell ansprechen zu können. Ist CE auf 1, werden Schreib- oder Leseoperationen ignoriert.

Das kann dazu genutzt werden, um mehrere Module an einem gemeinsamen Adress- und Datenbus zu betreiben. Es darf dann jeweils  nur ein Modul mit CE aktiviert werden.

13 WR
(Write)
Ist dieser Eingang 0, werden die Daten auf D0-D7 an die Adresse geschrieben, die an A0-A5 angegeben ist.

WR darf nicht gemeinsam mit RD 0 sein, das führt zu einem undefinierten Verhalten.

18 RD
(Read)
Ist dieser Eingang 0, werden auf D0-D7 die Daten der Adresse ausgegeben, die mit A0-A5 angegeben ist.

RD darf nicht gemeinsam mit WR 0 sein, das führt zu einem undefinierten Verhalten.

2 FL
(Flash)
Ist dieser Eingang auf 0 kann das „Flash RAM“ beschrieben werden. Die Adressen A0-A2 geben die Position des Zeichens an, dass beschrieben wird. Mit D0 gibt man an, ob das Zeichen blinken soll (1) oder nicht (0). D1-D7 und A4/A5 werden dann ignoriert.

Um Texte auszugeben oder benutzerdefinierte Zeichen zu schreiben, muss FL auf 1 sein.

3-6, 10 A0-A4 Adressbus als Eingang für das Schreiben und Lesen von Daten.

Die Adressen geben zusammen mit FL an, auf welchen Teil des Speichers man zugreifen möchte („-“ bedeutet „wird ignoriert“):

Speicherbereich FL A4 A3 A2-A0
Flash RAM 0 Zeichenposition
UDC-Adresse 1 0 0
UDC-RAM 1 0 1 Zeilennummer
Control Word Register 1 1 0
Character RAM 1 1 1 Zeichenposition
19-20, 23-28 D0-D7 Datenbus als Eingang für das schreiben (WR auf 0 und RD auf 1) bzw. Ausgang für das lesen von Daten (WR auf 1 und RD auf 0).

Ansteuerung

Die grundsätzliche Vorgehensweise für das Schreiben von Daten in das Display ist wie folgt:

  1. WR auf 1 setzen.
  2. RD auf 1 setzen (wenn man generell nur schreiben will, kann man diesen Eingang auch  dauerhaft mit VDD verbinden).
  3. CE auf 0 setzen um das Modul zu aktivieren (wenn man nur ein Modul betreibt, kann man diesen Eingang auch dauerhaft mit GND verbinden).
  4. FL, A0-A4 und D0-D7 nach Bedarf setzen.
  5. WR kurz auf 0 setzen, damit die Daten übernommen werden, dann WR wieder auf 1 setzen.

Die genauen Timing-Vorgaben kann man der Dokumentation des Herstellers entnehmen.

Als grobe Orientierung: nach Aktivierung des Moduls mit CE muss eine Pause von 160 ns eingehalten werden, bevor man Daten mit WR schreibt. Das Schreiben von Daten dauert mindesten 100 ns und danach ist Pause mit mindestens 20 ns erforderlich, bevor erneut Daten geschrieben werden können. Ich habe auf einem Raspberry Pi mit einem Python-Script zum testen eine feste Pause von 0,0001 Sekunden verwendet und damit keine Probleme gehabt.

Ausgabe von Text (Character RAM)

Für die Ausgabe von Text muss FL auf 1 gesetzt sein, da man sonst das „Flash RAM“ beschreibt. Die Position des auszugebenden Zeichens wird über die Adresse A0-A2 angegeben, A3 und A4 müssen auf 1 sein. Mit D0-D7 gibt man den Code des zu schreibenden Zeichens an und führt den Schreibvorgang aus.

CE FL RD WR A4 A3 A2 A1 A0 D7 D6 D5 D4 D3 D2 D1 D0
1 0 1 1 1 1 1 1/0 1/0 1/0 1/0 1/0 1/0 1/0 1/0 1/0 1/0 1/0
2 0 1 1 0 1 1 1/0 1/0 1/0 1/0 1/0 1/0 1/0 1/0 1/0 1/0 1/0
3 0 1 1 1 1 1 1/0 1/0 1/0 1/0 1/0 1/0 1/0 1/0 1/0 1/0 1/0

Der Zeichencode ist wie folgt definiert: 0-31 (0x00-0x1f) sind Sonderzeichen, 32-127 (0x20-0x7f) entsprechen ASCII, 128-143 (0x80-0x8f) wählt eines von 16 benutzerdefinierten Zeichen und die Werte 144-255 (0x90-0xff) sind nicht definiert.

D0-D3 →
D4-D7 ↓
0 1 2 3 4 5 6 7 8 9 A B C D E F
0 ¿ ñ Ñ α β γ η θ λ μ π σ Σ
1 Τ Φ Ω Å å Ä ä Ö ö Ü ü ² £ ¥
2 ! # $ % & ( ) * + , . /
3 0 1 2 3 4 5 6 7 8 9 : ; < = > ?
4 @ A B C D E F G H I J K L M N O
5 P Q R S T U V W X Y Z [ \ ] _
6 ` a b c d e f g h i j k l m n o
7 p q r s t u v w x y z { | } ~
8

Blinken einzelner Zeichen steuern (Flash RAM)

Wird FL auf 0 gesetzt, beschreibt man mit A0-A2 und D0 das „Flash RAM“. Damit können einzelne Zeichen auf dem Display blinkend angezeigt werden. A0-A2 gibt die Zeichenposition (0-7) an und D0, ob das Zeichen blinken soll (1) oder nicht (0). Die übrigen Adress- und Datenleitungen werden ignoriert.

CE FL RD WR A4 A3 A2 A1 A0 D7 D6 D5 D4 D3 D2 D1 D0
1 0 0 1 1 1/0 1/0 1/0 1/0
2 0 0 1 0 1/0 1/0 1/0 1/0
3 0 0 1 1 1/0 1/0 1/0 1/0

Benutzerdefinierte Zeichen (User Defined Character) schreiben (UDC RAM)

Für das Schreiben benutzerdefinierter Zeichen gibt man zuerst an, welches Zeichen beschrieben werden soll. Dazu setzt man FL auf 1,  A3 und A4 auf 0. Mit D0-D3 das zu beschreibende Zeichen (0-15) an. Die übrigen Adress- und Datenleitungen werden ignoriert.

CE FL RD WR A4 A3 A2 A1 A0 D7 D6 D5 D4 D3 D2 D1 D0
1 0 1 1 1 0 0 1/0 1/0 1/0 1/0
2 0 1 1 0 0 0 1/0 1/0 1/0 1/0
3 0 1 1 1 0 0 1/0 1/0 1/0 1/0

Nach diesem Schreibzugriff kann man den Inhalt des Zeichens beschreiben, indem man A3 auf 1 und A4 auf 0 setzt. A0-A2 geben die Zeile der Zeichenmatrix an, D0-D4 das Bitmuster für diese Zeile. D5-D7 werden ignoriert, da die Zeichen nur 5 Pixel breit sind.

CE FL RD WR A4 A3 A2 A1 A0 D7 D6 D5 D4 D3 D2 D1 D0
1 0 1 1 1 0 1 1/0 1/0 1/0 1/0 1/0 1/0 1/0 1/0
2 0 1 1 0 0 1 1/0 1/0 1/0 1/0 1/0 1/0 1/0 1/0
3 0 1 1 1 0 1 1/0 1/0 1/0 1/0 1/0 1/0 1/0 1/0

Display-Einstellungen über das „Control Word Register“ ändern

Das Display hat verschiedene Einstellungen, die man nach Bedarf ändern kann. Dazu wird FL auf 1 gesetzt, A3 und 0 und A4 auf 1. Die übrigen Adressleitungen werden ignoriert.

CE FL RD WR A4 A3 A2 A1 A0 D7 D6 D5 D4 D3 D2 D1 D0
1 0 1 1 1 1 0 1/0 1/0 1/0 1/0 1/0 1/0 1/0
2 0 1 1 0 1 0 1/0 1/0 1/0 1/0 1/0 1/0 1/0
3 0 1 1 1 1 0 1/0 1/0 1/0 1/0 1/0 1/0 1/0

Das „Control Word Register“ wird dann über D0-D7 wie folgt beschrieben:

Bits Funktion
D0-D2 Display-Helligkeit:

000: 100%
001: 80%
010: 53%
011: 40%
100: 27%
101: 20%
110: 13%
111: 0%

D3 0: Flash nicht aktiv.
1: Flash aktiv, d.h. die im Flash-RAM angegebene Zeichenpositionen blinken.
D4 0: Blinken nicht aktiv.
1: Blinken aktiv, das gesamte Display blinkt.
D5 Ohne Funktion beim schreiben.

Beim lesen gibt es das Ergebnis des Selbsttest aus:

0: Selbsttest fehlerhaft
1: Selbsttest OK

D6 0: Normalbetrieb
1: Selbsttest starten, das Ergebnis wird dann in D5 zurückgemeldet
D7 0: Normalbetrieb
1: Inhalt des Character-RAM und Flash-RAM löschen.

Testaufbau mit einem Raspberry Pi

Um zu testen, ob meine alten Displays noch funktionieren, habe einen Testaufbau mit einem Raspberry Pi auf einem „Dish“ von Adafruit gemacht.

Wichtig: der Eingang RD des Displays sollte dauerhaft mit +5 V verbunden sein, damit das Modul die Datenleitungen D0-D7 nur als Eingang nutzt! Anderenfalls könnten die GPIO-Anschlüsse des Raspbery Pi beschädigt werden!

Nachfolgend ist als Einstieg die Ansteuerung eines einzelnen Displays beschrieben. Weiter unten habe ich das erweitert auf mehrere Displays.

HDSP-2112, Test mit Raspberry Pi

Die Ansteuerung erfolgt mit einem Python-Script. Dazu muss man sicherstellen, dass alle GPIO-Pins als Ausgänge nutzbar sind, d.h. ggf. sollte man mit raspi-config alle Interface-Optionen wie SPI, I2C und die serielle Schnittstelle ausschalten, bevor man das Script started.

Das Modul wurde wie folgt verkabelt:

Pin Funktion Anschluss Pin Funktion Anschluss
1 RST siehe Text 28 D7 GPIO 9
2 FL +5V 27 D6 GPIO 10
3 A0 GPIO 7 26 D5 GPIO 22
4 A1 GPIO 8 25 D4 GPIO 27
5 A2 GPIO 25 24 D3 GPIO 17
6 A3 GPIO 24 23 D2 GPIO 4
7 N.C. 22
8 N.C. 21
9 N.C. 20 D1 GPIO 3
10 A4 GPIO 23 19 D0 GPIO 2
11 CLS +5 V 18 RD +5 V
12 CLK 17 CE GND
13 WR GPIO 15 16 GND (logic) GND
14 VDD +5 V 15 GND (supply) GND

Reset-Schaltung

Um dass Modul beim Einschalten in einen definierten Zustand zu versetzen, wurde ein R/C-Glied eingebaut: ein Kondenstator mit 220 nF von RST zu GND, ein Widerstand mit 100k von RST an +5 V und eine Diode parallel zum Widerstand mit der Kathode an +5 V, damit sich der der Kondensator schneller entlädt, wenn die Spannungsversorgung abgeschaltet wird:

HDSP-2112, R/C-Schaltung für Reset

Die Anschlussbelegung ist im nachfolgende Python-Script am Anfang definiert und muss ggf. angepasst werden, wenn man nicht die obige Verkabelung verwendet. Das Script demonstriert folgende Schritte:

  1. Initialisierung der GPIO-Ports.
  2. Reduzieren der Display-Helligkeit auf auf 13%.
  3. Definition von zwei eigenen Zeichen (UDC).
  4. Ausgabe des Textes „Hello“ gefolgt von einem Smiley, der als eigenes Zeichen erzeugt wurde.
  5. Ausgabe eines scrollenden Textes mit einem weiteren selbstdefinierten Zeichen.

Der Code dient nur zur Demonstrationszwecken und kann für eigene Anwendungen beliebig genutzt werden.

Update 2021-05-22:

Die Funktion io_init() hat WR nicht auf 1 gesetzt, was zu undefiniertem Verhalten beim ersten Schreibzugriff führen kann. Ich habe das korrigiert – damit funktioniert jetzt die Einstrellung der Display-Helligkeit mit nur einem Aufruf nach dem Einschalten des Displays.

In der Funktion hdsp_send_text() war ursprünglich noch die unnötige Ausgabe von acht Leerzeichen zum Löschen des Displays vor der Ausgabe des eigentlichen Textes enthalten, was zu einer flimmernden Ausgabe geführt hat. Das habe ich entfernt, da die Funktion ohnehin den Text immer auf acht Zeichen erweitert und ggf. Leerzeichen anhängt, wenn nötig.

#!/usr/bin/python

# Testing a HDSP-2112 display with a Raspberry Pi
# An example by Arno Welzel (https://arnowelzel.de)
# 
# Prerequisites:
# 
# Make sure, all GPIO pins are usable as outputs.
# If needed disable SPI, IC2, UART etc. in raspi-config first.
# 
# The following pin numbers are BMC based, change if needed.

import time
import RPi.GPIO as GPIO

HDSP_WR = 15
HDSP_A0 = 7
HDSP_A1 = 8
HDSP_A2 = 25
HDSP_A3 = 24
HDSP_A4 = 23
HDSP_D0 = 2
HDSP_D1 = 3
HDSP_D2 = 4
HDSP_D3 = 17
HDSP_D4 = 27
HDSP_D5 = 22
HDSP_D6 = 10
HDSP_D7 = 9

E_PULSE = 0.0001

def io_init():
    GPIO.setmode(GPIO.BCM)
    GPIO.setwarnings(False)
    GPIO.setup(HDSP_WR, GPIO.OUT)
    GPIO.setup(HDSP_A0, GPIO.OUT)
    GPIO.setup(HDSP_A1, GPIO.OUT)
    GPIO.setup(HDSP_A2, GPIO.OUT)
    GPIO.setup(HDSP_A3, GPIO.OUT)
    GPIO.setup(HDSP_A4, GPIO.OUT)
    GPIO.setup(HDSP_D0, GPIO.OUT)
    GPIO.setup(HDSP_D1, GPIO.OUT)
    GPIO.setup(HDSP_D2, GPIO.OUT)
    GPIO.setup(HDSP_D3, GPIO.OUT)
    GPIO.setup(HDSP_D4, GPIO.OUT)
    GPIO.setup(HDSP_D5, GPIO.OUT)
    GPIO.setup(HDSP_D6, GPIO.OUT)
    GPIO.setup(HDSP_D7, GPIO.OUT)
    GPIO.output(HDSP_WR, GPIO.HIGH)
    
def hdsp_send_byte(data, adr):
    GPIO.output(HDSP_D0, GPIO.LOW)
    GPIO.output(HDSP_D1, GPIO.LOW)
    GPIO.output(HDSP_D2, GPIO.LOW)
    GPIO.output(HDSP_D3, GPIO.LOW)
    GPIO.output(HDSP_D4, GPIO.LOW)
    GPIO.output(HDSP_D5, GPIO.LOW)
    GPIO.output(HDSP_D6, GPIO.LOW)
    GPIO.output(HDSP_D7, GPIO.LOW)
    GPIO.output(HDSP_A0, GPIO.LOW)
    GPIO.output(HDSP_A1, GPIO.LOW)
    GPIO.output(HDSP_A2, GPIO.LOW)
    GPIO.output(HDSP_A3, GPIO.LOW)
    GPIO.output(HDSP_A4, GPIO.LOW)
    
    if data & 0x01 == 0x01:
        GPIO.output(HDSP_D0, GPIO.HIGH)
    if data & 0x02 == 0x02:
        GPIO.output(HDSP_D1, GPIO.HIGH)
    if data & 0x04 == 0x04:
        GPIO.output(HDSP_D2, GPIO.HIGH)
    if data & 0x08 == 0x08:
        GPIO.output(HDSP_D3, GPIO.HIGH)
    if data & 0x10 == 0x10:
        GPIO.output(HDSP_D4, GPIO.HIGH)
    if data & 0x20 == 0x20:
        GPIO.output(HDSP_D5, GPIO.HIGH)
    if data & 0x40 == 0x40:
        GPIO.output(HDSP_D6, GPIO.HIGH)
    if data & 0x80 == 0x80:
        GPIO.output(HDSP_D7, GPIO.HIGH)
    if adr & 0x01 == 0x01:
        GPIO.output(HDSP_A0, GPIO.HIGH)
    if adr & 0x02 == 0x02:
        GPIO.output(HDSP_A1, GPIO.HIGH)
    if adr & 0x04 == 0x04:
        GPIO.output(HDSP_A2, GPIO.HIGH)
    if adr & 0x08 == 0x08:
        GPIO.output(HDSP_A3, GPIO.HIGH)
    if adr & 0x10 == 0x10:
        GPIO.output(HDSP_A4, GPIO.HIGH)
    
    time.sleep(E_PULSE)
    GPIO.output(HDSP_WR, GPIO.LOW)
    time.sleep(E_PULSE)
    GPIO.output(HDSP_WR, GPIO.HIGH)

def hdsp_send_text(text):
    text = text.ljust(8,' ')
    for i in range(8):
        hdsp_send_byte(ord(text[i]), 0x18+i)

def hdsp_scroll_text(text):
    text = '        '+text+'        '
    for i in range(len(text)-7):
        hdsp_send_text(text[i:i+8])
        time.sleep(0.25)

def hdsp_send_udc(character, matrix):
    hdsp_send_byte(character, 0x00)
    adr = 0x08
    for line in matrix:
        byte = 0
        bit = 0x10
        for pos in range(5):
            if line[pos:pos+1] == '*':
                byte = byte | bit
            bit >>= 1
        hdsp_send_byte(byte, adr)
        adr += 1

if __name__ == '__main__':
    # initialize GPIOs
    io_init()
    # set brightness to 13%
    hdsp_send_byte(0x06,0x10);
    hdsp_send_byte(0x06,0x10);
    # Define custom characters
    hdsp_send_udc(
        0, [
            '*...*',
            '.....',
            '..*..',
            '..*..',
            '.....',
            '*...*',
            '.***.'])
    hdsp_send_udc(
        1, [
            '..***',
            '..***',
            '..**.',
            '..**.',
            '.....',
            '..**.',
            '..**.'])
    # do some stuff
    hdsp_send_text('Hello '+str(b'\x80'))
    time.sleep(4)
    hdsp_scroll_text('Scrolling text and custom characters '+str(b'\x81')+str(b'\x81')+str(b'\x81'))

Mehrere Displays ansteuern

Am Raspberry Pi 1 sind nach dem obigen Aufbau noch zwei GPIO-Ports frei, die ich dazu genutzt habe, zwei Displays parallel anzusteuern. Dazu werden alle Daten- und Adressleitungen und die Reset-Schaltung parallel an beide Displays angeschlossen. CE wird nicht mehr mit GND verbunden, sondern jeweils an einen eigenen GPIO-Port, damit man sie getrennt voneinander ansteuern kann. Empfehlenswert ist auch, dass bei einem Display der CLS-Eingang auf GND gelegt wird und der CLK-Anschlüsse beider Displays verbunden werden. Damit ist der Takt beider Displays synchron.

Die erweiterte Verkabelung im Detail:

Pin Funktion Display 1 Display 2 Pin Funktion Display 1 Display 2
1 RST siehe Text 28 D7 GPIO 9 GPIO 9
2 FL +5V +5V 27 D6 GPIO 10 GPIO 10
3 A0 GPIO 7 GPIO 7 26 D5 GPIO 22 GPIO 22
4 A1 GPIO 8 GPIO 8 25 D4 GPIO 27 GPIO 27
5 A2 GPIO 25 GPIO 25 24 D3 GPIO 17 GPIO 17
6 A3 GPIO 24 GPIO 24 23 D2 GPIO 4 GPIO 4
7 N.C. 22
8 N.C. 21
9 N.C. 20 D1 GPIO 3 GPIO 3
10 A4 GPIO 23 GPIO 23 19 D0 GPIO 2 GPIO 2
11 CLS GND +5 V 18 RD +5 V +5 V
12 CLK CLK Display 2 CLK Display 1 17 CE GPIO 18 GPIO 11
13 WR GPIO 15 GPIO 15 16 GND (logic) GND GND
14 VDD +5 V +5 V 15 GND (supply) GND GND

Für die Verkabelung habe ich jetzt feste Drähte verwendet, damit der Aufbau weniger fragil ist und die Kabel flach verlegt werden können:

HDSP-2112, Test mit zwei Diaplays und Raspberry Pi

Nach dem selben Schema kann man sogar noch mehr Displays steuern, allerdings reichen dafür die GPIO-Pins bei meinem alten Raspberry Pi 1 nur für maximal drei Displays aus. Wenn es mehr werden, ist ein Binär-Decoder-Chip erforderlich, wie z.B. MOS 4028 mit einem 4 Bit-Eingang, über den man einen von 10 Ausgängen aktivieren kann. Dazu wird noch ein Inverter MOS 4049 benötigt. Man kann auch nur zwei oder vier Bit für vier oder acht Ausgänge nutzen und ungenutzten Eingänge auf GND legen.

Das Python-Script habe ich etwas erweitert, so dass die Erzeugung von benutzerdefinierten Zeichen und die Text-Ausgabe beide Displays verwendet:

#!/usr/bin/python

# Testing two HDSP2112 modules combined as one
# 16 character display with a Raspberry Pi
# An example by Arno Welzel (https://arnowelzel.de)
# 
# Prerequisites:
# 
# Make sure, all GPIO pins are usable as outputs.
# If needed disable SPI, IC2, UART etc. in raspi-config first.
# 
# The following pin numbers are BMC based, change if needed.

import time
import RPi.GPIO as GPIO

HDSP_WR = 15
HDSP_A0 = 7
HDSP_A1 = 8
HDSP_A2 = 25
HDSP_A3 = 24
HDSP_A4 = 23
HDSP_D0 = 2
HDSP_D1 = 3
HDSP_D2 = 4
HDSP_D3 = 17
HDSP_D4 = 27
HDSP_D5 = 22
HDSP_D6 = 10
HDSP_D7 = 9
HDSP_CE0 = 18
HDSP_CE1 = 11

E_PULSE = 0.0001

def io_init():
    GPIO.setmode(GPIO.BCM)
    GPIO.setwarnings(False)
    GPIO.setup(HDSP_WR, GPIO.OUT)
    GPIO.setup(HDSP_A0, GPIO.OUT)
    GPIO.setup(HDSP_A1, GPIO.OUT)
    GPIO.setup(HDSP_A2, GPIO.OUT)
    GPIO.setup(HDSP_A3, GPIO.OUT)
    GPIO.setup(HDSP_A4, GPIO.OUT)
    GPIO.setup(HDSP_D0, GPIO.OUT)
    GPIO.setup(HDSP_D1, GPIO.OUT)
    GPIO.setup(HDSP_D2, GPIO.OUT)
    GPIO.setup(HDSP_D3, GPIO.OUT)
    GPIO.setup(HDSP_D4, GPIO.OUT)
    GPIO.setup(HDSP_D5, GPIO.OUT)
    GPIO.setup(HDSP_D6, GPIO.OUT)
    GPIO.setup(HDSP_D7, GPIO.OUT)
    GPIO.setup(HDSP_CE0, GPIO.OUT)
    GPIO.setup(HDSP_CE1, GPIO.OUT)
    GPIO.output(HDSP_CE0, GPIO.HIGH)
    GPIO.output(HDSP_CE1, GPIO.HIGH)
    GPIO.output(HDSP_WR, GPIO.HIGH)
    
def hdsp_send_byte(chip, data, adr):
    if chip == 0:
        GPIO.output(HDSP_CE0, GPIO.LOW)
        GPIO.output(HDSP_CE1, GPIO.HIGH)
    elif chip == 1:
        GPIO.output(HDSP_CE0, GPIO.HIGH)
        GPIO.output(HDSP_CE1, GPIO.LOW)
    
    GPIO.output(HDSP_D0, GPIO.LOW)
    GPIO.output(HDSP_D1, GPIO.LOW)
    GPIO.output(HDSP_D2, GPIO.LOW)
    GPIO.output(HDSP_D3, GPIO.LOW)
    GPIO.output(HDSP_D4, GPIO.LOW)
    GPIO.output(HDSP_D5, GPIO.LOW)
    GPIO.output(HDSP_D6, GPIO.LOW)
    GPIO.output(HDSP_D7, GPIO.LOW)
    GPIO.output(HDSP_A0, GPIO.LOW)
    GPIO.output(HDSP_A1, GPIO.LOW)
    GPIO.output(HDSP_A2, GPIO.LOW)
    GPIO.output(HDSP_A3, GPIO.LOW)
    GPIO.output(HDSP_A4, GPIO.LOW)
    
    if data & 0x01 == 0x01:
        GPIO.output(HDSP_D0, GPIO.HIGH)
    if data & 0x02 == 0x02:
        GPIO.output(HDSP_D1, GPIO.HIGH)
    if data & 0x04 == 0x04:
        GPIO.output(HDSP_D2, GPIO.HIGH)
    if data & 0x08 == 0x08:
        GPIO.output(HDSP_D3, GPIO.HIGH)
    if data & 0x10 == 0x10:
        GPIO.output(HDSP_D4, GPIO.HIGH)
    if data & 0x20 == 0x20:
        GPIO.output(HDSP_D5, GPIO.HIGH)
    if data & 0x40 == 0x40:
        GPIO.output(HDSP_D6, GPIO.HIGH)
    if data & 0x80 == 0x80:
        GPIO.output(HDSP_D7, GPIO.HIGH)
    if adr & 0x01 == 0x01:
        GPIO.output(HDSP_A0, GPIO.HIGH)
    if adr & 0x02 == 0x02:
        GPIO.output(HDSP_A1, GPIO.HIGH)
    if adr & 0x04 == 0x04:
        GPIO.output(HDSP_A2, GPIO.HIGH)
    if adr & 0x08 == 0x08:
        GPIO.output(HDSP_A3, GPIO.HIGH)
    if adr & 0x10 == 0x10:
        GPIO.output(HDSP_A4, GPIO.HIGH)
    
    time.sleep(E_PULSE)
    GPIO.output(HDSP_WR, GPIO.LOW)
    time.sleep(E_PULSE)
    GPIO.output(HDSP_WR, GPIO.HIGH)

def hdsp_send_text(text):
    text = text.ljust(16,' ')
    for i in range(8):
        hdsp_send_byte(0, ord(text[i]), 0x18+i)
    for i in range(8,16):
        hdsp_send_byte(1, ord(text[i]), 0x18+i-8)

def hdsp_scroll_text(text):
    text = '                '+text+'                '
    for i in range(len(text)-15):
        hdsp_send_text(text[i:i+16])
        time.sleep(0.25)
        i += 1

def hdsp_send_udc(character, matrix):
    hdsp_send_byte(0, character, 0x00)
    hdsp_send_byte(1, character, 0x00)
    adr = 0x08
    for line in matrix:
        byte = 0
        bit = 0x10
        for pos in range(5):
            if line[pos:pos+1] == '*':
                byte = byte | bit
            bit >>= 1
        hdsp_send_byte(0, byte, adr)
        hdsp_send_byte(1, byte, adr)
        adr += 1

if __name__ == '__main__':
    # initialize GPIOs
    io_init()
    # set brightness to 13%
    hdsp_send_byte(0, 0x06, 0x10);
    hdsp_send_byte(1, 0x06, 0x10);
    # Define custom characters
    hdsp_send_udc(
        0, [
            '*...*',
            '.....',
            '..*..',
            '..*..',
            '.....',
            '*...*',
            '.***.'])
    hdsp_send_udc(
        1, [
            '..***',
            '..***',
            '..**.',
            '..**.',
            '.....',
            '..**.',
            '..**.'])
    # do some stuff
    hdsp_send_text('Hello '+str(b'\x80'))
    time.sleep(4)
    hdsp_scroll_text('Scrolling text and custom characters '+str(b'\x81')+str(b'\x81')+str(b'\x81'))