Eine 7-Segment Anzeige mit dem Raspberry Pi ansteuern
Sieben-Segment-Anzeigen begegnen uns im täglichen Leben häufig. Die Ziffern auf der Uhr oder auf dem Taschenrechner werden damit dargestellt. Auf dem Taschenrechner sind dies für gewöhnlich die besonders stromsparenden LCDs (Liquid Crystal Display), zu deutsch Flüssigkeitskristallanzeige. Auf dem Radiowecker meist die etwas stromhungrigeren LEDs.Mit der in einer Acht-Form angeordneten Segmente in Form von Strichen lassen sich zudem behelfsmäßige Buchstaben anzeigen - zugegeben: das M oder W ist allerdings ein bisschen schwierig darzustellen und nicht gleich intuitiv wiederzuerkennen, aber bei Ziffern ist die Wiedererkennung auf für Unbedarfte hoch.
Rechts erkennt man die Anordnung der Segmente gut. Außer den sieben Strich-Segmente gibt es noch eine zusätzliche LED für den Dezimalpunkt unten rechts.
Auf der Rückseite des Bauteiles mit der Bezeichnung 5161AS finden sich 10 Anschlusspins, die - von der Vorderseite aus gesehen unten von links nach rechts mit 1 bis 5 und oben von rechts nach links von 6 bis 10 nummeriert sind.
Die interne Verdrahtung lässt sich bei diesem Exemplar Bild ganz gut erkennen. Es gibt aber auch noch ältere Exemplare Bild, die anders beschaltet ist. Hier hilft nur ausprobieren: GND finden: das sollten die Pins seien, die miteinander verbunden sind. Dann Spannung (Durchgangsmesser) über Vorwiderstand anlegen und schauen, welches Segment leuchtet.
Der Abstand zwischen den Pins ist wie gewöhnlich ein Zehntel Zoll, also 2.54 mm. Damit passt es gut auf unser Breadboard.
Die Segmente nummeriert man von 1 bis 7 oder aber wie häufiger getan mit A bis G. Dabei find man mit dem Segment oben in der Mitte an, geht dann einmal im Uhrzeigersinn im Kreis. Das mittlere Segment bezeichnet man als G.
Der Dezimalpunkt hat normalerweise keine eigene Bezeichnung, weil er meist nicht mehr zum Zeichen gehört, sondern eine besondere Bedeutung hat, z. B. als Dezimalpunkt auf dem Tastenrechner, Trennpunkt Zwischen Stunden und Minuten oder als Sekundensignal. Man könnten könnte ihn aber als 8. Segment oder H bezeichnen.
Jedes der Segmente ist eine einzelne LED, die den hellen Bereich eines Segments ausleuchtet. Die beiden mittleren Pins sind die gemeinsame Kathode, also der Minusanschluss der LEDs. Die insgesamt acht Plus-Leitungen der 8 LEDs sind ein wenig eigentümlich nummeriert. Im Prinzip wieder im Uhrzeigersinn reihum, nur der Punkt mogelt sich dazwischen und F und G tanzen aus der Reihe und wechseln die Plätze.
Am eine Ziffer darzustellen müssen wir einfach die LEDs zum Leuchten bringen, die zusammen genommen die Ziffer darstellen. Also z. B. für eine 1 die beiden rechte B und C. Oder für eine 2 dann A, B, G, E, D. Und die 3 wären die LEDS A, B, G, D, C.
Dazu müssen wir nur einmal für alle LEDs die Masse auf die GND-Leitung legen und dann für die einzuschaltenden LEDs die Pins über einen Vorwiderstand auf +3.3V.
Der Widerstand sollte nicht zu niedrig gewählt werden, weil sonst die LEDs Schaden nehmen. Aber erkennen muss man das Display natürlich auch noch bei etwas Sonnenlicht. Der nötige Vorwiderstand hängt auch von der der 7-Segment-Anzeige ab. Gerne könnt ihr meinen kleinen Vorwiderstandsrechner benutzen:
Für meine rote Anzeige haben sich 220 Ohm als ein guter Wert herausgestellt.
Rechts die aufgebaute Schaltung (anklicken zum vergrößern). Wie man sieht, gibt es 8 Widerstände, die von der GPIO-Reihe weggehen. Im unteren rechten Teil gehen dann die Leitungen zu den einzelnen Segmenten ab. Außerdem brauchen wir noch eine Leitung, die die gemeinsame Kathode der Anzeige mit GND des Raspberry Pi verbindet.
Was man nicht unbedingt machen sollte, auch wenn es verführerisch ist, ist nur einen Vorwiderstand zwischen die gemeinsame Kathode (oder auch Anode, je nach Modell) und GND (bzw. VCC) klemmen, denn dann leuchtet die Anzeige unterschiedlich hell, je nachdem wieviele Segmente gerade an ist. Ich bin in einem neueren Artikel noch einmal genauer darauf eingegangen und zu dem Schluss gekommen: schadet den LEDs zwar nicht, sieht aber schlecht aus.
Für die GPIO-Reihe benutzen wir wieder unser Flachbandkabel. Es ist die linke Seite der GPIO-Stiftleiste des Raspi angeschlossen, sprich Pin 1 bis 39. Wobei Pin 1 ganz rechts und Pin 39 ganz links auf dem Breadboard liegen.
Der Pin ganz links ist GND und kommt an den GND-Pin der Anzeige. Für die Plospole der 8 LEDs in der Anzeige brauchen wir 8 GPIO-Leitungen. Dies sind die bewährten Pins BCM 26, 19, 13, 6, 5, 11 und 9 für die Segmente A, B, C, D, E, F, G und BCM 10 für den Punkt.
Von den GPIO-Leistungen führt jeweils ein 220 Vorwiderstand an die untere Hälfte des Breadboard, von der wir dann Kabel zu den Eingängen der Anzeige legen.
Hier am besten an der Abbildung oben orientieren und dann von links nach rechts die Leitungen von A bis G (und den Punkt) einstecken.
Ob wir alles richtig verkabelt haben, sollte unser Testprogramm zeigen, das folgende Dinge durchtestet:
- alle Segmente eingeschaltet - wenn nicht alles leuchtet, wurde ein Segment vergessen
- alle Segmente der Reihe nach von A bis G (plus Punkt) werden durchgeschaltet - stimmt die Reihenfolge?
- die äußeren Segmente werden in einer Kreis-Animation der Reihe nach und wiederholt angesprochen
- der Punkt blinkt ein paar mal - ist er richtig angeschlossen
- Ziffer 0 bis 0 ausgeben
- Buchstaben A bis Z ausgeben
- "Hallo Welt" ausgeben
Dabei hilfreich ist dieses kleine Tool mit dem man sieht, wie eine beliebige Segment-Kombinaton, etwa "AGD", aussieht. Dann einfach AGD in das Eingabe-Feld schreiben, zu Grafik dekodieren auswählen und auf ausführen klicken.
Der Code ist wie immer mit vielen Kommentaren versehen. Im Anschluss werde ich dann noch auf Besonderheiten oder neue Befehle eingeben.
# -*- encoding: utf-8 -*-
# (C) 2018 by Oliver Kuhlemann
# Bei Verwendung freue ich mich über Namensnennung,
# Quellenangabe und Verlinkung
# Quelle: http://cool-web.de/raspberry/
import RPi.GPIO as GPIO # Funktionen für die GPIO-Ansteuerung laden
from time import sleep # damit müssen wir nur noch sleep() statt time.sleep schreiben
from sys import exit # um das Programm ggf. vorzeitg zu beenden
GPIO.setmode(GPIO.BCM) # die GPIO-Pins im BCM-Modus ansprechen
segmente=[26,19,13,6,5,11,9] # Segmente A-G hängen an BCM ...
punkt=10 # Punkt hängt an BCM ...
# Dictionary: welche Ziffer/Buchstabe -> welche Segmente sind an
chars = {" ":"", "0":"ABCDEF", "1":"BC", "2":"ABDEG", "3":"ABCDG", "4":"BCFG", "5":"ACDFG", "6":"ACDEFG", "7":"ABC", "8":"ABCDEFG", "9":"ABCDFG", "A":"ABCEFG", "B":"CDEFG", "C":"ADEF", "D":"BCDEG", "E":"ADEFG", "F":"AEFG", "G":"ACDEF", "H":"BCEFG", "I":"AE", "J":"ACD", "K":"ACEFG", "L":"DEF", "M":"ACEG", "N":"ABCEF", "O":"CDEG", "P":"ABEFG", "Q":"ABCFG", "R":"EG", "S":"ACDF", "T":"DEFG", "U":"BCDEF", "V":"BEFG", "W":"BDFG", "X":"CE", "Y":"BCDFG", "Z":"ABDE"}
def show(char): # das übergebene Zeichen auf der 7-Segment-Anzeige anzeigen
# erstmal alle Segmente aus
for segment in segmente:
GPIO.output(segment, GPIO.LOW)
# segmente für char suchen
try:
onSegs = chars[char]
except KeyError:
print "Das Zeichen " + char + " ist nicht definiert."
return
# die Segmente in onSegs einschalten
segment=0
for seg in "ABCDEFGH":
if onSegs.find(seg) > -1:
GPIO.output(segmente[segment], GPIO.HIGH)
segment +=1
def showDot(an): #Dezimalpunkt an (1) oder aus (0)
if (an):
GPIO.output(punkt, GPIO.HIGH)
else:
GPIO.output(punkt, GPIO.LOW)
def say(word): # mehrere Zeichen wiedergeben
for char in word.upper():
show (char)
sleep (.5)
show (" ") # alles wieder aus
sleep (.1)
def test1(): # Test, ob alle Segmente funktionieren
for segment in segmente:
GPIO.output(segment, GPIO.HIGH)
showDot(1)
sleep (1)
for segment in segmente:
GPIO.output(segment, GPIO.LOW)
showDot(0)
def test2(): # alle Segmente der Reihe nach testen - Reihenfolge richtig? A-G und DP
for i in range(0,7):
GPIO.output(segmente[i], GPIO.HIGH)
sleep (.5)
GPIO.output(segmente[i], GPIO.LOW)
showDot(1)
sleep (.5)
showDot(0)
def waitAnim(wdhl): # Round and round it goes.. Wdhl = wie oft
for wd in range(0,wdhl):
for i in range(0,6): # segmente ein paar mal im kreis laufen lassen
GPIO.output(segmente[i], GPIO.HIGH)
sleep (.1)
GPIO.output(segmente[i], GPIO.LOW)
def waitAnim2(secs): # lässt den Punkt im Sekundentakt blinken
for i in range(0,secs):
showDot(1)
sleep (.5)
showDot(0)
sleep (.5)
def testZiffern():
for ziffer in "0123456789 ":
show (ziffer)
sleep (.5)
def testBuchstaben():
for bst in "ABCDEFGHIJKLMNOPQRSTUVWXYZ ":
show (bst)
sleep (.5)
# --- Ende Funktionen --- Beginn Hauptprogramm -------------------------------------------
for segment in segmente: # LEDS sind Output
GPIO.setup(segment, GPIO.OUT)
GPIO.setup(punkt, GPIO.OUT)
test1()
sleep (1)
test2()
sleep (1)
waitAnim(5)
sleep (1)
waitAnim2(5)
sleep (1)
testZiffern()
sleep (1)
testBuchstaben()
sleep (1)
say ("Hallo Welt ")
sleep (1)
GPIO.cleanup() # Programm sauber verlassen und Ressourcen wieder freigeben
Im Array segmente=[26,19,13,6,5,11,9] und der Zuweisung punkt=10 ist definiert, welche Leitungen zur Ansteuerung der Anzeige benutzt werden. Diese können natürlich angepasst werden, solltet ihr eine andere Beschaltung bevorzugen.Im Dictionary Chars ist definiert, wie ein Zeichen dargestellt wird, welche Segmente für das Zeichen eingeschaltet werden. Das kann nach eigenem Gusto angepasst und ergänzt werden.
Die Funktion show(char) zeigt ein definiertes Zeichen char an, indem es zuerst alle Segmente ausschaltet und dann die zum Zeichen gehörenden an. show(" ") löscht die Anzeige.
Mit der Funktion showDot(an) kann man den Dezimalpunkt ein- und wieder ausschalten. Eine extra Funktion für den Punkt ist wichtig, wenn man Ziffern und den Punkt zusammen und unabhängig voneinander benutzen will. So kann man eine Uhrzeit anzeigen und den Punkt als Sekundenindikator blinken lassen.
Mit der Funktion say(word) wird gleich ein ganzes Wort oder ein Satz angezeigt, indem die darin befindlichen Zeichen der Reihe nach angezeigt werden. Dazwischen erfolgt immer eine kurze Pause von einer Zehntel Sekunde, damit man doppelte Buchstaben leichter erkennt.
Die nachfolgenden Test dürfte selbsterklärend sein, genauso wie das folgende Hauptprogramm, dass nur die Funktionen der Reihe nach mit einer Pause dazwischen aufruft.