7-Segment-Anzeige mit 74HC595 (Detail)

7-Segment-Anzeigen mit dem 74HC595 steuern

Typische 7-Segment-Anzeigen bestehen aus sieben LEDs (meist plus einer weiteren für den Dezimalpunkt), die einzeln angesteuert werden und über eine gemeinsame Anode (common anode) oder Kathode (common cathode) verfügen. Um eine Anzeige zu steuern, werden also sieben (bzw. acht) Digitalpins des Mikrocontrollers belegt. Bei Verwendung einer einzelnen Anzeige ist das noch halbwegs praktikabel, bei mehreren nicht mehr. Zum Bereitstellen zusätzlicher Ausgabeports kann man Schieberegister wie das 74HC595 nutzen. Hierbei werden die Steuerdaten bitweise seriell zum Schieberegister übertragen, das diese dann auf Anforderung an einem Stück (parallel) auf acht Datenpins ausgibt. Man kommt für die Ansteuerung des 74HC595 mit drei Leitungen aus, selbst wenn man mehrere Register hintereinander schaltet, um z.B. zwei 7-Segment-Anzeigen oder eine Gruppe von Relais zu steuern.

7-Segment-Anzeige SMA42056

Ich verwende im folgenden zwei Anzeigen vom Typ SMA42056 mit gemeinsamer Kathode (Datenblatt). Wie der Name vermuten lässt, sind die beiden Kathoden-Pins miteinander verbunden – es genügt also, einen der beiden mit Masse zu verbinden. Wie Standard-LEDs werden auch diese Displays nicht direkt, sondern nur über einen passenden Vorwiderstand angeschlossen. Dessen Berechnung erfolgt unten.

Die Segmente bzw. LEDs werden mit den Buchstaben A bis G bezeichnet, die wie folgt den Pins zugeordnet sind:

7-Segment-Anzeige
7-Segment-Anzeige mit Beschriftung der Pins und Segmente (Vorlage: Fritzing)
Pin Segment
1 E
2 D
3 gemeinsame Kathode
4 C
5 Dezimalpunkt (DP; decimal point)
6 B
7 A
8 gemeinsame Kathode
9 F
10 G

Schieberegister 74HC595

Schieberegister 74HC595
Schieberegister 74HC595: Bezeichnung der Pins

Das 74HC595 (Hersteller: Texas Instruments; vollständige Bezeichnung: SN74HC595N; Datenblatt) besteht aus zwei Registern: einem Schieberegister zur bitweisen seriellen Dateneingabe und einem Speicher- oder Ausgaberegister. Durch ein Steuersignal werden die acht Daten-Bits aus dem Schieberegister ins Speicherregister übernommen und parallel an den acht Pins QA bis QH ausgegeben. Die Steuerung erfolgt über die Pins SER (serielle Daten), SRCLK (Takt für das Schieberegister; shift register clock) und RCLK (Takt für das Speicherregister; (storage) register clock). SRCLR (Reset des Schieberegisters; shift register clear) wird mit VCC verbunden, OE (output enable) mit Masse. Um mehrere Register hintereinander zu schalten, wird der Ausgang QH’ (Pin 9) des ersten mit dem Eingang SER des folgenden Registers verbunden. (Eine ausführliche Beschreibung der Funktionsweise des 74HC595 kann man bei mikrocontroller.net nachlesen.)

Berechnung des Vorwiderstands für die LEDs

Die Ausgabepins des 74HC595 können zusammen maximal einen Strom von 70 mA liefern (jeder einzelne max. 35 mA) – pro LED also 10 mA (8,75 mA bei Verwendung des Dezimalpunkts). Der Vorwiderstand muss die Differenzspannung zwischen Durchlassspannung der LED (VF = 1,8 V) und Versorgungsspannung (VCC = 3,3 V) von der LED abhalten. Sein Wert errechnet sich nach dem Ohmschen Gesetz als

R = U / I = (VCC – VF) / I = (3,3 V – 1,8 V) / 8,75 mA = (1,5 / 0,00875) Ω = 171 Ω.

Als nächsthöhere passende Widerstandsgröße ergibt sich also ein Wert von 200 oder 220 Ω (bei einer Betriebsspannung von 5 V sind es 366 Ω, also nimmt man einen 470 Ω-Widerstand). Statt selbst zu rechnen, kann man auch einen Online-Rechner wie den LED-Vorwiderstandsrechner auf elektronik-kompendium.de verwenden; dort gibt es auch eine ausführliche Erläuterung.

Die Durchlassspannung wird auch als Flussspannung bezeichnet; meist findet man den Wert unter dem englischen Begriff forward voltage im Datenblatt der LED.

Materialliste

  • ESP32
  • Breadbord (groß, 830 Kontakte; alternativ zwei kleine mit je 400 Kontakten)
  • 2 7-Segment-Anzeigen SMA42056 (common cathode)
  • 2 Schieberegister 74HC595
  • 2 Widerstände 200 oder 220 Ω
  • 1 Temperatursensor DS18B20
  • 1 Widerstand 4,7 KΩ
  • ca. 40 Kabel und/oder Steckbrücken

Die einfache Variante (die ich gewählt habe) ist, je eine der gemeinsamen Kathoden der Anzeigen über den Vorwiderstand mit Masse zu verbinden. Je nach Anzahl leuchtender Segmente leuchtet die Anzeige dann aber mit leicht unterschiedlicher Lichtstärke. Für mich ist das kaum sichtbar, aber falls es stört, verbindet man die Kathode direkt mit Masse und setzt in jede Steuerleitung zu den LEDs einen Vorwiderstand ein; statt zwei werden also 14 bzw. 16 (mit Dezimalpunkt) Widerstände benötigt.

Schaltung

Um etwas zum Anzeigen zu haben, verwende ich Messwerte des Temperatursensors DS18B20, den ich in einem anderen Beitrag vorgestellt habe. (Wer sich diesen Teil der Schaltung sparen möchte, zählt stattdessen z.B. in einer Schleife Zahlenwerte von 0-99 hoch.) Im Programm gebe ich auch eine Nachkommastelle der Temperatur aus und nutze deshalb den Dezimalpunkt der linken Anzeige. Werden nur ganzzahlige Werte dargestellt, muss man die entsprechenden Segmente der Displays nicht verbinden.

7-Segment-Anzeige und 74HC595
Steuerung von zwei 7-Segment-Anzeigen über Schieberegister 74HC595

Im Diagramm verwende ich rote Leitungen für Verbindungen mit der Versorgungsspannung und schwarze für Masse. Die Leitungen innerhalb der beiden Gruppen aus Schieberegister und 7-Segment-Anzeige sind jeweils nach dem gleichen Muster eingefärbt, z.B. QA zu Pin 7 gelb, QB zu Pin 6 blau usw. Man sieht schon am Fritzing-Diagramm, dass es auf dem Breadboard mit so vielen Kabeln etwas unübersichtlich wird. Im realen Aufbau wird das noch deutlicher. Zum Ausprobieren und Lernen ist das ok, bequemer in der Nutzung von 7-Segment-Anzeigen sind fertige Module z.B. mit dem TM1637 (vierstellige Displays für Zeitanzeigen u.ä.) oder MAX7219 (acht Stellen mit Dezimalpunkten). Auch Module mit zwei LEDs und zwei Schieberegistern (also genau wie im hier aufgebauten Beispiel) sind für weniger als 4 € bei chinesischen Versendern erhältlich. Nützlicher dürften die Schieberegister bei anderen Einsatzzwecken sein, die mehr digitale Ausgabepins erfordern als am ESP32 verfügbar sind.

Programmierung

Besondere Bibliotheken müssen für die 7-Segment-Anzeige nicht installiert werden. Für die Abfrage des Temperatursensors DS18B20 müssen die Bibliotheken OneWire und DallasTemperature vorhanden sein.

Die Zeichen, die auf einer 7-Segment-Anzeige darstellbar sind, sind als achtstellige Bitfolgen codiert – Segment A als niederwertigstes Bit (20), Segment B als zweitniedrigstes (21) bis zu Segment G (26) und dem Dezimalpunkt (27). Im Programm sind diverse darstellbare Zeichen angegeben – wenn man nur die Hexadezimalziffern 0-9 und A-F braucht, kann man den Rest auskommentieren. Einen Dezimalpunkt nach einem Zeichen erhält man, indem in der Bitfolge das höchstwertige Bit durch eine ODER-Verknüpfung mit dem Wert 0x80 (27 = 128) gesetzt wird.

Beim Schieben der Daten in das Register wird zuerst das rechts stehende Zeichen ausgegeben, dann das linke. Nach jedem Bit wird der serielle Takt (Leitung SRCLK) kurz auf HIGH und dann auf LOW gesetzt, um die Daten im Register (und Register übergreifend) eine Stelle weiterzuschieben und das neue Bit zu übernehmen. Sind die Daten übertragen, werden sie durch HIGH-Setzen des Speichertakts (RCLK) ausgegeben.

Je nach gemessener Temperatur werden folgende Daten angezeigt:

  • – –: kein Sensor gefunden
  • Lo: Temperatur unter 0 °C
  • Hi: Temperatur über 100 °C
  • einstellige Temperaturen werden mit einer Nachkommastelle ausgegeben
  • bei zweistelligen Temperaturen werden eine Sekunde lang die Vorkommastellen (Zehner und Einer) angezeigt, dann eine Sekunde lang die Einer mit einer Nachkommastelle
/* Anzeige von Zahlenwerten auf zwei 7-Segment-Anzeigen vom Typ SMA42056
 * unter Verwendung von Schieberegistern 74HC595
 *
 * 2019-05-26 Heiko (unsinnsbasis.de)
 */
 
// Einbinden der benötigten Bibliotheken für den Sensor DS18B20
#include <OneWire.h>
#include <DallasTemperature.h>
 
// GPIO-Pin für DS18B20
#define GPIO_PIN 23
 
// Steuerpins für Schieberegister SN74HC595
#define   SER_PIN   18   // GPIO-Pin für serielle Daten
#define   RCLK_PIN  19   // GPIO-Pin: storage register clock
#define   SRCLK_PIN 21   // GPIO-Pin: shift register clock
 
// OneWire-Objekt erstellen ...
OneWire ow(GPIO_PIN);
// ... und einen Zeiger darauf an ein Sensor-Objekt übergeben
DallasTemperature ds_sensor(&ow);
 
DeviceAddress addr;  // ID des Sensors
 
// Kodierung der Zeichendarstellung auf dem 7-Segment-Display
byte seven_seg_code[30] =
                // G F E D C B A
                // HEX digits 0-9, A-F
    { 0x3f,     // 0 1 1 1 1 1 1 - 0
      0x06,     // 0 0 0 0 1 1 0 - 1
      0x5b,     // 1 0 1 1 0 1 1 - 2
      0x4f,     // 1 0 0 1 1 1 1 - 3
      0x66,     // 1 1 0 0 1 1 0 - 4
      0x6d,     // 1 1 0 1 1 0 1 - 5
      0x7d,     // 1 1 1 1 1 0 1 - 6
      0x07,     // 0 0 0 0 1 1 1 - 7
      0x7f,     // 1 1 1 1 1 1 1 - 8
      0x6f,     // 1 1 0 1 1 1 1 - 9
      0x77,     // 1 1 1 0 1 1 1 - A
      0x7c,     // 1 1 1 1 1 0 0 - b
      0x39,     // 0 1 1 1 0 0 1 - C
      0x5e,     // 1 0 1 1 1 1 0 - d
      0x79,     // 1 1 1 1 0 0 1 - E
      0x71,     // 1 1 1 0 0 0 1 - F
      0x80      // decimal point
            /* uncomment if needed */
      ,         // 13 additional characters
                // for words like: Lo, Hi, PUSH (PU5H), PULL, UP...
      0x38,     // 0 1 1 1 0 0 0 - c
      0x76,     // 1 1 1 0 1 1 0 - H
      0x74,     // 1 1 1 0 1 0 0 - h
      0x04,     // 0 0 0 0 1 0 0 - i
      0x0e,     // 0 0 0 1 1 1 0 - J
      0x38,     // 0 1 1 1 0 0 0 - L
      0x5c,     // 1 0 1 1 1 0 0 - o
      0x73,     // 1 1 1 0 0 1 1 - P
      0x67,     // 1 1 0 0 1 1 1 - q
      0x50,     // 1 0 1 0 0 0 0 - r
      0x3e,     // 0 1 1 1 1 1 0 - U
      0x1c,     // 0 0 1 1 1 0 0 - u
      0x40      // 1 0 0 0 0 0 0 - minus sign
            /* */
    };
 
// 1 Byte bitweise an das Schieberegister ausgeben
// nach der Übertragung jedes Bits SRCLK kurz auf HIGH setzen,
// dann auf LOW
void shift_to_74hc595(byte data) {
    int i;
 
    // Datenbyte bitweise ausgeben (höchstes Bit zuerst)
    for(i=0; i<8; i++) {
        digitalWrite(SER_PIN, 0x80 & (data << i));
        digitalWrite(SRCLK_PIN, HIGH);
        delay(1);
        digitalWrite(SRCLK_PIN, LOW);
    }
}
 
// Anzeigen aktualisieren
// die Zeichen werden nacheinander von rechts nach links(!) ausgeben
// - rechtes Zeichen rausschieben
// - linkes Zeichen rausschieben
// - Taktung kurz auf HIGH, dann auf LOW
void display_2_digits(byte left, byte right) {
    shift_to_74hc595(right);
    shift_to_74hc595(left);
    digitalWrite(RCLK_PIN, HIGH);
    delay(1);
    digitalWrite(RCLK_PIN, LOW);
}
 
void setup(void) {
    Serial.begin(115200);
    ds_sensor.begin();     // Sensor initialisieren
 
    pinMode(RCLK_PIN, OUTPUT);
    pinMode(SRCLK_PIN, OUTPUT);
    pinMode(SER_PIN, OUTPUT);
 
    // Anzeigen initialisieren: alles aus
    digitalWrite(SRCLK_PIN, LOW);
    digitalWrite(RCLK_PIN, LOW);
    display_2_digits(0x00, 0x00);
    Serial.println("Setup done");
}
 
 
void loop(void) {
    byte i;
    float temp;
 
    // ROM-Adresse des Sensors auf dem OneWire-Bus ermitteln
    if (!ow.search(addr)) {
        Serial.println("-- Kein Sensor gefunden --");
        // Text "--" anzeigen
        display_2_digits(seven_seg_code[29], seven_seg_code[29]);
    } else {
        // Abfrage der Temperatur starten
        ds_sensor.requestTemperatures();
        temp = ds_sensor.getTempC(addr);
        Serial.print("Temperatur: ");
        Serial.print(temp, 1);  // eine Nachkommastelle
        Serial.println(" °C");
        ow.reset_search();  // OneWire-Suche zurücksetzen
        if (temp < 0.0) {
            // Text "Lo"
            display_2_digits(seven_seg_code[22], seven_seg_code[23]);
            delay(2000);
        } else if (temp >= 100.0) {
            // Text "Hi"
            display_2_digits(seven_seg_code[18], seven_seg_code[20]);
            delay(2000);
        } else if (temp < 10.0) {
            // bei einstelligen Temperaturen Wert mit Dezimalkomma und
            // einer Nachkommastelle anzeigen
            display_2_digits(seven_seg_code[((int)temp % 10)] | 0x80,
                    // gerundete Nachkommastelle
                    seven_seg_code[(int)(round(temp * 10)) % 10]);
            delay(2000);
        } else {
            // bei zweistelligen Werten eine Sekunde lang die
            // Vorkommastellen anzeigen (Zehner und Einer) ...
            display_2_digits(seven_seg_code[(int)(temp / 10)],
                    seven_seg_code[(int)temp % 10]);
            delay(1000);
            // ... dann Einer mit Dezimalkomma und eine Nachkommastelle
            display_2_digits(seven_seg_code[((int)temp % 10)] | 0x80,
                    seven_seg_code[(int)(round(temp * 10)) % 10]);
            delay(1000);
        }
    }
}

Datenblätter

Schieberegister 74HC595 mit Verkabelung
Schieberegister 74HC595 mit Verkabelung
7-Segment-Anzeigen mit Schieberegistern
Kabelsalat mit 7-Segment-Anzeigen und Schieberegistern an einem ESP32 😉

3 Kommentare

    1. Hallo Thomas,

      ich habe die Schaltung nun auch noch einmal aufgebaut, und sie funktioniert wie vorgesehen.
      Überprüfe am besten noch einmal alle Kabel bzw. Steckverbindungen, insbes. + und – (3,3 V und Masse).
      Bei meinen Breadboards gibt es verschiedene Varianten, was die Belegung der Stromschienen angeht: bei den meisten Boards ist sie wie im Fritzing-Diagramm zu sehen, also Masse (blau) in den Stromschienen oben, die Versorgungsspannung (rot, 3,3 Volt vom ESP32) jeweils in der unteren Reihe. Ich habe aber auch Breadboards, bei denen die Reihen genau andersherum angeordnet sind.
      Mit Masse müssen die Pins unten in der Mitte der 7-Segment-Anzeigen verbunden sein (über einen Widerstand von 200 oder 220 Ohm) und an den 74HC595 jeweils oben die vierten Pins von links und unten die Pins ganz rechts. Spannung liegt an den 74HC595 in der oberen Reihe am ersten und vorletzten Pin. Die 7-Segment-Anzeigen haben keine direkte Masse-Verbindung.

      Die 74HC595 sind so im Breadboard eingesetzt, dass die Kerbe auf der Oberseite des Chips nach links zeigt.

      Die 7-Segment-Anzeigen SMA42056, die ich hier verwende, besitzen eine gemeinsamer Kathode (engl. common cathode) – es gibt aber auch (nicht ganz so gebräuchlich) welche mit gemeinsamer Anode (common anode). Bitte prüfe, welchen Typ du verwendest – meist ist die Angabe auf dem Gehäuse aufgedruckt – und suche dir per Suchmaschine das zugehörige Datenblatt. Eine englischsprachige Anleitung für Anzeigen mit gemeinsamer Anode gibt es z.B. auf https://www.instructables.com/Arduino-common-anode-7-segment-display/.

      Ich hoffe, die Hinweise helfen weiter,
      Heiko

      1. Hallo Heiko,
        danke für Deine Hinweise. ich habe alle Leitungen nochmal gesteckt (unter Spannung) die einzelnen LED Balken leuchten auf wenn ich die Leitungen stecke. Am Ende leuchten alle LED. Am seriellen Monitor wird die Temp. angezeigt, also die Datenerfassung klappt schonmal.

Kommentar hinterlassen

Deine E-Mail-Adresse wird nicht veröffentlicht.