- -
- 100%
- +
Über den Befehl delay hast du eine zeitliche Unterbrechung des Sketches eingeleitet, damit die LED eine bestimmte Zeit an beziehungsweise aus war.
Mithilfe des NOT-Operators in Verbindung mit dem Befehl digitalRead haben wir eine verkürzte Variante des Codes für das Blinken der LED kennengelernt.
Wenn man eine LED betreiben möchte, ist ein entsprechend dimensionierter Widerstand – auch Vorwiderstand genannt – unerlässlich.
Wir haben gesehen, wie sich ein Vorwiderstand mit Hilfe des Ohmschen Gesetzes berechnen lässt.
Mithilfe der Farbtabelle ist es sehr einfach, einen Widerstandswert anhand der aufgedruckten Farbringe zu ermitteln.
Wir haben die Ansteuerung einer LED über einen PWM-Pin gesehen.
Workshop zur blinkenden LED
Ich möchte dir am Ende dieses Projektes die Aufgabe stellen, den Sketch so abzuändern, dass du die Zeit, in der die LED leuchtet beziehungsweise aus ist, in zwei Variablen auslagerst. Darüber kann der sogenannte Tastgrad eingestellt werden. Er beschreibt das Verhältnis von Impulsdauer und Periodendauer. Das Ergebnis wird meist in Prozent angegeben. Auf dem folgenden Impulsdiagramm siehst du die unterschiedlichen Zeiten für t bzw. T:

Abb. 8: Der Verlauf des Pegels am digitalen Ausgang Pin 13 bei einem Tastgrad von 25%
t = Impulsdauer
T = Periodendauer
Die Formel zur Berechnung des Tastgrades lautet:

Programmiere den Sketch so, dass die LED 0,5s leuchtet und 1,5s dunkel ist. Der Tastgrad würde sich wie folgt berechnen:

Das entspricht also einem Tastgrad von 0,25 und im Hinblick auf die gesamte Periodendauer leuchtet die LED also zu 25%.
Bastelprojekt 2:
Arduino-Low-Level-Programmierung
Der Arduino Uno besitzt als Herzstück einen Mikrocontroller, der die zentrale Recheneinheit auf dem Board ist. Neben der Spannungsversorgung sind zur Kommunikation mit der Außenwelt natürlich weitere Anschlüsse vorhanden. Da gibt es die analogen und digitalen Ein- beziehungsweise Ausgänge – wir haben das schon in Kapitel 1 gesehen –, die abgefragt und auf die Einfluss genommen werden kann. Da ein Mikrocontroller auf unterster Ebene digital arbeitet, werden die Informationen als HIGH- bzw. LOW-Pegel gespeichert und verarbeitet. Diese finden in bestimmten Speicherbereichen ihr Zuhause, die man Register nennt. In diesem Bastelprojekt werden wir die ganze Sache auf unterster Ebene beleuchten, was zwar knifflig anmutet, doch zum Verständnis der Grundlagen sicherlich hilfreich ist. Aber keine Bange, ich erkläre es Schritt für Schritt.
Was um Himmels Willen ist denn ein Register? Wenn es um die Programmierung eines Mikrocontrollers geht, dann besitzt er zur internen Verwaltung und Speicherung von Werten bestimmte Speicherstellen. Die meisten davon haben einen Schreib- und Lesezugriff, was bedeutet, man kann dort etwas ablegen und auch wieder auslesen. Andere können lediglich ausgelesen werden und stellen somit nur einen Lesezugriff zur Verfügung. Derartige Speicherbereiche werden Register genannt. Wenn wir gleich die sogenannten Ports kennenlernen, dann handelt es sich um Register
Die Zugänge des Mikrocontrollers
Um mit einem Mikrocontroller in Verbindung zu treten, muss es eine Möglichkeit geben, Signale zu senden und zu empfangen. Aus diesem Grund sind bestimmte Zugänge geschaffen worden, die Ports genannt werden. Port kommt aus dem Lateinischen von porta, was Tür beziehungsweise Zugang bedeutet. Auf dem Arduino-Board befinden sich mehrere nebeneinanderliegende Pins, die teilweise zu Funktionsgruppen zusammengefasst wurden. Sie werden Ports genannt und haben eine Datenbreite von acht Bits. Auf der folgenden Abbildung 1 sehen wir einige dieser Ports:

Abb. 1: Die Ports des Arduino Uno
Die farbig markierten Ports sind mit den folgenden Pins verbunden:
Port B: Digitale Pins 8 bis 13
Port C: Analoge Eingänge (A0 bis A5)
Port D: Digitale Pins 0 bis 7
Da jeder der drei genannten Ports individuell programmiert werden kann, sind zusätzliche Register erforderlich, die für die Konfigurationen notwendig sind. Der kleine Buchstabe x wird später durch den benötigten Port ersetzt. Die Ports haben ebenfalls eine Datenbreite von acht Bits und lauten wie folgt:
DDRx (Data Direction Register): Definiert einen Pin entweder als Eingang (0) oder als Ausgang (1): read/write.
PORTx (Pin Output Value): Setzt den Pin-Status auf HIGH oder LOW: write.
PINx (Pin Input Value): Liest den Wert eines Pins: read only.

http://www.arduino.cc/en/Reference/PortManipulation
Die Programmierung eines Ports
Sehen wir uns die Sache einmal im Detail an, wobei ich nochmal erwähne, dass diese Art des Arbeitens schon in Richtung Fortgeschrittenenprogrammierung geht, doch zum tieferen Verständnis trägt dieses Wissen allemal bei. Werfen wir doch einmal einen Blick auf Port B mit den digitalen Pins 8 bis 13.

Abb. 2: Port B
An den Buchsen, die auch Header genannt werden, sind nicht alle Pins einem Port zugeordnet. Wir erkennen das hier an den kleinen diagonalen Kreuzen. Auf der Seite der Header befinden sich Beschriftungen, die Hinweis auf die Funktion geben, was in meinen Augen eine sehr nützliche und hilfreiche Sache ist. Die vier Anschlüsse von links gesehen können nicht für unsere Vorhaben verwendet werden, da sie dem I²C-Bus, der Spannungsversorgung und der Masse zugeordnet sind. Damit wir auf die digitalen Pins 8 bis 13 zugreifen können, müssen entsprechende Register vorbereitet werden. Doch zuvor sollten wir uns im Klaren darüber sein, welche Pins als Ein- und welche als Ausgänge arbeiten sollen. Wir machen es uns einfach und legen Folgendes fest:
Pin 8, 9 und 10: Eingänge
Pin 11, 12 und 13: Ausgänge
Ich habe anfangs schon die Register erwähnt, die zur Konfiguration und zur Ansteuerung der Ports verwendet werden. Auf der folgenden Abbildung 3 sehen wir zwei Register mit acht Bit Datenbreite, die diese Funktion übernehmen, wobei wir später in diesem Projekt noch die Bekanntschaft mit einem weiteren Register machen:

Abb. 3: Die Register DDRx und PORTx
Sie haben die Bezeichnung DDRx und PORTx. Fangen wir mit DDRx an, das für die Datenflussrichtung verantwortlich ist, wobei das x für den jeweiligen Port steht. In unserem Fall also DDRB. Wir wissen, dass Eingänge mit dem Wert 0 und Ausgänge mit dem Wert 1 konfiguriert werden.

Abb. 4: Die Konfiguration von Port B
Die Pfeile geben die Datenflussrichtung an und wir müssen die Programmierung, wie im nachfolgenden Sketch zu sehen, in die Entwicklungsumgebung eingeben. Ich möchte noch einmal darauf hinweisen, was ich im letzten Bastelprojekt 1 bereits ausführlich dargestellt habe: Die setup-Funktion wird einmalig zum Sketch-Start ausgeführt und die loop-Funktion kontinuierlich in einer Endlosschleife:
void setup() { DDRB = 0b11111000; // Pin 8, 9, 10 als INPUT. Pin 11, 12, 13 als OUTPUT PORTB = 0b00111000; // Pin 11, 12, 13 auf HIGH-Pegel setzen } void loop() {/* leer */}
In diesem Beispiel befindet sich nur in der setup-Funktion der Quellcode, denn wir benötigen lediglich eine einmalige Ausführung und deswegen ist die loop-Funktion leer. Die Zuweisung eines Wertes an das jeweilige Register kann im Binärformat erfolgen, was die Sache in meinen Augen sehr vereinfacht, denn auf diese Weise ist sofort ersichtlich, wie die einzelnen Pins des Ports arbeiten. Durch das Vorangestellte 0b erreichen wir die Interpretation des nachfolgenden Wertes als Binärzahl:
DDRB = 0b11111000; // Entspricht dem Dezimalwert 248
Was wir brauchen
Für dieses Bastelprojekt benötigen wir folgende Bauteile:
Tabelle 1: Bauteilliste Bauteil Bild LED grün 6x



Der Schaltplan zur Ansteuerung der LEDs sieht wie folgt aus:

Abb. 5: Der Schaltplan mit 6 LEDs
Der Versuchsaufbau auf einem Arduino Discoveryboard könnte wie folgt aussehen:

Abb. 6: Der Versuchsaufbau mit sechs Leuchtdioden auf dem Arduino Discoveryboard
Auf diese Weise kann mit unterschiedlichen Werten in der Ansteuerung gespielt werden und das Ergebnis ist sofort ersichtlich. Es gilt zu beachten, dass lediglich die Pins 11, 12 und 13 als Ausgänge konfiguriert wurden. Der Aufbau zeigt jedoch sechs Leuchtdioden an den Pins 8 bis 13. Was muss geändert werden, damit alle sechs Leuchtdioden angesteuert werden können? Die Antwort ist sicherlich einfach. Doch halt! Was ist überhaupt eine Leuchtdiode und was ist bei der Ansteuerung zu beachten? Eine Leuchtdiode – auch kurz LED (Light Emitting Diode) genannt – ist ein Halbleiterbauelement, das Licht einer bestimmten Wellenlänge abgibt und abhängig vom verwendeten Halbleitermaterial ist. Wie der Name Diode schon vermuten lässt, ist beim Betrieb auf die Stromrichtung zu achten, denn nur in Durchlassrichtung sendet die LED Licht aus. Bei entgegengesetzter Polung geht die LED nicht kaputt, sie bleibt aber einfach dunkel. Es ist unbedingt darauf zu achten, dass eine LED immer mit einem richtig dimensionierten Vorwiderstand betrieben wird. Andernfalls leuchtet sie einmal in einer beeindruckenden Helligkeit auf und dann nie wieder. Wie du den Wert des Vorwiderstands bestimmst, hast du schon im Bastelprojekt 1 gelernt. Ein Wert von 330Ω ist da ein guter Wert. Genau wie bei einer Diode gibt es bei der Leuchtdiode zwei Kontakte, von denen einer die Anode und der andere die Kathode ist. Das Schaltzeichen sieht ähnlich aus und hat zusätzlich zwei Pfeile, die das ausstrahlende Licht andeuten:

Abb. 7: Die Schaltzeichen einer Leuchtdiode
Kommen wir zurück zu unserer ursprünglichen Konfiguration, wo die Pins 8, 9 und 10 als Eingänge konfiguriert sind. Wie testen wir das Verhalten? Dazu muss ich ein wenig ausholen. In der Digitaltechnik gibt es nichts Schlimmeres als einen Schaltkreis, der als Eingang definiert ist und an dem nichts angeschlossen wurde. Wie ist das zu verstehen? Sehen wir uns die folgenden Schaltungen etwas genauer an:

Abb. 8: Ein offener Eingang
Ist der Taster geschlossen, liegen +5V am Eingangs-Pin an und öffnen wir den Taster, sollten man meinen, dass nun 0V dort anliegen. Das stimmt jedoch nicht, denn über den offenen Eingang, dem kein definierter Pegel zugewiesen wurde, können Störsignale einfließen. Es reicht schon aus, wenn mit dem Finger der Eingangs-Pin berührt wird, um einen sich ständig wechselnden Pegel zu erreichen. Aus diesem Grund verwenden wir die folgende Schaltung mit einem sogenannten Pulldown-Widerstand.

Abb. 9: Ein offener Eingang mit Pulldown-Widerstand
Ist der Taster geschlossen, ändert sich zur vorherigen Situation nichts und die +5V liegen am Eingangs-Pin an beziehungsweise fallen über dem Pulldown-Widerstand von 10KΩ nach Masse ab. Wird der Taster losgelassen, wird über den Widerstand das Massepotential an den Eingang geleitet, so dass dort ein LOW-Pegel von 0V anliegt. Wir haben also in beiden Tastersituationen ein definiertes Signal am Eingangs-Pin vorherrschen. Für das nun folgende Bastelprojekt wird wieder das Arduino Discoveryboard genutzt, das über fest verdrahtete Pulldown-Widerstände verfügt. Der Schaltplan für das kommende Bastelprojekt sieht wie folgt aus:

Abb. 10: Der Schaltplan mit drei LEDs und drei Tastern
Sehen wir uns den entsprechenden Versuchsaufbau mit den zusätzlichen drei Tastern an:

Abb. 11: Der Versuchsaufbau mit zusätzlichen Tastern
Natürlich müssen wir die Programmierung anpassen:
void setup() { DDRB = 0b11111000; // Pin 8, 9, 10 als INPUT. Pin 11, 12, 13 als OUTPUT PORTB = 0b00111000; // Pin 11, 12, 13 auf HIGH-Pegel setzen Serial.begin(9600); // Serielle Schnittstelle mit 9600 Baud vorbereiten } void loop() { // Binäre Ausgabe von Register PINB über // die serielle Schnittstelle Serial.println(PINB, BIN); delay(1000); // Pause von 1 Sekunde }
Bevor wir den Code besprechen, müssen wir noch ein weiteres Register besprechen. Es nennt sich PINx, wobei das x wieder für den entsprechenden Port steht:

Abb. 12: Das Register PINx
Bei dem Register PINB (Input Pin Address) handelt es sich quasi um ein Statusregister, das den Zustand des Ports widerspiegelt. Es kann nur lesend darauf zugegriffen werden. Wir verwenden es, um den Status aller Pins auf dem sogenannten Serial Monitor anzuzeigen. In der setup-Funktion wird die serielle Schnittstelle mit ihrer Übertragungsrate von 9600 Baud initialisiert. Die spätere Ausgabe erfolgt innerhalb der loop-Funktion über println (Print Linefeed) mit dem zusätzlichen Parameter BIN, der eine binäre Ausgabe des Wertes erzwingt.
Der sogenannte Serial Monitor wird über ein Symbol in der Entwicklungsumgebung geöffnet, das ich rot umrandet habe:

Abb. 13: Das Öffnen des Serial Monitors
Nach einem Mausklick darauf öffnet sich der Monitor:

Abb. 14: Das Fenster des Serial Monitors
Die drei niedrigsten Bits auf der rechten Seite im Serial Monitor spiegeln den Status der drei Taster wider. Welche Taster oder welchen Taster habe ich wohl gedrückt, um die hier gezeigten Bitkombinationen zu erreichen?
Was ist beim Input-Register PINx zu beachten?

Hinsichtlich des Input-Registers PINx werden alle Statusinformationen des jeweiligen Ports auf einmal gelesen.
Register und C++-Befehle
Zur Programmierung und Ansteuerung der verschiedenen Pins ist diese Art der Programmierung vielleicht etwas umständlich und deswegen stehen verschiedene Befehle in der Programmiersprache C++ zur Verfügung, die uns die Sache etwas vereinfachen. Wir kommen im Detail im nächsten Bastelprojekt 3 darauf zu sprechen, aber ich möchte dennoch den direkten Zusammenhang an dieser Stelle verdeutlichen:
Tabelle 2: Register und ihre Entsprechungen Register C++-Befehl Beispiel DDRB pinMode pinMode(13, OUTPUT); PORTB digitalWrite digitalWrite(10, HIGH); PINB digitalRead digitalRead(8);Hier noch einige Informationen zu den verwendeten Befehlen:
pinMode
Der Befehl pinMode programmiert die Datenflussrichtung eines digitalen Pins, wobei zwei Parameter notwendig sind. Der erste gibt den gewünschten Pin an und der zweite die Richtung, wobei OUTPUT für Ausgang und INPUT für Eingang steht.
digitalWrite
Der Befehl digitalWrite beeinflusst den Zustand eines digitalen Pins, wobei zwei Parameter notwendig sind. Der erste gibt den gewünschten Pin an und der zweite den Pegel, wobei HIGH 5V und LOW 0V entspricht.
digitalRead
Der Befehl digitalRead liest den Zustand eines digitalen Pins, wobei das Ergebnis entweder HIGH oder LOW sein kann.
Was ist beim Input-Register PINx zu beachten?

Hinsichtlich der beiden Pins RX und TX der seriellen Schnittstelle, die in ihren Datenflussrichtungen nicht verändert werden sollten und sich auf Port D befinden, gibt es eine sicherere Methode. Das nachfolgende Beispiel programmiert Pin 2 bis 7 als Ausgänge und verändert Pin 0 und 1 nicht: DDRD |= 0b11111100;
Warum ist das so? Wir verwenden eine binäre Oder-Verknüpfung des binären Wertes mit dem gezeigten Register. An den kritischen Stellen Pin 0 und 1 erfolgt eine Oder-Verknüpfung mit dem Wert 0, was bedeutet, dass diese beiden Bits unverändert bleiben. Nähere Informationen zur Manipulation von Bits sind unter der folgenden Adresse zu finden:

http://playground.arduino.cc/Code/BitMath
Für Detailinformationen zum Pin-Mapping ist die folgende Adresse sicherlich hilfreich:

http://www.arduino.cc/en/Reference/Atmega168Hardware
Der Pullup-Widerstand
Wir haben gesehen, dass ein offener Eingang an einem digitalen Pin zu Problemen führen kann und deswegen eine externe Beschaltung zum Beispiel über einen Pulldown-Widerstand erforderlich ist. Nun gibt es aber auch eine Schaltung, bei der ein sogenannter Pullup-Widerstand eingesetzt wird. Es handelt sich dabei um einen ganz normalen Widerstand, der jedoch im Gegensatz zum Pulldown, der an Masse liegt, jetzt mit 5V der Versorgungsspannung verbunden ist. Bei einem offenen Eingang würden demnach 5V am betreffenden Pin anliegen. Sehen wir uns dazu die folgende Schaltung an:

Abb. 15: Ein offener Eingang mit Pullup-Widerstand
Worauf ich hinaus möchte, ist die Tatsache, dass der Mikrocontroller intern über eingebaute Pullup-Widerstände verfügt, die bei Bedarf aktiviert werden können. Wie funktioniert das? Wir müssen dazu zwei Schritte durchführen, die eigentlich widersprüchlich sind:
Einen Pin als Eingang programmieren.
Den Pin mit einem HIGH-Pegel versehen.
Warum habe ich widersprüchlich gesagt? Nun, wenn ein Pin als Eingang programmiert wird, dann erwartet man doch, dass von außen ein Pegel anliegt, der sich auch ändern kann. Wenn wir jetzt aber im zweiten Schritt diesen Pin mit dem Wert HIGH versehen und so tun, als wäre der Pin als Ausgang programmiert, wird der interne Pullup-Widerstand aktiviert. Sehen wir uns dazu den entsprechenden Sketch an, der die Register DDB und PORTB verwendet:
void setup() { DDRB = 0b00000000; // Alle Pins als INPUT PORTB = 0b00000111; // Pullup für Pin 8, 9 und 10 aktiviert Serial.begin(9600); // Serielle Schnittstelle mit 9600 Baud vorbereiten } void loop() { Serial.println(PINB, BIN); delay(500); // Pause von 500 Millisekunden }
Wenn wir jetzt lediglich drei Mikrotaster ohne Widerstände an die digitalen Eingänge 8, 9 und 10 anschließen, dann funktioniert unsere Schaltung perfekt, denn die internen Pullup-Widerstände sorgen für einen sauberen und störungsfreien Pegel. Natürlich können für dieses Bastelprojekt die auf dem Arduino Discoveryboard vorhandenen Taster nicht verwendet werden, da sie über einen fest verdrahteten Pulldown-Widerstand verfügen. Das ist aber kein Problem, denn es befindet sich auf dem Arduino Discoveryboard ein kleines Breadboard, auf dem die kleinen Mikrotaster sehr gut eingesteckt werden können.

Abb. 16: Eine Schaltung mit drei Tastern
Wenn wir jetzt den Serial Monitor öffnen, werden wir feststellen, dass bei nicht gedrückten Tastern die jeweiligen Bits auf HIGH-Pegel liegen, was ja auch zu erwarten war. Drücken wir jetzt einen der Taster, ändert sich der betreffende Pegel des Bits von HIGH- auf LOW-Pegel. Natürlich kann man die internen Pullup-Widerstände auch mit einem konventionellen Arduino-Befehl aktivieren oder deaktivieren.