Teil 1
Hallo liebe Bastler!
In den folgenden Beiträgen möchte ich Ihnen zeigen, wie wir einen 8-Bit-Binärkonverter aus einem Arduino Mikrocontroller, einem LCDisplay mit I2C-Adapter und einigen Schaltern umsetzen können. Wir werden damit Binärcodes in Hexadezimal- und Dezimalzahlen umrechnen.
Im ersten Teil gebe ich Ihnen einfache Tipps zum Umrechnen vom binären in das hexadezimale sowie dezimale Zahlensystem. Ich zeige Ihnen, wie man ein 20x4 LCDisplay mit nur zwei (respektive vier) Leitungen ansteuern kann. Dafür erkläre ich auch kurz die I2C-Schnittstelle. Außerdem laden wir die ersten Beispielprogramme für das Display auf den Arduino.
Im zweiten Teil zeige ich Ihnen, wie der Quellcode für unser Programm aussieht. Wir nutzen die Bitmanipulation sowie Portmanipulation. Das hilft uns, wenn wir alle Schalter gleichzeitig auslesen möchten. Dafür benötigen wir auch ein wenig boolesche Algebra, die ich ebenfalls kurz erläutern werde. Außerdem erzeugen wir eigene Symbole, die wir auf dem Display anzeigen können. Es ist äußerlich kein großes Projekt.
Daher werde ich mehr ins Detail gehen, um denen von Ihnen zu helfen, die noch nicht sicher im Umgang mit Arduino-Programmierung sind. Los geht’s.
Binärumrechnung
Zu Beginn möchte ich noch einmal auf die Theorie der Umrechnung zwischen binär, dezimal und hexadezimal eingehen. Das ist eigentlich sehr leicht. Binär hat zwei Wertigkeiten, 0 und 1. Dezimal zählt von 0 bis 9. Für jede Zehnerstelle wird eine 1 vorangestellt und dann wird wieder von 0 bis 9 gezählt. Das hexadezimale System zählt von 0 bis 15, wobei die Zahlen 10 bis 15 durch Buchstaben ersetzt werden. Wir nutzen 8 Bit und geben jedem Bit von rechts nach links eine Wertigkeit, die sich von 1 beginnend immer verdoppelt.
Wertigkeit | 128 | 64 | 32 | 16 | 8 | 4 | 2 | 1 |
---|
Geben wir nun jedem Bit noch die Möglichkeit, den Zustand 1 oder 0 einzunehmen.
Wertigkeit | 128 | 64 | 32 | 16 | 8 | 4 | 2 | 1 |
---|---|---|---|---|---|---|---|---|
Zustand | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
Als Nächstes stellen wir uns die Zustände als Schalter vor. Wir addieren die Wertigkeiten in der oberen Zeile zusammen. Aber nur die Werte, die in der unteren Zeile 'eingeschaltet' wurden.
Summe: | |||||||||
---|---|---|---|---|---|---|---|---|---|
Wertigkeit | 128 | 64 | 32 | 16 | 8 | 4 | 2 | 1 | 28 |
Zustand | 0 | 0 | 0 | 1 | 1 | 1 | 0 | 0 |
Damit erhalten wir aus der binären Zahl 0001 1100 die dezimale Zahl 28. Man kann natürlich auch von dezimal in binär umrechnen. Nehmen wir an, wir möchten dezimal 7 in binär umrechnen. Wir schauen in die Tabelle von links nach rechts, ob die Wertigkeit in unsere Zahl passt. Immer dort, wo es nicht passt, setzen wir den Zustand auf 0.
Summe: | |||||||||
---|---|---|---|---|---|---|---|---|---|
Wertigkeit | 128 | 64 | 32 | 16 | 8 | 4 | 2 | 1 | 7 |
Zustand | 0 | 0 | 0 | 0 | 0 |
In diesem Fall ist die 4 die erste Wertigkeit, die in unsere 7 passt. Also setzen wir deren Zustand auf 1. Wir müssen nun 4 von 7 abziehen, da 4 Wertigkeiten verbraucht wurden.
Summe: | |||||||||
---|---|---|---|---|---|---|---|---|---|
Wertigkeit | 128 | 64 | 32 | 16 | 8 | 4 | 2 | 1 | 3 |
Zustand | 0 | 0 | 0 | 0 | 0 | 1 |
Die weiteren Wertigkeiten passen ebenfalls in unsere Zwischensummen. Somit werden sie auch auf 1 gesetzt.
Summe: | |||||||||
---|---|---|---|---|---|---|---|---|---|
Wertigkeit | 128 | 64 | 32 | 16 | 8 | 4 | 2 | 1 | 0 |
Zustand | 0 | 0 | 0 | 0 | 0 | 1 | 1 | 1 |
Bleibt von unserer Dezimalzahl nichts mehr übrig, sind wir fertig und lesen nur noch die Binärzahl ab: 0000 0111.
Hinweis: Sind alle acht Zustände auf 1 gesetzt und man addiert die Wertigkeiten, erhält man die Zahl 255. Man kann also mit 8 Bit Werte von 0 bis 255 abbilden.
Hinweis: Binärzahlen mit einer 1 an der niedrigsten Stelle (hier rechts) sind ungerade Zahlen.
Nun möchten wir nicht nur zwischen binär und dezimal umrechnen, sondern das Ergebnis auch in hexadezimal angezeigt bekommen. Das Zahlensystem rechnet von 0 bis 15. Also 16 Werte. Allerdings werden die Werte 10 bis 15 mit Buchstaben dargestellt.
Dezimalwert | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Hexadezimalwert | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B | C | D | E | F |
Kleine Eselsbrücken: 12 (Cwölf, auch wenn es falsch geschrieben ist), 13 (Dreizehn) und 15 (Fünfzehn).
Um nun von binär in hexadezimal umzurechnen, zerteilt man die 8 Bit in jeweils 4 Bit. 8 Bit sind 1 Byte. Zwei mal 4 Bit sind zwei Halbbytes oder auch 'Nibbles' genannt. In der ursprünglichen Tabelle ersetzen wir die Wertigkeiten 128, 64, 32 und 16 durch 8, 4, 2, 1.
Wertigkeit | 128 | 64 | 32 | 16 | 8 | 4 | 2 | 1 |
---|---|---|---|---|---|---|---|---|
Nibblewertigkeit | 8 | 4 | 2 | 1 | 8 | 4 | 2 | 1 |
Zustand | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
Das Beispiel für die Binärzahl von vorher nutzen wir hier auch noch einmal.
Summe: | |||||||||
---|---|---|---|---|---|---|---|---|---|
Wertigkeit | 128 | 64 | 32 | 16 | 8 | 4 | 2 | 1 | 28 |
Nibblewertigkeit | 8 | 4 | 2 | 1 | 8 | 4 | 2 | 1 | 1 | 12 |
Zustand | 0 | 0 | 0 | 1 | 1 | 1 | 0 | 0 |
In der zweiten Zeile werden die Wertigkeiten für beide Seiten getrennt addiert, abhängig von den 'Schaltern' in der untersten Zeile. Das ergibt für die linke Seite 1 und für die rechte Seite 12. Da im hexadezimalen System Werte ab 10 durch Buchstaben ersetzt wer- den, entspricht die 12 dem Buchstaben C. Unser Ergebnis ist also 1C (hex).
Summe: | |||||||||
---|---|---|---|---|---|---|---|---|---|
Wertigkeit | 128 | 64 | 32 | 16 | 8 | 4 | 2 | 1 | 28 |
Nibblewertigkeit | 8 | 4 | 2 | 1 | 8 | 4 | 2 | 1 | 1 || 12 |
Zustand | 0 | 0 | 0 | 1 | 1 | 1 | 0 | 0 | |
Hex-Wert | 1 | C |
Hinweis: An den zweistelligen hexadezimalen Zahlen erkennt man sofort, dass es sich um 8 Bit handelt.
Möchte man nun von hexadezimal in binär oder dezimal umrechnen, ist das der gleiche Vorgang wie weiter oben schon beschrieben. Man teilt die beiden hexadezimalen Werte auf und übernimmt sie in die letzte gezeigte Tabelle. Wir probieren das mit der Zahl AF (hex).
Summe: | |||||||||
---|---|---|---|---|---|---|---|---|---|
Wertigkeit | 128 | 64 | 32 | 16 | 8 | 4 | 2 | 1 | |
Nibblewertigkeit | 8 | 4 | 2 | 1 | 8 | 4 | 2 | 1 | |
Zustand | |||||||||
Hex-Wert | A (10) | F (15) |
Man prüft dann die Wertigkeiten der Nibbles aus Zeile zwei von links nach rechts, ob die Werte dort hineinpassen. Wenn ja, setzt man eine 1 und zieht die Wertigkeit ab. Ist von den ursprünglichen beiden Zahlen nichts mehr übrig, hat man seine Binärzahl erhalten.
Summe: | |||||||||
---|---|---|---|---|---|---|---|---|---|
Wertigkeit | 128 | 64 | 32 | 16 | 8 | 4 | 2 | 1 | |
Nibblewertigkeit | 8 | 4 | 2 | 1 | 8 | 4 | 2 | 1 | |
Zustand | 1 | 1 | |||||||
Hex-Wert | 2 | 7 |
Als Letztes addiert man die Wertigkeiten der ersten Zeile abhängig von den Zuständen und erhält das dezimale Ergebnis.
Summe: | |||||||||
---|---|---|---|---|---|---|---|---|---|
Wertigkeit | 128 | 64 | 32 | 16 | 8 | 4 | 2 | 1 | 175 |
Nibblewertigkeit | 8 | 4 | 2 | 1 | 8 | 4 | 2 | 1 | |
Zustand | 1 | 0 | 1 | 0 | 1 | 1 | 1 | 1 | |
Hex-Wert | 0 | 0 |
Das Ergebnis aus AF(HEX) ist also 10101111(BIN) oder 175(DEZ).
Benötigte Hardware
Kommen wir nun zum praktischen Teil. Natürlich brauchen wir Hardware. Dazu gehören:
Anzahl | Bauteil | Anmerkung |
---|---|---|
PC mit der Arduino IDE und Internetverbindung | ||
1 | Steckbrett | |
1 | Arduino Uno 3 | |
1 | 8 Schalter (hier in Form von Dipswitches) | |
1 | 20x4 Liquid Chrystal Display (LCD) | |
1 | I2C-Adapter für LCDs | |
1 | Verbindungskabel |
Schaltplan
Hier sehen Sie schon einmal den Schaltplan für unser Projekt:
Abbildung 1: Schaltplan
Was ist I2C?
Da wir im nächsten Abschnitt die I2C (I squared C, also I quadrat C) -Schnittstelle verwenden, möchte ich darauf noch kurz eingehen. Was ist das eigentlich? Es handelt sich dabei um ein serielles Datenbussystem, dessen Vorteil ist es, mehrere Geräte miteinander zu verbinden und sie in diesem 'Netzwerk' zu adressieren. Dadurch sind nur zwei Datenleitungen notwendig.
Es basiert auf dem Master-Slave-Prinzip. Der Master initiiert den Datenaustausch, der oder die Slaves sprechen darauf an. Im Idealfall haben die einzelnen Geräte zwei Eingänge (SDA und SCL) sowie zwei Ausgänge (ebenfalls SDA und SCL). So können sie in einer Kette hintereinander angeschlossen werden. Der Master nutzt dann die Geräteadressen, um jedes einzelne Gerät anzusprechen. Nachteil hierbei ist allerdings, dass die Kabellängen sehr eingeschränkt sind. Man kann damit keine meterlangen Strecken überwinden.
Display ansteuern
Damit wir eine Ausgabe erhalten, schließen wir zuerst das Display an. Mit dem I2C- Adapter ist es möglich, mit nur zwei Leitungen (Daten und Takt) sowie Spannungsversorgung (5V und Masse) das Display in Betrieb zu nehmen. Man spart sich die aufwendige Verkabelung, die sonst notwendig ist.
Allerdings kann es sein, dass man den Lötkolben zur Hand nehmen muss. Der Adapter passt wie ein Shield auf die Rückseite des Displays. Beim Anbringen muss man darauf achten, dass die vier Anschlüsse GND, VCC, SDA und SCL auf der von vorn gesehen linken Seite zeigen. So wie es auch in Abbildung 1 zu sehen ist. Abbildung 2 zeigt die Rückseite mit dem montierten Adapter (auch Backpack genannt).
Abbildung 2: I2C Backpack
Die Anschlüsse SDA und SCL liegen beim Arduino Uno auf den Pins A4 (SDA) und A5 (SCL). Nutzt man andere Boards, muss man eventuell das Datenblatt hinzuziehen. Es ist möglich, dass es dann eine andere Pinbelegung gibt.
Wir schließen nun also das Display an den Arduino an und testen zuerst, ob wir ein 'Bild' erhalten.
Dafür starten wir die Arduino IDE und installieren zuerst die Bibliothek
liquid_- chrystal_i2c. Wir öffnen den Bibliotheksverwalter unter dem Menüpunkt 'Werkzeuge'. Dort geben wir in die Suche den Namen der Bibliothek ein und suchen in der Liste nach dem passenden Eintrag. Wählt man ihn aus, kann man auf installieren klicken. Anschließend steht die Bibliothek zur Verfügung.
Abbildung 3: Bibliotheksverwalter
Wählt man nun aus dem Menü Datei die Beispiele und scrollt nach unten, findet man den Eintrag für diese Bibliothek und kann die mitgelieferten Beispiele laden. Wir öffnen das Projekt HelloWorld und laden es auf den Arduino hoch. Man kann sich dann auch gleich ein wenig mit der Umgangsweise des Displays vertraut machen. Dazu später mehr.
Wir brauchen nun noch 8 Schalter, die unsere 8 Bit repräsentieren. Im Grunde sind Bits nichts anderes als logische Schalter. Daher passt das hier ganz gut.
Um ein wenig Platz zu sparen, verwende ich Dipswitches. Man kann natürlich auch acht separate Schalter jeder beliebigen Form verwenden. Im Schaltplan sind es acht Dips. Mehr benötigen wir nicht. Wir nutzen die digitalen Pins 0 bis 7 des Arduino und schließen dort jeweils die eine Seite der Schalter an. Die anderen werden an die Masse angeschlossen (Pull-up- Widerstände schalten wir per Software hinzu).
Es ist auch darauf zu achten, dass wir später die Bits von rechts nach links 'lesen'. Also sollte auch der Schalter rechts außen an Pin 0 des Arduino angeschlossen werden. Dann von rechts nach links die restlichen Pins.
Tipp: Wenn die Pins 0 (RX) und 1 (TX) verwendet werden, können beim Upload auf den Arduino Probleme auftreten. Auch der serielle Monitor ist dadurch beeinträchtigt. Man könnte auf andere Pins ausweichen. Ich möchte aber die Portmanipulation nutzen und bleibe daher auf den Pins 0 bis 7, die alle auf dem Port D liegen.
Zum Hochladen ziehe ich die beiden Pins einfach kurz ab und stecke sie später wieder drauf. Den seriellen Monitor nutzen wir nicht.
Ein weiteres Codebeispiel für das Display ist das Projekt CustomChars. Dort wird gezeigt,wie man eigene Symbole erzeugt. Jedes Feld des Displays besteht aus 5x8 kleinen Pixeln. Unter folgendem Link:
https://i.stack.imgur.com/1TKZH.gif
findet man eine Übersicht, bei der alle Zeichen aufgeführt sind, die im Speicher des Displays zur Verfügung stehen. Man kann die ersten 8 Speicherplätze selbst füllen. Dafür erzeugt man ein Array, in dem für jede Zelle eines Feldes eine 1 oder 0 geschrieben wird. Man kann es auch in hexadezimaler Form umsetzen.
Dadurch wird der Quellcode kleiner, aber nicht unbedingt lesbarer.
In Binärform kann man die Symbole unter Umständen auch direkt erkennen. Unter diesem Link:
https://maxpromer.github.io/LCD-Character-Creator/
kann man eigene Symbole erzeugen und den automatisch generierten Quellcode in sein Projekt kopieren. Wir werden uns später einen Kreis, ein Schaltersymbol für 'aus' und ein weiteres Schaltersymbol für 'an' generieren.
Vorschau
Sie haben nun einen Einblick in die Umrechnung zwischen Zahlensystemen erhalten. Außerdem können wir ein LCDisplay mit dem I2C-Backpack sehr einfach mit dem Arduino ansteuern und eigene Zeichen ausgeben. Im zweiten Teil zeige ich Ihnen, wie wir den Quellcode umsetzen.
Wir nutzen Port- und Pinmanipulation. Außerdem erstellen wir uns eine Binär-Dezimal-Hexadezimal-Tabelle auf dem Display. Wir nutzen ein wenig boolesche Algebra, um Bitmasken zu verrechnen.