Bitschiebereien Teil 1: 74HC595 mit 8 LEDs am Raspi

  • Servus zusammen,
    weil es in letzter Zeit immer wieder mal Thema war, habe ich mir gedacht, ich mache mal ein kleines Tutorial zur Ansteuerung von LEDs und 7-Segment-Anzeigen über Schieberegister mit einem Raspi.
    Geplant sind zwei Teile:


    1. Ansteuern von 8 LEDs über ein 74HC595 Schieberegister
    2. Ansteuern einer 7-Segment-Anzeige mit einem 74HC595 Schieberegister


    Ich kann leider nur mit jeweils einem C-Programm als Beispiel dienen, weil ich, wie ihr mittlerweile alle wissen werdet, nix mit Python anfangen kann.
    Die Software ist aber so simpel, dass ich davon überzeugt bin, dass selbst ein Python-Anfänger sie leicht umsetzen kann.


    Dann los mit Teil 1: Ansteuern von 8 LEDs über ein 74HC595 Schieberegister


    Wir brauchen dazu
    Material-Liste:
    8 Stück LEDs, z.B. rot mit 3mm Durchmesser
    8 Stück Widerstand 470 Ohm oder etwas mehr (bei roten LEDs)
    1 Stück Schieberegister 74HC595 DIP 16 (oder SO16 mit Adapter)
    1 Breadboard
    xx Dupont-/Jumper-Kabel male/male in versch. Farben
    natürlich einen Raspi, dabei ist es egal, ob Zero, Pi1, Pi2, Pi3 als A, A+, B oder B+ Modell
    ein Multimeter zur Kontrolle
    optional: einen Levelshifter 3V3 <-> 5V


    Anmerkung:
    Größere LEDs könnt ihr natürlich auch nehmen. Allerdings brauchen acht Stück mit 5 oder sogar 8 mm Durchmesser eine Menge Platz. Das solltet ihr berücksichtigen.


    Anmerkung:
    An dieser Stelle wollte ich noch eine Korrektur einbringen: in der vorherigen Version hatte ich hier angemerkt, dass ihr darauf achten solltet einen 74HC595 und nicht die TTL-Variante 74HCT595 zu verwenden. Das muß ich jetzt widerrufen ... Der 74HC595 funktioniert zwar einwandfrei, aber die TTL-Variante ist für den Raspi besser geeignet. Ich hatte einige 74HC595 seit längerem hier rumliegen und nur noch in Erinnerung, sie extra für den Raspi bestellt zu haben. Der Grund waren aber nicht die Eingangspegel, sondern die Idee, die ICs direkt am Raspi mit 3V3 zu betreiben. Und das geht mit den TTL-Teilen eben nicht. Zu allem Überfluss habe ich dann das Datenblatt der ICs nur überflogen (mich interessierten nur die Zeiten, die ein HIGH/LOW anliegen muss und die maximale Frequenz) und dabei einfach übersehen, dass der minimale HIGH-Pegel des 74HC595 für den Raspi sehr nah am undefinierten Bereich ist. Da der Pi aber sehr stabil im 3V3 Bereich läuft, weil sonst wohl auch andere Komponenten spinnen würden, ist der Einsatz des 74HC595 schon ok.
    Bei längeren Verbindungen und/oder wenn die Schaltung spinnt, wäre eine Maßnahme, die 74HC595 gegen 74HCT595 auszutauschen. Das wollte ich nur noch kundtun um nicht den Eindruck zu erwecken, ich sei beratungsresistent ;) ...


    Achtet zudem darauf, dass ihr das Schieberegister in der Bauform "DIP 16" bekommt. Meist werden sie in der Bauform SO 16 (SO für Small Outline) angeboten. Das geht auch, dann braucht ihr aber einen Adapter SO16 -> DIP16 oder müsst Euch was einfallen lassen, wie ihr den IC mit dem Breadboard verbunden bekommt.
    Der Wert der Widerstände schliesslich hängt von der Farbe der verwendeten LEDs ab. Auf -> dieser Seite des Elektronik-Kompendiums <- könnt ihr den Widerstand berechnen lassen.
    Bei roten LEDs ( Klick auf RT ) und einer Betriebsspannung von 5V (die Schieberegister betreiben wir mit 5V ... dazu später mehr) und einem maximalen Strom von 8 mA (den gebt ihr in das dritte Feld ein) ist der Vorwiderstand (klick auf Errechne) 425 Ohm. Der nächste passende Wert sind dann 470 Ohm.
    Warum 8 mA? Das Schieberegister verkraftet laut Datenblatt ( -> hier zu finden <- ) 70 mA. Wenn wir alle acht LEDs durchsteuern, müssen wir unter diesem Wert bleiben. Also sind 8 mA der maximale Strom per LED.
    Warum 5V? Nun, wir schliessen am Schieberegister nur I/Os des Raspi an, die als Ausgang geschaltet sind. Dadurch "sieht" der Raspi niemals etwas von den 5V Betriebsspannung des Bausteins. Allerdings müsst ihr darauf achten, nicht die falschen Kabel mit dem Raspi zu verbinden.
    Wer auf Nummer Sicher gehen will, kann natürlich den oben genannten Levelshifter verwenden.
    Auf alle Fälle solltet ihr die Spannung messen, bevor ihr die Kabel am Raspi anschliesst.


    Aufbau der Schaltung:
    Steckt das IC auf das Breadboard, und zwar so, dass die Mittelrinne zwischen den Beinchen des IC verläuft. Anschliessend werden die Ausgänge Q0 bis Q7 (Pin 15, 1, 2, 3, 4, 5, 6, 7) über einen Widerstand jeweils mit der Kathode einer LED verbunden. Die Anoden der LEDs verbindet ihr mit Vcc (rote Lane des Breadboards).
    Es ist sinnvoll dabei eine gewissen Reihenfolge einzuhalten, also z.B. von links nach rechts Q0 aufsteigend bis Q7. Ihr werdet später sehen, warum.
    Lasst Euch übrigens vom Fritzing-Bild der Schaltung nicht verunsichern. Es sieht so aus, als wären die Widerstände falsch mit den Ausgängen verbunden. Bedenkt: das ist ein Breadboard, dessen vertikale "Spalten" untereinander verbunden sind. Hoizontal dagegen besteht keine Verbindung!
    Die Kathoden der LEDs über den Vorwiderstand mit den Ausgängen des Schieberegistern zu verbinden ist durchaus bewusst von mir so gewählt worden. Ihr werdet später sehen, warum.
    Den Pin 10 (MR) des IC legt ihr auf Vcc (rote Lane), den Pin OE (13) auf GND (blaue Lane).
    Anschliessend kommt noch die Versorgungsspannung des IC an Pin 16 (Vcc) und Masse (GND) an Pin 8.
    Als letztes verbindet ihr einen GND-Pin (z.B. Pin #6) mit einer der blauen Lanes des Breadboards (falls ihr später beide blauen Lanes benutzt, müsst ihr natürlich die beiden verbinden. Es sei denn, ihr verwendet ein Breadboard-Power-Board).


    Als Stromversorgung für solche Aufbauten auf dem Breadboard verwende ich gerne spezielle "Breadboard Power Boards" ... die Dinger kosten fast nix und ich finde sie unheimlich praktisch, weil sie sowohl 5V als auch 3V3 liefern und einfach auf das Breadboard gesteckt werden.
    In unserem Fall können auch einer der 5V- sowie einer der GND-Pins des Raspi verwendet werden.
    Überprüft mit dem Multimeter, ob Eure Schaltung evtl. einen Kurzschluß enthält. Und versichert Euch lieber einmal zu viel als zu wenig, dass alle Verbindungen stimmen.
    Trennt ausserdem unbedingt Euren Pi vom Netz bevor ihr die Verbindung der Pins GND und 5V mit dem Breadboards herstellt.


    Beim Einschalten des Raspi bzw. der Breadboard-Stromversorgung sollten jetzt alle acht LEDs leuchten. Tun sie das nicht, habt ihr irgendwo einen Fehler eingebaut.


    Ein kurzer Ausflug zur Funktionsweise des Schieberegister IC


    Zur Steuerung benötigen wir drei Leitungen:
    SHCP (Pin 11 / shift register clock input / Schiebetakt)
    STCP (12 / storage register clock input / Transfer der internen Bits in das Ausgaberegister)
    DS (14 / serial data input / Eingang bitweise Daten)


    Zum besseren Verständnis hier mal der stark vereinfachte Funktions-Ablauf in einem solchen Schieberegister:
    Der Eingang DS des IC wird auf einen Bitwert gesetzt - also HIGH oder LOW. Anschliessend wird der Eingang SHCP auf HIGH und gleich wieder auf LOW gesetzt. Das ist das Signal für den IC das Signal, das an DS anliegt, in das aktuelle interne Bitregister zu übernehmen.
    Dieser Vorgang wird jetzt z.B. achtmal für ein Byte wiederholt. Das interne Bitregister wird dabei bei jedem "Takt" (Wechsel SHCP HIGH/LOW) um eins erhöht.
    Schliesslich wird der Eingang STCP auf HIGH und gleich wieder auf LOW gesetzt. Dieser Pegelwechsel signalisiert dem Chip, die acht internen Bit-Register in die Ausgabe-Register ( repräsentiert durch Q0 bis Q7) zu übertragen. Das interne Bitregister wird wieder auf die erste Position gesetzt. Die Folge ist, dass die vorher einzeln (seriell) übertragenen Bits jetzt nebeneinander (parallel) an den Ausgängen Q0 bis Q7 zur Verfügung stehen.
    Dieser letzte Vorgang kann jederzeit erfolgen ... es ist also nicht zwangsläufig vorgegeben, acht Stellen zu schieben. Das können mehr oder auch weniger sein. Treten mehr als acht Schiebetakte auf, erfolgt ein Überlauf und das interne Bitregister wird wieder auf die erste Position gesetzt.



    Zurück zu unserer Schaltung.


    Wie bereits erwähnt brauchen wir zum Ansteuern des IC nur drei Leitungen, und zwar die Pins 11, 12 und 14 des IC.
    Bevor wir den Strom der Schaltung wieder abschalten messen wir diese drei Pins ... die Pegel sollten unter 1V liegen.
    Jetzt machen wir sowohl den Raspi als auch die Schaltung wieder stromlos.
    Als GPIOs habe ich GPIO17, GPIO27 und GPIO22 des Pi verwendet.
    Wir verbinden also GPIO17 (Pin #11) mit SHCP (Pin #11), GPIO27 (Pin #13) mit STCP (Pin #12) und GPIO22 (Pin #15) mit DS (Pin #14).


    Der Pin 9 (Q7S) des IC bleibt unbeschaltet.


    Wer jetzt einen Levelshifter dazwischen schalten möchte, muß die Verbindungen über diesen herstellen. Dabei ist darauf zu achten, dass die 5V-Seite (oft mit HV bezeichnet) mit dem Schieberegister und die 3V3-Seite (oft mit LV bezeichnet) mit den GPIOs des Raspi verbunden sind. Wichtig dabei: die Massen zusammenschalten.


    Nach einer weiteren Kontrolle der Schaltung können wir jetzt die Schaltung in Betrieb nehmen und den Raspi hochfahren.


    Das Software-Beispiel:


    Um das Beispielprogramm zu übersetzen benötigt ihr die pigpio-Bibliothek. Ihr könnt sie ganz einfach mit

    Code
    sudo apt-get install pigpio


    installieren.
    Speichert den C-Source ab und übersetzt ihn mit

    Code
    gcc -Wall -o 74hc595 74hc595.c -lpthread -lpigpio


    Das Beispielprogramm könnt ihr dann mit

    Code
    sudo ./74hc595


    ausführen.


    Was macht das Programm?


    Ich denke, das ist fast selbsterklärend. Nach dem Initialisieren der pigpio-Bibliothek werden die benötigten GPIOs als Ausgang definiert.
    In einer Schleife werden dann alle Werte von 0 bis 255 durchlaufen und der Wert jeweils über den DS Ausgang an den IC gesendet und mittels Triggern des STCP Pins in die Ausgaberegister geschrieben.


    Achtung: unser -> evil <- hatte -> hier <- den Einwand, dass es sinnvoll sein könnte zwischen dem Setzen der Clock-Signale (STCP/SHCP) auf HIGH und gleich anschliessend wieder auf LOW, eine kurze Pause einzulegen um sicherzustellen, dass das Signal auch erkannt wird.
    Damit hat er prinzipiell recht. In unserem speziellen Fall sagt das Datenblatt des IC, dass die minimals Puls-Länge für einen Wechsel HIGH/LOW lediglich 5 ns beträgt. Damit sind wir in einem Bereich, der m.E. nicht mehr berücksichtigt werden muss, weil ich davon überzeugt bin, dass allein die Ausführung des gpioWrite() schon länger dauert.
    Für den Fall, dass es Timing-Probleme gibt kann es jedenfalls nicht schaden, den Hinweis mit der Pause im Hinterkopf zu behalten.



    Anmerkung: die shiftOut-Funktion habe ich, der Einfachheit halber, -> hier geklaut <- ;)


    Nur ... irgendwas stimmt nicht, oder?
    Richtig ... die LEDs sind alle an und gehen, abhängig vom übertragenen Wert wieder aus. Dabei stellt jede LED die zugehörige 2er Potenz dar. Habt ihr die Reihenfolge Q0 -> Q7 eingehalten, seht ihr an den Positionen die gesetzten bzw. gelöschten Bits.
    Doch zurück zur Ungereimtheit mit dem Leuchten bzw. Erlöschen der LEDs.


    Wir erinnern uns: wir haben die Anoden der LEDs mit Vcc verbunden. Der Stromkreis wird geschlossen und bringt die LEDs zum Leuchten, wenn der Ausgang des Schieberegisters auf LOW (GND) gesetzt wird.
    In der Schleife setzen wir die Ausgänge aber auf HIGH, wenn wir die Variable hochzählen. Deshalb das "umgekehrte" Verhalten der LEDs.
    Es gibt jetzt zwei Möglichkeiten hier Abhilfe zu schaffen: wir drehen alle LEDs um ( verbinden also die Kathoden mit Masse und die Anoden über den Vorwiderstand mit den Ausgängen). Das birgt aber jetzt wieder die Gefahr falscher Verdrahtungen oder von Kurzschlüssen.
    Einfacher ist es, wir drehen einfach den Wert um, den wir in das Schieberegister schreiben.
    In "C" geschieht dies durch eine vorangestellte Tilde (~). Den selben Effekt erreicht man über eine XOR- (Exklusiv-Oder-) Operation des Wertes mit sich selbst. Hier gilt: logisch 1 XOR logisch 1 gibt logisch 0 und logisch 0 XOR logisch 0 gibt logisch 1.
    So werden alle gesetzten Bits gelöscht und alle gelöschten Bits gesetzt.


    Warum dieser Umweg? Der Grund hierfür ist, dass wir schon mal umdenken lernen, wenn wir im zweiten Teil eine 7-Segment-Anzeige mit gemeinsamer Anode ansteuern werden. Bei der können wir nämlich nicht einfach die Polungen der einzelnen LEDs vertauschen.


    Also ... in der Zeile

    Code
    shiftOut(PIN_SERIAL_DATA_IN, PIN_SHIFT_REGISTER_CLOCK, LSBFIRST, val);


    dem Wert val eine Tilde voranstellen:

    Code
    shiftOut(PIN_SERIAL_DATA_IN, PIN_SHIFT_REGISTER_CLOCK, LSBFIRST, ~val);


    Das Ganze neu übersetzen und jetzt sollte unsere Logik stimmen.


    Das war Teil 1. Zu Teil 2 geht's hier lang: http://www.forum-raspberrypi.d…-segment-anzeige-am-raspi
    Ich hoffe, dass sich keine Fehler eingeschlichen haben.
    Viel Spass schon mal beim Nachbauen.
    Fragen und Anregungen bitte in einem eigenen, gesonderten Thread z.B. unter "GPIO & Elektrotechnik" mit Verweis auf dieses Tutorial posten.
    Eure Mitleser werden es Euch danken ;)


    ciao,
    -ds-

  • Hallo Dreamshader,


    sehr schöne Anleitung. Besonders gefällt mir daß die SW in C geschrieben ist. Python ist für mich einfach nur gruselig.
    Wenn es aber sein muss: Unter http://www.holgerschurig.de/de/raspi-lauflicht/ gibt es sowas in Python. Dort wird neben der "händischen" Ansteuerung des Schieberegisters auch ein Codeschnipsel mit
    Verwendung des SPI Busses gezeigt.

    1 + 1 = 2 das muß ich glauben, denn ich kann es nicht beweisen