Grundlagen der Programmierung 1

Dieses Kapitel behandelt die erforderlichen grundlegenden Kenntnisse einer Programmiersprache.

  1. Programmstruktur
  2. Variablen und Datentypen
  3. Konstanten
  4. Operatoren
  5. Entscheidungen (if)
  6. Wiederholungen (while)
  7. Hardware Interaktion
  8. Unterbrechungen (delay)

Programmstruktur

Ein (Arduino-)Programm löst ein konkretes Problem. Die verwendete Programmiersprache kann dabei genutzt werden, um den Lösungsalgorithmus in konkrete C-Strukturen zu überführen, die letztendlich die Lösung darstellt. Der Anwender gibt dabei Textbausteine ein, die vom Compiler als C – Schlüsselwörter interpretieren werden.

Dabei wird jeder Textbaustein, der nicht innerhalb eines Kommentars steht, als Quellcode betrachtet und der Compiler versucht diesen in Maschinencode zu überführen.

Der Compiler übersetzt dabei die Textbausteine nach dem Prinzip des „case sensitive“ – Verfahren. Bei der Textkompilierung wird auf Groß – und Kleinschreibung geprüft. Textbausteine, wie zum Beispiel „hallo“ und „Hallo“, würden vom Compiler unterschiedlich interpretiert werden.

Wie schon beschrieben hat der Compiler die Aufgabe den Programmcode zu übersetzen, damit dies erfolgreich durchgeführt werden kann, sollte sich der Nutzer beim Programmieren an Programmierregeln halten, auf die der folgende Text eingehen möchte.

Blöcke

Ein Block wird durch ein Paar geschweiften Klammern gebildet. Dabei wird dieser durch die öffnende geschweiften Klammer „{“ eingeleitet und durch die schließende geschweiften Klammer „}“ wieder geschlossen. Blöcke bilden dabei isolierte logische Einheiten, die untereinander nicht in Beziehung stehen. Blöcke können auch verschachtelt werden, sodass ein Block einen weiteren Block beinhalten könnte. Die folgende Abbildung visualisiert mehrere Blöcke, die hier farblich markiert und verschachtelt wurden.

Die in der gleichen Farbe markierten Klammern bilden einen Block

Befehle

Ein Programmierbefehl ist eine Arbeitsanweisung, die der Computer abarbeiten kann. Die Arbeitsanweisung addiere 1 und 5 soll hier als Beispiel dienen. Programme bestehen meist aus einer Befehlsabfolge. Jeder Befehl entspricht dabei einen Programmarbeitsschritt.

Die Arbeitsschritt-Beendigung wird durch das Semikolon- Zeichen („;“) eingeleitet. So kann der Compiler jeden einzelnen Befehl spezifizieren und übersetzen.

Die folgende Abbildung visualisiert dabei den Befehl der Addition.

Kommentare

Kommentare ermöglichen den Anwender den Quellcode zu dokumentieren.

  1. Die Zeichen „//“ leiten dabei einen Kommentar ein. Alle folgenden Zeichen einer Zeile werden dann vom Compiler ignoriert.
  2. Die Zeichen „/*“ und „*/“ leiten einen mehrzeiligen Kommentar ein. Text, welcher zwischen den Zeichen „/*“ und „*/“ steht, wird dabei vom Compiler ignoriert. Der Kommentar kann sich hierbei über mehrere Zeilen ausdehnen.

Kommentare dienen der Programmdokumentation und werden vom Compiler völlig ignoriert. Sie sollten fester Bestandteil bei einer Programmentwicklung sein und helfen den Anwender bei der Fehlerbeseitigung. Sie helfen beim Programmverständnis und vereinfachen das Lesen und Verstehen des eigentlichen Programmcodes erheblich. Auch Nutzer, die den Programmcode nicht selber verfasst haben, erhalten so eine einfache und effiziente Möglichkeit den Programmcode nachzuvollziehen und diesen bei Bedarf zu ergänzen.

Die folgende Abbildung visualisiert den Einsatz eines dokumentierenden Kommentars. Hier wird die Codefunktionalität dokumentiert und auf eine umgesetzte Bedingung (if-Klausel) aufmerksam gemacht. Konkret soll nur dann ein Datenschreibzugriff erfolgen, wenn dieser programmbedingt benötigt wird. Die Lebensdauer des Speicherplatzes wird dadurch verlängert.

Arduino spezifisch

Die folgenden beschriebenen Codestrukturen sind Arduino-spezifisch. Diese Strukturelemente machen nur in Bezug mit dem Arduino richtig Sinn.

Die beiden Funktionen „setup“ und „loop“ werden automatisch von der IDE generiert, wenn der Anwender ein neues Arduino-Projekt erzeugt.

(siehe Code-Editor)

Setup

Codefragmente, die sich innerhalb der Setup Funktion befinden, werden beim ersten Start des Programms auf den Arduino einmalig abgearbeitet. Die geschweiften Klammern „{“ und „}“ bilden dabei den Funktionskörper und strukturieren die Programmfunktionalitäten.

Die Setup-Funktion eignet sich hervorragend, um Daten und Funktionalitäten zu initialisieren. Zum Beispiel könnten Datenbereiche (Variabel) mit Daten oder Funktionen initialisiert werden.

Loop

Codefragmente, die sich innerhalb der Loop-Funktion befinden, werden in regelmäßigen zeitlichen Einheiten ständig abgearbeitet. Diese Abarbeitungskette endet, wenn der Arduino ausgeschaltet wird.

Die Loop-Funktion eignet sich für Codefragmente, die ständig abgearbeitet werden müssen.

Folgende Abbildung visualisiert die beiden Grundfunktionen des Arduinos. Die geschweiften Klammerpaare bilden jeweils die individuellen Funktionskörper.

Variablen und Datentypen

Variablen

Variablen sind wichtige Computerprogramm-Bestandteile. Sie dienen der Wertspeicherung. Variablen können unterschiedliche Werte eines Typs speichern. Arithmetische Berechnungen können zum Beispiel durchgeführt und dessen Ergebnisse in numerischen Variablen gespeichert werden.

Variablen können als Container bezeichnet werden, die Speicherplatz für einen konkreten Datentyp (z.B. Zahlen) bereitstellen.

Die folgende Abbildung visualisiert das Codefragment einer Variabel-Initialisierung. Dabei werden drei Variablen definiert, die den Datentyp int zugewiesen bekommen. Diese drei Speicherbereiche können jetzt Ganzzahlen speichern. Die Einleitung der Initialisierung beginnt mit dem Schlüsselwort int gefolgt vom Variabel-Namen. Die eigentliche Wertzuweisung wird durch den Zuweisungsoperator „=“ eingeleitet. Die Variable mit dem Namen „a“ enthält den Ganzzahlwert 5 zugewiesen. Die anderen Variabel die Ganzzahlwerte 2 und 0. Durch eine anschließende Addition der Variabel-Werte a und b erhält die Variabel C durch den Zuweisungsoperator den Wert 7 zugewiesen. Alle Variabel können nur natürliche Zahlen, einschließlich der negativen und der Null, aufnehmen. Die Darstellungsgrößen der größten und kleinsten speicherbaren natürlichen Zahlen werden vom deren Speicherplatzbedarf begrenzt.

Initialisierte Variabel-Namen müssen eindeutig sein. Die Definition einer Variabel mit identischem Name ist hier nicht möglich. Der Compiler würde einen Fehler auswerfen und den Kompilierungsvorgang unterbrechen.

Globale Variablen

Globale Variablen sind für alle Blöcke sichtbar. Auf deren Werte kann jede Block-Codestruktur zugreifen und Veränderungen durchführen.

Folgende Abbildung visualisiert das Codefragment einer globalen Variabel-Definition. Die Int-Variablen mit den Namen „globaleVariableWert“, „globaleVariableErgebnis“, und „globaleVariableErgebnis2“ können von jedem Codeblock aus beschrieben und gelesen werden. Im Codeblock der Setup-Funktion wird eine arithmetische Operation mit dem globalen Werten durchgeführt. Im Codeblock der Loop-Funktion eine erneute Operation auf die globalen Werte. Die Verwendung globaler Variablen ist sehr fehleranfällig und deren Werte können von jedem beliebigen Codefragment aus geändert werden.

Lokale Variablen

Datenzugriffe auf lokale Variablen können nur in Blockbereichen passieren, wo die Variable-Initialisierung stattfand. Dabei wären Datenzugriffe aus untergeordneten Code-Blockbereichen ebenfalls möglich. Datenzugriffe aus separat-definierten Code-Blockbereichen wären allerdings nicht möglich. Die folgende Abbildung möchte diesen Sachverhalt nochmals verdeutlichen. Die lokal initialisierte Integer-Variabel „nummer“ erhält in ihrem Code-Blockbereich eine Wertzuweisung. Der Datenzugriff kann nicht aus einem separat-definierten Blockbereich geschehen, der hier durch die Loop-Funktion gebildet wird. Der Compiler würde einen Fehler auswerfen, weil die Datenstruktur im entsprechenden Codebereich nicht bekannt wäre.

Lokale Variablen können identische Namen tragen, allerdings müsste deren Initialisierung und Definierung in separaten Code-Blockbereichen erfolgen. Die folgende Abbildung möchte diesen Sachverhalt nochmals verdeutlichen. Die Integer-Variabel „x“ wird im Blockbereich der Loop-Funktion initialisiert und definiert. Die erneute Initialisierung und Definierung einer Integer-Variabel, die einen identischen Namen trägt, ist in einem separat-definierten untergeordneten Blockbereich der Loop-Funktion möglich.

Namenskonvention

Bei der Namensvergabe an Variabeln, Konstanten und Funktionen besteht eine Namenskonvention. Die beliebige Zusammensetzung eines Namens aus Zeichen ist nicht möglich. Der Compiler überprüft Namenszusammensetzungen auf folgenden Konventionen.

  1. C-Schlüsselwörter bzw. reservierte Wörter dürfen nicht verwendet werden.
  2. Die Zeichenlänge kann zwischen 1 und 255 betragen.
  3. Der Variabelname muss mit dem Unterstrich (_) oder einem Zeichen des Alphabets beginnen.
  4. Ab dem zweiten Zeichen können auch Ziffern gewählt werden.
  5. Der Namen darf keine Sonderzeichen und Leerzeichen beinhalten. Der Unterstrich (_) wäre aber erlaubt.

Datentypen

Der Datentyp einer Variablen spezifizieren die Art der Daten und dessen Speicherplatzbedarf. Die Speicherung Ganzer und gebrochener Zahlen und Zeichenketten ist dabei möglich.

Der Anwendungsfall liefert dabei den zu verwendeten Datentyp.

Die folgende Tabelle listet wichtige Datentypen auf. Dabei werden Speicherplatzverbrauch und Wertebereiche der Datentypen aufgeführt. Der Integer – Datentyp „unsignet int“ kann zum Beispiel nur positive ganze Zahlen darstellen.

https://www.startertutorials.com/blog/wp-content/uploads/2016/04/data-types-sizes-in-c.png

Die Datentypen char und short benötigen zum Beispiel 1 Byte Speicherplatz. Der Datentyp Short kann für die Zahlendarstellung genutzt werden. Der Datentyp Char repräsentiert dabei ein Zeichen. Jedes Zeichen wird einer konkreten Zahl zugeordnet (siehe ASCII Tabelle). Dem Datentyp char können also Zeichen und Zahlen zugeordnet werden. Die Zeichenzuordnung erfolgt durch das Hochkommata (‚).

Mathematische Bedingungen können durch den Datentyp „bool“ realisiert werden. Der Datentyp bildet die Wahrheitswerte „true“ oder „false“ ab. Er benötigt 1 Byte Speicherplatz.

Die folgende Abbildung visualisiert die Code-Definierung und Initialisierung zweier Bool-Variablen. Der Wahrheitswert „true“ steht stellvertretend für den Zahlenwert 1 und „false“ für den Zahlenwert 0.

Der String-Datentyp dient der Speicherung von Zeichenketten. Die Speicherung von char-Ketten ist dabei möglich. String-Variablen besitzen dabei eine Zeichenkettenlänge. Die Zeichenketten-Zuweisung wird durch das Anführungszeichen eingeleitet („).

Konstanten

Konstanten besitzen vergleichbar zu Variablen einen Datentyp. Sie können ebenfalls mit einem Wert initialisiert werden, allerdings kann dieser Vorgang nur einmalig stattfinden. Der Wert der Konstanten kann anschließend dann nicht mehr im laufenden Betrieb des Computerprogrammes verändert werden. In Gegensatz zu Variablen, die mit der Hilfe des Zuweisungsoperators eine Wertänderung erhalten können.

Die folgende Abbildung visualisiert das Codefragment einer Integer-Konstanten-Initialisierung. Konstanten werden mit dem Schlüsselwort „const“ eingeleitet, um sie von den Variablen abzugrenzen.

Konstanten können, wie Variablen, die gleichen Datentypen annehmen.

Die folgende Abbildung visualisiert Berechnungsvorschriften, die arithmetische Operationen auf Zahlen beschreiben. Die farblich markierten Zahlen könnten durch eine Konstanten ersetzt werden, um bei deren Wertänderung nur die entsprechende Konstante anpassen zu müssen (const int Zahl_5 = 5).

Konstanten können spezifischen Name haben, so dass der Quellcode bedingt dokumentiert und lesbarer gestaltbarer wäre. Die folgende Abbildung visualisiert die Konstanten-Initialisierung der mathematischen Zahl PI.

Operatoren

Operatoren sind Berechnungsvorschriften, die Daten manipulieren und verknüpfen.

Unäre Operatoren

Unäre Operatoren beziehen sich dabei auf einem Datenbereich.

OperatorFunktionBeispiel
Umkehrung des Vorzeichens einer Zahlint a = 5;
int b = -a; // b ist jetzt -5
++Erhöhen um 1 (Inkrementieren)int a = 5;
a++; // a ist jetzt 6
−−Vermindern um 1 (Dekrementieren)int a = 5;
a−−; // a ist jetzt 4
!Logische negation von boolschen Wertenbool a = true;
bool b = !a; // b ist jetzt false

Binäre Operatoren

Binäre Operatoren werden auf zwei Operanten angewendet. Die folgende Tabelle listet einige wichtige binäre Operatoren auf.

OperatorFunktionBeispiel
*Multiplikation zweier Zahlenint a = 5;
int b = 7;
a * b; // Ergebnis 45
/Division zweier Zahlenint a = 20;
int b = 5;
a / b; // Ergebnis 4
%Modulooperation auf zwei Zahlenint a = 13;
int b = 7;
a % b; // Ergebnis 6
+Addition zweier Zahlenint a = 5;
int b = 5;
a + b; // Ergebnis 10
Subraktion zweier Zahlenint a = 2;
int b = 22;
a – b; // Ergbnis -20
>Größer Verlgiechint a = 50;
int b = 51;
a > b; // Ergbnis false
b > a; // Ergbis true
a > a; // Ergbnis false
<Kleiner Vergleichint a = 50;
int b = 51;
a < b; // Ergebnis true
b < a; // Ergebnis false
a < a; // Ergbnis false
>=Größer-gleich Vergleichint a = 50;
int b = 51;
a >= b; // Ergebnis false
b >= a; // Ergebnis true
a >= a; // Ergbnis true
<=Kleiner-gleich Vergleichint a = 50;
int b = 51;
a <= b; // Ergebnis true
b <= a; // Ergebnis false
a <= a; // Ergbnis true
==Gleichheit Vergleichint a = 50;
int b = 51;
a == b; // Ergebnis false
a == 50; // Ergbnis true
!=Ungleichheit Vergleichint a = 50;
int b = 51;
a != b; // Ergebnis true
a != 50; // Ergbnis false
||Logisches Oderfalse|| false; // Ergebnis false
true || false; // Ergebnis true
false || true; // Ergebnis true
true || true; // Ergebnis true
&&Logisches Undfalse && false; // Ergebnis false
true && false; // Ergebnis false
false && true; // Ergebnis false
true && true; // Ergebnis true
=Zuweisungint a = 50;
a = 60; // a hat jetzt den Wert 60

Beliebige Operatoren-Verknüpfungen sind dabei möglich.

Der farblich markierte Codebereich kombiniert unterschiedliche Operatoren zu einem mathematischen Ausdruck.

Diese Berechnugsvorschrift kann in kleineren Teilberechnungen aufgelöst werden, damit der Ausdruch vereinfacht werden kann. Dabei werden mathematische Gesetzmäßigkeiten angewendet, um eine Formelauflösung zu erreichen.

Der aktuell betrachtete Ausdruck wird gelb markiert, der aktuell betrachtete Operator orange.

Der erste Ausdruck, der ausgewertet wird, ist (correctionFactor / 100). Das Ergebnis dieses Ausdrucks ist 0,005.
((microseconds + (1000000 * (1 + (correctionFactor / 100)))) >= micros())

Dieser Ausdruck wird anschließend durch den „+“-Operator mit 1 zusammengerechnet, sodass das Ergebnis des verschachtelten Ausdrucks 1,005 ist.
((microseconds + (1000000 * (1 + (correctionFactor / 100)))) >= micros())

Im Anschluss wird 1,005 mit 1.000.000 durch den „*“-Operator multipliziert. Das Ergebnis dieser Operation ist 1.005.000.
((microseconds + (1000000 * (1 + (correctionFactor / 100)))) >= micros())

Danach wird die Variable microseconds zu dem Ergebnis hinzu addiert, womit das Ergebnis 2.255.000 ist.
((microseconds + (1000000 * (1 + (correctionFactor / 100)))) >= micros())

Zum Schluss wird geprüft, ob dieser Wert größer oder gleich der Variable „micros()“ ist. Da 2.255.000 größer ist als der Wert der Variable „micros()“ (2.000.000) ist das Ergebnis des letzten und damit des gesamten Ausdrucks true.
((microseconds + (1000000 * (1 + (correctionFactor / 100)))) >= micros())

Dieser Umstand ermöglicht die Vereinfachung komplexer verschachtelter Ausdrücke zu simpel strukturierten Ausdrücken.

Entscheidungen (if)

Mathematische Berechnungen können durch die Kombination verschiedener Operatoren realisiert werden. Dabei können deren Ergebnisse in Variablen gespeichert werden. Kontrollstrukturen, die mathematische Bedingungen überprüfen können, müssen bei einer modernen Programmiersprache vorhanden sein, um konkrete Problemlösung erreichen zu können. Das if-Statement überprüft den Wahrheitswert eines mathematischen Ausdrucks und trifft entsprechend eine Entscheidung in der Bearbeitungskette des Computerprogramms.

if

Wie schon beschrieben überprüft die if-Klausel einen mathematischen Ausdruck, der einen bool’schen Wert zurückliefert. Die Klammern „(“ und „)“ umschließen dabei den mathematischen Ausdruck bzw. die boolische Variabel. Der nachfolgende Codeblock definiert dabei die Berechnungsvorschriften, die ausgeführt werden, wenn der mathematische Ausdruck wahr wäre. Bei unwahrem Wert wird dieser Block übersprungen und die eigentliche Berechnungskette wird fortgesetzt. Die folgende Abbildung visualisiert das Codefragment einer If-Klausel. Der nachfolgende Codeblock wird nur bearbeitet, wenn die Bedingung des mathematischen Ausdrucks wahr ist, ansonsten wird dieser übersprungen.

Die folgende Abbildung visualisiert Codefragmente eingesetzter If-Klauseln.

else

Durch das Schlüsselwort „else“ kann die If-Klausel erweitert werden. Durch die Angabe eines Else-Codeblockbereiches kann auf einen unwahren Ausdruckswert reagiert werden. Dieser Codebereich wird nur abgearbeitet, wenn der mathematische Ausdruck unwahr zurückliefert.

Ein Else-Statement-Block kann nicht ohne vorheriger Definition eines if-Statement-Block beschrieben werden. Dabei kann aber ein if-Statement ohne else-Statement verwendet werden.

Die folgende Abbildung visualisiert das Codefragment einer If-Else-Klausel.

else if

Das Prüfen mehrerer Bedingungen bezüglich eines mathematischen Ausdrucks kann durch das Schlüsselwort „else if“ eingeleitet werden.

Die folgende Abbildung visualisiert Programmcode, der das Überprüfen einer Mehrfachbedingung umsetzt.
Hierbei liefert ein Berührungssensor, der mit den Arduino verbunden ist, einen Messwert an die IDE zurück. Dieser Wert wird in der Variable mit den Namen „sensorWert“ gespeichert. Ist der Wert < 0, so meldet der Sensor einen Fehler. Ist der Wert = 0, so wurde keine Berührung festgestellt. Ist der Wert > 0, so wurde eine Berührung festgestellt.

Die folgende Abbildung visualisiert den Quellcode der Mehrfachbedingung in einer kompakteren bzw. knapperen Form.

Die „else-if“ – Block-Codebreiche werden nur ausgeführt, wenn alle darüber liegenden „if“ – und „else-if“ – Statements eine unwahre Bedingung zurückliefern würden. Entsprechend wird der else-Codebereich ausgeführt, wenn alle Vorbedingungen unwahr wären. Siehe Abbildung und Liste.

  • Keine Berührung : sensorWert = 0 , Abarbeitung else-Codeblock , beruehrung = false , fehler = false
  • Berührung : sensorWert = 0.7 , Abarbeitung else-if-Codeblock , beruehrung = true , fehler = false
  • Messfehler : sensorWert = -0.4 , Abarbeitung if-Codeblock , beruehrung = false , fehler = true

Wiederholungen (while)

Ein wichtiges Programmierprinzip ist die Schleifenbildung. Dabei wird ein Codeblockbereich so lange ausgeführt bis eine Bedingung unwahr wird.

Das Schlüsselwort „while“ leitet dabei das Konstrukt ein. Die entsprechend zu überprüfende Bedingung folgt in Klammern eingeschlossen entsprechend. Danach folgt der Codebereich, der bei wahren Bedingungswert abgearbeitet wird, der aber zwischen geschweiften Klammern stehen sollte. Die folgende Abbildung visualisiert den Quellcode einer While-Schleife.

Ein Durchlauf des While-Codeblocks wird als Iteration bezeichnet.

Die Loop-Schleife ist ein weiteres Konstrukt und ähnelt bezüglich Funktionsweise der While-Schleife.

Hardware Interaktion

Die Arduino – Interaktion mit der Außenwelt erfordert entsprechende Programmierbefehle, die im folgenden Verlauf vorgestellt werden sollen.

Der Arduino besitzt eine Pinnleiste, um elektrische Signale zu lesen und zu schreiben. Die folgende Abbildung visualisiert eine Übersicht der entsprechenden Arduino Pins. Die Pins D0 bis D13 und A0 bis A5 sollen dabei genauer betrachtet werden.

https://content.arduino.cc/assets/Pinout-UNOrev3_latest.png

Ausgabe

Die Realisierung einer LED-Ansteuerung kann durch die einfache Signalausgabe erfolgen. Hierfür existiert der spezifische Befehl „digitalWrite“. Dessen Klammerpaar umfasst dabei zwei zusätzliche Parameter, die den Befehl übergeben werden. Der erste Parameter spezifiziert die Signalausgabepins. Der zweite Parameter den Signalwert, der im konkreten Fall den Zustand „HIGH“ oder „LOW“ annehmen könnte. Diese Zustände entsprechen wiederum konkreten Spannungswerten.

Digitale Pins besitzen die Bezeichnung D0 bis D13. Analoge Pins die Bezeichnung A0 bis A5. Der Befehl „digitalWrite“ ermöglicht ebenfalls die Ansteuerung der analogen Pins.

Der Zustand „HIGH“ eines Pins entspricht in der Regel den Spannungspegel von 5V. Der entsprechende „LOW“ – Zustand eine Spannung von 0V.

Bei der Pin-Signalausgabe darf der maximale Ausgangsstrom von 40mA nicht überschritten werden. Der Arduino würde ansonsten beschädigt werden können.

Beim ersten Start des Arduino werden alle Pins standardmäßig als Ausgabeeinheiten konfiguriert. Diese Konfiguration könnte durch einen spezifischen Befehl abgeändert werden. Dem Befehl „pinMode“ folgt ein Klammerpaar, das zwei Parameter einschließt. Der erste Parameter spezifiziert dabei die Nummer des Pins. Der zweite Parameter dessen Verhalten bei der Signalkommunikation. Die folgende Abbildung visualisiert den Aufbau einer LED – Ansteuerungsschaltung. Der Pin13 wird dabei als Ausgabeeinheit konfiguriert.

Die folgende Abbildung visualisiert den entsprechenden Quellcode. Durch den „pinMode“-Befehlt wird Pin13 als Ausgabeeinheit konfiguriert. Die Loop-Funktion setzt den Pin-Pegel auf HIGH durch den „digitalWrite“ – Befehl. Am Pin13 liegt jetzt eine Spannung von 5V an, die die LED jetzt mit Strom versorgt und diese zum Leuchten bringt.

Eingabe

Digitale Eingabe

Die Arduino-Pins können nicht nur als Ausgabeeinheit dienen, sondern auch als Eingabeeinheit. Der Befehl „pinMode“ kann hier ebenfalls verwendet werden, um die Konfiguration durchzuführen. Der erste Parameter ist auch hier wieder die Nummer des entsprechenden Pins. Der zweite Parameter spezifiziert wieder das Kommunikationsverhalten des Pins.

Dabei darf die Pin-Eingangsspannung nicht höher als 5V sein. Die untere Grenze dieser Spannung liegt dabei bei 0V Werden diese Grenzen missachtet, so könnte die Arduino-Elektronik Schaden nehmen.

Die Eingangssignale können mit Hilfe des Befehls „digitalRead“ gelesen werden. Dieser benötigt nur einen Parameter, der für die Nummer des Pins steht. Dabei können HIGH oder LOW Werte registriert werden. Die Werte entsprechen den logischen Zuständen true und false.

Die folgende Abbildung visualisiert eine elektrische Schaltung bestehend aus einer LED und einen Taster. Die entsprechende LED leuchtet nur, wenn der entsprechende Taster betätigt wird. .

Wenn der Taster betätigt wird, leuchtet die LED.

Die grün markierte Leitung führt das 0V Potential des Tasters. Bei dessen Betätigung würde ein 5V Potenzial anliegen. Der 100kΩ Widerstand blockiert dabei die Versorgungsleitung des Tasters zur Spannungsquelle. Das Potential liegt also bei 0V, durch Einsatz des Widerstands. Der Einsatz eines hochohmigen Widerstands ist hier sinnvoll, weil der Stromfluss bei Taster-Aktivierung möglich gering sein sollte. Diese Widerstände werden in Bereich der Elektronik auch als Pull-Down Widerstände bezeichnet, weil sie bei deaktivierten Taster das Schalter-Potential auf 0V begrenzen.

Analog zu Pull-Down Widerständen gibt es auch Pull-Up Widerstände, die das Potenzial bei deaktivierten Taster auf 5V anheben würden. Der Arduino besitzt bereits integrierte, sodass der Schaltungsleitungsaufwand und der Bauteileaufwand geringer ausfallen. Die entsprechende Pin-Konfiguration kann durch den Parameter „INPUT_PULLUP“ eingeleitet werden.

Die folgende Abbildung visualisert den entsprechenden Quellcode. Die grün markierte Leitung führt bei deaktivierten Taster ein 5V Potential, also ein HIGH-Signal. Bei Taster-Betätigung ein LOW-Signal, also ein Potential von ca. 0V. Die folgende Visualisierung des Quellcodes will diesen Sachverhalt nochmals verdeutlichen.

Pin 13 kann nicht mit einem Pull-Up Widerstand verwendet werden. Die Konfiguration INPUT_PULLUP für den Pin 13 würde falsche Messergebnisse liefern. Ein externer Pull-Up Widerstand würde aber die Messergebnisse wieder korrigieren.

Spannungen über 3V werden als HIGH-Signal interpretiert. Spannungen unter 1,5V als LOW-Signal. Spannungen zwischen 1,5V und 3V sollte bei digitalen Messanordnungen vermieden werden.

Die Signalerfassung kann bis zu 5 Mikrosekunden andauern.

Analoge Eingabe

Digitale Signale können die Zustände HIGH und LOW annehmen. Der Arduino ist in der Lage Spannung zwischen 0V und 5V zu erfassen. Die Erfassung von analogen Signalen erfplgt über die Pins A0 bis A5.

Der Befehl „analogRead“ erfasst dabei anliegende Spannungen der entsprechen vorkonfigurierten Pins. Der entsprechende Parameter ist auch hier die entsprechende Nummer des Pins. Die Messgenauigkeit des Arduinos liegt bei 4,9mV pro Einheit und liefert Werte zwischen 0 und 1023. Die Multiplikation dieser Werte mit dem Faktor 4,9mV liefert anschließend den ungefähr tatsächlich anliegenden Spannungswert.

Liefert der analogRead(A0)-Befehl zum Beispiel den Wert 626, so würde ein Spannungspotential von ca. 3,0674V am Pin 0 anliegen. Der Rechenvorgang liefert mit 626 * 4,9mV = 3,0674V das Ergebnis mit einer Abweichung von 0,0049V.

Die folgende Abbildung visualisiert den Sachverhalt nochmals. Der „analogRead„-Befehl liefert entsprechende Messergebnisse bei der Teilspannungserfassung des Spannungsmessgeräts.

Die Spannungsquelle liefert Werte zwischen 0V und 30V und liefert Energie für einen Spannungsteiler, der aus einem 50kΩ und einem 10kΩ Widerstand besteht. Der analogen Pin 0 erfasst die Spannung der blau markierten Leitungsstücks des Spannungsteilers. Die analogen Pins 3 bis 5 sind mit einer LED verbunden (braune, graue und orange Leitung). Abhängig der Eingangsspannung würde jetzt die entsprechende LED aufleuchten.

Eingangsspannung ist 5V, entsprechend leuchtet die LED
Eingangsspannung ist 15V, entsprechend leuchtet die LED
Eingangsspannung ist 25V, entsprechend leuchtet die LED

Die analoge Signalerfassung kann bis zu 100 Mikrosekunden andauern. Dabei benötigt der Messvorgang deutlich mehr Zeit als bei der digitalen Signalerfassung. Bei zeitkritischen Anwendungen kann diese Zeitdauer zu Problemen führen.

Unterbrechungen (delay)

Die analoge Signalerfassung kann bis zu 100 Mikrosekunden andauern. Dabei benötigt der Messvorgang deutlich mehr Zeit als bei der digitalen Signalerfassung. Bei zeitkritischen Anwendungen kann diese Zeitdauer zu Problemen führen.

Die folgende Abbildung visualisiert Quellcode, der eine LED zeitgesteuert mit Energie versorgt. Die Leuchtdauer beträgt hier eine Sekunde. Der Vorgang wird periodisch wiederholt.

Jede zweite Sekunde leuchtet die LED eine Sekunde lang
Jede zweite Sekunde ist die LED eine Sekunde lang aus

Der „delay„-Befehl erzwingt das Pausieren der Verarbeitungskette des Arduinos. Es werden also keine zusätzlichen Verarbeitungsschritte ausgeführt.