Textanzeigen werden am häufigsten in Arduino-basierten Projekten verwendet, grafische LCDs sind relativ selten.
Überraschenderweise vergessen viele die dritte Möglichkeit, nämlich 7-Segment-Anzeigen. Mit diesen lassen sich relativ einfache Informationen darstellen. Sicherlich assoziiert sie jeder mit Digitaluhren oder Multimetern.
Bestellen Sie ein Set mit Elementen und beginnen Sie mit dem Lernen in der Praxis! Hier gehts zum Shop >>
Die meisten Bildschirme, denen wir begegnen, bestehen aus Pixeln, d. h. aus kleinen, leuchtenden Punkten. Aus diesen wird ein Text/Grafik gebildet. Bei den hier besprochenen 7-Segment-Anzeigen ist das ganz anders – sie bestehen aus 7 großen “ Punkten“.
Jeder dieser Punkte ist eine Leuchtdiode, die die Form eines Rechtecks hat. Die Segmente werden mit den Buchstaben a, b, c, d, e, f, g bezeichnet – ihre Anordnung ist immer gleich, wie unten gezeigt:
Zur Anzeige eines bestimmten Zeichens müssen die entsprechenden Segmente aufleuchten. Für die Ziffer 1 müssen beispielsweise die Segmente B und C eingeschaltet werden, für die Ziffer 2 die Segmente A, B, D, E, G, usw.
Einige Anzeigen haben zusätzlich ein separates „achtes Segment“ mit der Bezeichnung P. Das sind Punkte, die bei der Anzeige von nicht ganzzahligen Werten nützlich sein können. Sie können aber auch in einer ganz anderen Funktion verwendet werden – das hängt ganz von der Idee des Entwicklers ab. Dieses Element kann wie eine separate Leuchtdiode behandelt werden. Dies ist jedoch nicht die Hauptfunktion einer solchen Anzeige.
Manchmal kommt es trotz des vorhandenen Punktes auf der Vorderseite des Displays vor,
dass die LED überhaupt nicht vorhanden ist und wir sie nicht kontrollieren können.
Konfigurationen der 7-Segment-Anzeige
Displays werden in verschiedenen Konfigurationen zum Verkauf angeboten. Erstens gibt es sie in verschiedenen Größen und Farben. Zweitens ist es üblich, eine einzige Anzeige im Gehäuse zu finden, aber es gibt natürlich auch Versionen, die mehrere Ziffern nebeneinander darstellen können.
Die Anordnung der Anschlüsse am Gehäuse kann von Fall zu Fall unterschiedlich sein, daher ist es immer eine gute Idee, sich mit dem Datenblatt des Displays zu helfen. Man kann natürlich auch versuchen, alle Anschlüsse selbst zu identifizieren, was aber mehr Zeit in Anspruch nimmt.
Gemeinsame Kathode/Anode
Wie bei den RGB-LEDs kombinieren die Hersteller die Kathoden/Anoden der einzelnen Segmente, um Platz im Inneren dieser Anzeigen zu sparen. In der Praxis bedeutet dies, dass eine der folgenden Varianten im Inneren des Gehäuses zu finden sein wird:
Einfach ausgedrückt: In einer Konfiguration sind alle „Minuse“ der Dioden verbunden, so dass das Segment aufleuchtet, wenn an seinem Eingang ein „Plus“ anliegt. In der anderen Konfiguration sind die „Pluspunkte“ verbunden, so dass die Segmente aufleuchten, wenn an ihrem Eingang ein „Minus“ angelegt wird.
Aber genug der Theorien, jetzt geht es an die Praxis…
Fertige Sets für Forbot-Kurse
Die Komponenten für die Übungen aus dem Arduino-Kurs (Stufe 2) sind als fertige Sets erhältlich! Darin enthalten sind programmierbare Dioden, analoge und digitale Thermometer, 7-Segment-Anzeigen und ein Bewegungssensor (PIR).
Getestetes Display
Die Bauteil-Sets für diesen Kurs enthalten eine Doppelanzeige mit einer gemeinsamen Kathode. Das Symbol des Herstellers ist je nach Set das folgende: LDD040AUE-101A oder LDD040AAG-101. Diese Anzeigen sind identisch und unterscheiden sich nur in der Farbe der Beleuchtung (es macht also keinen Unterschied, welche man genau hat).
Nun muss man einen Blick auf das Datenblatt werfen, um die Beschreibung der Pinbelegung zu finden:
Wie man sieht, sind die Strukturen im Inneren des Displays völlig unabhängig voneinander – im Grunde haben wir hier zwei separate Displays in einem Gehäuse. Es ist übrigens erwähnenswert, dass es hier keine Informationen über die Pins gibt, die den Anschluss P (Punkt) steuern. Wie ich bereits erwähnt habe, kommt es vor, dass dieser Punkt nicht aktiv ist – das wird hier der Fall sein.
Achtung: Ich hoffe, es ist in diesem Stadium des Kurses klar, dass die LEDs über Widerstände gespeist werden müssen. Hier ist es noch wichtiger, dass die Dioden im Inneren der Anzeige noch leichter durchbrennen als normale LEDs!
Bleibt noch das Rätsel zu lösen, wie die Anschlüsse nummeriert sind. Hier wird es einfach, denn der Hersteller hat die entsprechenden Nummern (1 und 16) auf der Rückseite des Displays angebracht:
Schließen wir nun das erste der beiden Displays an den Arduino an. An dieser Stelle habe ich eine schlechte Nachricht. Es wird schwierig sein, die gesamte Schaltung von diesem Teil des Kurses ordentlich anzuschließen. Man kann es natürlich schneller machen, auf eine chaotische Weise. In meinen Lösungen habe ich aber versucht, es ganz ordentlich zu machen….
Anschließen des Displays an den Arduino
Wir interessieren uns für die erste Anzeige, d.h. die Segmente, die an die Pins 1, 2, 3, 13, 14, 15, 16 angeschlossen sind. Natürlich müssen wir Widerstände an jeden der Pins anschließen, und das ist ein guter Anfang. Die Dioden in der Anzeige sind hell, so dass hier ein 1k-Widerstand gut funktionieren wird.
Wir beginnen also damit, die Widerstände an jedes Segment von Display Nr. 1 anzuschließen. Wir möchten später in der Lage sein, jeden Widerstand mit einer Leitung vom Arduino zu verbinden. In meinem Fall sah das so aus:
Da die Platine schmal ist (jedes Signal hat nur 5 gemeinsame Pins), musste ich für eine gute Verteilung der Widerstände auch den Platz unter dem Display nutzen. Auf diesem Weg habe ich den Widerstand zu Bein 13 (Segment B) geführt:
Der nächste Schritt ist einfach, wir verbinden jeden Widerstand mit einer Leitung mit dem Arduino UNO. Die Reihenfolge kann beliebig sein, ich habe die folgende angenommen:
- Anschluss Nr 1 (Segment C), an Arduino Pin Nr 2,
- Anschluss Nr 2 (Segment E), an Arduino Pin Nr 3,
- Anschluss Nr 3 (Segment D), an Arduino Pin Nr 4,
- Anschluss Nr 13 (Segment B), an Arduino Pin Nr 5,
- Anschluss Nr 14 (Segment G), an Arduino Pin Nr 6,
- Anschluss Nr 15 (Segment A), an Arduino Pin Nr 7,
- Anschluss Nr 16 (Segment F), an Arduino Pin Nr 8.
Ganz zum Schluss müssen wir noch die Masse mit dem vierten Anschluss des Arduino verbinden. Auf dem Bild unten kannst du sehen, dass ich dies mit einer blauen Leitung und einem Stück abgeschnittenen Widerstandsbein getan habe.
Jetzt kann man zum Programm übergehen, das sehr einfach ist, wir steuern lediglich 7 LEDs…. Das nachstehende Beispiel sollte jedes der Segmente (A bis F) nacheinander ansteuern.
#define SEG_C 2
#define SEG_E 3
#define SEG_D 4
#define SEG_B 5
#define SEG_G 6
#define SEG_A 7
#define SEG_F 8
void setup() {
//Konfiguration der Pins als Ausgang
pinMode(SEG_A, OUTPUT);
pinMode(SEG_B, OUTPUT);
pinMode(SEG_C, OUTPUT);
pinMode(SEG_D, OUTPUT);
pinMode(SEG_E, OUTPUT);
pinMode(SEG_F, OUTPUT);
pinMode(SEG_G, OUTPUT);
//Test der Segmente
digitalWrite(SEG_A, HIGH);
delay(800);
digitalWrite(SEG_B, HIGH);
delay(800);
digitalWrite(SEG_C, HIGH);
delay(800);
digitalWrite(SEG_D, HIGH);
delay(800);
digitalWrite(SEG_E, HIGH);
delay(800);
digitalWrite(SEG_F, HIGH);
delay(800);
digitalWrite(SEG_G, HIGH);
}
void loop() {
}
Natürlich kann alles kürzer, schneller und besser geschrieben werden. Ich habe mich jedoch darauf konzentriert, das gesamte Programm lesbar und einfach zu gestalten. Alle Segmente funktionieren korrekt, wenn der Effekt wie folgt ist:
Anzeige von einzelnen Ziffern
Fürs Erste (!) ist die Situation noch einfach, so dass wir sehr leicht unsere eigene Funktion schreiben können, die eine Zahl als Argument nimmt, die sie dann auf das Display überträgt. Die in Teil 6 des ersten Arduino-Kurses beschriebene Switch-Anweisung ist dafür ideal.
Unsere Funktion kann wie folgt aussehen:
void Display(int Zahl) {
//Die Switch-Anweisung stellt die entsprechenden Ausgangszustände ein
//in Abhängigkeit von der angegebenen Zahl
switch (Zahl) {
case 0:
digitalWrite(SEG_A, HIGH);
digitalWrite(SEG_B, HIGH);
digitalWrite(SEG_C, HIGH);
digitalWrite(SEG_D, HIGH);
digitalWrite(SEG_E, HIGH);
digitalWrite(SEG_F, HIGH);
digitalWrite(SEG_G, LOW);
break;
case 1:
digitalWrite(SEG_A, LOW);
digitalWrite(SEG_B, HIGH);
digitalWrite(SEG_C, HIGH);
digitalWrite(SEG_D, LOW);
digitalWrite(SEG_E, LOW);
digitalWrite(SEG_F, LOW);
digitalWrite(SEG_G, LOW);
break;
case 2:
digitalWrite(SEG_A, HIGH);
digitalWrite(SEG_B, HIGH);
digitalWrite(SEG_C, LOW);
digitalWrite(SEG_D, HIGH);
digitalWrite(SEG_E, HIGH);
digitalWrite(SEG_F, LOW);
digitalWrite(SEG_G, HIGH);
break;
case 3:
digitalWrite(SEG_A, HIGH);
digitalWrite(SEG_B, HIGH);
digitalWrite(SEG_C, HIGH);
digitalWrite(SEG_D, HIGH);
digitalWrite(SEG_E, LOW);
digitalWrite(SEG_F, LOW);
digitalWrite(SEG_G, HIGH);
break;
case 4:
digitalWrite(SEG_A, LOW);
digitalWrite(SEG_B, HIGH);
digitalWrite(SEG_C, HIGH);
digitalWrite(SEG_D, LOW);
digitalWrite(SEG_E, LOW);
digitalWrite(SEG_F, HIGH);
digitalWrite(SEG_G, HIGH);
break;
case 5:
digitalWrite(SEG_A, HIGH);
digitalWrite(SEG_B, LOW);
digitalWrite(SEG_C, HIGH);
digitalWrite(SEG_D, HIGH);
digitalWrite(SEG_E, LOW);
digitalWrite(SEG_F, HIGH);
digitalWrite(SEG_G, HIGH);
break;
case 6:
digitalWrite(SEG_A, HIGH);
digitalWrite(SEG_B, LOW);
digitalWrite(SEG_C, HIGH);
digitalWrite(SEG_D, HIGH);
digitalWrite(SEG_E, HIGH);
digitalWrite(SEG_F, HIGH);
digitalWrite(SEG_G, HIGH);
break;
case 7:
digitalWrite(SEG_A, HIGH);
digitalWrite(SEG_B, HIGH);
digitalWrite(SEG_C, HIGH);
digitalWrite(SEG_D, LOW);
digitalWrite(SEG_E, LOW);
digitalWrite(SEG_F, LOW);
digitalWrite(SEG_G, LOW);
break;
case 8:
digitalWrite(SEG_A, HIGH);
digitalWrite(SEG_B, HIGH);
digitalWrite(SEG_C, HIGH);
digitalWrite(SEG_D, HIGH);
digitalWrite(SEG_E, HIGH);
digitalWrite(SEG_F, HIGH);
digitalWrite(SEG_G, HIGH);
break;
case 9:
digitalWrite(SEG_A, HIGH);
digitalWrite(SEG_B, HIGH);
digitalWrite(SEG_C, HIGH);
digitalWrite(SEG_D, HIGH);
digitalWrite(SEG_E, LOW);
digitalWrite(SEG_F, HIGH);
digitalWrite(SEG_G, HIGH);
break;
}
}
Ich habe das Ein- und Ausschalten einzelner Elemente auf der Grundlage des Layouts der Segmente aufgegliedert. Natürlich kann jeder seine eigenen Änderungen vornehmen, um die „Schriftart“ anzupassen. Man braucht nur die folgende Darstellung vor sich zu haben:
So kann beispielsweise die Ziffer „1“ auch auf den Segmenten F und E angezeigt werden.
Zähler auf 7-Segment-Anzeige
Es ist an der Zeit zu überprüfen, ob die von dir geschriebene Funktion fortlaufende Ziffern anzeigt. Das folgende Testprogramm besteht aus einer for-Schleife (die von 0 bis 9 läuft), die fortlaufende Ziffern aufruft:
#define SEG_C 2
#define SEG_E 3
#define SEG_D 4
#define SEG_B 5
#define SEG_G 6
#define SEG_A 7
#define SEG_F 8
void setup() {
//Konfiguration der Pins als Ausgang
pinMode(SEG_A, OUTPUT);
pinMode(SEG_B, OUTPUT);
pinMode(SEG_C, OUTPUT);
pinMode(SEG_D, OUTPUT);
pinMode(SEG_E, OUTPUT);
pinMode(SEG_F, OUTPUT);
pinMode(SEG_G, OUTPUT);
}
void loop() {
int i = 0;
//Schleife von 0 bis 9
for (i = 0; i < 10; i++) {
Display(i); //Anzeige des Wertes auf dem Display
delay(500); //500 ms warten
}
}
void Display(int Zahl ) {
//
Die Switch-Anweisung stellt die entsprechenden Zustände an den Ausgängen ein
//in Abhängigkeit von der angegebenen Zahl
switch (Zahl ) {
case 0:
digitalWrite(SEG_A, HIGH);
digitalWrite(SEG_B, HIGH);
digitalWrite(SEG_C, HIGH);
digitalWrite(SEG_D, HIGH);
digitalWrite(SEG_E, HIGH);
digitalWrite(SEG_F, HIGH);
digitalWrite(SEG_G, LOW);
break;
case 1:
digitalWrite(SEG_A, LOW);
digitalWrite(SEG_B, HIGH);
digitalWrite(SEG_C, HIGH);
digitalWrite(SEG_D, LOW);
digitalWrite(SEG_E, LOW);
digitalWrite(SEG_F, LOW);
digitalWrite(SEG_G, LOW);
break;
case 2:
digitalWrite(SEG_A, HIGH);
digitalWrite(SEG_B, HIGH);
digitalWrite(SEG_C, LOW);
digitalWrite(SEG_D, HIGH);
digitalWrite(SEG_E, HIGH);
digitalWrite(SEG_F, LOW);
digitalWrite(SEG_G, HIGH);
break;
case 3:
digitalWrite(SEG_A, HIGH);
digitalWrite(SEG_B, HIGH);
digitalWrite(SEG_C, HIGH);
digitalWrite(SEG_D, HIGH);
digitalWrite(SEG_E, LOW);
digitalWrite(SEG_F, LOW);
digitalWrite(SEG_G, HIGH);
break;
case 4:
digitalWrite(SEG_A, LOW);
digitalWrite(SEG_B, HIGH);
digitalWrite(SEG_C, HIGH);
digitalWrite(SEG_D, LOW);
digitalWrite(SEG_E, LOW);
digitalWrite(SEG_F, HIGH);
digitalWrite(SEG_G, HIGH);
break;
case 5:
digitalWrite(SEG_A, HIGH);
digitalWrite(SEG_B, LOW);
digitalWrite(SEG_C, HIGH);
digitalWrite(SEG_D, HIGH);
digitalWrite(SEG_E, LOW);
digitalWrite(SEG_F, HIGH);
digitalWrite(SEG_G, HIGH);
break;
case 6:
digitalWrite(SEG_A, HIGH);
digitalWrite(SEG_B, LOW);
digitalWrite(SEG_C, HIGH);
digitalWrite(SEG_D, HIGH);
digitalWrite(SEG_E, HIGH);
digitalWrite(SEG_F, HIGH);
digitalWrite(SEG_G, HIGH);
break;
case 7:
digitalWrite(SEG_A, HIGH);
digitalWrite(SEG_B, HIGH);
digitalWrite(SEG_C, HIGH);
digitalWrite(SEG_D, LOW);
digitalWrite(SEG_E, LOW);
digitalWrite(SEG_F, LOW);
digitalWrite(SEG_G, LOW);
break;
case 8:
digitalWrite(SEG_A, HIGH);
digitalWrite(SEG_B, HIGH);
digitalWrite(SEG_C, HIGH);
digitalWrite(SEG_D, HIGH);
digitalWrite(SEG_E, HIGH);
digitalWrite(SEG_F, HIGH);
digitalWrite(SEG_G, HIGH);
break;
case 9:
digitalWrite(SEG_A, HIGH);
digitalWrite(SEG_B, HIGH);
digitalWrite(SEG_C, HIGH);
digitalWrite(SEG_D, HIGH);
digitalWrite(SEG_E, LOW);
digitalWrite(SEG_F, HIGH);
digitalWrite(SEG_G, HIGH);
break;
}
}
Die korrekte Funktionsweise des Programms ist in der folgenden Animation zu sehen:
Zusätzliche Aufgabe 6.1
Erweitere die Funktion display() so, dass sie in der Lage ist, Informationen über eine Bereichsüberschreitung anzuzeigen. Wenn wir einen Wert größer als 9 eingeben, sollte ein Fehlersymbol, bestehend aus den leuchtenden Segmenten A, G, D, angezeigt werden.
Zusätzliche Aufgabe 6.2
Füge der Schaltung Tasten hinzu, um einen Zähler zu bauen:
- S1 – erhöht die auf dem Display angezeigte Ziffer um 1,
- S2 – verringert die auf dem Display angezeigte Ziffer um 1,
- S3 – setzt die Schaltung zurück.
Verwendung eines zweiten Displays
Jetzt wird es schwieriger… Zumindest hinsichtlich der Verbindungen. Wir werden nun das zweite Display einsetzen. Am bequemsten wäre es, es an weitere 7 Pins des Arduinos anzuschließen, aber dann hätten wir kaum noch freie Anschlüsse.
Schlimmer noch, der Anschluss von mehr Displays (z. B. 3) wäre niemals möglich. Zum Glück kann man es ein wenig geschickter anstellen!
Verbinden wir zunächst die Segmente beider Displays miteinander. Auf diese Weise werden wir mit Hilfe der 7 Pins die Werte auf beiden Displays gleichzeitig anzeigen – vorerst wird es die gleiche Zahl sein. Mit der Anzeige unterschiedlicher Werte werden wir uns etwas später beschäftigen.
Das heißt, wir streben jetzt eine Situation wie diese an:
Die Verbindung der Segmente der beiden Anzeigen kann mit Hilfe der von den Widerständen abgeschnittenen Beine schöner gestaltet werden. Dies erfordert jedoch eine gewisse riskante Lösung. Aufgrund des begrenzten Platzes werden wir jeweils 2 Drähte in ein Loch der Kontaktplatte stecken.
Diese Lösung ist riskant und wird wahrscheinlich nicht oft verwendet, da sie zu schwer zu diagnostizierenden Fehlern führen kann. Aber bei einer so einfachen Schaltung können wir das Risiko eingehen.
Zur Erinnerung noch einmal das Diagramm der Anschlüsse:
Wir beginnen mit den Segmenten C, D und E. Wir müssen also die Anschlüsse in dieser Reihenfolge vornehmen:
- 1 > 8
- 2 > 7
- 3 > 6
Dies kann wie folgt geschehen:
Um diese Verbindung herzustellen, ist es natürlich notwendig, den Draht, der die Masse zum ersten Display führte, zu lösen. Wir werden nun die Erdungen zu den Seiten herausführen (links vom ersten und rechts vom zweiten):
Der nächste Schritt besteht darin, die verbleibenden Segmente zu verbinden, d. h. wir verbinden die Anschlüsse:
- 13 > 12
- 14 > 11
- 15 > 10
- 16 > 9
In meinem Fall habe ich es geschafft, das Ganze wie folgt zusammenzusetzen:
Natürlich müssen die fehlenden Masseverbindungen am Ende noch hinzugefügt werden. Für den Moment reicht eine einfache Kabelverbindung aus. Auf dem Foto unten habe ich sie in Schleifen gewickelt, um es deutlicher zu machen:
Die Funktionsweise der Anzeigen hat sich bewährt, also ist es an der Zeit, einen Schritt weiter zu gehen. Es ist unwahrscheinlich, dass die doppelte Anzeige desselben Wertes für uns jemals von Nutzen sein wird….
Multiplexing von Displays
Die Lösung des Problems ist Multiplexing. Wenn wir abwechselnd jede Anzeige ein- und ausschalten, können wir bei einer schnellen Änderung des angezeigten Wertes auf jedem Display eine andere Ziffer anzeigen (dank der Trägheit unseres Sehvermögens ist dies eine Illusion)! Natürlich werden wir die Kathoden nicht von Hand von der Masse abtrennen. Wir werden den Arduino benutzen!
Wenn alle Segmente eingeschaltet sind, kann das gesamte Display
„von der Kathode“ mehr als 20 mA ziehen, daher sollte man es nicht direkt an den Arduino anschließen!
Steuerung von Displays durch Transistoren
Zur Sicherheit steuert der Arduino die gemeinsamen Kathoden über NPN-Transistoren. Im Bauteilset sind BC547-Transistoren enthalten, die hier perfekt funktionieren werden.
Der Anschluss wird wie folgt aussehen:
- Wir schließen die Kollektoren der Transistoren direkt an die Kathoden der Displays an. Das heißt, wir verbinden den Kollektor des ersten Transistors mit Bein 4 des Displays und den Kollektor des zweiten BC546 mit Bein 5.
- Die Basis der Transistoren verbinden wir über einen 10k-Widerstand mit den Arduino-Pins. Wir verbinden die Basis des ersten Transistors mit dem Arduino-Pin Nr. 10 und den zweiten Transistor mit Pin Nr. 9.
- Die Emitter beider Transistoren schließen wir an Masse an.
Der obige Anschluss kann wie folgt realisiert werden:
Von nun an wird ein hoher Zustand an den Arduino-Pins 9 oder 10
einen der Displays einschalten.
Multiplexing in der Praxis
Nun ist es an der Zeit, die hinzugefügten Transistoren in der Praxis zu verwenden. Zunächst müssen neue Definitionen hinzugefügt werden:
#define WYSW_1 10
#define WYSW_2 9
Der zweite Schritt besteht darin, die Konfiguration der Ausgänge hinzuzufügen:
pinMode(WYSW_1, OUTPUT);
pinMode(WYSW_2, OUTPUT);
Es ist nun möglich, die Displays getrennt zu verwenden. Beginnen wir mit einem Programm, das abwechselnd (jede Sekunde) eines der Displays startet, einen Wert anzeigt und nach einer Weile das andere Display mit einem anderen Wert startet. Das heißt, wir erwarten diesen Effekt:
In der Hauptschleife des Programms müssen wir zyklisch das erste Display einschalten, auf dem z.B. der Wert 5 angezeigt wird. Dann, nach einer Sekunde, schalten wir es aus, schalten das zweite Display ein und zeigen auf ihm den Wert 3 an. Diese Aufgabe wird von dem folgenden Programm übernommen:
#define SEG_C 2
#define SEG_E 3
#define SEG_D 4
#define SEG_B 5
#define SEG_G 6
#define SEG_A 7
#define SEG_F 8
#define WYSW_1 10
#define WYSW_2 9
void setup() {
//Konfiguration der Pins als Ausgang
pinMode(SEG_A, OUTPUT);
pinMode(SEG_B, OUTPUT);
pinMode(SEG_C, OUTPUT);
pinMode(SEG_D, OUTPUT);
pinMode(SEG_E, OUTPUT);
pinMode(SEG_F, OUTPUT);
pinMode(SEG_G, OUTPUT);
pinMode(WYSW_1, OUTPUT);
pinMode(WYSW_2, OUTPUT);
}
void loop() {
digitalWrite(WYSW_1, HIGH); //Erstes Display einschalten
digitalWrite(WYSW_2, LOW); //Zweites Display ausschalten
Display(5); //Wert auf Display anzeigen
delay(1000);
digitalWrite(WYSW_1, LOW); //Erstes Display ausschalten
digitalWrite(WYSW_2, HIGH); //Zweites Display einschalten
Display(3); //Wert auf Display anzeigen
delay(1000);
}
void Display(int Zahl) {
//Die Switch-Anweisung stellt die entsprechenden Zustände an den Ausgängen ein
//in Abhängigkeit von der angegebenen Zahl
switch (Zahl) {
case 0:
digitalWrite(SEG_A, HIGH);
digitalWrite(SEG_B, HIGH);
digitalWrite(SEG_C, HIGH);
digitalWrite(SEG_D, HIGH);
digitalWrite(SEG_E, HIGH);
digitalWrite(SEG_F, HIGH);
digitalWrite(SEG_G, LOW);
break;
case 1:
digitalWrite(SEG_A, LOW);
digitalWrite(SEG_B, HIGH);
digitalWrite(SEG_C, HIGH);
digitalWrite(SEG_D, LOW);
digitalWrite(SEG_E, LOW);
digitalWrite(SEG_F, LOW);
digitalWrite(SEG_G, LOW);
break;
case 2:
digitalWrite(SEG_A, HIGH);
digitalWrite(SEG_B, HIGH);
digitalWrite(SEG_C, LOW);
digitalWrite(SEG_D, HIGH);
digitalWrite(SEG_E, HIGH);
digitalWrite(SEG_F, LOW);
digitalWrite(SEG_G, HIGH);
break;
case 3:
digitalWrite(SEG_A, HIGH);
digitalWrite(SEG_B, HIGH);
digitalWrite(SEG_C, HIGH);
digitalWrite(SEG_D, HIGH);
digitalWrite(SEG_E, LOW);
digitalWrite(SEG_F, LOW);
digitalWrite(SEG_G, HIGH);
break;
case 4:
digitalWrite(SEG_A, LOW);
digitalWrite(SEG_B, HIGH);
digitalWrite(SEG_C, HIGH);
digitalWrite(SEG_D, LOW);
digitalWrite(SEG_E, LOW);
digitalWrite(SEG_F, HIGH);
digitalWrite(SEG_G, HIGH);
break;
case 5:
digitalWrite(SEG_A, HIGH);
digitalWrite(SEG_B, LOW);
digitalWrite(SEG_C, HIGH);
digitalWrite(SEG_D, HIGH);
digitalWrite(SEG_E, LOW);
digitalWrite(SEG_F, HIGH);
digitalWrite(SEG_G, HIGH);
break;
case 6:
digitalWrite(SEG_A, HIGH);
digitalWrite(SEG_B, LOW);
digitalWrite(SEG_C, HIGH);
digitalWrite(SEG_D, HIGH);
digitalWrite(SEG_E, HIGH);
digitalWrite(SEG_F, HIGH);
digitalWrite(SEG_G, HIGH);
break;
case 7:
digitalWrite(SEG_A, HIGH);
digitalWrite(SEG_B, HIGH);
digitalWrite(SEG_C, HIGH);
digitalWrite(SEG_D, LOW);
digitalWrite(SEG_E, LOW);
digitalWrite(SEG_F, LOW);
digitalWrite(SEG_G, LOW);
break;
case 8:
digitalWrite(SEG_A, HIGH);
digitalWrite(SEG_B, HIGH);
digitalWrite(SEG_C, HIGH);
digitalWrite(SEG_D, HIGH);
digitalWrite(SEG_E, HIGH);
digitalWrite(SEG_F, HIGH);
digitalWrite(SEG_G, HIGH);
break;
case 9:
digitalWrite(SEG_A, HIGH);
digitalWrite(SEG_B, HIGH);
digitalWrite(SEG_C, HIGH);
digitalWrite(SEG_D, HIGH);
digitalWrite(SEG_E, LOW);
digitalWrite(SEG_F, HIGH);
digitalWrite(SEG_G, HIGH);
break;
}
}
Überprüfe unbedingt, was passiert, wenn wir die Zeit zwischen den Änderungen schrittweise verringern. Es lohnt sich, z. B. 100 ms, 50 ms, 20 ms und 10 ms auszuprobieren.
Bei sehr schnellen Änderungen machen wir uns die Tatsache zunutze, dass das menschliche Auge nicht in der Lage ist, so häufige Änderungen zu erkennen. Bei ~10 ms sehen wir statt des Blinkens einen konstanten Wert von 53!
Genau darum ging es – denk daran, dass die Displays praktisch gleich angeschlossen sind, und wir unterschiedliche Werte sehen.
Zusätzliche Aufgabe 6.3
Schreibe ein Programm für den Zähler, dessen Wert sich von 0 bis 99 ändert. Die Änderung des Wertes kann automatisch erfolgen („zu jeder festen Zeit“) oder z.B. durch das Drücken einer Taste.
Wie lässt sich eine solche Lösung in der Praxis anwenden?
Alle elektronischen Verbindungen, die wir hier hergestellt haben, sind gut und können sicherlich in vielen Projekten verwendet werden. Aber wenn es um die Programmierung geht, ist dieser Ansatz …. dürftig!
Wenn wir komplexere Programme schreiben, können wir es uns nicht leisten
das Ganze mit solchen Verzögerungen zu stoppen!
Ziel der obigen Übungen war es, in der Praxis zu demonstrieren, wie 7-Segment-Anzeigen funktionieren und was Multiplexing bedeutet. In der Praxis erfordert ein sinnvolles Multiplexing den Einsatz komplexerer Mechanismen, die in Mikrocontrollern eingebaut sind.
Arduino ist jedoch dafür bekannt, dass man für alle komplizierten Sachen
fertige Bibliotheken finden kann!
Fertige Bibliothek für 7-seg-Displays.
Natürlich gibt es für die „sinnvolle“ Verwendung von 7-Segment-Anzeigen viele Bibliotheken, die im Hintergrund schwierigere Dinge erledigen. Ich wollte nicht gleich mit einer fertigen Lösung beginnen, da einige Leser das Prinzip einer solchen Anzeige vielleicht nicht verstehen – daher dieser handgefertigte Code…
Es ist an der Zeit, unsere 7-Segment-Displays mit einer vorgefertigten Bibliothek zu betreiben, was ihre Verwendung in anderen Projekten erleichtern wird. Zumindest einige solcher vorgefertigten Funktionen sind im Internet zu finden; wir werden in der weiteren Beschreibung die SevSeg Library verwenden.
Auf der obigen Seite steht, dass der eigentliche Code auf GitHub zu finden ist, zum Herunterladen der Bibliothek verwenden wir die Schaltfläche Clone or Download → Download ZIP:
Anschließend entpacken wir das Archiv und kopieren den gesamten Ordner SevSeg-master, den wir dann in das Verzeichnis der Arduino-Bibliotheken einfügen, in meinem Fall war das:
C:\Users\Damian\Documents\Arduino\libraries
Nach dem Neustart der Arduino IDE finden wir im Menü Datei → Beispiele eine neue Kategorie namens SevSeg. Dies bedeutet, dass die Bibliothek korrekt installiert wurde. Wir werden die vorgefertigten Beispiele jetzt aber nicht verwenden.
Versuchen wir, die Displays selbst zu starten – die in der Dokumentation enthaltenen Informationen sollten dafür ausreichen. Am Anfang finden wir ein Fragment einer Beispielkonfiguration:
byte numDigits = 4;
byte digitPins[] = {2, 3, 4, 5};
byte segmentPins[] = {6, 7, 8, 9, 10, 11, 12, 13};
bool resistorsOnSegments = false; // Use 'true' if on digit pins
byte hardwareConfig = COMMON_ANODE; // See README.md for options
sevseg.begin(hardwareConfig, numDigits, digitPins, segmentPins, resistorsOnSegments);
[...]
Natürlich müssen wir es nun an unsere Hardware anpassen. Als erstes ändern wir die Breite des Displays (von 4 auf 2 Ziffern). Die erste Zeile der Konfiguration sollte also wie folgt aussehen:
byte numDigits = 2;
Außerdem geben wir die Pin-Nummern an, an die die Transistoren angeschlossen sind “ Ziffer-Steuerung „:
byte digitPins[] = {10, 9};
Als nächstes müssen wir Informationen über die Verbindung der Segmente (A-G) an die Bibliothek weitergeben:
byte segmentPins[] = {7, 5, 2, 4, 3, 8, 6};
Im nächsten Schritt fügen wir Informationen darüber hinzu, wie die Verbindung hergestellt wird:
bool resistorsOnSegments = true; // Use 'true' if on digit pins
byte hardwareConfig = N_TRANSISTORS; // See README.md for options
N_TRANSISTORS – If you use N-type transistors to sink current
(or any other active-high, low-side switches).
Nach Vervollständigung der obigen Informationen sieht unsere Grundskizze wie folgt aus:
#include "SevSeg.h"
SevSeg sevseg; //Instantiate a seven segment controller object
void setup() {
byte numDigits = 2;
byte digitPins[] = {10, 9};
byte segmentPins[] = {7, 5, 2, 4, 3, 8, 6};
bool resistorsOnSegments = true; // Use 'true' if on digit pins
byte hardwareConfig = N_TRANSISTORS; // See README.md for options
sevseg.begin(hardwareConfig, numDigits, digitPins, segmentPins, resistorsOnSegments);
}
void loop() {
}
Von nun an können wir das Objekt sevseg in unserem Programm verwenden. Beginnen wir mit der Anzeige einer Zahl:
#include "SevSeg.h"
SevSeg sevseg; //Instantiate a seven segment controller object
void setup() {
byte numDigits = 2;
byte digitPins[] = {10, 9};
byte segmentPins[] = {7, 5, 2, 4, 3, 8, 6};
bool resistorsOnSegments = true; // Use 'true' if on digit pins
byte hardwareConfig = N_TRANSISTORS; // See README.md for options
sevseg.begin(hardwareConfig, numDigits, digitPins, segmentPins, resistorsOnSegments);
}
void loop() {
sevseg.setNumber(34, 2); //Anzeige der Zahl 34 über zwei Displays
sevseg.refreshDisplay();
}
Die erste Zeile in der Schleife loop() ist für die Anzeige der Zahl 34 mit 2 Displays zuständig. In unserem Fall wird das zweite Argument der Funktion immer 2 sein, da wir nicht die Möglichkeit haben, „Punkte“ in der Anzeige zu aktivieren. Gäbe es eine solche Option, könnten wir mit diesem Parameter die Formatierung der Zahlen festlegen, z. B. könnte der Wert 3 als „03“ oder „3.0“ angezeigt werden.
Die zweite Zeile von sevseg.refreshDisplay(); ist für die Auffrischung des Displays verantwortlich, d.h. für das Multiplexing, das wir zuvor manuell durchgeführt haben. Die Bibliothek selbst berechnet auf der Grundlage unserer Konfiguration, wie oft die Displays umgeschaltet werden sollten, um das Bild stabil zu halten.
Die Wirkung des Programms ist unten zu sehen:
Die genannte Bibliothek ermöglicht es, die 7-Segment-Anzeigen auf eine komplexere Weise zu verwenden. Zum Beispiel definiert sie auch Buchstaben/Symbole. Natürlich werden die meisten von ihnen aufgrund der begrenzten Anzahl von Segmenten schlecht (oder gar nicht) dargestellt….
Es ist jedoch sicher möglich, Buchstaben wie A, b, H, C usw. zu lesen. Verwende dazu die neue Funktion sevseg.setChars();. Im folgenden Beispiel werden die Buchstaben AC angezeigt:
#include "SevSeg.h"
SevSeg sevseg; //Instantiate a seven segment controller object
void setup() {
byte numDigits = 2;
byte digitPins[] = {10, 9};
byte segmentPins[] = {7, 5, 2, 4, 3, 8, 6};
bool resistorsOnSegments = true; // Use 'true' if on digit pins
byte hardwareConfig = N_TRANSISTORS; // See README.md for options
sevseg.begin(hardwareConfig, numDigits, digitPins, segmentPins, resistorsOnSegments);
}
void loop() {
sevseg.setChars("AC");
sevseg.refreshDisplay();
}
Der Effekt des Codes ist in der folgenden Abbildung zu sehen:
Alle definierten Zeichen können in der Datei SevSeg.cpp (der Hauptdatei der betreffenden Bibliothek) eingesehen werden. Das Fragment selbst mit der Definition aller Zeichen sieht wie folgt aus:
// GFEDCBA Segments 7-segment map:
B00111111, // 0 "0" AAA
B00000110, // 1 "1" F B
B01011011, // 2 "2" F B
B01001111, // 3 "3" GGG
B01100110, // 4 "4" E C
B01101101, // 5 "5" E C
B01111101, // 6 "6" DDD
B00000111, // 7 "7"
B01111111, // 8 "8"
B01101111, // 9 "9"
B01110111, // 65 'A'
B01111100, // 66 'b'
B00111001, // 67 'C'
B01011110, // 68 'd'
B01111001, // 69 'E'
B01110001, // 70 'F'
B00111101, // 71 'G'
B01110110, // 72 'H'
B00000110, // 73 'I'
B00001110, // 74 'J'
B01110110, // 75 'K' Same as 'H'
B00111000, // 76 'L'
B00000000, // 77 'M' NO DISPLAY
B01010100, // 78 'n'
B00111111, // 79 'O'
B01110011, // 80 'P'
B01100111, // 81 'q'
B01010000, // 82 'r'
B01101101, // 83 'S'
B01111000, // 84 't'
B00111110, // 85 'U'
B00111110, // 86 'V' Same as 'U'
B00000000, // 87 'W' NO DISPLAY
B01110110, // 88 'X' Same as 'H'
B01101110, // 89 'y'
B01011011, // 90 'Z' Same as '2'
B00000000, // 32 ' ' BLANK
B01000000, // 45 '-' DASH
Das letzte Beispiel mit einer 7-Seg-Anzeige
Als praktisches Beispiel wäre es sinnvoll, einen Sensor an den Arduino anzuschließen, dessen Informationen später auf dem Display angezeigt werden sollen. Idealerweise eignet sich hier „etwas“, das analog ausgelesen werden kann. Das könnte z. B. ein Fotowiderstand sein, der in einer Spannungsteilerschaltung angeschlossen ist.
Diese Lösung wurde im Kurs schon oft verwendet, daher überspringe ich diesen Hardwareteil. Wahrscheinlich wird jeder etwas finden, das er dort anschließen möchte. Für meinen Test habe ich den letzten freien Platz auf der Kontaktplatte genutzt und das Potentiometer dort platziert.
Der Anschluss war wie folgt:
- äußerster linker Anschluss an 5V,
- mittlerer Anschluss an A0,
- äußerster rechter Anschluss an Masse (GND).
Um den aktuellen Wert auf dem Display anzeigen zu können, ist eine Skalierung notwendig. Hier ist natürlich die Funktion map() hilfreich. Das gesamte Programm ist unten zu sehen:
#include "SevSeg.h"
SevSeg sevseg; //Instantiate a seven segment controller object
void setup() {
byte numDigits = 2;
byte digitPins[] = {10, 9};
byte segmentPins[] = {7, 5, 2, 4, 3, 8, 6};
bool resistorsOnSegments = true; // Use 'true' if on digit pins
byte hardwareConfig = N_TRANSISTORS; // See README.md for options
sevseg.begin(hardwareConfig, numDigits, digitPins, segmentPins, resistorsOnSegments);
}
void loop() {
int Potentiometer = analogRead(A0); //Auslesen von Informationen aus dem Fotowiderstand
Potentiometer = map(Potentiometer , 0, 1023, 0, 99); //
Skalierung auf Display
sevseg.setNumber(Potentiometer , 2);
sevseg.refreshDisplay();
}
Nach dem Einschalten zeigt die 7-Segment-Anzeige einen Wert von 0-99 an, der mit dem Potentiometer stufenlos verändert werden kann:
Die Bibliothek löst nicht alle Probleme
Die hier beschriebene Bibliothek trägt dazu bei, die Einrichtung und den Betrieb von Displays dieser Art zu erleichtern. Sie löst jedoch nicht alle Probleme. Das „Problem“ ist immer die Notwendigkeit, die Displays häufig zu multiplexen. In diesem Fall erzwingt sie häufige Aufrufe der Funktion sevseg.refreshDisplay();
Programme, die mit 7-Segment-Anzeigen arbeiten sollen, dürfen daher die Funktion delay() nicht verwenden!
Alle Verzögerungen sollten durch einen ausgefeilteren Mechanismus auf der Grundlage der Funktion millis() ersetzt werden. Bei Interesse verweise ich auf die entsprechende Arduino-Dokumentation und auf das in der SevSeg-Bibliothek enthaltene Beispiel, nämlich: Datei → Beispiele → SevSeg → SevSeg_Counter.
In diesem Kurs gehe ich nicht auf die Funktion milis() ein, da ich dieses Thema
wahrscheinlich in einer separaten Serie über „Multithreading im Arduino“ behandeln werde.
Zusammenfassung
Dieser Teil des Kurses ist ein wenig abwegig geworden. Er wurde mehrmals praktisch von Grund auf neu erstellt, weil es jedes Mal einen etwas anderen Plan dafür gab. Ich hoffe, dass es am Ende gelungen ist, die Funktionsweise des Displays zu erklären, so dass er später in der Praxis besser genutzt werden kann.
Im nächsten Teil werden wir uns mit neuen Sensoren beschäftigen. Diesmal werden wir analoge und digitale Temperatursensoren in der Praxis kennenlernen.
Bestellen Sie ein Set mit Elementen und beginnen Sie mit dem Lernen in der Praxis! Hier gehts zum Shop >>