McPrx-Logo

Mikrocontrollerpraxis

Flowcode und Arduino - Lauflicht

Schaltplan Lauflicht
Bild 1: Schaltplan Lauflicht

Unser zweites kleines Programmierprojekt soll die Erstellung eines Lauflichtes werden. Dazu wollen wir acht Leuchdioden mit digitalen Ausgängen des Arduinos verbinden. Ein Arduino Nano verfügt über insgesamt 14 Digital-I/O-Pins, welche allerdings nicht alle absolut gleichwertig sind. Aus Sicht des Mikrocontrollers werden die Digital-Pins intern in Achtergruppen über sogenannte Spezial-Funktions-Register (SFR) verwaltet. Eine derartige Gruppe wird auch als Port bezeichnet und mit einem Buchstaben versehen. Die Arduino-Pins D0 bis D7 bilden den Mikrocontroller-Port D, während die Pins D8 bis D13 die sechs niederwertigen Bits von Port B bilden. Auf den ersten Blick empfiehlt es sich, die Leuchtdioden mit den Arduino-Pins D0 bis D7 zu verbinden. Es ist jedoch zu beachten, dass die Pins D0 und D1 auch für die Kommunikation über die USB-Schnittstelle genutzt werden. Intern im Mikrocontroller wird dafür vom Bootloader das On-Chip-Modul USART aktiviert. Um diese Pins als Digital-Ausgänge nutzen zu können, ist es deshalb erforderlich, den USART wieder zu deaktivieren.

Wir können, wie im Schaltplan von Bild 1 dargestellt, auf dem Steckbrett an die Pins D0 bis D7 acht LED jeweils über einen Vorwiderstand anschließen. Alternativ können wir auch eine kleine Platine (Bild 2), welche acht LED, eine 4x4 Tastatur-Matrix und vier weitere Einzel-Taster enthält, mittels Jumper-Kabel mit unserem Steckbrett verbinden. Platine und Jumper-Kabel sind preiswert über ebay.de erhältlich. Die Jumper-Kabel gibt es in drei unterschiedlichen Ausführungen entweder beidseitig mit Buchsen oder Stecker sowie auf einer Seite mit Buchsen und auf der anderen mit Steckern (Bild 3). Die fertig verdrahtete Steckbrettschaltung ist in Bild 4 zu sehen.

Arduino Lauflicht
Bild 4: Verdrahtete Hardware
Jumper Kabel
Bild 3: Jumper Kabel
Platine
Bild 2: Platine mit LED u. Tastern
Schaltplan
Bild 5: Schaltplan Lauflicht (Anoden der LED an 5V)

Auf der Platine sind die Anoden der LED miteinander verbunden. Dadurch ergibt sich eine Schaltung nach Bild 5. In der Software ist bei dieser Schaltung zu beachten, dass eine LED leuchtet, wenn an dem entsprechenden Pin Null ausgegeben wird.

Nachdem wir mit Flowcode ein neues Projekt angelegt haben, fügen wir als erstes wieder eine Endlosschleife (Loop) in das Programmfluss-Diagramm 'Main' ein. Vor die Endlosschleife muß, wie oben bereits angesprochen, das USART-Modul deaktiviert werden. Dafür benötigen wir direkt nach 'BEGIN' einen Anweisungsblock vom Typ 'C Code' ein. Durch Doppelklick öffen wir dessen Eigenschaftsdialog-Dialog (Properties) und programmieren folgende C-Code-Zeile.

UCSR0B = 0;

Dieser Befehl setzt alle Bits des Spezialfunktions-Registers (SFR) USART Control and Status Register 0B (Register B von USART 0) zu Null. Mit den Spezialfunktions-Registern des Mikrocontrollers wollen wir uns aber an dieser Stelle nicht weiter auseinandersetzten, da dieses Know-how weitgehend in Flowcode integriert ist.

Main-Funktion
Bild 6: Lauflicht-Hauptprogramm

Damit unser Programmfluss-Diagramm möglichst übersichtlich bleibt, soll in der Endlosschleife ein Unterprogramm verwendet werden. Dazu dient der Anweisungsblock 'Macro'. Das Diagramm sollte jetzt den Stand haben, wie in Bild 6 dargestellt. Im Eigenschafts-Dialog von 'Call Macro' doppelklicken wir auf '...Create a New Macro...'. Im sich öffnenden Dialog vergeben wir eine Namen für unser Unterprogramm (z.B. Lauflicht) und schließen diesen Dialog mit OK. Den Eigenschafts-Dialog von 'Macro' schließen wir mit dem Button 'OK & Edit Macro'.

Die erste Idee zur Realisierung eines Lauflichtes ist häufig die Programmierung von acht Ausgabe-Aktionen jeweils gefolgt von einer Delay-Aktion. Bei den Ausgabeblöcken wählen wir diese Mal die Optionen 'PORTD' und 'Entire Port' um gleichzeitig acht Bit auszugeben. Nun müssen wir noch überlegen, welche Konstanten notwendig sind, um jeweils immer nur eine LED einzuschalten. Dazu hilft eine Blick auf das Thema Zahlensysteme. Wie wir schon wissen, werden in digitalen Systemen intern alle Werte in Bits abgebildet. Ein Bit kann dabei die Zustände Null oder Eins haben. Also immer einen von zwei. Deshalb spricht man von einem binären System oder wenn aus mehrenen Bits Zahlen gebildet werden, vom binären Zahlensystem. Während bei dem uns vertrauten dezimalen Zahlensystem jede Ziffer einer Zahl die Wertigkeit einer Zehner-Potenz wiedergibt, werden beim binären Zahlensystem Zweier-Potenzen verwendet.

Zehnerpotenz
Bild 7: Zahl 5239 in Zehner-Potenz-Darstellung

Dazu wollen wir uns ein Beispiel ansehen. Nehmen wir die Zahl 5239 (Bild 7). Das geht genauso im Binärsystem. Nehmen wir die Zahl 10110111. Aus gutem Grund habe ich genau acht Bit gewählt (8 Bit = 1 Byte).

Zweierpotenz
Bild 8: Zahl 10110111 in Zweier-Potenz-Darstellung

Wie in Bild 8 zu sehen, entspricht die Binärzahl 10110111 also der Dezimalzahl 183. Um deutlich zu machen, welchem Zahlensystem eine Zahl entstammt, wird häufig ein Buchstabe angehängt. D.h. in unserem Beispiel ist also 10110111B = 183D. Die Dezimal-Konstante einer Binär-Zahl, die immer nur eine Eins enthält, entspricht genau der Wertigkeit der entsprechenden Einser-Stelle.

Macro
Bild 9: Lauflicht-Macro

Aber zurück zu unserem Lauflicht-Unterprogramm. Wir waren ja auf der Suche nach den Konstanten, für die Folge der Ausgabe-Aktionen. Da immer nur eine LED leuchten soll, haben wir die Frage indirekt schon im vorherigen Absatz beantwortet. Aber Achtung, bei den acht Bitstellen muss genau eine Bitstelle auf Null sein, wenn wir die Platine mit der Schaltung in Bild 4 verwenden. Da das Programmfluss-Diagramm für unser Macro insgesamt 16 aufeinanderfolgende Aktions-Bölöcke enthält, ergibt sich schon eine recht lange Schlange. Deshalb habe ich in Bild 9 nur die ersten Aktionen dargestellt. Für die Logik-Invertierung habe ich übrigends einen kleinen Trick angewendet. Vor der jeweiligen auszugebenden Konstante steht der Operator ~. Dieser sorgt dafür, dass aus jedem Bit mit dem Wert 1 eine 0 wird und umgekehrt.

So richtig Toll, ist aber unsere erste Lösung eigentlich noch nicht. Stellen wir uns doch einfach mal vor, wir wollen nicht sechzehn Aktionen, sondern vielleicht doppelt so viele oder einhundert Aktionen nacheinander durchführen. Dann müssten wir überlegen, ob es nicht doch noch eine etwas intelligentere Lösung für das Problem gibt. Und meistens ist das auch der Fall.

Für unsere Aufgabe bietet es sich an, nicht Konstanten für die Ausgabe zu nutzen, sondern eine Variable. Deren Inhalt lässt sich nämlich im Programm durch geschickte Berechnungs-Aktionen modifizieren. Wenn wir uns die Konstanten noch mal genauer ansehen, sehen wir, dass sich der Wert von einer Ausgabe zur nächsten immer verdoppelt. Wir brauchen also nur eine Multiplikation mit zwei.

Globale Variable
Bild 10: Globale Variable 'led_zeile'

Also legen wir zunächst eine globale Variable mit dem Namen 'led_zeile' im Project Explorer an (siehe Bild 10). Durch einen Doppelklick auf 'Variables' öffnet sich der Dialog 'Create a New Variable'. In das erste Eingabefeld tragen wir den Variablen-Namen ein. Weiter unten stellen wir den Start-Wert der Variable auf 1 (Initial Value) und wählen als Typ Byte aus.

Jetzt wieder zu unserem Macro. Wir lösche alle Aktionen bis auf eine Ausgabe und ein Delay. In der Ausgabe-Aktion ersetzen wir die Konstante durch unsere Variable. Jetzt fügen wir eine Aktion von Typ 'Calculation' ein, in der wir die Multiplikation mit zwei durchführen (led_zeile = led_zeile * 2). So wird also bei jedem Macro-Durchlauf der Inhalt der Variable verdoppelt. Aus 1 wird 2 dann 4 dann 8 usw. Doch was passiert, wenn 128 verdoppelt wird? Das Ergebnis ist 256.

Unterprogramm Lauflicht
Bild 11: Macro Version 2

Leider ist der größte Wert den wir in unserer Variable vom Type Byte speichern können 255. Wenn also 128 in unserer Variable steht, dürfen wir den Wert nicht mehr verdoppeln, sondern müssen die Variable wieder auf ihren Startwert 1 zurücksetzen. Dafür brauchen wir jetzt eine Programmverzweigung (Decision). Das Ergebnis sehen wir in Bild 11.

© Heiko Böhmer, Stand: 03.06.16