Mikrocontroller-Programmierung

Im Folgenden wird der Arduino[1] eingesetzt, auf dem ein ATmega328 verbaut ist. Grundlage für den Unterricht ist das Handbuch des SparkFun Inventor’s Kits.

Vorsicht: Schließen Sie keine Bauteile an den Mikrocontroller an, ohne vorher die Eignung genau zu prüfen! Der Mikrocontroller kann durch falsche Beschaltung beschädigt werden!

Sehr umfangreiche Sets bietet z. B. Elegoo an. Empfehlungen: (Die Anschaffung ist für den Unterricht nicht vorgeschrieben und nicht erforderlich.)

Die Plattform Autodesk Tinkercad bietet nach Registrierung zahlreiche Tutorials und umfangreiche Simulation.

1 Vorbereitung

Nach Bearbeitung dieses Kapitels können Sie ...

  • ... den korrekten Mikrocontroller und dessen COM-Port in der IDE einstellen.
  • ... ein Programm kompilieren und auf den angeschlossenen Mikrocontroller übertragen.

  1. Installieren Sie die Software (Seite 4).
  2. Evtl. muss noch der USB-Treiber installiert werden[2]
  3. Machen Sie sich mit der IDE (Seiten 6-8) und dem Kit (Seiten 12-17) vertraut.

Alternativ kann für Visual Studio 2017 eine Erweiterung installiert werden.

Das Programm, das auf den Arduino übertragen wird, wird 'Sketch' genannt. Das Grundgerüst besteht immer aus drei Teilen:

  • Im Deklarationsteil werden evtl. zusätzliche Bibliotheken geladen und globale Variablen deklariert und initialisiert.
  • Der Initialisierungsteil void setup(){ ... }[3] - hier werden z.B. Ein- und Ausgänge festgelegt.
  • Die Ausführungsschleife void loop(){ ... }[4] beinhaltet den Programmteil, der immer wieder ausgeführt wird, um kontinuierlich Taster oder Sensoren abzufragen.

Achten Sie in der Statuszeile darauf, dass das richtige Board (Arduino/Genuino Uno) und der korrekte COM-Port ausgewählt sind. Ändern Sie die Werte ggf. im Werkzeuge-Menü. Die Nummern der COM-Ports können Sie im Geräte-Manager unter Anschlüsse (COM&LPT) ermitteln.

2 Ausgänge schalten

Nach Bearbeitung dieses Kapitels können Sie ...

  • ... LEDs mit Vorwiderständen an einem Mikrocontroller anschließen.
  • ... angeschlossene LEDS ein- und ausschalten.
  • ... Zeit zwischen ein- und ausschalten festlegen.

Zunächst sollen LEDs[5] über einen digitalen Ausgang ein- und ausgeschaltet werden. Der Arduino hat eine Ausgangsspannung von 5 Volt. Da diese Spannung für die beiliegenden LEDs zu hoch ist, müssen Vorwiderstände (330 Ohm - orange-orange-braun) vorgeschaltet werden[6].

Achtung: Die Ausgänge dürfen jeweils mit maximal 40mA belastet werden! Der gesamte Arduino mit maximal 200mA!

Im Initialisierungsteil müssen für die Ausgänge mit digitalWrite(pinNumber, LOW); das Register auf einen definierten Zustand gebracht und mit pinMode(pinNumber, OUTPUT);[7] als Ausgang deklariert werden.

In der Ausführungsschleife können die Zustände dann geschaltet werden:

  • digitalWrite(pinNumber, HIGH);[8] schaltet den Ausgang ein
  • digitalWrite(pinNumber, LOW); schaltet den Ausgang aus
  • delay(1000);[9] wartet eine Sekunde

Arbeitsauftrag:

  1. Bauen Sie den Schaltkreis 1 nach (Seiten 18-24).
  2. Ein Freund von Ihnen möchte für seine Modelleisenbahn eine Ampel bauen, die realistische Lichtzeichen gibt. Ihnen kommt sofort die Idee, dafür einen Mikrocontroller einzusetzen.
    Kommentieren Sie den Quellcode und speichern Sie diesen unter dem Namen '1-2-1-Ampel' ab.

3 Taster abfragen

Nach Bearbeitung dieses Kapitels können Sie ...

  • ... in Abhängigkeit eines Tasterdrucks verschiedene Befehle ausführen.

Damit immer ein definierter Zustand am Eingang des Arduino anliegt, muss ein Pull-Up-Widerstand (10 kiloOhm - braun-schwarz-orange)[10] eingesetzt werden, der auf 5 Volt liegt. Alternativ kann er als Pull-Down-Widerstand auf Masse liegen. Der Taster schaltet dann die 5 Volt durch.

Um einen Taster abzufragen, muss der entsprechende Pin im Initialisierungsteil als Input definiert werden pinMode(pinNumber, INPUT);.

In der Ausführungsschleife kann der Zustand des Tasters mit buttonState = digitalRead(buttonPin);[11] abgefragt werden. Dabei ist zu beachten, wenn Sie einen Pull-Up-Widerstand verwenden, dass der Taster auf Masse schaltet (also LOW) und im nicht-gedrückten Zustand 5 Volt anliegen (HIGH).

Arbeitsauftrag:

  1. Bauen Sie den Schaltkreis 5 nach (Seiten 37-40)
  2. Erweitern Sie die Schaltung und entwickeln Sie ein Programm, dass die vier Zustände der beiden Taster wie folgt darstellt.
    Kommentieren Sie den Quellcode und speichern Sie diesen unter dem Namen '1-3-1-Zustaende' ab.
    • kein Taster - LEDs aus
    • Taster 1 - LED grün an
    • Taster 2 - LED gelb an
    • Taster 1+2 - LED rot an
  3. Erstellen Sie ein Programm, das auf Tastendruck einen Wert von 0 bis 7 hoch zählt und anschließend wieder bei 0 beginnt. Das Ergebnis soll binär auf den LEDs dargestellt werden. Lagern Sie die binäre Darstellung der Zahl in eine Funktion[12] aus.
    Kommentieren Sie den Quellcode und speichern Sie diesen unter dem Namen '1-3-2-Zaehler' ab.

4 Taster entprellen

Beim Abfragen des Tasters haben Sie sicher festgestellt, dass der Arduino nicht immer wie erwartet schaltet. Ursache hierfür ist das Prellen der Taster, d.h. bei der Betätigung werden mehrere Schaltimpulse gegeben[13]. Um dem entgegen zu wirken, können prellfreie Schalter verwendet werden, die allerdings sehr teuer sind. Eine weitere Möglichkeit besteht in elektronischen Schaltungen[14], was jedoch einen zusätzlichen Aufwand nach sich zieht. (Zusammenfassung)

Die einfachste und preiswerteste Möglichkeit ist das softwaretechnische Entprellen. Für zeitunkritische Anwendungen reicht es aus, nach jedem Tastendruck eine Wartezeit einzufügen. Bei zeitkritischen Anwendungen ist diese unnötige Belastung des Prozessors sehr ungünstig.

Arbeitsauftrag:

  1. Öffnen Sie die Datei '1-3-2-Zaehler'. Nach jedem Tastendruck soll eine bestimmte Zeit vergehen, bis der nächste Tastendruck akzeptiert wird. Testen Sie, welche Zeit hierfür ausreichend ist.
    Kommentieren Sie den Quellcode und speichern Sie diesen unter dem Namen '1-4-1-Zaehler' ab.
  2. Öffnen Sie die Datei '1-3-2-Zaehler' und entprellen Sie alle Tasterabfragen mit Hilfe der Flankenerkennung.
    Kommentieren Sie den Quellcode und speichern Sie diesen unter dem Namen '1-4-2-Zaehler' ab.

5 Werte ausgeben

Nach Bearbeitung dieses Kapitels können Sie ...

  • ... beliebigen Text und Werte im Seriellen Monitor ausgeben.
  • ... beliebigen Text und Werte auf einem angeschlossenen LC-Display ausgeben.

5.1 Serieller Monitor

Werte können auch auf dem Serial-Monitor ausgegeben werden, was den Vorteil hat, dass auch die zurückliegenden Werte angezeigt werden.
Zur Verwendung muss im Initialisierungsteil die Übertragungsrate mit Serial.begin(9600);[15] eingestellt werden.
Anschließend können in der Ausführungsschleife mit Serial.println(iWert);[16] Werte ausgegeben werden.

Weitere Infos: Margolis, Seiten 89-148.

Achtung: Wenn das Ausgabefenster von Processing geöffnet ist, ist die Kommunikation mit dem Arduino-Board nicht möglich, weil Processing auf die serielle Schnittstelle zugreift, die auch für die Kommunikation des Arduino-Board mit der Entwicklungsumgebung benötigt wird. Dieser Port ist also durch Processing blockiert und muss erst wieder durch das Schließen des Ausgabefensters freigegeben werden.

5.2 LC-Display steuern

Dem Kit liegt ein LC-Display[17] mit zwei Zeilen und je 16 Zeichen bei.

LCD-Pin Arduino-Pin
1
GND
VSS
2 +5V VDD
3 - V0 - Kontrasteinstellung über 10K oder 20K Poti
4 12 RS - Register Select
5 GND R/W - Read/Write / fest auf Masse (HIGH: Read / LOW: Write)
6 11 E - Enable
11 5 D4 - Datenleitung
12 4 D5 - Datenleitung
13 3 D6 - Datenleitung
14 2 D7 - Datenleitung
15 - A - Anode (+) (evtl. über Vorwiderstand 330 Ohm!)
16 GND K - Kathode (-)

Zur Ansteuerung muss im Deklarationsteil die Library eingebunden werden #include <LiquidCrystal.h>[18].
Anschließend muss noch mit LiquidCrystal lcd(rs, en, d4, d5, d6, d7);[19] ein Objekt instanziert werden, wobei die Pinbelegung dem Konstruktor übergeben wird.
Im Initialisierungsteil wird dann die Größe des Displays lcd.begin(16, 2);[20] festgegelegt.
In der Ausführungsschleife können dann beliebige Zeichen lcd.print("hello, world!");[21] ausgegeben werden.
Um Text in der zweiten Zeile auszugeben, muss der Cursor zunächst mit lcd.setCursor(0, 1); dorthin gesetzt werden.
Wenn an den Text eine Zahl angehängt werden soll, muss diese zunächst mit lcd.print("Zahl: " + String(iZahl)); in einen Text umgewandelt werden.
Mit lcd.clear(); kann das Display wieder gelöscht werden.

Arbeitsauftrag:

  1. Bauen Sie den Schaltkreis 15 (Seiten 77-80) nach.
  2. Zeigen Sie die Zahl, die im letzten Kapitel durch drei LEDs binär dargestellt wurde nun zusätzlich dezimal auf dem Display und im Serial-Monitor an.
    Kommentieren Sie den Quellcode und speichern Sie diesen unter dem Namen '1-5-1-Display' ab.

6 Analoge Eingänge

Nach Bearbeitung dieses Kapitels können Sie ...

  • ... Sensoren an dem Mikrocontroller anschließen.
  • ... Messwerte eines Sensors auslesen, umrechnen und ausgeben.

In der Praxis werden oft Licht- oder Temperatursensoren oder Potentiometer eingesetzt, die analoge Werte in Form eines variablen Widerstandes und damit einer variablen Spannung liefern. Der Arduino hat sechs analoge Eingänge (A0 - A5), die über iWert = analogRead(pinNumber);[22] mit einer Auflösung von 10Bit eingelesen werden können. Das bedeutet, dass die Spannung zwischen 0 und 5 Volt in 1024 verschiedene Integer-Werte umgewandelt wird.
Diese Werte können mit iWert = map(iWert, 0, 1023, 0, 100);[23] in einen anderen Bereich umgerechnen werden.
Zusätzlich sollte mit iWert = constrain(iWert, 0, 100);[24] der Zahlenbereich eingeschränkt werden.

Achtung: Die Spannung von 5 Volt darf auf keinen Fall überschritten werden, da der Mikrocontroller dadurch zerstört wird.

6.1 Potentiometer

Dem Kit liegt ein Potentiometer[25],[26] mit 0-10 kiloOhm bei, das einen Spannungsteiler darstellt, dessen Teilungsverhältnis sich proportional zur Einstellung verändert.

Arbeitsauftrag:

  1. Bauen Sie den Schaltkreis 2 (Seiten 25-28) nach und regeln Sie die Blinkfrequenz durch Drehen des Potentiometers.
    Kommentieren Sie den Quellcode und speichern Sie diesen unter dem Namen '1-6-1-Poti' ab.
  2. Verändern Sie das Programm, dass bei Erreichen eines Schwellwertes die LED eingeschaltet und bei Unterschreiten des Schwellwertes wieder abgeschaltet wird.
    Kommentieren Sie den Quellcode und speichern Sie diesen unter dem Namen '1-6-2-Poti' ab.
  3. Ergänzen Sie das Programm und zeigen Sie die Stellung des Potentiometers in Prozent auf dem Seriellen Monitor an.
    Kommentieren Sie den Quellcode und speichern Sie diesen unter dem Namen '1-6-3-Poti' ab.

6.2 Photo-Sensor

Photo-Sensoren, auch LDR (Light Dependent Resistor) genannt, verändern abhängig von der Helligkeit ihren Widerstand. Da der Arduino nur Spannungen messen kann, muss aus dem LDR und einem 10 kiloOhm-Widerstand (braun-schwarz-orange) ein Spannungsteiler gebaut werden.

Arbeitsauftrag:

  1. Bauen Sie den Schaltkreis 6 (Seiten 41-44) nach und geben Sie den ermittelten Wert in Prozent auf dem Seriellen Monitor aus.
    Kommentieren Sie den Quellcode und speichern Sie diesen unter dem Namen '1-6-4-PhotoSensor' ab.

6.3 Temperatur-Sensor

Der analoge TMP36[27]-Sensor lässt sich sehr einfach benutzen, da er linear arbeitet, d.h. der Widerstand ändert sich proportional zur Temperatur. Es kann ein Temperaturbereich von -40° bis 125° gemessen werden. Bei einer Versorgungsspannung von 5V und einer Temperatur von 25° liegen am Signal-Pin 750mV an. Diese Spannung ändert sich um 10mV je ein Grad Celsius und muss im Programm umgerechnet werden.

Achtung:

  • der TMP36 sieht in dem TO-92-Gehäuse einem Transistor zum Verwechseln ähnlich!!
  • auf richtige Polung achten!

Arbeitsauftrag:

  1. Bauen Sie den Schaltkreis 7 (Seiten 45-48) nach und geben Sie den ermittelten Wert Grad Celsius auf dem Seriellen Monitor aus.
    Kommentieren Sie den Quellcode und speichern Sie diesen unter dem Namen '1-6-5-TempSensor' ab.

7 'Analoge' Ausgänge

Nach Bearbeitung dieses Kapitels können Sie ...

  • ... Aktoren regulieren.

Da sich die Ausgangsspannung eines Mikrocontrollers nicht regeln lässt, also kein 'echtes' analoges Signal erzeugt werden kann, muss zur Ansteuerung z.B. von Motoren oder LEDs ein Rechtecksignal erzeugt werden. Die Fläche dieser Rechtecke ist ein Maß für die zugeführte Energie. Der Abstand der Impulse muss dabei so kurz wie möglich gewählt werden, dass diese nicht wahrgenommen werden können. Dieses Verfahren nennt sich PulsWeitenModulation (PWM)[28]. Der Arduino unterstützt eine PWM-Ausgabe an den Pins 3, 5, 6, 9, 10 und 11 (mit Tilde '~' markiert).
Die Breite der Impulse lässt sich mit analogWrite(pinNumber, iWert);[29] in einem Bereich von 0-255 einstellen.

Der Mittelwert der Ausgangsspannung berechnet sich wie folgt: Upwm = U * (Tein / Tein+Taus) oder: Upwm = U * Tein *fpwm

Vorsicht: Für das jeweilige Anwendungsgebiet muss die Ausgangsbeschaltung berücksichtigt werden, damit der Arduino nicht überlastet oder eine LED nicht mit zu hoher Spannung betrieben wird. Die Verwendbarkeit ist bei jeder Schaltung vorher zu prüfen.

Arbeitsauftrag:

  1. Bauen Sie erneut den Schaltkreis 2 (Seiten 25-28) nach.
  2. Verändern Sie das Programm und regeln Sie die Helligkeit der LED durch Drehen des Potis. Nutzen Sie zur Umrechnung des analogen Eingangssignals (0-1023) die map(...);-Funktion[30].
    Kommentieren Sie den Quellcode und speichern Sie diesen unter dem Namen '1-7-1-PWM' ab.
  3. Verändern Sie das Programm so, dass die PWM mit digitalWrite(pinNumber, ...); und delay(...);simuliert wird. Hierzu müssen die delay-Zeiten nach dem Ein- und Ausschalten der LED durch drehen des Potis so verändert werden, dass ein PWM-Signal entsteht.
    Kommentieren Sie den Quellcode und speichern Sie diesen unter dem Namen '1-7-1-PWMsim' ab.
  4. Ergänzen Sie die Schaltung um die RGB-LED aus Schaltkreis 3 (Seiten 29-32) und verändern Sie Farbe der LED durch drehen des Potis.
    Kommentieren Sie den Quellcode und speichern Sie diesen unter dem Namen '1-7-2-PWM' ab.
  5. Erweitern Sie die Schaltung um vier Taster. Verändern Sie den roten Lichtanteil mit dem Poti und die beiden anderen Lichtanteile mit jeweils zwei Tastern. Zeigen Sie die drei Farbwerte auf dem Seriellen Monitor an.
    Kommentieren Sie den Quellcode und speichern Sie diesen unter dem Namen '1-7-3-PWM' ab.

7.1 Servo steuern

Die Ansteuerung von Servos ist sehr einfach, da über die Steuerleitung mit Hilfe eines PWM-Signals dem Servo nur der Winkel 'mitgeteilt' wird. Zuerst muss die Header-Datei eingebunden werden #include <Servo.h>[31], danach wird im Deklarationsteil ein Servo-Objekt instanziert Servo servo1; und im Initialisierungsteil mit servo1.attach(pinNumber);[32] festgelegt, an welchem PWM-Pin das Servo angeschlossen ist. Im Ausführungsteil kann dann mit servo1.write(Winkel);[33] der Winkel des Servos zwischen 0 und 180 eingestellt werden.

Arbeitsauftrag:

  1. Bauen Sie den Schaltkreis 8 (Seiten 49-52) nach.
  2. Verändern Sie das Programm so, dass der Winkel des Servos mit einem Potentiometer eingestellt werden kann. Geben Sie den Wert des Winkels auch auf dem Seriellen Monitor aus.
    Kommentieren Sie den Quellcode und speichern Sie diesen unter dem Namen '1-8-1-Servo' ab.
  3. Bauen Sie den Schaltkreis 9 (Seiten 53-56) Flex-Sensor nach und geben Sie den Winkel des Servos auch auf dem Seriellen Monitor aus.

8 Links