Arduino Code-Referenz (deutsch)
Arduino Code-Referenz (deutsch)
Hier geht es zum original PDF


Arduino Code-Referenz (deutsch) als unformatierte und reine TXT - CrawlVersion

ARDUINO
Befehlsübersicht

Übersetzt in deutsche Sprache
Mit zusätzlichen Erklärungen, Ergänzungen
und hilfreichen Tipps




https://arduinoforum.de
DAS deutsche Arduino-Forum, die beste Quelle für Fragen, Probleme, Hilfe,
Hardwaretipps etc. rund um die ARDUINO-Programmierung!


Unter dem Link: https://www.arduinoforum.de/code-referenz kann diese Referenz
heruntergeladen werden. Hier gibt es immer die aktuelle Version.


In diesem Zusammenhang Dank auch an verschiedene Mitglieder des deutschen ARDUINO-Forums und andere
Bastler, die mir schon bei Fragen geholfen haben. An geeigneter Stelle sind diese namentlich erwähnt, wenn ich
ihr Wissen verwendet habe.









*** Andreas Nagel *** Stand: 11. August 2017 ***


Quellenverzeichnis
[0 https://arduinoforum.de
[1 http://torrentula.to.funpic.de/dokumentation/code-referenz
[2 http://arduino.cc/en/Reference/ CC BY-SA
[3 http://www.arduino-tutorial.de
[4 http://popovic.info/html/arduino/arduinoUno_1.html#LCD CC BY-SA
[5 http://www.macherzin.net/article38-LC-Displays-am-Arduino
[6 http://playground.arduino.cc/ CC BY-SA
[7 http://tushev.org/articles/arduino/item/46-arduino-and-watchdog-timer
[8 https://github.com/thomasfredericks/Bounce-Arduino-Wiring/wiki
[9 http://www.leonardomiliani.com/2012/come-gestire-loverflow-di-millis/?lang=en CC-BY-NC-ND
[10 https://www.arduinoforum.de/arduino-Thread-was-heist-15UL
[11 http://www.cpp-entwicklung.de/cpplinux/cpp_main/cpp_main.html CC-BY-NC-ND
[12 http://www.cprogramming.com/reference/
[13 http://www.mathertel.de/Arduino/OneButtonLibrary.aspx
[14 https://github.com/JChristensen/DS3232RTC CC BY-SA
[15 https://www.arduino.cc/en/Tutorial/PWM CC BY-SA
[16 https://datasheets.maximintegrated.com/en/ds/DS18B20.pdf
[17 https://de.wikipedia.org/wiki/I%C2%B2C
[18 https://playground.arduino.cc/Main/I2cScanner
[19 https://github.com/fdebrabander/Arduino-LiquidCrystal-I2C-library
[20 https://github.com/thefekete/LM75
[21 https://github.com/skywodd/pcf8574_arduino_library


Diese Übersicht des ARDUINO-Befehlssatzes wurde aus verschiedenen Quellen, vieler eigener Übersetzung aus
dem Englischen, sowie zusätzlichen eigenen Anmerkungen, Erweiterungen und Informationen erstellt. Sie ist
nicht vollständig bzw. abschließend.

Jegliche Verantwortung, Haftung oder Schadensersatz aufgrund der Benutzung dieser Anleitung wird durch den
Verfasser ausgeschlossen. Gegebenenfalls einfach mal jemand fragen, der sich mit sowas auskennt!

Hinweise, konstruktive Kritik (kein Genörgele!) nehme ich gern unter meiner E-Mail DL1AKP@web.de entgegen.


Copyrighthinweis
Jegliche Benutzung und Weitergabe dieses Werkes ist nur zu privaten und nichtkommerziellen Zwecken erlaubt.
Eine anderweitige Nutzung, gleich welcher Art, bedarf der Erlaubnis des Autors. Dazu zählen auch Beigabe zu
kommerziellen Produkten, Übersetzung, Mikroverfilmung, Einspeicherung und Verarbeitung in kommerziellen
elektronischen Systemen. Etwaige weitere Nutzungshinweise ergeben sich aus den Quellenangaben (siehe oben).
Die grafisch schönen Handskizzen habe ich selbst erstellt. 
Alle Warennamen werden ohne Gewährleistung der freien Verwendbarkeit benutzt und sind möglicherweise
eingetragene Warenzeichen.


Inhaltsverzeichnis

Quellenverzeichnis ........................................................................................................................................2
Copyrighthinweis ..........................................................................................................................................2
Inhaltsverzeichnis ..................................................................................................................... 3
Vorwort .................................................................................................................................. 10
Begriffserklärungen ................................................................................................................ 11
Programmstruktur ..................................................................................................................................... 11
Variablen .................................................................................................................................................... 11
Befehle ....................................................................................................................................................... 11
Funktionen ................................................................................................................................................. 11
Methoden .................................................................................................................................................. 12
Operatoren ................................................................................................................................................. 12
Abfragen ..................................................................................................................................................... 13
Schleifen ..................................................................................................................................................... 13
Bibliotheken ............................................................................................................................................... 13
Struktur .................................................................................................................................. 14
setup() ........................................................................................................................................................ 14
loop() .......................................................................................................................................................... 14
Weitere Syntax ....................................................................................................................... 15
Kommentare .............................................................................................................................................. 15
; Semikolon ................................................................................................................................................. 15
{} geschweifte Klammern ........................................................................................................................... 15
#define ....................................................................................................................................................... 16
#include ...................................................................................................................................................... 17
Datentypen ............................................................................................................................. 18
void ............................................................................................................................................................. 18
byte ( uint8_t ) .......................................................................................................................................... 18
int ( int16_t ) ............................................................................................................................................. 18
short ........................................................................................................................................................... 19
word ( uint16_t ) ...................................................................................................................................... 19
unsigned int ( uint16_t ) ........................................................................................................................... 19
long ( int32_t) ........................................................................................................................................... 19
unsigned long ( uint32_t ) ........................................................................................................................ 19
float ............................................................................................................................................................ 19
double ........................................................................................................................................................ 20
boolean ( bool ) ........................................................................................................................................ 20
Array‘s ........................................................................................................................................................ 20
char ( int8_t ) ............................................................................................................................................ 21
unsigned char ( uint8_t ) .......................................................................................................................... 21
string (Datentyp & char-Array) ........................................................................................................... 21
Datentypen-Bezeichner z.B. UL, U, L etc. ................................................................................................... 24
Konstanten ............................................................................................................................. 25
Logische Pegel, true und false (Bool’sche Konstanten) ............................................................................. 25
false ......................................................................................................................................................... 25
true .......................................................................................................................................................... 25
Pin-Zustände HIGH und LOW .................................................................................................................... 25
HIGH ........................................................................................................................................................ 25
LOW ......................................................................................................................................................... 26
Digitale Pins konfigurieren, INPUT, INPUT_PULLUP, und OUTPUT mit dem Befehl pinMode .................. 26
Pins konfiguriert als Eingänge (INPUT) .................................................................................................... 26
Pins konfiguriert als INPUT_PULLUP (internen Pullup-Widerstand einschalten) .................................. 26
Pins konfiguriert als Ausgänge (Outputs) ................................................................................................ 27
Integer Konstanten .................................................................................................................................... 27
Floating point Konstanten (Fließkomma) .................................................................................................. 27
Verzweigungen und Schleifen .................................................................................................. 28
for-Schleifen ............................................................................................................................................... 28
if (Bedingung) und ==, !=, <, > (Vergleichsoperatoren) .............................................................................. 28
Vergleichsoperatoren................................................................................................................................. 29
if / else ........................................................................................................................................................ 29
switch / case Anweisungen ........................................................................................................................ 30
while - Schleifen ......................................................................................................................................... 30
do – while ................................................................................................................................................... 31
break .......................................................................................................................................................... 31
continue ..................................................................................................................................................... 32
return ......................................................................................................................................................... 32
goto ............................................................................................................................................................ 32
Rechenoperationen ................................................................................................................. 34
= Zuweisungsoperator ............................................................................................................................... 34
Grundrechenarten (Addition, Subtraktion, Division, Multiplikation) ........................................................ 34
% Modulo ................................................................................................................................................... 35
Verknüpfungsoperationen (Boolsche Operatoren) ................................................................... 36
&& (logisches und) ..................................................................................................................................... 36
|| (logisches oder) ..................................................................................................................................... 36
! (nicht) ....................................................................................................................................................... 36
Digital In / Out ........................................................................................................................ 37
pinMode() .................................................................................................................................................. 37
digitalWrite() .............................................................................................................................................. 37
digitalRead() ............................................................................................................................................... 38
Grundlegendes Analog In / Out ............................................................................................... 39
analogReference() ...................................................................................................................................... 39
analogRead() .............................................................................................................................................. 39
analogWrite() ............................................................................................................................................. 40
Gleichspannung analog ausgeben ............................................................................................................. 41
Erweitertes Analoges In / Out ................................................................................................. 43
tone() .......................................................................................................................................................... 43
noTone() ..................................................................................................................................................... 43
shiftOut() .................................................................................................................................................... 44
shiftIn() ....................................................................................................................................................... 45
pulseIn() ..................................................................................................................................................... 46
Datenkonvertierung ................................................................................................................ 47
byte() .......................................................................................................................................................... 47
int() ............................................................................................................................................................. 47
word() ......................................................................................................................................................... 48
long() .......................................................................................................................................................... 48
float() .......................................................................................................................................................... 48
Zeit ......................................................................................................................................... 50
delay() ........................................................................................................................................................ 50
micros() ...................................................................................................................................................... 50
millis() ......................................................................................................................................................... 51
delayMicroseconds() .................................................................................................................................. 51
Richtige Benutzung des millis() – Befehles ................................................................................................ 52
Zusammengesetzte Operatoren .............................................................................................. 54
Zusammengesetztes bitweises ODER (|=) ................................................................................................. 54
Zusammengesetztes bitweises UND (&=) .................................................................................................. 54
+= , -= , *= , /= Zusammengesetzte + - * / ................................................................................................ 54
++ (inkrement) / — (dekrement) ............................................................................................................... 55
Bitoperatoren ......................................................................................................................... 56
Bitweises links- (<<) und bitweises rechtsschieben (>>) ............................................................................ 56
Bitweises NICHT (~) .................................................................................................................................... 57
Bitweises UND (&) ...................................................................................................................................... 57
Bitweises ODER (|) ..................................................................................................................................... 57
Bitweises XOR (^) ....................................................................................................................................... 58
Zufallszahlen ........................................................................................................................... 59
randomSeed(seed) ..................................................................................................................................... 59
random() .................................................................................................................................................... 59
Externe Interrupts ................................................................................................................... 61
attachInterrupt() ........................................................................................................................................ 61
detachInterrupt() ....................................................................................................................................... 62
Interrupts (global) ................................................................................................................... 63
interrupts() ................................................................................................................................................. 63
noInterrupts() ............................................................................................................................................. 63
Mathematische Funktionen ..................................................................................................... 65
min(x, y)...................................................................................................................................................... 65
max(x, y) ..................................................................................................................................................... 65
abs(x) .......................................................................................................................................................... 65
constrain(x, a, b) ......................................................................................................................................... 66
map(value, fromLow, fromHigh, toLow, toHigh) ....................................................................................... 66
pow(base, exponent) ................................................................................................................................. 67
sqrt(x) ......................................................................................................................................................... 67
Geltungsbereich und Qualifikatoren ........................................................................................ 69
Geltungsbereich von Variablen .................................................................................................................. 69
static ........................................................................................................................................................... 69
volatile ........................................................................................................................................................ 70
const ........................................................................................................................................................... 71
#define oder const? ................................................................................................................................... 71
Trigonometrie (Dreiecksberechnungen) ................................................................................... 72
sin(rad) ....................................................................................................................................................... 72
cos(rad) ...................................................................................................................................................... 72
tan(rad) ...................................................................................................................................................... 72
Zeichen (Character-) Funktionen .............................................................................................. 73
isAlphaNumeric(thisChar) .......................................................................................................................... 73
isAlpha(thisChar) ........................................................................................................................................ 73
isAscii(thisChar) .......................................................................................................................................... 74
isWhiteSpace(thisChar) .............................................................................................................................. 74
isControl(thisChar) ..................................................................................................................................... 75
isDigit(thisChar) .......................................................................................................................................... 75
isGraph(thisChar) ....................................................................................................................................... 76
isLowerCase(thisChar) ................................................................................................................................ 76
isPrintable(thisChar) ................................................................................................................................... 77
isPunct(thisChar) ........................................................................................................................................ 77
isSpace(thisChar) ........................................................................................................................................ 78
isUpperCase(thisChar) ................................................................................................................................ 78
isHexadecimalDigit(thisChar) ..................................................................................................................... 79
Hilfsfunktionen ....................................................................................................................... 80
sizeof .......................................................................................................................................................... 80
PROGMEM ................................................................................................................................................. 80
F()-Makro................................................................................................................................................. 82
Bits und Bytes ......................................................................................................................... 83
lowByte() .................................................................................................................................................... 83
highByte() ................................................................................................................................................... 83
bitRead() ..................................................................................................................................................... 83
bitWrite() .................................................................................................................................................... 84
bitSet() ........................................................................................................................................................ 84
bitClear() .................................................................................................................................................... 84
bit() ............................................................................................................................................................. 85
Serielle Kommunikation (UART) .............................................................................................. 86
Allgemeines ................................................................................................................................................ 86
Serial.begin(speed)..................................................................................................................................... 87
Serial.print(data) Serial.print(data, encoding) ....................................................................................... 87
Serial.println(data) Serial.println(data, encoding)................................................................................. 88
Serial.available() ......................................................................................................................................... 88
Serial.read() ................................................................................................................................................ 88
Serial.flush .................................................................................................................................................. 88
String Objects ......................................................................................................................... 89
Allgemeines ................................................................................................................................................ 89
String() ........................................................................................................................................................ 89
charAt() ...................................................................................................................................................... 90
compareTo() ............................................................................................................................................... 91
concat() ...................................................................................................................................................... 91
endsWith().................................................................................................................................................. 92
equals() ....................................................................................................................................................... 92
equalsIgnoreCase() ..................................................................................................................................... 93
getBytes() ................................................................................................................................................... 94
indexOf() .................................................................................................................................................... 94
lastIndexOf() ............................................................................................................................................... 95
length() ....................................................................................................................................................... 96
replace() ..................................................................................................................................................... 96
setCharAt() ................................................................................................................................................. 97
startsWith() ................................................................................................................................................ 97
substring() .................................................................................................................................................. 98
toCharArray() ............................................................................................................................................. 98
toInt() ......................................................................................................................................................... 99
toFloat() ...................................................................................................................................................... 99
toLowerCase() .......................................................................................................................................... 100
toUpperCase() .......................................................................................................................................... 100
trim() ........................................................................................................................................................ 100
String Operatoren ................................................................................................................. 102
[
(
Zu
g
rif
f auf
Ze
ich
en) .............................................................................................................................. 102
+ (Operator „Anhängen“) ...................................................................................................................... 102
== (Operator „Vergleich“) ..................................................................................................................... 103
LCD-Anzeigen und deren Benutzung ...................................................................................... 104
Allgemeines .............................................................................................................................................. 104
LiquidCrystal() .......................................................................................................................................... 105
begin() ...................................................................................................................................................... 105
clear() ....................................................................................................................................................... 106
home() ...................................................................................................................................................... 106
setCursor() ................................................................................................................................................ 106
write() ....................................................................................................................................................... 107
print() ....................................................................................................................................................... 107
cursor() ..................................................................................................................................................... 108
noCursor() ................................................................................................................................................ 108
blink() ....................................................................................................................................................... 109
noBlink() ................................................................................................................................................... 109
display() .................................................................................................................................................... 109
noDisplay() ............................................................................................................................................... 110
scrollDisplayLeft() ..................................................................................................................................... 110
scrollDisplayRight() ................................................................................................................................... 110
autoscroll() ............................................................................................................................................... 111
noAutoscroll() ........................................................................................................................................... 111
leftToRight() ............................................................................................................................................. 112
rightToLeft() ............................................................................................................................................. 112
createChar() ............................................................................................................................................. 112
Sonderzeichen, Symbole und Umlaute .................................................................................................... 113
EEPROM schreiben und lesen ................................................................................................ 115
Allgemeines .............................................................................................................................................. 115
Die EEPROM-Library ................................................................................................................................. 115
EEPROM.read() ......................................................................................................................................... 115
EEPROM.write()........................................................................................................................................ 116
EEPROM.update() .................................................................................................................................... 116
EEPROM.put() .......................................................................................................................................... 117
EEPROM[ ................................................................................................................................................. 117
Timer-Interrupts und deren Benutzung .................................................................................. 119
Allgemeines .............................................................................................................................................. 119
Verwendung des Timer1 .......................................................................................................................... 119
Taster und deren Benutzung.................................................................................................. 121
Anschließen von Tastern .......................................................................................................................... 121
Taster nach GND ................................................................................................................................... 121
Taster nach +5V ..................................................................................................................................... 121
Benutzung von Tastern mit Interrupts ..................................................................................................... 121
Entprellen von Tastern ............................................................................................................................. 122
Allgemeines ........................................................................................................................................... 122
Verwendung der Debounce-Library ...................................................................................................... 122
Entprellen mit zusätzlichen Bauteilen ................................................................................................... 123
Mehrfachfunktionen mit Tastern (Doppelklick, langer Klick etc.) ........................................................... 123
Benutzung der Library OneButton ........................................................................................................ 124
Einfacher kurzer Klick ............................................................................................................................ 124
Doppelklick ............................................................................................................................................ 124
Langer Klick wiederholte Funktion ........................................................................................................ 125
Langer Klick einfach ............................................................................................................................... 125
RTC-Uhr und deren Benutzung............................................................................................... 126
Allgemeines .............................................................................................................................................. 126
Die RTC DS3231 ........................................................................................................................................ 126
Beschaltung .............................................................................................................................................. 127
Benutzung der Library .............................................................................................................................. 127
Sommer- / Winterzeit Berechnung .......................................................................................................... 128
Temperatursensoren und deren Benutzung ........................................................................... 129
Allgemeines .............................................................................................................................................. 129
DS18B20 / DS18S20 (1wire-Bus-Sensor) .................................................................................................. 129
Anschliessen des Sensors ...................................................................................................................... 129
Programmierung ................................................................................................................................... 130
MCP9700 (analoger Sensor)..................................................................................................................... 131
Anschliessen des Sensors ...................................................................................................................... 131
Programmierung ................................................................................................................................... 131
LM75 (I2C-Sensor) .................................................................................................................................. 132
Der I2C-Bus und seine Benutzung .......................................................................................... 133
Allgemeines .............................................................................................................................................. 133
I2C-LCD-Displays....................................................................................................................................... 133
LM75 Temperatursensor .......................................................................................................................... 134
Der Watchdog-Timer und seine Benutzung ............................................................................ 136
Allgemeines .............................................................................................................................................. 136
Benutzung des Watchdog-Timers ............................................................................................................ 136
Kleine hilfreiche Programm-Teile ........................................................................................... 138
Freien RAM anzeigen ............................................................................................................................... 138
Programm anhalten (für immer) .............................................................................................................. 138
Software-Reset ......................................................................................................................................... 138
RAM sparen bei Serial.print ..................................................................................................................... 139
Digital-Ausgang (z.B. LED) togglen ........................................................................................................... 139
Binaerausgabe 8bit, 16bit, 32bit auf seriellem Port ................................................................................ 139
Binärausgabe 8bit ................................................................................................................................. 139
Binärausgabe 16bit ............................................................................................................................... 139
Binärausgabe 32bit ............................................................................................................................... 140
String nach char kopieren ........................................................................................................................ 140
Stichwortverzeichnis ............................................................................................................. 141

Vorwort
In diesem Buch sind die wichtigsten Befehle und Funktionen der ARDUINO-Sprache aufgeführt, und
dies alles komplett in Deutsch. Weiterhin auch einige meiner Meinung nach wichtigen Libraries und
deren Funktionen / Befehle.
Zur Benutzung von Libraries gibt es stark unterschiedliche Ansichten. Diese reichen von totaler
Abneigung bis hin zu Euphorie. Ich persönlich nutze gern und viel Libraries, beschleunigen sie doch das
Erstellen des funktionierenden Projektes massiv. Auch ist der Code wesentlich leichter lesbar und kürzer
(der Quellcode in der ARDUINO-IDE). Nachteil ist, dass der Hex-Code, welcher hochgeladen wird,
deutlich größer ist und man eventuell an die Speichergrenze kommt. Dann kann man nachdenken,
entweder weniger Libraries zu benutzen, oder einen ARDUINO mit mehr Speicherplatz im Flash. Die
Entscheidung obliegt jedem selbst, ich hatte diesen Fall noch nicht.
Ich denke, das Ergebnis ist entscheidend: Das Projekt soll wie gewünscht funktionieren. Tut es das, OK!
Warum sich Gedanken machen, ob man noch das eine oder andere Prozent an Speicher einsparen kann,
oder das Programm ein paar Microsekunden schneller läuft? Die Zeit kann man doch lieber mit einem
neuen, faszinierenden Projekt verbringen, oder nicht?
Auch über das „optische“ Ergebnis lässt sich streiten. Also: Ist mein Sketch auch schön? Schönheit liegt
immer im Auge des Betrachters. Also macht es so, dass es für Euch am optimalsten ist. Viel
Erläuterungen einfügen, Hinweise, Beschaltungen und ähnliches. Gefällt es einem anderen nicht – was
soll’s! Er kann ja seine Projekte machen, wie er es möchte.
Ziel dieses Buches ist es, dem Leser den Einstieg so leicht wie möglich zu machen. Das geht am besten in
der Muttersprache. Ich kann fliessend englisch, aber einen Fachartikel in englisch zu lesen und zu
verstehen ist nochmal etwas ganz Anderes. Diese Erkenntnis animierte mich zur Erstellung dieses
Werkes.
Ich bemühe mich, dieses Buch mit weiteren, sinnvollen Kapiteln zu ergänzen. Also zum Beispiel die am
häufigsten benutzten Sensoren, Libraries, Aktoren. Ein bisschen Schaltungstechnik, wie schliesse ich ein
Relais an, und so weiter. Dabei soll es so bleiben, dass der Laie nicht überlastet wird und die Lust verliert,
das wäre schade. Daher wird es keine komplizierten, theoretischen Abhandlungen geben, keine
Berechnungen und Verweise auf etwaige zu beschaffende, teure Messtechnik.
Bei der Programmierung von ARDUINO’s gibt es die berühmten vielen Wege, die nach Rom führen.
Meine Ausführungen in den Kapiteln zur Benutzung der verschiedenen Sensoren, Aktoren etc. sind daher
nur eine von vielen. Sicher gibt es andere, oder elegantere, oder schnellere, oder schönere, oder bessere,
oder coolere, oder libraryfreie, oder… Also nagelt mich nicht fest, das meine Version die einzig wahre
ist. Aber es ist eine von mir getestete und funktionierende Variante.
Also: Lasst uns anfangen, faszinierende Projekte umzusetzen, ob es eine Uhr für das Wohnzimmer ist,
eine Steuerung für den Gartenspringbrunnen, oder gar ein Roboter…
Es ist wichtig zu wissen, dass auch alle sonstigen C/C++ Befehle benutzt werden können.
Das kann hier nicht aufgeführt werden, da es extrem umfangreich ist, und einfach zu weit führen würde.
Wer sich dafür interessiert oder C/C++Befehle verwenden will, sei auf das Internet verwiesen, hier
speziell auf Quelle [12
.

Es stehen auch Beispieldateien sowei die verwendeten Libraries zum Download bereit. Im Buch wird
darauf hingeweisen, wenn es sowas gibt.
Andreas Nagel, im Juli 2017
Begriffserklärungen
Programmstruktur
Ein Programm in Arduino-Sprache besteht aus mindestens zwei Methoden. Eine Methode ist ein
Anweisungsblock, also eine Gruppe von Befehlen, die durch den Aufruf des Methodennamens ausgeführt
werden. Die Methode void setup() wird einmal ausgeführt, die Methode void loop() wird ständig
wiederholt.
void setup(){
}

void loop(){
}
Variablen
Eine Variable ist ein Container für Werte des Typs der Variable. Variablentypen sind:
Variablentyp Bedeutung Beschreibung
int Integer ganze Zahlen (-32.768 bis 32.767)
long ganze Zahlen (-2 Milliarden bis 2 Milliarden)
float Fließkommazahl gebrochene Zahlen (3,14 etc.)
char Charakter Alphanumerische Zeichen (Buchstaben, Zahlen, Sonderzeichen)
array Variablenfeld mehrere Werte eines Variablentyps können gespeichert werden
Variablen können global (überall verfügbar) oder lokal (nur in der jeweiligen Methode verfügbar)
deklariert werden. Das ist unbedingt zu beachten, sonst kann es zu Fehlermeldungen oder unlogische
Programmabläufen kommen
Befehle
Befehle sind Anweisungen, die Methoden in der Arduino-Software aufrufen.
z.B. pinMode(), digitalWrite etc.….

Funktionen
Funktionen sind Programmanweisungsblöcke. Wiederkehrende Abfolgen von Befehlen können in
Funktionen sinnvoll strukturiert werden. Parameter können an Funktionen übergeben und Werte
zurückgeliefert werden. In BASIC wird so etwas „Unterprogramm“ genannt, C ist aber im Umgang mit
Funktionen wesentlich leistungsfähiger als BASIC.
Eine einfache Funktion könnte so aussehen:
void led(){
// Anweisungsblock Start
digitalWrite(ledPin, HIGH);
delay(500);
digitalWrite(ledPin, LOW);
delay(500);
// Anweisungsblock Ende
}
Nun kann man die Funktion, z.B. aus dem void loop(), aufrufen mit: led();
Parameter lassen sich auch an Funktion übergeben. Die Struktur sieht dann so aus:
void led (int thePin, int dauer){
digitalWrite(thePin, HIGH);
delay(dauer);
digitalWrite(thePin, LOW);
delay(dauer);
}
Hierbei wird der Parameter thePin und dauer übergeben. Der Aufruf kann dann so erfolgen:
led(3,1000);.
Man kann auch einen Wert von der Funktion zurückgeben lassen. Dafür verwendet man anstelle von void
den Variablentyp, den das Ergebnis haben wird und liefert es am Ende des Anweisungsblockes mit dem
Schlüsselwort return an die Funktion.
float quadrat(float x){
float ergebnis = x*x;
return ergebnis;
}
Der Aufruf wäre z.B.:
wert = quadrat(12.3);

Methoden
Methoden sind Funktionen, wenn sie Elemente einer Klasse sind.
Im Code kann man das leicht unterscheiden: Besteht der Name aus 2 Teilen: Objektname.methodenname()
handelt es sich um eine Methode. Z.B. Serial.Begin(9600); oder Servo.write(90);
Bei einfachen Namen wie z.B. digitalWrite(); ist es nur eine normale Funktion.
Danke für diese Erklärung an Microbahner aus dem deutschen Arduinoforum.

Operatoren
Operatoren sind mathematische oder logische Funktionen. Hier die wichtigsten im Überblick.

Operator Bedeutung Anwendung Funktion
Arithmetische Operatoren
= Zuweisung a=2*b Weist der linken Seite den
Wert auf der rechten Seite zu.
+ Addition a=b+c
- Subtraktion a=b-c
++ Inkrementieren a++ Zählt zu der Variable 1 hinzu
(+1)
-- Dekrementieren a-- Zieht von der Variable 1 ab (-
1)
* Multiplikation a=b*c
/ Division a=b/c Dabei darf c nie gleich Null
sein
% Modulo a=b%c
a=7%5 ; a=2
a=10%5 ; a=0

Liefert den Rest bei der
Division von b/c. Ist b durch c
teilbar, so ist das Ergebnis = 0.
Vergleichsoperatoren
== Gleichheit a==b Prüft auf Gleichheit.
!= Ungleichheit a!=b Prüft auf Ungleichheit
< kleiner als a > größer als a>b
<= kleiner gleich a<=b
>= größer gleich a>=b
Boolesche Operatoren (Können wahr oder falsch sein.)
&& UND (a==2)&&(b==5) Wenn beide Seiten wahr sind,
ist das Ergebnis auch wahr.
|| ODER (a==2)||(b==5) Wenn eine oder beide Seiten
wahr sind, ist das Ergebnis
wahr.
! NICHT !(a==3) Ist wahr, wenn a nicht 3 ist.

Abfragen
Eine Abfrage prüft, ob z.B. eine Variable einen bestimmten Wert hat. Abfragen können also den
Programmablauf steuern.

Beispiele: if-Abfrage, switch-case-Abfrage

Schleifen
Schleifen können Anweisungen bis zum Erreichen einer Abbruchbedingung wiederholen.

Beispiele: for-Schleife, do-while-Schleife

Bibliotheken
Bibliotheken (Libraries) erweitern den Funktionsumfang der Arduino-Software um weitere Befehle. Es
gibt Bibliotheken für Servo‘s, LCD, und hunderte mehr. Will man sie verwenden, müssen sie in den
Sketch eingefügt werden. Im Hauptmenü findet man unter ‚Sketch‘ den Befehl ‚Bibliothek einfügen‘.
Hier wählt man einfach die Bibliothek aus, die man verwenden will und im Sketch erscheint die Include-
Zeile. Z.B.:
#include
Man kann auch eine neue Library hinzufügen. Der entpackte Ordner der Library muss in den Libraries-
Ordner kopiert werden. Existiert dieser Ordner nicht, muss man ihn anlegen. Nach dem Programm-
Neustart steht die Bibliothek zum Einfügen in den Sketch bereit.
Struktur
setup()
Die setup() Funktion wird zu Beginn des Programms aufgerufen. Sie wird benutzt, um Pinzustände,
Variablen und Bibliotheken zu initialisieren. Sie wird nur einmal beim Programmstart als erste Funktion
aufgerufen z.B. bei einem Reset des Arduino oder das Anlegen der Betriebsspannung.

Beispiel
int buttonPin = 3;

void setup()
{
Serial.begin(9600);
pinMode(buttonPin, INPUT);
}

void loop()
{
// ...
}


loop()
Die loop() Funktion wird nach der setup() Funktion aufgerufen und stellt eine Endlosschleife dar. Hier
ist der Platz für das Hauptprogramm.

Beispiel
int buttonPin = 3;

// setup initialisiert serial und den button pin
void setup()
{
beginSerial(9600);
pinMode(buttonPin, INPUT);
}

// loop überprüft den button pin jedes Mal
// und sendet ein H wenn der button gedrückt wird
void loop()
{
if (digitalRead(buttonPin) == HIGH)
serialWrite('H');
else
serialWrite('L');

delay(1000);
Weitere Syntax
Kommentare
Kommentare in einem Programm sind Zeilen im Programmcode, um sich selbst oder andere darüber zu
informieren, wie das Programm funktioniert. Kommentare werden vom Compiler ignoriert und nehmen
keinen Platz auf dem Chip in Anspruch.
Es gibt zwei Arten von Kommentaren: einzeilige und mehrzeilige Kommentare.

Beispiel
x = 5; // Das ist ein einzeiliger Kommentar, alles in dieser Zeile
// ist ein Kommentar bis zum Ende der Zeile

/* Das ist ein mehrzeiliger Kommentar, er kann benutzt werden,
um ganze Passagen auszukommentieren

if (gwb == 0){ // ein einzeiliger Kommentar in einem mehrzeiligen ist ok
x = 3; /* noch ein mehrzeiliger Kommentar ist nicht ok */
}
// Vergiss nicht den "schließenden" Kommentar!
*/

Hinweis
Wenn man im Programmcode nach Fehlern sucht, kann es hilfreich sein, ganze Teile des Programms
auszukommentieren. Dies behält die Zeilen des möglicherweise nicht funktionalen Codes bei und der
Compiler ignoriert diese Zeilen.
Weiterhin empfiehlt es sich auf jeden Fall, nicht mit Kommentaren zu geizen. Sie kosten nichts und
es kommt ganz sicher der Zeitpunkt, wo man sich später mal fragt: „Man, was habe ich mir hierbei nur
gedacht…?“

; Semikolon
Das Semikolon wird benutzt, um eine Anweisung abzuschließen.
Beispiel
int a = 13;

Hinweis
Ein vergessenes Semikolon hat einen compiler error zur Folge. Die Fehlermeldung des Compilers ist
oftmals sehr kryptisch und (jedenfalls ich) man kann nichts damit anfangen. Wenn eine Fehlermeldung
immer wieder auftritt, sollte zuerst nach einem fehlenden Semikolon in der Zeile gesucht werden, die in
der Fehlermeldung genannt wird. Ein Semikolon kann auch weit über oder unter der in der
Fehlermeldung genannten Zeile fehlen! Das hätte ich mir komfortabler gewünscht, aber es ist eben so.
{} geschweifte Klammern
Die geschweiften Klammern sind einer der wichtigsten Bestandteile der C-Syntax. Beginner werden oft
durch die vielen geschweiften Klammern abgeschreckt oder verwirrt. Auf eine öffnende “{” Klammer
muss immer eine schließende “}” Klammer folgen. Eine vergessene schließende Klammer kann zu
kryptischen Fehlermeldungen des Compilers führen.
Ein guter Weg, um dem Vergessen von Klammern vorzubeugen, ist es, direkt eine öffnende und
schließende Klammer hintereinander zu setzen und einfach ein paar Zeilenumbrüche einzufügen und den
Code dann dort hineinzuschreiben. (Mittlerweile macht die IDE die schliessende Klammer oft
automatisch, wenn man eine öffnende setzt)
Verwendungszwecke der geschweiften Klammern:
Funktionen
void meineFunktion(datatyp Argument){
// Anweisungen
}
Schleifen
while (boolean Ausdruck)
{
// Anweisungen
}

do
{
// Anweisungen
} while (boolean Ausdruck);

for (Initialisation; Abbruchbedingung; Inkrementierung)
{
// Anweisungen
}
Bedingungsabfrage
if (boolean Ausdruck)
{
// Anweisungen
}

else if (boolean Ausdruck)
{
// Anweisungen
}
else
{
// Anweisungen
}
#define
#define ist eine hilfreiche C-Komponente, die es erlaubt, ein bestimmte Konstante oder einen Alias zu
definieren. Der Vorteil ist, dass diese Konstante kein Speicherplatz auf dem Chip benötigt, da der
Compiler eine Referenz zur definierten Konstante/Alias während des Kompilierens durch den definierten
Wert ersetzt wird.
Dies kann allerdings auch zu einigen negativen Nebeneffekten führen, wenn z.B. der Name einer
definierten Konstante in einem anderen Variablennamen verwendet wird.
Um Konstanten zu definieren sollte der Typqualifikator const eingesetzt werden.

Syntax
#define NamederKonstante Wert

Beispiel
#define ledPin 3
// Der Compiler wird während des Kompilierens jede Referenz zu ledPin
// mit dem Wert 3 ersetzen

Hinweis
Nach dem #define wird kein Semikolon und auch kein “=” benötigt:
#define ledPin 3; // dies ist ein Fehler
#define ledPin = 3 // dies ist ebenfalls ein Fehler

#include
#include wird benutzt um externe Software-Bibliotheken in das Programm einzubinden (siehe auch
„Bibliotheken“), welche bereits einige Standardfunktionen beinhalten. #include erlaubt den Zugriff auf
Standard C Bibliotheken und auch auf Arduino spezifische Bibliotheken. Eine Auswahl vieler
Bibliotheken ist auf arduino.cc zu finden, und auch in vielen Foren im Internet, bei Anbietern von
Hardware etc.
Zu beachten ist, dass #include genau wie #define kein Semikolon am Ende benötigt!
Beispiel
Dieses Beispiel bindet eine Bibliothek ein, die benutzt wird, um Daten in den flash-Speicher anstatt in
den RAM-Speicher zu legen. Dies spart Platz im RAM-Speicher, wenn dynamischer Speicher benötigt
wird und macht große Datentabellen praktischer.
#include

prog_uint16_t meineKonstanten[
8456,0,0,0,0,0,0,0,0,29810,8968,29762,29762,4500};
Datentypen
Datentypen geben an, welches Format oder Art die unter dem entsprechenden Namen gespeicherten
Werte haben, bzw. haben dürfen. Hier gibt es bedingt aus dem C/C++ Sprachraum noch weitere
Bezeichnungen, die ich hier als „alternative“ Datentypen angebe. Sie sind nicht so leicht verständlich und
nur der Vollständigkeit halber erwähnt. Eventuell hat man ja mal einen Code eines anderen
Programmierers, der diese Bezeichner verwendet. So steht man nicht auf dem Schlauch, und weiß, was
gemeint ist.

void
void wird als Keyword nur zur Deklaration von Funktionen eingesetzt. Es zeigt an, dass die Funktion
keine Rückgabewerte an die aufrufende Funktion zurück liefert.

// die Aktionen werden in den Funktionen "setup" und "loop" ausgeführt,
// aber keine Werte werden an das aufrufende,
// übergeordnete Gesamtprogramm übergeben
void setup()
{
// ...
}
void loop()
{
// ...
}

byte ( uint8_t )
Byte speichert einen 8-bit numerischen, ganzzahligen Wert ohne Dezimalkomma. Der Wert
kann zwischen 0 und 255 sein.

byte someVariable = 180; // deklariert 'someVariable'
// als einen 'byte' Datentyp

int ( int16_t )
Integer ist der verbreitetste Datentyp für die Speicherung von ganzzahligen Werten ohne
Dezimalkomma. Sein Wert hat 16 Bit und reicht von -32.767 bis 32.767.

int someVariable = 1500; // deklariert 'someVariable'
// als einen 'integer' Datentyp

Hinweis:
Integer Variablen werden bei Überschreiten der Limits 'überrollen'. Zum Beispiel
wenn x = 32767 und eine Anweisung addiert 1 zu x, x = x + 1 oder x++, wird 'x' dabei
'überrollen' und den Wert -32,768 annehmen.

short
Ein short ist ein 16Bit Datentyp und reicht von -32.767 bis 32.767. Bei den ATMEGA und ARM-
basierten ARDUINO’s ist ein short also mit dem int identisch. Es sollte besser ein int verwendet werden.

short someVariable = 1500; // deklariert 'someVariable'
// als einen 'short' Datentyp

word ( uint16_t )
Ein word speichert eine vorzeichenlose 16-bit Zahl, von 0 bis 65535. Genauso wie eine
unsigned int.

word w = 60000; // Variable zu groß für int, aber word ist OK!

unsigned int ( uint16_t )
Vorzeichenlose Integer-Variable. Wert kann von 0 bis 65535 sein.

unsigned int variable = 40000;

long ( int32_t)
Datentyp für lange Integer mit erweiterter Größe, ohne Dezimalkomma, gespeichert in einem
32-bit Wert in einem Spektrum von -2,147,483,648 bis 2,147,483,647.

long someVariable = 90000; // deklariert 'someVariable'
// als einen 'long' Datentyp


unsigned long ( uint32_t )
Vorzeichenlose long-Variable. Wert 0 bis 4.294.967.295

unsigned long variable = 3000000;

float
Ein Datentyp für Fließkomma Werte oder Nummern mit Nachkommastelle. Fließkomma
Nummern haben eine bessere Auflösung als Integer und werden als 32-bit Wert mit einem
Spektrum von -3.4028235E+38 bis 3.4028235E+38 gespeichert.

float someVariable = 3.14; // deklariert 'someVariable'
// als einen 'float' Datentyp

Hinweis:
Fließkommazahlen sind nicht präzise und führen möglicherweise zu
merkwürdigen Resultaten, wenn sie verglichen werden. Außerdem sind Fließkomma
Berechnungen viel langsamer als mit Integer Datentypen. Berechnungen mit Fließkomma
Werten sollten nach Möglichkeit vermieden werden. Siehe auch hier.

double
Eine Fliesskommazahl mit doppelter Auflösung als float. Allerdings ist bei den UNO’s, NANO’s und
andere ATMEGA-basierten Boards die Auflösung genau identisch mit der von float. Man hat also keinen
Gewinn an Genauigkeit.

Beim ARDUINO DUE ist double eine 8 Byte Zahl (64bit) und hat somit die doppelte Auflösung als float.

Hinweis
Wenn man sich Code aus anderen Projekten „borgt“ und in das eigene Projekt einfügt, oder ganze
Sketche, sollte man vorher schauen, ob die höhere Präzision der double im eigenen Projekt gebraucht
wird oder nicht. Ansonsten kann es zu ungenauen Ergebnissen führen. Da ist dann nur der Einsatz eines
DUE möglich, oder aber anderes Coding.

boolean ( bool )
Der Datentyp boolean kann zwei Zustände haben: true oder false.
Die Datentypen kann man angelehnt an die digitale Elektronik sehen, in denen man auch von 0 und 1
redet (oder HIGH und LOW). Siehe auch hier in der Referenz.

boolean buzzerflag = false; // Flag zur Erkennung
bool buzzerflag = false; // das gleiche…

Ich benutze sehr gern sogenannte Flags, um im Programm zu markieren, ob ein gewisser Zustand gerade
aktiv ist oder nicht. Dazu verwende ich den Datentyp boolean.

false: bedeutet immer 0 (Null)
true: bedeutet 1, ABER: auch jeder andere Wert außer Null ist true.



Array‘s
Ein Array ist eine Sammlung von Werten, auf die mit einer Index Nummer zugegriffen wird.
Jeder Wert in dem Array kann aufgerufen werden, indem man den Namen des Arrays und die
Indexnummer des Wertes abfragt. Die Indexnummer fängt bei einem Array immer bei 0 an.
Ein Array muss deklariert werden und optional mit Werten belegt werden, bevor es genutzt
werden kann.

int myArray[

Genauso ist es möglich ein Array zuerst mit Datentyp und Größe zu deklarieren und später
einer Index Position einen Wert zu geben.

int myArray[5// deklariert Datentyp 'integer' als Array mit 6
Positionen
myArray[3 = 10; // gibt dem 4. Index den Wert 10

Um den Wert eines Arrays auszulesen kann man diesen einfach einer Variablen mit Angabe
des Arrays und der Index Position zuordnen.

x = myArray[3// x hat nun den Wert 10

Arrays werden oft für Schleifen verwendet, bei dem der Zähler der Schleife auch als Index
Position für die Werte im Array verwendet wird. Das folgende Beispiel nutzt ein Array um
eine LED zum Flackern zu bringen. Mit einer for-Schleife und einem bei 0 anfangenden Zähler
wird eine Indexposition im Array ausgelesen, an den LED Pin gesendet, eine 200ms Pause
eingelegt und dann dasselbe mit der nächsten Indexposition durchgeführt.

int ledPin = 10; // LED auf Pin 10
byte flicker[
// Array mit 8 verschiedenen Werten
void setup()
{
pinMode(ledPin, OUTPUT); // Setzt den OUTPUT Pin
}
void loop()
{
for(int i=0; i<7; i++) // Schleife gleicht der Anzahl
{ // der Werte im Array
analogWrite(ledPin, flicker[i// schreibt den Indexwert auf die LED
delay(200); // 200ms Pause
}
}
char ( int8_t )
Ein Datentyp, der 1 Byte Speicher braucht um einen Buchstaben zu speichern. Buchstaben müssen in
einfache Anführungszeichen gesetzt werden: 'A'. Für mehrere Buchstaben (Wörter) sind doppelte
Anführungszeichen erforderlich: "ABC".
Wie auch immer – Buchstaben werden immer als Byte-Zahl gespeichert (im ASCII-Code).
Der char-Datentyp ist ein Vorzeichen-Typ, was bedeutet, dass Buchstaben immer von -128 bis 127
codiert werden.

char myChar = 'A';
char myChar = 65; // beides bedeutet das gleiche

unsigned char ( uint8_t )
Ein unsiged char speichert ein vorzeichenloses 8-bit Zeichen mit dem Wertebereich von 0 bis 255.
Identisch mit byte. Um konsistent mit dem Arduino Programmierstil zu sein, sollte man den Datentyp
byte verwenden.

unsigned char meinZeichen = 240;

string (Datentyp & char-Array)
Text-Strings können auf zwei Arten gebildet werden:
1. Man kann den Datentyp „String“ (String-Object) verwenden.
2. Man bildet ein Array von Typ „char“. Dieses muß mit einem Null-Terminator beendet werden.
Das macht der Compiler entweder selbst (unteres Beispiel Str2), oder man hängt diese ‚\0‘ selbst
an (Beispiel Str3). Hier geht es um das Array vom Typ char.
Für weiterführende Details über das String-Object, (Punkt 2), welches mehr Möglichkeiten bietet, aber
auch mehr Speicher braucht, siehe hierzu String Objects. Diese Möglichkeiten sind sehr umfangreich,
und bedürfen Einarbeitungszeit.
Die folgenden Beispiele sind alles gültige String-Deklarationen:
char Str1[15 // nimmt 15 Objekte der Klasse String auf
char Str2[8,};
char Str3[8\0'};
char Str4[
char Str5[8
char Str6[15

Möglichkeiten der oben genannten String-Deklaration:
1. Array von Buchstaben, ohne es zu initialisieren  siehe Str1
2. Deklariere ein Array von Buchstaben (mit einem zusätzlichen Zeichen) und der Compiler wird
die notwendige Null selbst hinzufügen  siehe Str2
3. Geben sie den null-termination explizit mit an  siehe Str3
4. Initialisiere eine String-Konstante in Anführungszeichen. Der Compiler bildet die erforderliche
String-Größe selbst, fügt den null-termination hinzu, sodass alles passt.  siehe Str4
5. Initialisiere das Array selbst mit einer genauen Größe und String-Konstanten  siehe Str5
6. Initialisiere das Array selbst und lass zusätzlichen Platz für größere, längere Wörter  siehe
Str6

null termination / null character
Normalerweise werden Strings mit einem “null Character” beendet (ASCII Code 0). Dies gibt Funktionen
wie Serial.Print() die Möglichkeit, das Ende des Strings zu erkennen. Ohne diesen würde die
Funktion weitere folgende Bytes lesen, die nicht Teil des gewünschten Strings sind.
Das bedeutet, dass der String immer Platz haben muss für ein zusätzliches Zeichen als der Text enthält,
der im String gespeichert werden soll. Deshalb hat Str2 und Str5 8 Zeichen, obwohl das Wort „Arduino“
nur 7 Buchstaben hat. Die letzte freie Position wird automatisch mit dem „null character“ gefüllt. Str4
wird automatisch auf die Größe von 8 Buchstaben gebracht, einen für die Extra-Null. In Str3 haben wir
selbst den „null character“ angefügt (wird '\0’ geschrieben).
Beachten Sie, dass es möglich ist, einen String zu haben OHNE den null character (z.B., wenn Sie Str2
mit der Länge von 7 anstatt von 8 deklariert haben). Das wird das korrekte Arbeiten der meisten
Funktionen zerstören, welche Strings nutzen. Das sollte man also unterlassen. Wenn Sie also seltsames
Verhalten im Zusammenhang der Benutzung von Strings feststellen (z.B. arbeiten mit Buchstaben,
welche nicht im String vorkommen), dann könnte das die Ursache sein.
Einfache oder doppelte Anführungszeichen?
Strings (ganze Wörter, Sätze) werden immer definiert in doppelten Anführungszeichen ("Abc"), einzelne
Buchstaben dagegen in einfachen Anführungszeichen ('A').
Einbinden langer Strings (Sätze)
Lange Sätze oder Wörter können Sie so einbinden:
char myString[
" this is the second line"
" etcetera"; // Semikolon am Ende !!

String-Array‘s
Oftmals ist es sehr komfortabel, wenn man mit langen Zeichenketten, Wörtern oder Sätzen arbeitet (z.B.
ein Projekt mit LCD-Anzeige), dann ein String-Array zu bilden. Da Strings ja selbst schon ein Array sind,
handelt es sich hier also um ein zweidimensionales Array.
In dem unten angeführten Code-Beispiel bedeutet und bezeichnet der Stern hinter dem Datentyp char,
dass es sich hierbei um einen String mit “Pointern” handelt. Da alle Arraynamen eigentlich Pointer sind,
ist das notwendig, um eine Array von Arrays zu bilden (Zweidimensionales Array). Pointer sind ein Teil
der eher „esoterischen“ Teile der C-Programmiersprache und schwer zu verstehen für Anfänger. Aber in
diesem Codebeispiel ist es nicht notwendig, die Benutzung von Pointern zu verstehen, um sie effizient
einzusetzen (ideal für Auswahl unterschiedlicher Anzeigetexte in LCD’s aufgrund von Entscheidungen
im Programm [A.N.
).
char* myStrings[ing 2", "This is string 3",
"This is string 4", "This is string 5","This is string 6"};

void setup(){ // Setup wird einmal durchlaufen
Serial.begin(9600); // serielle Schnittstelle 9600Bd initialisieren
}

void loop(){ // Hauptprogramm wird in Schleife durchlaufen
for (int i = 0; i < 6; i++){ // 6 mal ausführen
Serial.println(myStrings[i
delay(500); // Pause 0,5 Sekunden
}

String-Objects
Das ist ein sehr umfangreiches Kapitel, deshalb ist ihm auch ein extra Abschnitt gewidmet. Siehe „String
Objects.

Datentypen-Bezeichner z.B. UL, U, L etc.
Manchmal kann es sinnvoll sein, die verwendeten Datentypen im Code zu bezeichnen. Danke hierzu an
Mitglied Scheams im ARDUINO-Forum (Quelle 10). Hier ist es nicht notwendig:
unsigned int var = 5U; // unnötig ->
unsigned int var = 5;
Wenn man aber sowas hat:
var = (15000 * 20000) / 9375;
wäre theoretisch: 300.000.000 / 9.375 = 32.000
Diese 300.000.000 passen aber nicht in den Bereich (-32.768 bis +32.768) von einem int (bei blanken
Zahlen wird meist ein int angenommen) und es könnte ein Overflow entstehen, d.h. das Ergebnis wäre
ganz was anderes. Wenn man aber:
var = (15000UL * 20000UL) / 9375;
verwendet, ist das 1. Zwischenergebnis (300.000.000) im Bereich des "UL = unsigned long" (0 -
~4.300.000.000) und es wird kein Overflow passieren.
Konstanten
Konstanten sind vordefinierte Variablen in der Arduino-Sprache. Sie machen die Programme einfacher zu
lesen und zu verstehen. Wir klassifizieren die Konstanten in verschiedenen Gruppen.
Logische Pegel, true und false (Bool’sche Konstanten)
Es gibt zwei Variablen in der Arduino-Sprache um wahr und falsch zu definieren: true, und false.
false
false ist die einfachere der beiden: false ist definiert als Logisch 0 (zero)
true
True wird oft mit Logisch 1 definiert, was auch richtig ist. ABER true hat noch eine weitergehende
Definition. Jede Integerzahl (Datentyp int), die nicht 0 ist, ist true. (in der Booleschen Algebra)
Also sind -1, 2, 200, -200 ebenfalls definiert als true, in der Booleschen Algebra.
Beachten Sie, das true und false Konstanten in Kleinbuchstaben geschrieben werden, während HIGH,
LOW, INPUT, OUTPUT in Großbuchstaben geschrieben werden!

Pin-Zustände HIGH und LOW
Wenn auf einen Pin des ARDUINO geschrieben oder gelesen werden soll, dann gibt es nur zwei
mögliche Werte: HIGH und LOW. (auch analogWrite schreibt nur HIGH und LOW, aber eben als
pulsweitenmodulierte Spannung…)
HIGH
Die Bedeutung von HIGH (in Bezug auf einen Schaltkreis-Pin) ist etwas unterschiedlich, je nachdem ob
der Pin als INPUT oder OUTPUT gesetzt ist. Wenn ein Pin mit pinMode als INPUT konfiguriert ist, und
mit digitalRead gelesen wird, dann wird der Arduino ein HIGH melden, wenn die anliegende Spannung
am Pin 3V oder mehr beträgt.
Ein Pin kann auch als INPUT konfiguriert werden mit pinMode und danach auf HIGH gesetzt werden
mit digitalWrite. Das schaltet den internen Pullup-Widerstand von 20k ein. Das setzt den Pin auf HIGH,
wenn er nicht beschaltet ist. Um ein LOW zu erzeugen, muss der Pin extern auf LOW (Potential GND)
gezogen werden, z.B. durch einen Taster, Sensor etc. Genauso arbeitet auch der Befehl
INPUT_PULLUP.
Wenn ein Pin als OUTPUT konfiguriert ist mit dem Befehl pinMode und auf HIGH gesetzt wird mit
digitalWrite, dann liegt eine Spannung von 5V (bzw. die ARDUINO-Betriebsspannung) am Pin an.
Der Ausgang kann nun Strom treiben gegen Masse, z.B. um eine LED mit Vorwiderstand zum Leuchten
zu bringen. Der Maximalstrom des Ausganges ist hier zu beachten und die gesamte maximale
Verlustleistung (Datenblatt) des gesamten Schaltkreises. Auch die Verbindung mit einem anderen Pin ist
möglich, wenn dieser als INPUT gesetzt ist.
LOW
Die Bedeutung von LOW ist auch unterschiedlich, je nachdem ob es sich um einen Pin als INPUT oder
OUTPUT handelt. Ist ein Pin als INPUT konfiguriert mit pinMode und wird mit digitalRead gelesen,
dann wird der Arduino ein LOW melden, wenn die Spannung 2V oder kleiner ist.
Ist der Pin als OUTPUT konfiguriert, dann ist der Pin auf 0V. In diesem Zustand kann der Pin ebenfalls
Strom treiben, aber hier gegen +5V! Die LED muss hier also mit Vorwiderstand gegen +5V geschaltet
werden. Hier handelt es sich also um eine negative Logik (LOW-aktiv), d.h. die LED leuchtet, wenn der
Pin auf LOW gelegt wird.

Digitale Pins konfigurieren, INPUT, INPUT_PULLUP, und
OUTPUT mit dem Befehl pinMode
Digitale Pins können benutzt werden als INPUT, OUTPUT oder INPUT_PULLUP. Das ändern eines
Pins mit pinMode ändert auch das elektrische Verhalten des Pins.
Pins konfiguriert als Eingänge (INPUT)
Arduino (Atmega) Pins, die als INPUT konfiguriert sind mit pinMode, haben einen hohen
Innenwiderstand. (high-impedance state). INPUT-Pins verbrauchen extrem wenig Strom aus der
Schaltung, vergleichbar mit einem Widerstand von 100 Megaohm oder mehr. Das macht sie tauglich um
einen Sensor zu lesen, aber nicht um eine LED zu treiben. Siehe auch hier.
Wenn ein Pin als INPUT konfiguriert ist, dann will man ihn oft auf einem definierten Potential haben.
Das wird erreicht mit einem Pulldown-Widerstand vom Pin nach Masse. Dann liegt der Pin im
unbeschalteten Zustand auf LOW. Das Gegenteil wird erreicht bei Benutzung des internen Pullup mit
INPUT_PULLUP.
Analoge Eingänge, welche mit dem Befehl analogRead abgefragt werden sollen, müssen nicht mit
PinMode konfiguriert werden. (Es schadet aber auch nicht.)
pinMode(1, INPUT); // Setzt den Digital-Pin 1 als Eingang

Pins konfiguriert als INPUT_PULLUP (internen Pullup-Widerstand einschalten)
Der ATMega-Chip, welcher sich auf den Arduino-Boards befindet, hat interne Pullup-Widerstände, die
Sie zuschalten können, wenn nötig. Wenn sie diese den extern in die Schaltung zu bringenden
Widerstände vorziehen, dann können sie mit INPUT_PULLUP als Argument im Befehl pinMode()
eingeschaltet werden.
pinMode(1, INPUT_PULLUP); // setzt Pin1 als Eingang und aktiviert Pullup
Pins konfiguriert als Ausgänge (Outputs)
Pins, welche als Ausgänge konfiguriert sind, befinden sich in einem Zustand mit geringem
Innenwiderstand (low-impedance state). Das bedeutet, dass sie einen bestimmten Strom in andere Teile
der Schaltung treiben können. Bei den AVR’s im Arduino ist dieser Strom maximal 40mA, welcher
getrieben (gegen Masse) oder gezogen (nach +5V) werden kann. Das macht sie nützlich, um LED’s zum
Leuchten zu bringen, oder Relais zu schalten, oder auch andere Teile der Schaltung anzusteuern.
Die gesamte maximale Verlustleistung der AVR’s ist auch hier zu beachten. So ist es nicht möglich, alle
verfügbaren Pin’s als Ausgang zu konfigurieren und dann alle auf HIGH zu setzen und jeweils 40mA
Strom zu treiben. Dann wird der ARDUINO mit hoher Wahrscheinlichkeit Schaden nehmen.
pinMode(13, OUTPUT); // Setzt den Digital-Pin 13 als Ausgang

Integer Konstanten
Konstanten mit dem Datentyp int speichern Integer-Zahlen (-32768 bis 32768) und können nicht geändert
werden. Sie erleichtern das Lesen des Codes.

const int LED = 13; // LED verbunden mit Pin 13

In diesem Fall wird dem Compiler der Arduino-IDE gesagt, er soll jedes Mal, wenn das Wort „LED“
erscheint, dieses mit der Zahl 13 ersetzen. Wie man sieht, kann man hier viel tun, um den Code einfacher
lesbar zu gestalten. Die Zahlen können auch im Binärcode, Oktal, hexadezimal etc. angeben. Wen das
näher interessiert, dem möge die Original-Referenz in Englisch helfen.


Floating point Konstanten (Fließkomma)
Hier gilt das eben gesagte, halt für Fließkommazahlen.

const float pi = 3.14; // Konstante „pi“ erhält den Wert 3,14

Fliesskomma-Konstanten können auch in wissenschaftlicher Darstellung eingegeben werden. Hierzu
kann das „E“ wie auch“e“ als Indikator des Exponenten verwendet werden

const float test = 5.87E5 // entspricht 587000
const float test2 = 4.3e-3 // entspricht 0.0043


Verzweigungen und Schleifen
for-Schleifen
For-Schleifen werden benutzt um bestimmte Aktionen wiederholt auszuführen, z.B. um ein Array mit
Daten eines Sensors zu füllen.
Eine for-Schleife benötigt drei Parameter:

for (Initialisierung; Bedingung; Inkrement)
{
// Anweisungen
}

Die Initialisierung geschieht nur einmal. Danach wird die Bedingung geprüft und falls diese Bedingung
stimmt, wird das Inkrement (i++) ausgeführt (der Zählerwert wird erhöht (i++) bzw. verkleinert (i--), je
nach Anwendung).

// Eine LED dimmen mithilfe von PWM

int PWMpin = 10; // LED ist an Pin 10 angeschlossen

void setup()
{
// es wird kein setup benötigt
}

void loop()
{
for (int i=0; i <= 255; i++){
analogWrite(PWMpin, i);
delay(10);
}
}

Die for-Schleife in C ist viel flexibler als for-Schleifen in anderen Programmiersprachen. Das
Inkrement/Dekrement kann aus jeder C konforme Rechenoperation bestehen, z.B. eine Multiplikation,
Addition oder sogar Potenzierung:

for(int x = 2; x < 100; x = x * 1.5)
{
println(x);
}


if (Bedingung) und ==, !=, <, > (Vergleichsoperatoren)
if in Verbindung mit einem Vergleichsoperator prüft, ob eine bestimmte Bedingung erfüllt ist, z.B. ob
der Wert einer Variablen einen festgelegten Wert überschritten hat.
Eine if-Abfrage kann z.B. so aussehen:
if (Variable > 50) Serial.print(„Variable ist größer als 50”);
Diese Kurzversion funktioniert nur, wenn nur eine einzige Anweisung der Bedingung folgt.
Die normale Schreibweise ist im Folgenden aufgeführt:

if (Variable > 50)
{
// Führe eine Aktion aus. Wenn der Wert in Variable die 50 überschritten hat,
// z.B. setze den Wert von Variable zurück
}

Wenn die Bedingungen in den runden Klammern erfüllt sind, wird der Code in den geschweiften
Klammern ausgeführt. Wenn die Bedingung nicht erfüllt ist, wird der Code in den geschweiften
Klammern einfach übersprungen.

Vergleichsoperatoren
x == y (x entspricht y)
x != y (x ungleich y)
x < y (x ist kleiner als y)
x > y (x ist größer als y)
x <= y (x ist kleiner oder gleich y)
x >= y (x ist größer oder gleich y)

Zu beachten ist, dass == verwendet wird, um zu prüfen ob eine Variable einem Wert entspricht!

Verkürzte Schreibweise
if (wert != 0) ist gleichbedeutend mit if (wert)
if (wert == 0) ist gleichbedeutend mit if (!wert)


if / else
if/else erlaubt eine bessere Kontrolle über den Programmablauf als die simple if-Abfrage, da mehrere
Bedingungen geprüft werden können.
Eine Anwendung könnte z.B. so aussehen: Die Spannung an einem analogen Eingang wird gemessen, in
einen Wert umgewandelt und es soll eine Aktion ausgeführt werden, wenn der Wert größer als 500 ist
oder wenn er kleiner als 500 ist.

if(analogRead(5) < 500)
{
// Aktion A
}
else
{
// Aktion B
}

Wenn der Wert größer als 500 ist, wird Aktion A ausgeführt, andernfalls wird Aktion B ausgeführt.
Else und if können auch kombiniert werden, dabei wird solange zur nächsten else if-Anweisung
gesprungen bis eine Bedingung erfüllt ist.

if (analogRead(5) < 500)

{ // Aktion A

}
else if (analogRead(5) >= 1000)
{
// Aktion B
}
else
{
// Aktion C
}

switch / case Anweisungen
Ähnlich wie if-Anweisungen erlauben die switch/case-Anweisungen die Ausführung bestimmter
Abläufe zu kontrollieren. Eine switch-Anweisung vergleicht den Wert einer Variablen mit den Werten
aus den case-Anweisungen. Wenn eine Übereinstimmung gefunden wird, wird das Programm ab der
jeweiligen case-Anweisung bis zum nächsten break ausgeführt.


Syntax
switch (var) {
case label:
// Anweisungen
break;
case label:
// Anweisungen

break;
default:
// Anweisungen
}

Parameter
var: eine Variable deren Wert zwischen den einzelnen case-Anweisungen verglichen wird
label: ein Wert der mit var verglichen wird

Beispiel
switch (var) {
case 1:
//etwas tun wenn var == 1
break;
case 2:
//etwas tun wenn var == 2
break;
default:
// wenn nichts zutrifft, führe default (standard) code aus
// default ist optional, sollte aber immer hinzugefügt werden
}


while - Schleifen
Eine while-Schleife wiederholt den Code innerhalb der geschweiften Klammern bis die Bedingung in
den runden Klammern nicht mehr wahr ist bzw. nicht mehr zutrifft. Der Wert muss geändert werden, sei
es innerhalb der Schleife durch eine Variable die inkrementiert wird oder durch den Druck eines Tasters,
um die Schleife zu verlassen.
Syntax
while(Bedingung)
{
// Anweisung(en)
}

Parameter
eine Bedingung die entweder wahr oder falsch sein kann
Beispiel
var = 0;
while(var < 200)

{
// wiederhole etwas 200 mal
var++; // erhöhe var jedes Mal um 1
}

do – while
Die do-Schleife verhält sich genau wie die while-Schleife, nur, dass die Bedingung immer am Ende der
Schleife geprüft wird. Das bedeutet, dass die Schleife immer mindestens einmal durchlaufen wird.

Syntax
Do
{
// Anweisung(en)
}
while (Bedingung);


Beispiel
do
{
delay(50); // warte 50 Millisekunden
x = readSensors(); // Lese die Sensoren aus

}
while (x < 100);
break
break wird benutzt, um eine do, for oder while-Schleife zu verlassen, ohne dass die Bedingung zum
Schleifenabbruch erfüllt ist.

for (x = 0; x < 255; x ++)
{
digitalWrite(PWMpin, x);
sens = analogRead(sensorPin);
if (sens > Grenzwert) { // verlasse Schleife, wenn der Sensor einen größeren Wert
// als den Grenzwert liefert
x = 0;
break;
}
delay(50);
}
continue
Die Anweisung continue springt ans Ende der aktuellen Schleifenanweisungen (do, for oder while
Schleife). Die Schleife setzt mit der Prüfung der Schleifenbedingung fort und führt entsprechend der
Schleife die nächste Iteration aus.

for (x = 0; x < 255; x++)
{
if (x > 40 && x < 120){
// überspringe die Anweisungen weiter unten, wenn x zwischen 40 und 120 liegt
continue;
}

digitalWrite(PWMpin, x);
delay(50);
}
return
Beendet eine Funktion und gibt der aufrufenden Funktion einen Wert zurück, wenn dies gewünscht ist.

Syntax
return;
return wert; // beide Formen sind korrekt

Parameter
wert: beliebige Variable oder Konstante

Beispiel
Eine Funktion, die den Sensorwert mit einem Grenzwert vergleicht
int checkSensor(){
if (analogRead(0) > 400) {
return 1;
}
else{
return 0;
}
}
goto
Leitet den Programmfluss zu einer bestimmten Sektion im Programmcode, welcher im Label definiert ist.

Syntax
label;
goto label; // leitet den Programmfluss zur Sektion "label"

Hinweis
Die Benutzung des goto-Befehls ist unter C-Programmierern verpönt, da man einen undefinierten
Programmfluss erzeugen kann, welcher sich nicht debuggen lässt.

Dennoch kann der goto-Befehl in manchen Situationen sehr nützlich sein, z.B. um aus stark verzweigten
for-Schleifen auszusteigen.

Beispiel
for(byte r = 0; r < 255; r++){
for(byte g = 255; g > -1; g--){
for(byte b = 0; b < 255; b++){
if (analogRead(0) > 250){ goto ausstieg;}
// weitere Anweisungen
}
}
}
ausstieg:

Rechenoperationen
= Zuweisungsoperator
Speichert den Wert rechts des = in die Variable links des =.
Das =-Zeichen in der Programmiersprache C heißt Zuweisungsoperator. Das = funktioniert ähnlich wie
man es aus dem Matheunterricht kennt. Die linke Seite ist gleich der rechten Seite. Allerdings funktioniert
das nur in diese Richtung!
Beispiel
// Ein kleiner Tipp:

int a = 10; // funktioniert, schreibt den Wert 10 in die Variable a
5 = a; // funktioniert nicht, da 5 nicht der Wert aus a zugewiesen werden kann,
//da 5 bereits selber ein Wert ist

// Deklaration und Wertzuweisung getrennt
int sensVal;
sensVal = analogRead(0);

// Deklaration mit sofortiger Wertezuweisung
int sensVal = analogRead(0);


Hinweis
Die Variable auf der linken Seite des Zuweisungsoperators muss groß genug sein, um den zugewiesenen
Wert zu speichern, andernfalls ist der gespeicherte Wert inkorrekt. Der Wert 1023 (10-bit groß) kann also
nicht in eine byte-Variable (8-bit groß) gespeichert werden.
= (einfaches =) und == (doppeltes =) dürfen nicht verwechselt werden, da = der Zuweisungsoperator, zum
Zuweisen eines Wertes, und == der Vergleichsoperator ist, welcher prüft, ob zwei Werte gleich groß sind.

Grundrechenarten (Addition, Subtraktion, Division,
Multiplikation)
Die Rechenoperatoren ermöglichen alle Grundrechenarten. Die Operatoren geben die Summe, die
Differenz, das Produkt oder den Quotienten der Faktoren rechts und links der Operatoren zurück. Das
Ergebnis hängt maßgeblich vom Datentypen der gewählten Variablen ab.
Ein kleines Beispiel:

int ergebnis = 9 / 4 schreibt den Wert 2 in die Variable ergebnis, obwohl der Quotient beider Zahlen
ja eigentlich 2,25 ist, da der Datentyp int nur ganzzahlige Werte aufnehmen kann. Der Rest 0.25 wird
einfach “abgeschnitten”, weil er hinter dem Komma steht. Nur Variablen des typs float oder double
können Dezimalbrüche (Zahlen mit Nachkommastellen) aufnehmen.
Syntax
ergebnis = Faktor1 + Faktor2;
ergebnis = Faktor1 - Faktor2;
ergebnis = Faktor1 * Faktor2;
ergebnis = Faktor1 / Faktor2;

Parameter
Faktor1: Eine Variable beliebigen Datentyps
Faktor2: Eine Variable beliebigen Datentyps

Beispiel
w = w + 3;
x = x - 7;
y = y * 6;
z = z / 5;

% Modulo
Der Modulo Operator gibt den Rest einer Division zweier ganzzahligen Faktoren zurück.
Zu kompliziert? Also ein kleines Beispiel:
9 / 2 ergibt 4,5. Wenn wir diesen Wert allerdings in eine int-Variable schreiben, nimmt die Variable den
Wert 4 an, da der Nachkommawert einfach abgeschnitten wird.
Der Modulo Operator gibt nun den Rest der Division zurück:
9 % 2 ergibt 1. Wieso?
Besser zu verstehen ist das, wenn wir uns einmal das Konzept des schriftlichen Dividierens in der 3.
Klasse anschauen. Wir schauen, wie oft die 2 in die 9 hineinpasst. Die 2 passt 4-mal in die 9, denn 4*2 =
8 Rest 1. Das Modulo gibt uns diesen Rest zurück.
Der Vollständigkeit halber mache ich hier nun weiter: wir setzen ein Komma hinter die 4 und zu der 1
ziehen wir eine 0 hinunter. Jetzt fragen wir uns, wie oft passt die 2 in die 10 hinein? Klar, 5-mal. Hinter
die 4, schreiben wir jetzt also eine 5 und wir bekommen 4,5.
Syntax
ergebnis = dividend % divisor

Parameter
dividend: die zu teilende Zahl
divisor: der Teiler

Beispiel
x = 7 % 5; // x enthält 2
x = 9 % 5; // x enthält 4
x = 5 % 5; // x enthält 0
x = 4 % 5; // x enthält 4

Hinweis
Der Modulo Operator funktioniert logischerweise nicht mit floats. (Fließkommazahlen)
Verknüpfungsoperationen (Boolsche
Operatoren)
Diese Operatoren können innerhalb einer if-Schleife benutzt werden, um z.B. zwei Bedingungen logisch
zu verknüpfen.
&& (logisches und)
ist nur wahr, wenn beide Bedingungen erfüllt sind, z.B.
if (digitalRead(2) == HIGH && digitalRead(3) == HIGH) { // lese zwei Schalter aus
// ...
}

Prüft, ob beide Eingänge logisch HIGH sind.

|| (logisches oder)
ist wahr, wenn eine der beiden Bedingungen wahr ist, z.B.
if(x > 0 || y > 0){
// ...
}

Ist wahr, wenn x oder y größer 0 ist.

! (nicht)
wahr wenn die Bedingung nicht wahr ist, z.B.
if(!(x==3)){
// ...
}

ist wahr, wenn x nicht gleich 3 ist.

Hinweis
Beachte, dass das logische UND ein „&&“ ist und das bitweise UND ein „&“ ist, denn die beiden sind
komplett verschieden! Auch haben das logische ODER ( || ) und das bitweise ODER ( | ) unterschiedliche
Funktionen. Das bitweise NICHT ~ sieht zwar anders aus als das logische NICHT !, aber man sollte sich
doch im Klaren sein, welches wo verwendet wird.

if (a >= 10 && a <= 20){} // ist wahr wenn a zwischen 10 und 20 liegt
Digital In / Out
pinMode()
Beschreibung
Bestimmt die Datenrichtung eines Pins, d.h. ob ein Pin als Ausgang oder Eingang genutzt wird.
Siehe auch hier.

Syntax
pinMode(pin, modus);

Parameter
pin: die Pinnummer des Pins, der konfiguriert werden soll (z.B. 13)
modus: entweder INPUT für Eingang oder OUTPUT für Ausgang

Beispiel
int ledPin = 13; // LED an digital pin 13
int eingang = 10; // Eingang an Pin 10

void setup()
{
pinMode(ledPin, OUTPUT); // Pin 13 als Ausgang konfigurieren
pinMode (eingang, INPUT); //
}

Analoge Eingänge, welche mit analogRead ausgelesen werden sollen, müssen nicht mit pinMode
konfiguriert werden.

digitalWrite()
Beschreibung
Den Pin auf logisch HIGH oder LOW setzen.
Wenn der Pin als Ausgang konfiguriert ist, dann liegt der Pin bei HIGH auf der Betriebsspannung (5V
oder 3.3V) des Boards und bei LOW auf 0V, sprich Masse (GND).
Wenn der Pin als Eingang konfiguriert ist, dann wird bei HIGH ein interner 20kOhm Pullup-Widerstand
an den Pin geschaltet (kann verwendet werden, um die Spannung an dem Pin auf 5V bzw. 3.3V zu halten,
sodass ein definierter Zustand herrscht), bei LOW wird dieser wieder von Pin getrennt.

Syntax
digitalWrite(pin, wert);

Parameter
pin: die Pinnummer des Pins, der konfiguriert werden soll (z.B. 13)
wert: entweder HIGH oder LOW

Beispiel
int ledPin = 13; // LED an digital pin 13
int eingang = 10; // Eingang an Pin 10

void setup()
{
pinMode(ledPin, OUTPUT); // digital pin 13 als Ausgang konfigurieren
pinMode (eingang, INPUT); //
digitalWrite(eingang, HIGH); // schaltet den internen PullUp-Widerstand ein
}

digitalWrite(ledPin, HIGH); // setzt ledPin auf logisch HIGH

Hinweis
Die Analog-Pins können auch als digitale Ausgänge genutzt werden, sie heißen A0 bis A5.

digitalRead()
Beschreibung
Liest den Zustand des Pins entweder HIGH oder LOW ein und gibt diesen zurück.

Syntax
digitalWrite(pin);

Parameter
pin: die Pinnummer des Pins, der konfiguriert werden soll (z.B. 13)

Beispiel
int ledPin = 13; // LED an pin 13
int inPin = 7; // Taster an Digital-Pin 7
int val = 0; // variable um den Pinstatus zu speichern

void setup()
{
pinMode(ledPin, OUTPUT); // setzt pin 13 als Ausgang
pinMode(inPin, INPUT); // setzt pin 7 als Eingang
}
void loop()
{
val = digitalRead(inPin); // liest pin 7 ein
digitalWrite(ledPin, val); // setzt pin 13 auf den Wert von pin 7
}

Hinweis
Die beiden Analog-Pin’s A6 und A7 können nicht als digitale Eingänge benutzt werden! (Danke an
Member hotsystems und Bitklopfer).
Hier hilft nur, falls man mehr digitale Eingänge benötigt, ein Portexpander oder aber diese Eingänge mit
analogRead auszulesen und dann den Analogwert auszuwerten als digitalen Wert.
Grundlegendes Analog In / Out
analogReference()
Beschreibung
Bestimmt die Referenzspannung für die analogen Eingänge (den ADC):

 DEFAULT: Die standardmäßige Referenzspannung für den ADC beträgt 5V bzw. 3.3V (je nach
Betriebsspannung des Boards)
 INTERNAL: Interne Spannungsreferenz beim ATmega168 und ATmega328P beträgt die
Referenzspannung 1.1V, beim ATmega8 2.56 (nicht beim Arduino Mega vorhanden)
 INTERNAL1V1: Interne Spannungsreferenz von 1.1V (nur Arduino Mega)
 INTERNAL2V56: Interne Spannungsreferenz von 2.56V (nur Arduino Mega)
 EXTERNAL: Die Spannung am AREF Pin wird als Spannungsreferenz verwendet. Achtung!
Maximal 5V!
Syntax
analogReference(type);

Parameter
Eines der oben genannten Makros z.B. EXTERNAL

Hinweis
Der AREF Pin darf nur mit Spannungen zwischen 0V und 5V beschaltet werden, ansonsten kann der
Controller beschädigt werden! Wenn der AREF-Pin beschaltet ist muss zuerst die Referenzspannung mit
analogReference(EXTERNAL) auf extern gestellt werden, bevor analogRead() aufgerufen wird,
ansonsten werden die interne und externe Referenzspannung kurzgeschlossen und der Controller wird
beschädigt.

analogRead()
Beschreibung
Liest den angegebenen Analogeingang aus. Der Arduino hat einen 6-Kanal (8 beim Mini und Nano, 16
beim Mega) 10-bit ADC, dass bedeutet der Arduino wandelt Spannungen von 0V bis 5V in Zahlen von 0
bis 1023 um. Bei 5V Referenzspannung ist das eine Auflösung von 5V / 1024 = 0.0049V = 4,9mV.
Es dauert ungefähr 100µs einen Analogwert zu lesen, somit ergibt sich eine theoretische, maximale
Frequenz von 10.000 Abfragen pro Sekunde.

Syntax
analogRead(pin);

Parameter
pin: die Pinnummer des Pins, der konfiguriert werden soll (A0 bis A5 bei den meisten Boards, A0 bis A7
beim Mini und Nano, A0 bis A15 beim Mega)

Rückgabewert
int ( Integer-Wert) zwischen 0 und 1023

Beispiel
int analogPin = 3; // Potentiometer Schleifer am Pin A3
int val = 0; // Variable um Messergebnis zu
speichern

void setup()
{
Serial.begin(9600); // serielle Kommunikation
einschalten
}

void loop()
{
val = analogRead(analogPin); // Eingang auslesen
Serial.println(val); // Messwert über serielle
Verbindung senden
}


analogWrite()
Beschreibung
Gibt eine PWM (Pulsweitenmodulation, Rechteckspannung) am definierten Pin aus. Diese PWM kann
z.B. benutzt werden um eine LED zu dimmen oder einen Motor in der Geschwindigkeit zu regeln
(natürlich über einen Treiber). Die PWM wird solange ausgegeben bis die Pulsweite durch einen weiteren
Aufruf von analogWrite() geändert wird oder digitalWrite() bzw. digitalRead() für diesen Pin aufgerufen
wird.
Die PWM-Frequenz liegt beim ARDUINO UNO (und den ATMega328-basierten Boards) bei ca. 490Hz
an den Pins 3,9,10,11 und ca. 980Hz an Pins 5 und 6. Diese kann aber auch geändert werden (siehe
Internet). Die Spannung am Ausgang liegt jedoch immer entweder bei 0V oder 5V. Siehe hierzu nächstes
Kapitel!
analogWrite() funktioniert nur bei den Pins, die für PWM vorgesehen sind. Das sind im Allgemeinen 3, 5,
6, 9, 10, 11. Es gibt aber noch mehr Möglichkeiten per Software (bei Bedarf im Netz nachlesen)
Syntax
analogWrite(pin, pulsweite);

Parameter
pin: die Pinnummer des Pins, an dem die PWM ausgegeben werden soll
pulsweite: zwischen 0 und 255

Beispiel
int ledPin = 9; // LED an Pin 9
int analogPin = 3; // Potentiometer an A3
int val = 0; // Variable um den Analogwert zu speichern

void setup()
{
pinMode(ledPin, OUTPUT); // den Pin als Ausgang konfigurieren
}

void loop()
{
val = analogRead(analogPin); // Pin A3 lesen
analogWrite(ledPin, val / 4); // analogRead Werte reichen von 0 bis 1023,
analogWrite Werte von 0 bis 255
}

Gleichspannung analog ausgeben
Der Befehl analogWrite() ist etwas verwirrend, wird doch hier keine „analoge“ Spannung ausgegeben, sondern
eine Rechteckfrequenz mit unterschiedlicher Pulsbreite. Es ist also weiterhin eine „digitale“ Spannung mit den
Werten 0V (LOW) und +5V (HIGH).

Es gibt jedoch Anwendungsfälle, da braucht man eine echte Gleichspannung zwischen 0V und +5V. Um diesen
Fall geht es hier

analogWrite() macht folgendes:

Funktion des Befehls analog.Write() mit unterschiedlichen Werten. (Quelle [15


Das ist ja nun keine Gleichspannung (außer 0% und 100%)…. Was also tun?
Hier hilft uns althergebrachte Analog-Elektronik. Schön, dass es sie noch gibt. Ich arbeite sehr gern damit, habe
ich doch so meine Elektroniker-Tätigkeit vor mehr als 35 Jahren begonnen.

Als erstes braucht man ein sogenanntes RC-Glied als Tiefpass geschaltet. Dieses „glättet“ in gewisser Weise die
Impulse (vereinfacht gesagt). Die mathematische Funktion, welche dahintersteckt, nennt sich Integration. Ich will
das nicht unnötig verkomplizieren, daher unterlasse ich hier absichtlich weitere Erklärungen. Wer das näher
wissen will, kann im Netz Informationen finden.

Im nächsten Bild sieht man eine geeignete Schaltung. Der Widerstand mit 4,7kOhm und der Kondensator 10µF
bilden das RC-Glied. Diese beiden Bauteile sind zwingend erforderlich. Das nachfolgende Symbol (Bauteil) ist ein
sogenannter Operationsverstärker (OPV, OV opamp). Er dient hier als „Treiber“, d.h. er liefert den gegebenenfalls
höheren Strom für die nachfolgende Schaltung. Wird er weggelassen, dann kann es sein, dass die
Ausgangsspannung zusammenbricht und nicht mehr dem durch den ARDUINO programmierten Ausgangswert

entspricht. Dies verhindert der OPV weitgehend unter normalen Bedingungen. Geeignet sind hier
Operationsverstärker vom Typ „rail-to-rail“. Ein geeigneter und sehr günstiger Typ ist der MCP601

Wichtig: Der Kondensator C speichert Energie. Dadurch gibt es eine zeitliche Verzögerung vom Anlegen der
Ausgangsspannung mit dem Befehl analogWrite() bis dieser Wert exakt am Ausgang des OPV anliegt. Das ist
zu beachten! Gegebenenfalls die Funktion der Schaltung auf einem Steckbrett zusammenbauen und alles testen
und bei Bedarf die Werte von R und C ändern. Man kann das alles auch kompliziert berechnen, aber dies soll ja
ein Praxisbuch sein…

So ein Steckbrett (Breadboard) ist eine super Sache! Ich baue fast alles erst mal auf einem Steckbrett zusammen.
Wenn etwas nicht geht, oder nicht richtig, kann man schnell Änderungen machen. Funktioniert alles wie
gewünscht, kann man es auf einer Platine oder Lochrasterplatte aufbauen.


Erweitertes Analoges In / Out
tone()
Beschreibung
Gibt eine PWM mit der angegebenen Frequenz und 50% duty cycle (Tastverhältnis) an einem Pin aus.
Der Pin kann an einen Piezo-Lautsprecher angeschlossen werden um einen Ton auszugeben. Es kann eine
bestimmte Dauer für den Ton definiert werden, wenn keine Dauer angegeben wird, wird der Ton gespielt
bis zum nächsten Aufruf von noTone().
Es kann nur ein Ton zu einer Zeit gespielt werden. Wenn an einem Pin bereits ein Ton ausgegeben wird
hat der Aufruf von tone() an einem anderen Pin keinen Effekt. Wenn derselbe Pin aufgerufen wird, wird
die Frequenz geändert.
Um einen Ton an einem anderen Pin ausgeben zu können, muss zuerst noTone() aufgerufen werden,
bevor der nächste Aufruf von tone() erfolgt.
Achtung! Ein normaler Lautsprecher kann nicht direkt an einen ARDUINO-Pin
angeschlossen werden! Lautsprecher haben einen Innenwiderstand zwischen 4 Ohm und 16 Ohm. Das
würde den Ausgang des Arduino durch zu hohen Stromfluss beschädigen. In diesem Fall ist ein
Vorwiderstand, ein nachgeschalteter NF-Verstärker-IC oder eine Transistorstufe entsprechender
Dimensionierung nötig.
Syntax
tone(pin, frequenz);
tone(pin, frequenz, dauer);

Parameter
pin: die Pinnummer des Pins an dem der Ton ausgegeben werden soll
frequenz: die Frequenz des Tons (Tonhöhe)
dauer: die Tondauer in Millisekunden (optional)

noTone()
Beschreibung
Stoppt die Ausgabe einer PWM welche durch tone() verursacht wird.
Diese Funktion muss nach tone() aufgerufen werden, wenn mehrere Töne an verschiedenen Pins
ausgegeben werden sollen.

Syntax
noTone(pin);

Parameter
pin: die Pinnummer des Pins an dem der Ton gestoppt werden soll


shiftOut()
Beschreibung
Gibt ein Bit einer Bytevariablen an einem Port aus. Beginnt entweder von links (Most significant bit)
oder von rechts (least significant bit). Jedes Bit wird auf einen Data-Pin geschrieben, nachdem ein Clock-
Pin getaktet wurde (auf high setzen, dann wieder auf low), welches anzeigt, dass das Bit verfügbar ist. Es
kann immer nur ein Bit auf einmal ausgegeben werden. Sollen also alle acht Bits eines Bytes geändert
werden, ist dieser Befehl acht Mal auszuführen.
Wenn es um ein Gerät geht, das getaktet wird von steigenden Flanken, dann muss sichergestellt sein, dass
der Clock-Pin zuerst wieder auf Low sein muss, bevor shiftOut() aufgerufen werden kann. Z.B.
Das ist eine Software-Funktion; siehe hier auch SPI library. Die SPI-Library ist eine Hardware-Funktion,
diese ist schneller, funktioniert aber nur an bestimmten Pins.

Syntax
shiftOut(dataPin, clockPin, bitOrder, value)

Parameter
dataPin: Der Pin, an dem das Byte ausgegeben werden soll (int)
clockPin: Der Pin, der einmal getoggelt werden soll, nachdem Datapin auf den korrekten Wert
gesetzt wurde (int)

bitOrder: welche Richtung das Bit geschoben werden soll, MSBFIRST or LSBFIRST.
(Most Significant Bit zuerst, oder, Least Significant Bit zuerst)
value: Der Wert, welcher geschoben werden soll. (byte)

Rückgabewert
keiner

Hinweis
Der dataPin und clockPin müssen zuerst als Outputs konfiguriert sein, durch Aufruf des Befehls
pinMode().
shiftOut ist aktuell beschränkt darauf nur ein Byte (8 Bits) auszugeben. Es sind also zwei Operationen
notwendig

// Do this for MSBFIRST serial
int data = 500;
// shift out highbyte
shiftOut(dataPin, clock, MSBFIRST, (data >> 8));
// shift out lowbyte
shiftOut(data, clock, MSBFIRST, data);

// Or do this for LSBFIRST serial
data = 500;
// shift out lowbyte
shiftOut(dataPin, clock, LSBFIRST, data);
// shift out highbyte
shiftOut(dataPin, clock, LSBFIRST, (data >> 8));

Beispiel
Zwecks Schaltplan: siehe tutorial on controlling a 74HC595 shift register.
//**************************************************************//
// Name : shiftOutCode, Hello World //
// Author : Carlyn Maw,Tom Igoe //
// Date : 25 Oct, 2006 //
// Version : 1.0 //
// Notes : Code for using a 74HC595 Shift Register //
// : to count from 0 to 255 //
//****************************************************************

//Pin connected to ST_CP of 74HC595
int latchPin = 8;
//Pin connected to SH_CP of 74HC595
int clockPin = 12;
////Pin connected to DS of 74HC595
int dataPin = 11;

void setup() {
//set pins to output because they are addressed in the main loop
pinMode(latchPin, OUTPUT);
pinMode(clockPin, OUTPUT);
pinMode(dataPin, OUTPUT);
}

void loop() {
//count up routine
for (int j = 0; j < 256; j++) {
//ground latchPin and hold low for as long as you are transmitting
digitalWrite(latchPin, LOW);
shiftOut(dataPin, clockPin, LSBFIRST, j);
//return the latch pin high to signal chip that it
//no longer needs to listen for information
digitalWrite(latchPin, HIGH);
delay(1000);
}
}


shiftIn()
Beschreibung
Liest ein Byte von einem DataPin ein, immer nur ein Bit auf einmal. Beginnt entweder von links (Most
significant bit) oder von rechts (least significant Bit). Bei jedem Bit wird der ClockPin auf high gezogen,
das nächste Bit wird gelesen vom DataPin, und der ClockPin wird wieder auf Low gesetzt.
Das ist eine Software-Funktion; siehe hier auch SPI library. Die SPI-Library ist eine Hardware-Funktion,
diese ist schneller, funktioniert aber nur an bestimmten Pins.

Syntax
byte incoming = shiftIn(dataPin, clockPin, bitOrder)

Parameter
dataPin: Der Pin, an welchem das Bit eingelesen werden soll. (int)
clockPin: Der Pin, welcher getoggelt wird, um zu signalisieren, dass ein Bit am dataPin
eingelesen werden kann.
bitOrder: welcher Richtung das Bit gelesen werden soll, MSBFIRST or LSBFIRST.
(Most Significant Bit zuerst, oder, Least Significant Bit zuerst)

Rückgabe
den eingelesenen Wert (byte)

pulseIn()
Beschreibung
Misst die Dauer eines Pulses an einem Pin. Es kann entweder der Wert LOW oder HIGH übergeben
werden. Wenn der übergebene Wert HIGH ist, wird gewartet bis der Pin auf HIGH gezogen wird, startet
einen Timer und wenn der Pin wieder auf LOW fällt, stoppt der Timer und die Pulslänge in
Mikrosekunden (µs) wird zurückgegeben. Wenn ein Timeout spezifiziert wird, gibt die Funktion nach
dieser Dauer den Wert 0 zurück. Die Funktion wurde nur berechnet und kann bei längeren Pulsen zu
Fehlmessungen führen. Die Funktion kann Pulslängen von 10µs bis 3 Minuten messen.

Syntax
pulseIn(pin, wert);
pulseIn(pin, wert, timeout);

Parameter
pin: die Pinnummer des Pins an dem der Puls gemessen werden soll
wert: der Zustand bei dem der Timer gestartet werden soll, HIGH oder LOW
timeout: die Zeit die die Funktion auf einen Puls wartet, bis sie 0 zurückgibt und beendet wird

Rückgabewert
Die Pulslänge in Mikrosekunden oder 0 wenn kein Puls innerhalb des timeouts gestartet wurde

Beispiel

int pin = 7;
unsigned long dauer;

void setup()
{
pinMode(pin, INPUT);
}

void loop()
{
dauer = pulseIn(pin, HIGH);

Datenkonvertierung
byte()
Beispiel-Sketch verfügbar: byte_Datenkonvertierung.ino

Beschreibung
Konvertiert einen Wert in den Datentyp byte

Syntax
byte(x);

Parameter
x : beliebiger Wert

Rückgabewert
Variable im byte-Datentyp

Beispiel
byte meinByte;
char meinChar = 'A';
meinByte = byte(meinChar + 1);
int()
Beispiel-Sketch verfügbar: int_Datenkonvertierung.ino

Beschreibung
Konvertiert einen Wert in den Datentyp int.

Syntax
int(x)

Parameter
x: beliebiger Wert

Rückgabewert
Variable im int-Datentyp

Beispiel
byte meinByte = 200;
int meinInt;
meinInt = int(meinByte);

word()
Beschreibung
Wandelt einen Wert in den word-Datentyp oder bildet ein word aus zwei Bytes.

Syntax
word(x)
word(h, l)

Parameter
x: beliebiger Wert
h : höherwertiges Byte
l : niederwertiges Byte

Rückgabewert
Variable im word-Datentyp

long()
Beispiel-Sketch verfügbar: long_Datenkonvertierung.ino

Beschreibung
Wandelt einen Wert in den long Datentyp (Werte: –2,147,483,648 bis 2,147,483,647)

Syntax
long(x)

Parameter
x: beliebiger Wert

Rückgabewert
Variable im long-Datentyp

float()
Beschreibung
Wandelt einen Wert in den float-Datentyp (Fließkommazahl. Vorsichtig benutzen! Siehe hierzu Infos bei
Datentypen).

Syntax
float(x)

Parameter
x: beliebiger Wert

Rückgabewert
Variable im float-Datentyp (Fließkommazahl)

Hinweis
Der Datentyp „float“ ist eine Zahl mit einem Dezimalpunkt, d.h. mit Nachkommastellen. Sie werden oft
benutzt, um analoge und fortlaufende Werte mit hinreichender Genauigkeit darzustellen, weil sie einen
wesentlich größeren Wertebereich haben als Integers. Float’s können Werte annehmen von -
3.4028235E+38 bis 3.4028235E+38. Sie werden als 32bit-Information gespeichert (4 Bytes).

Float’s haben eine maximale Genauigkeit von 6 bis 7 Stellen. Das bedeutet insgesamt bis zu 7 Stellen,
und nicht die Anzahl der Dezimalstellen rechts vom Dezimalpunkt! Auf den ATMega-basierten Boards,
also auch UNO, NANO etc. haben die Fliesskommazahlen eine genauigkeit von 7 Stellen.
Verwendet man einen ARDUINO DUE kann man als Datentyp double verwenden. Dieser hat die
doppelte Genauigkeit und wird als 64bit-Wert behandelt.

Fliesskommazahlen sind nicht absolut genau und können seltsame Ergebnisse bei Vergleichen
hervorbringen. Zum Beispiel kann die Berechnung 6,00 geteilt durch 3,00 ein Ergebnis hervorbringen,
das nicht genau 2,00 ist. Wenn man float’s vergleicht sollte man stattdessen abprüfen, ob die beiden
Werte nur eine geringe Abweichung haben, anstatt zu prüfen, ob sie absolut identisch sind.

Weiterhin sind mathematische Operationen mit Fliesskommazahlen viel langsamer als Integer und sollten
vermieden werden, wenn es zum Beispiel nötig ist, die loop() mit maximaler Geschwindigkeit laufen zu
lassen wegen etwaiger zeitkritischer Funktionen. Daher gehen Programmierer auch manchmal den
Umweg über eine Konversion zu Integers, um bei mathematischen Operationen die Geschwindigkeit zu
erhöhen.

Wenn man mathematische Funktionen mit float’s ausführt, muss man einen Dezimalpunkt verwenden.
Ansonsten wird der Wert als Integer behandelt.
Zeit

Bei Benutzung von millis() und micros(): Siehe ergänzende Infos am Ende des Kapitels!
delay()
Beschreibung
Pausiert die Ausführung des Programms um den übergebenen Parameter in Millisekunden.

Syntax
delay(ms);

Parameter
ms: Die Dauer in Millisekunden um die das Programm pausiert werden soll.

Beispiel

int ledPin = 13; // LED an Pin 13

void setup()
{
pinMode(ledPin, OUTPUT); // setzt den ledPin auf Ausgang
}

void loop()
{
digitalWrite(ledPin, HIGH); // schaltet die LED ein
delay(1000); // wartet eine Sekunde
digitalWrite(ledPin, LOW); // schaltet die LED aus
delay(1000); // wartet eine Sekunde
}

Hinweis
Es ist zwar einfach eine LED mittels der delay()-Funktion zum blinken zu bringen, allerdings blockiert
diese Funktion die meisten anderen Aktivitäten des Chips, da keine Berechnungen oder Sensorabfragen
stattfinden können. Am besten ist es, die delay()-Funktion zu vermeiden wenn es sich um Pausen von
mehr als ein paar 10ms handelt, um die Rechenzeit effektiver nutzen zu können.
Fortgeschrittene Programmierer versuchen diese Funktion zu umgehen und verwenden stattdessen lieber
millis().
Ein paar Dinge geschehen jedoch während der delay() aktiv ist, da delay() keine Interrupts abschalten.
Somit können Daten weiterhin über die serielle Schnittstelle empfangen werden und auch alle anderen
Interrupts funktionieren so wie sie sollen.

micros()
Beschreibung
Die Funktion micros() gibt die Dauer in Mikrosekunden (µs) seit dem Beginn der Ausführung des
Programms zurück. Diese Zahl wird nach ungefähr 70 Minuten überlaufen (auf 0 zurückgesetzt).
Auf 16MHz Arduino Boards (UNO, Duemilanove etc.) hat die Funktion eine Auflösung von 4µs, d.h. der
Rückgabewert ist ein Vielfaches von 4. Auf 8MHz Boards (z.b. LilyPad) hat der Rückgabewert eine
Auflösung von 8µs.

Parameter
Keine

Beispiel

unsigned long zeit;

void setup(){
Serial.begin(9600);
}
void loop(){
Serial.print("Zeit: ");
zeit = micros();
// gibt die Zeit seit dem Start des Programms aus
Serial.println(zeit);
// eine Sekunde warten um massive Datenmengen zu verhindern
delay(1000);
}

millis()
Beschreibung
Die Funktion millis() gibt die Dauer in Millisekunden seit dem Beginn der Ausführung des Programms
zurück. Diese Zahl wird nach ungefähr 50 Tagen überlaufen (auf 0 zurückgesetzt).

Parameter
Keine

Beispiel
unsigned long zeit;

void setup(){
Serial.begin(9600);
}
void loop(){
Serial.print("Zeit: ");
zeit = millis();
// gibt die Zeit seit dem Start des Programms aus
Serial.println(zeit);
// eine Sekunde warten um massive Datenmengen zu verhindern
delay(1000);
}

delayMicroseconds()
Beschreibung
Pausiert die Ausführung des Programms um den übergebenen Parameter in Mikrosekunden.

Aktuell ist der größte verwendbare Wert 16383, um akkurate Zeiten zu erzeugen. Das könnte sich in
späteren Arduino-Versionen ändern. Für Pausen größer als ein paar tausend Mikrosekunden sollte man
besser delay() benutzen.
Syntax
delayMicroseconds(us)

Parameter
us: Anzahl Mikrosekunden, welche pausiert werden soll (Datentyp: unsigned int)

Rückgabewert
keiner

Beispiel

int outPin = 8; // digital pin 8 am Arduino Board

void setup()
{
pinMode(outPin, OUTPUT); // als Output setzen
}

void loop()
{
digitalWrite(outPin, HIGH); // Pin einschalten
delayMicroseconds(50); // Pause 50 Microsekunden
digitalWrite(outPin, LOW); // Pin ausschalten
delayMicroseconds(50); // Pause 50 Microsekunden
}

Konfiguriert Pin 8 als Ausgang. Sendet Impulse mit einer Periodendauer von 100µsek.
Hinweis
Diese Funktion arbeitet sehr akkurat im Bereich von 3 Mikrosekunden und höher. Darunter kann ein
korrekter Wert nicht garantiert werden.

Richtige Benutzung des millis() – Befehles
Wichtig ist die richtige Benutzung des millis()-Befehls, da es sonst beim Überlauf der Variable
Falschberechnungen entstehen! Bei langen Laufzeiten des ARDUINO unbedingt beachten!



// Deklarationen am Anfang des Sketches

Unsigned long Alte_Zeit; //Variable zum Speichern des alten Wertes
Unsigned long Zeitinterval; //Variable für gewünschte Zeitdauer (1sek=1000)


// im laufenden Programm…
if (millis() –Alte_Zeit > Zeitinterval)
{
Alte_Zeit = millis();
.... weiterer Code hier
}


Beispiel 1: Alte_Zeit sei 900.000
millis() sei 900.900
Zeitinterval sei 1000 (entspricht einer Sekunde)
900.900 – 900.000 = 900  900 ist NICHT größer als 1000, also if-Code wird NICHT
ausgeführt.

Beispiel 2: Alte_Zeit sei 900.000
millis() sei 901.100
Zeitinterval sei 1000 (entspricht einer Sekunde)
901.100 – 900.000 = 1100 1100 ist größer als 1000, also if-Code wird ausgeführt.

Aufgrund der Besonderheiten der Binär-Arithmetik funktioniert das auch bei einem Überlauf. Da wir
unsignedlong Variablen benutzen, kann der maximale Wert dieses Variablentypes 4.294.967.295 sein.

Angenommen, Alte_Zeit sei 4.294.967.000 und Zeitinterval ist 1000. Irgendwann einmal gibt es einen
Überlauf, und millis() gibt als Wert die 0 zurück. Man könnte nun meinen, der Vergleich ist folgender:
0 – 4.294.967.000 > 1000? Also nach mathematischer Logik: -4.294.967.000 > 1000 ?
Ergebnis des Vergleiches: False, d.h. if-Code wird nicht ausgeführt!

Aber bei der Benutzung von unsigned long Variablen kann es keinen negativen Wert geben und der
zurückgegebene Wert der Subtraktion wird 295 sein. Das hängt damit zusammen, dass der Maximalwert nur
4.294.967.295 sein kann. Dieser wird anstatt der 0 verwendet. Also:
4.294.967.295 - 4.294.967.000 > 1000?
Ergebnis des Vergleiches: False, d.h. if-Code wird nicht ausgeführt!

Also: Auch bei einem Überlauf funktioniert der Vergleich korrekt, es gibt keine Fehlberechnungen.
Die angegebene Verfahrensweise gilt analog auch bei micros().

Quelle: [9

Die Funktion millis() und micros() können auch mehrfach im Programm verwendet werden, mit
unterschiedlichen Zeiten. Damit kann man viele unterschiedliche Zeitabschnitte verwirklichen, wenn man es
braucht.

// Deklarationen am Anfang des Sketches

Unsigned long Alte_Zeit1;
Unsigned long Zeitinterval1;
Unsigned long Alte_Zeit2;
Unsigned long Zeitinterval2;

….
Zusammengesetzte Operatoren

Zusammengesetztes bitweises ODER (|=)
Beschreibung
Das zusammengesetzte bitweise ODER (|=) wird häufig verwendet, um gezielt bestimmte Bits innerhalb
eines Integers auf 1 zu setzen.

Syntax
x |= y; // entspricht x = x | y;

Parameter
x: eine char, int oder long Variable
y: eine ganzzahlige Konstante oder eine char, int oder long Variable

Zusammengesetztes bitweises UND (&=)
Beschreibung
Das zusammengesetzte bitweise UND (&=) wird oft verwendet, um gezielt bestimmte Bits innerhalb
eines Integers mit Hilfe einer Bitmaske auf 0 zu setzen. Oftmals wird dies “clearing” oder “resetting” von
Bits genannt.

Syntax
x &= y; // entspricht x = x & y;

Parameter
x: eine char, int oder long Variable
y: eine ganzzahlige Konstante oder eine char, int oder long Variable

+= , -= , *= , /= Zusammengesetzte + - * /
Beschreibung
Führt eine mathematische Operation an einer Variable mit einer anderen Variable oder Konstante durch,
+= usw. sind nur praktische Abkürzungen der Standard Syntax.

Syntax
x += y; // entspricht x = x + y;
x -= y; // entspricht x = x - y;
x *= y; // entspricht x = x * y;
x /= y; // entspricht x = x / y;

Parameter
x: jeder beliebige Datentyp
y: jeder beliebiger Datentyp oder Konstante
Beispiele
x = 2;
x += 4; // x = 6
x -= 3; // x = 3
x *= 10; // x = 30
x /= 2; // x = 15


++ (inkrement) / — (dekrement)
Beschreibung
Eine Variable inkrementieren (erhöhen / addieren) / dekrementieren (erniedrigen / subtrahieren)

Syntax
x++; // inkrementiere x um eins und gebe den alten Wert von x zurück
++x; // inkrementiere x um eins und gebe den neuen Wert von x zurück

x--; // dekrementiere x um eins und gebe den alten Wert von x zurück
--x; // dekrementiere x um eins und gebe den neuen Wert von x zurück

Parameter
x: (unsigned) int oder long

Rückgabewert
Der originale oder der inkrementierte / dekrementierte Wert von x

Beispiel

x = 2;
y = ++x; // x enthält 3, y enthält 3
y = x--; // x enthält wieder 2, y enthält immer noch 3
Bitoperatoren
Bitweises links- (<<) und bitweises rechtsschieben (>>)
Beschreibung
Es gibt zwei Bitschiebeoperatoren in C/C++: den Linksschiebe- (<<) und den Rechtsschiebeoperator
(>>). Diese Operatoren bewirken, dass die Bits im linken Parameter um die Anzahl der Bits im rechten
Parameter nach rechts oder links geschoben werden.

Syntax
Variable << Anzahl_der_Bits
Variable >> Anzahl_der_Bits

Parameter
Variable := (byte, int, long)
Anzahl_der_Bits := int <= 32

Beispiel
int a = 5; // binary: 0000000000000101
int b = a << 3; // binary: 0000000000101000, 40 in dezimal
int c = b >> 3; // binary: 0000000000000101, oder zurück zu 5 wie am Anfang

Wenn man den Wert x um y Bits nach links schiebt (x<<="" p="">
int a = 5; // binär: 0000000000000101
int b = a << 14; // binär: 0100000000000000 – die Erste 1 in 101 wurde "aus dem Byte
geschoben"

Wenn man davon ausgeht, dass keine der Bits links des Wertes aus dem Byte herausgeschoben werden,
dann kann man sich den << Operator etwas so vorstellen:
Er multipliziert den linken Wert mit 2 hoch dem rechten Wert also so:

1 << 0 == 1
1 << 1 == 2
1 << 2 == 4
1 << 3 == 8
...
1 << 8 == 256
1 << 9 == 512
1 << 10 == 1024

Wenn man x um y nach rechts schiebt (x>>y), dann hängt das genaue Ergebnis vom Datentyp des Wertes
ab. Wenn es sich um einen "normalen" also signed integer handelt (int), dann wird das Signed-Bit immer
mit nach rechts geschoben (signed extension):
int x = -16; // binary: 1111111111110000
int y = x >> 3; // binary: 1111111111111110

Meistens möchte man aber, dass das Signed-Bit nicht mitgeschoben wird, d.h. von links her werden 0en
eingeschoben, indem man per typecast zuerts einen unsigned int daraus macht:
int x = -16; // binary: 1111111111110000
int y = (unsigned int)x >> 3; // binary: 0001111111111110
Wenn man weiß, dass die Signed extension keine Probleme bereiten wird, dann kann man den >>
Operator als divisor verwenden. x wird geteilt durch 2 hoch y:


int x = 1000;
int y = x >> 3; // integer division von 1000 geteilt durch 8, Ergebnis y = 125

Bitweises NICHT (~)
Das bitweise NICHT ist dieses ~ Symbol. Das bitweise NICHT dient anders als das bitweise UND bzw.
ODER nicht zur Verknüpfung zweier Operanden, sondern der Invertierung eines Operanden:
0 1 operand1
----------
1 0 ~ operand1

int a = 103; // binär: 0000000001100111
int b = ~a; // binär: 1111111110011000 = -104

Es mag vielleicht überraschend sein, dass eine negative Zahl wie -104 bei der Invertierung als Ergebnis
auftaucht.
Dies liegt daran, dass in einer int (Integer) Variable das oberste Bit das sog. Signed-Bit ist, wenn es also
eine 1 ist, dann gilt die Zahl als negativ. Dieses Verfahren nennt man Zweierkomplement (engl. two’s
complement).
Mehr Information darüber kann auf Wikipedia nachgelesen werden.
Möchte man das Signed-Bit umgehen, muss man die Variable als unsigned int, also als Integer ohne
Vorzeichen deklarieren.

Bitweises UND (&)
Das bitweise UND ist ein einfaches & und wird zwischen zwei Integer Variablen eingefügt, um diese zu
verknüpfen. Das bitweise UND wirkt sich auf jedes Bit der Operanden aus, unabhängig von den anderen
Bits nach dem folgendem Schema: wenn beide Bits 1 sind, dann ist dieses Bit im Ergebnis auch 1,
andernfalls ist es 0.
0 0 1 1 operand1
0 1 0 1 operand2
----------
0 0 0 1 (operand1 & operand) = ergebnis
In der Arduino IDE ist der Datentyp int 16 bit breit also werden im folgenden Codeschnipsel 16 einzelne
UND Operationen durchgeführt:
int a = 92; // binär: 0000000001011100
int b = 101; // binär: 0000000001100101
int c = a & b; // Ergebnis: 0000000001000100, oder 68 in dezimal
Das bitweise UND wird oft verwendet, um gezielt Bits aus einem Integer auszuwählen, auch Maskieren
genannt.
Bitweises ODER (|)
Das bitweise ODER ist das | Symbol und wirkt sich wir das bitweise UND auf jedes Bit eines Integers
einzeln aus. Das bitweise ODER gibt eine 1 zurück, wenn mindestens eines oder beide Bits auch 1 sind,
andernfalls gibt es 0 zurück.
0 0 1 1 operand1
0 1 0 1 operand2
----------
0 1 1 1 (operand1 | operand2)
Angewendet auf unser vorheriges Beispiel bedeutet das:
int a = 92; // binär: 0000000001011100
int b = 101; // binär: 0000000001100101
int c = a | b; // Ergebnis: 0000000001111101, oder 125 in dezimal

Bitweises XOR (^)
Das bitweise EXKLUSIV ODER, auch XOR (ausgesprochen: “eks-or”), ist das ^ Symbol. Der Operator
ist ähnlich zum bitweisen ODER, allerdings ist das Ergebnis nur dann 1, wenn nur eines der Bits 1 ist:
0 0 1 1 operand1
0 1 0 1 operand2
----------
0 1 1 0 (operand1 ^ operand2)
Man kann sich das bitweise XOR auch so vorstellen, dass es eine 1 zurückgibt, wenn die Bits einer Stelle
in den Operatoren verschieden sind und eine 0 zurückgibt, wenn beide Bits in den Operatoren gleich sind.
Hier ein Codebeispiel:
int x = 12; // binär: 1100
int y = 10; // binär: 1010
int z = x ^ y; // binär: 0110, oder dezimal 6
Das bitweise XOR wird meist verwendet um bestimmte Bits zu “togglen” (engl. to toggle ["toggl"]:
umschalten), also von 0 auf 1 und umgekehrt zu schalten.
Hier ein Beispiel, welches eine LED an Pin 5 blinken lässt:
void setup(){
DDRD = DDRD | B00100000; // Pin 5 auf Ausgang
}

void loop(){
PORTD = PORTD ^ B00100000; // invertiere Bit 5, ohne andere Bits dabei zu
invertieren
delay(100);
}
Zufallszahlen
randomSeed(seed)
Beschreibung
Setzt einen Wert als Ausgangspunkt für die random() Funktion.

Der Arduino ist selber nicht in der Lage eine wirklich Zufallswerte zu produzieren. Mit
randomSeed() kann eine Variable als 'seed' verwendet werden um bessere Zufallsergebnisse
zu erhalten. Als 'seed' Variable oder auch Funktion können so zum Beispiel millis() oder
analogRead() eingesetzt werden um elektrisches Rauschen durch den Analogpin als Ausgang
für Zufallswerte zu nutzen.

Umgekehrt kann es manchmal notwendig sein pseudo-zufällige Sequenzen zu erzeugen, die sich exakt
wiederholen. Das kann erreicht werden durch Aufruf der randomSeed() Funktion mit einem festen Wert.

Parameter
Long oder int-Zahl, um die Random-Funktion zu starten.

Beispiel
long randNumber;

void setup(){
Serial.begin(9600);
randomSeed(analogRead(0));
}

void loop(){
randNumber = random(300);
Serial.println(randNumber);

delay(50);
}

random()
Beschreibung
Die random() Funktion erlaubt die Erzeugung der pseudo-zufälligen Werte innerhalb eines
definierten Bereiches von Minimum und Maximum Werten.
Benutzt wird dieses nach der randomSeed() Funktion.

Syntax
random(max)
random(min, max)

Parameter
min – unterer Startwert (inclusive) (optional)
max – oberer Endwert ( exclusive)

Rückgabewert
Zufallszahl zwischen min und max-1 (long-Datentyp)

Hinweis
Der Arduino ist selber nicht in der Lage eine wirklich Zufallswerte zu produzieren. Mit
randomSeed() kann eine Variable als 'seed' verwendet werden um bessere Zufallsergebnisse
zu erhalten. Als 'seed' Variable oder auch Funktion können so zum Beispiel millis() oder
analogRead() eingesetzt werden um elektrisches Rauschen durch den Analogpin als Ausgang
für Zufallswerte zu nutzen.

Umgekehrt kann es manchmal notwendig sein pseudo-zufällige Sequenzen zu erzeugen, die sich exakt
wiederholen. Das kann erreicht werden durch Aufruf der randomSeed() Funktion mit einem festen Wert.

Beispiel
long randNumber;

void setup(){
Serial.begin(9600);

// wenn Analog-Pin 0 offen ist, dann wird zufälliges Rauschen
// am Pin benutzt, um randomSeed aufzurufen.
// Jedesmal, wenn die Funktion aufgerufen wird, entstehen so unter-
// schiedliche Werte.

randomSeed(analogRead(0));
}

void loop() {
// Print Zufallszahl von 0 bis 299
randNumber = random(300);
Serial.println(randNumber);

// Print Zfallszahl von 10 bis 19
randNumber = random(10, 20);
Serial.println(randNumber);
delay(50);


Externe Interrupts
attachInterrupt()
Beschreibung
Erzeugt den Aufruf einer Funktion, wenn ein externes Interrupt eintritt, also ein Ereignis an einem Pin des
Arduino. Ersetzt etwaige vorher diesem Interrupt zugeordnete Funktionen. Die meisten Arduino Boards
haben zwei externe Interrupts: Interrupt 0 an DigitalPin 2 und Interrupt1 an DigitalPin 3. Die folgende
Tabelle zeigt die verfügbaren Interrupts an den unterschiedlichen Boards.

Board int.0 int.1 int.2 int.3 int.4 int.5
Uno, Ethernet 2 3
Mega2560 2 3 21 20 19 18
Leonardo 3 2 0 1
Due (siehe unten)
Das Arduino Due Board hat leistungsstarke Möglichkeiten, um einen Interrupt an allen verfügbaren Pins
zuzuordnen. Sie können den gewünschten Pin direkt im Befehl attachInterrupt() angeben.

Syntax
attachInterrupt(interrupt, function, mode)
attachInterrupt(pin, function, mode) (NUR Arduino Due)

Parameter
interrupt: Die Nummer des Interrupts (int-Datentyp)
pin: Die Pin-Nummer (NUR Arduino Due)
function: Die Funktion, welche aufgerufen werden soll, wenn
der Interrupt eintritt. Diese Funktion übernimmt keine
Parameter und gibt auch keine zurück. Diese
Funktion wird oft auch Interrupt service routine
genannt (ISR).

mode: Definiert, wann der Interrupt ausgelöst werden soll.
Vier Konstanten sind als gültige Werte vordefiniert:
LOW löst den Interrupt aus, wenn der Pin low ist
CHANGE löst den Interrupt aus, wenn der Zustand
des Pin sich ändert (von high nach low, von low nach
high)
RISING löst den Interrupt aus, wenn der Pin von low
nach high wechselt
FALLING löst den Interrupt aus, wenn der Pin von
high nach low wechselt.


Der Arduino Due bietet zusätzlich noch folgendes:
HIGH löst den Interrupt aus, wenn der Pin high ist

Rückgabewerte:
keine

Hinweis
Innerhalb der durch den Interrupt aufgerufenen Funktion arbeitet der Befehl delay() nicht, der Wert der
Variable millis() erhöht sich nicht, empfangene serielle Daten gehen möglicherweise verloren. Variablen,
welche in der durch den Interrupt aufgerufenen Funktion verwendet werden, sollten als volatile (  siehe
„Geltungsbereich von Variablen“  volatile ) deklariert werden.

Benutzung von Interrupts
Interrupts sind sehr nützlich, wenn Dinge automatisch passieren sollen im Arduino, ohne Zutun des
Nutzers und können helfen, einige Timing-Probleme zu lösen. Gute Anwendungen für Interrupts sind
z.B. das Auslesen eines Dreh-Encoders, Überwachen von Nutzer-Eingaben, Multitasking von LED-
Anzeigen.
Wenn Sie absolut sicher gehen wollen, dass ein Programm die Impulse eines Dreh-Encoders registriert,
und auch nicht einen Impuls verlieren soll, dann wird es sehr schwierig sein, ein Programm zu schreiben,
das auch noch etwas Anderes nebenbei tun kann. Es muss immer der Pin gepollt werden. Andere
Sensoren arbeiten oft ähnlich, z.B., wenn Sie feststellen wollen, ob ein Sound-Sensor einen Ton
registriert hat, oder ein PIR-Melder Bewegung. In all diesen Situationen wird die Benutzung eines
Interrupts den Controller frei halten für den normalen Programmablauf, und trotzdem keinen einzigen
Input eines so angeschlossenen Sensors verpassen.

Beispiel
int pin = 13;
volatile int state = LOW;

void setup()
{
pinMode(pin, OUTPUT);
attachInterrupt(0, blink, CHANGE);
}
void loop()
{
digitalWrite(pin, state);
}

void blink()
{
state = !state;
}
detachInterrupt()
Beschreibung
Schaltet das gewünschte Interrupt ab.

Syntax
detachInterrupt(interrupt)
detachInterrupt(pin) (NUR Arduino Due)

Parameter
interrupt: Die Nummer des zu deaktivierenden Interrupts (siehe attachInterrupt() für weiteres).
pin: die Pin-Nummer des zu deaktivierenden Interrupts (NUR Arduino Due)
Interrupts (global)
interrupts()
Beschreibung
Aktiviert Interrupts (sowohl interne wie externe) wieder, nachdem sie deaktiviert worden sind mit
noInterrupts(). Interrupts erlauben es, bestimmte Funktionen im Hintergrund passieren zu lassen und sind
standardmäßig aktiviert. Einige bestimmte Funktionen funktionieren nicht, während Interrupts deaktiviert
sind, und eingehende Kommunikation könnte ignoriert werden. Interrupts können aber auch den
Programmablauf kurz unterbrechen und so das Timing empfindlich stören. Für solche Fälle können
Interrupts deaktiviert werden.

Parameter
keine

Rückgabewerte
keine

Beispiel

void setup() {}

void loop()
{
noInterrupts();
// critical, time-sensitive code here
interrupts();
// other code here
}


noInterrupts()
Beschreibung
Deaktiviert Interrupts (sowohl interne wie externe. Sie können sie wieder reaktivieren mit interrupts().
Interrupts erlauben es, bestimmte Funktionen im Hintergrund passieren zu lassen und sind standardmäßig
aktiviert. Einige bestimmte Funktionen funktionieren nicht, während Interrupts deaktiviert sind, und
eingehende Kommunikation könnte ignoriert werden. Interrupts können aber auch den Programmablauf
kurz unterbrechen und so das Timing empfindlich stören. Für solche Fälle können Interrupts deaktiviert
werden.

Parameter
keine.

Rückgabewerte
Keine.

Beispiel
void setup() {}

void loop()
{
noInterrupts();
// critical, time-sensitive code here
interrupts();
// other code here
}
Mathematische Funktionen
min(x, y)
Beschreibung
Ermittelt die kleinere von zwei Zahlen.

Parameter
x: die erste Zahl, beliebiger Datentyp
y: die zweite Zahl, beliebiger Datentyp

Rückgabewerte
Die kleinere der beiden Zahlen.

Beispiel
sensVal = min(sensVal, 100); // setzt sensVal auf den kleineren Wert,oder 100
// stellt sicher, das sensVal niemals über den Wert 100 geht!

Hinweis
Wahrscheinlich nicht wirklich intuitiv, aber max() wird oft benutzt, um das untere Ende eines
Variablenbereiches zu begrenzen. Min() wird benutzt, um das obere Ende des Variablenbereiches zu
ermitteln.


max(x, y)
Beschreibung
Ermittelt die größere von zwei Zahlen.

Parameter
x: die erste Zahl, beliebiger Datentyp
y: die zweite Zahl, beliebiger Datentyp

Rückgabewerte
Die größere der beiden Zahlen.

Beispiel
sensVal = max(senVal, 20); // setzt sensVal auf den größeren Wert, oder 20
// (stellt sicher, das der Wert mindestens 20 beträgt)

Hinweis
Wahrscheinlich nicht wirklich intuitiv, aber max() wird oft benutzt, um das untere Ende eines
Variablenbereiches zu begrenzen. Min() wird benutzt, um das obere Ende des Variablenbereiches zu
ermitteln.
abs(x)
Beschreibung
Ermittelt den Absolutwert einer Zahl. Die Funktion macht also aus negativen Zahlen (unter 0) eine
positive Zahl. Wenn X=5 ist, dann wird 5 zurückgegeben, ist X=-5, dann wird ebenso 5 zurückgegeben.

Parameter
x: die Zahl

Rückgabewerte
x: immer eine positive Zahl, egal ob x vorher negativ oder positiv war.

Hinweis
Aufgrund der Art und Weise, wie die abs() Funktion implementiert ist, vermeiden sie es andere
Funktionen innerhalb der Klammern zu benutzen. Das könnte zu falschen Ergebnissen führen.

abs(a++); // vermeiden – ergibt falsches Ergebnis
a++; // stattdessen so – inkrementiert a als erstes
abs(a); // ermittelt dann den Absolutwert.

constrain(x, a, b)
Beschreibung
Begrenzt eine Zahl innerhalb eines Bereiches (von minimal bis maximal.

Parameter
x: die zu begrenzende Zahl, alle Datentypen
a: das niedrigere Ende des Bereiches, alle Datentypen
b: das obere Ende des Bereiches, alle Datentypen

Rückgabewerte
x: wenn x innerhalb des erlaubten Bereiches von a und b ist
a: wenn x kleiner als a ist
b: wenn x größer als b ist

Beispiel
sensVal = constrain(sensVal, 10, 150);
// begrenzt den Bereich des Sensors auf Werte von 10 bis 150

map(value, fromLow, fromHigh, toLow, toHigh)
Beschreibung
Wandelt eine Zahl von einem Wertebereich in einen anderen um. Das heißt, ein Wert wird vom Bereich
fromLow bis fromHigh in den Bereich toLow bis toHigh umgewandelt.
Die Werte werden nicht begrenzt, wie es die Funktion constrain macht, weil Werte außerhalb des
Bereiches manchmal nützlich sein können. Die constrain Funktion kann vorher oder nachher benutzt
werden, wenn Wertebegrenzung gewünscht ist.
Zu beachten ist hier, dass die Untergrenze jedes Bereiches größer oder kleiner sein kann als die
Obergrenze. Die map() Funktion kann also benutz werden, um einen Wertebereich umzukehren, z.B.
y = map(x, 1, 50, 50, 1);
Die Funktion kann auch mit negative Zahlen umgehen, also
y = map(x, 1, 50, 50, -100);
ist ebenfalls gültig und funktioniert auch gut.
Die map() Funktion benutzt Integer-Operationen, es gibt also keinen Rest, selbst wenn es einen
mathematischen Rest gäbe. Entstehende Reste (Nachkommastellen) werden einfach fallen gelassen, sie
werden nicht gerundet.

Parameter
value: die Zahl, die umgewandelt werden soll
fromLow: die Untergrenze des aktuellen Bereiches
fromHigh: die Obergrenze des aktuellen Bereiches
toLow: die Untergrenze des neuen Bereiches
toHigh: die Obergrenze des neuen Bereiches

Rückgabewerte
Der in den neuen Bereich umgerechnete Wert.

Beispiel
// umwandeln eines analogen Wertes in einen 8bit-Wert (0 bis 255)

void setup() {}

void loop()
{
int val = analogRead(0); // val als Analogwert von A0 (0 bis 1023)
val = map(val, 0, 1023, 0, 255); // umwandeln
analogWrite(9, val); // auf Analogpin A9 ausgeben
}
pow(base, exponent)
Beschreibung
Berechnet die Potenz einer Zahl.

Parameter
base: die Zahl (Basis) (float-Datentyp)
exponent: die Potenz, in welche die Basis erhoben warden soll (float-Datentyp)

Rückgabewert
Das Ergebnis der Potenzierung (double-Datentyp)

Beispiel
Siehe fscale.
sqrt(x)
Beschreibung
Berechnet die Quadratwurzel einer Zahl.

Parameter
x: die Zahl, beliebiger Datentyp

Rückgabewert
Die Quadratwurzel der Zahl (double-Datentyp).
Geltungsbereich und Qualifikatoren
Geltungsbereich von Variablen
Variablen in der C Programmiersprache, welche der Arduino benutzt, haben eine Eigenschaft, die
“Scope” (Geltungsbereich) genannt wird. Das ist einer der Unterschiede zu anderen Sprachen, z.B.
BASIC, wo Variablen immer globale (also überall geltende, im gesamten Programm) Variablen sind.
Eine globale Variable ist eine Variable, die von allen Funktionen im gesamten Programm gesehen
werden kann. Lokale Variablen sind Variablen, die NUR in den Funktionen gesehen werden können, in
denen sie deklariert wurden. In Arduino, JEDE Variable, die außerhalb einer Funktion deklariert wurde
(z.B. in setup(), loop(), etc. ), ist eine globale Variable.
Wenn ein Programm beginnt umfangreicher und komplexer zu werden, sind lokale Variablen nützlich,
um sicherzugehen, dass nur die genutzte Funktion Zugriff auf ihre Variablen hat. Das verhindert
Programmierfehler, wenn eine Funktion Variablen ändert, die gleichzeitig auch von einer anderen
Funktion genutzt werden.

Es ist auch manchmal nützlich, eine Variable innerhalb einer Schleife zu deklarieren und initialisieren.
Diese Variable kann NUR von innerhalb der Schleife benutzt werden.

Beispiele
int gPWMval; // das gesamte Programm sieht diese Variable

void setup()
{
// ...
}

void loop()
{
int i; // "i" ist nur sichtbar innerhalb von "loop"
float f; // "f" ist nur sichtbar innerhalb von "loop"
// ...

for (int j = 0; j <100; j++){
// Variable j kann nur innerhalb der for-loop-Klammern benutzt werden
}

}
static
Static wird benutzt, um Variablen zu erzeugen, die nur von einer Funktion gesehen und geändert werden
können. Anders als lokale Variablen, die jedes Mal neu generiert und gelöscht werden, wenn eine
Funktion aufgerufen wird – static-Variablen bleiben bestehen und behalten ihre Werte auch zwischen
Funktionsaufrufen. Static-Variablen werden nur einmal beim ersten Aufruf einer Funktion deklariert.

Beispiel

/* RandomWalk
* Paul Badger 2007
* RandomWalk bewegt sich zufällig zwischen zwei Endpunkten
* Der maximale Schritt in einem Durchlauf ist begrenzt durch
* den Parameter "stepsize".
* Eine static-Variable bewegt sich hoch und runter um einen zufälligen Betrag.
* Diese Technik ist auch bekannt als "pink noise" und "drunken walk".
*/

#define randomWalkLowRange -20
#define randomWalkHighRange 20
int stepsize;

int thisTime;
int total;

void setup()
{
Serial.begin(9600);
}

void loop()
{ // test randomWalk function
stepsize = 5;
thisTime = randomWalk(stepsize);
Serial.println(thisTime);
delay(10);
}

int randomWalk(int moveSize){
static int place; // Variable um Wert zu speichern innerhalb random walk
//deklariert, um die Werte zwischen den Aufrufen beizubehalten und
//keine andere Funktion kann darauf zugreifen

place = place + (random(-moveSize, moveSize + 1));

if (place < randomWalkLowRange){ // check untere + obere Limits
place = place + (randomWalkLowRange - place); // reflect number back in
positive direction
}
else if(place > randomWalkHighRange){
place = place - (place - randomWalkHighRange); // reflect number back in
negative direction
}

return place;
}

volatile
Volatile ist ein Schlüsselwort, das normalerweise vor dem Datentyp einer Variablen benutzt wird,
um die Art zu bestimmen, in der das folgende Programm und der Compiler die Variable behandelt. Eine
Variable als „volatile“ zu deklarieren ist eine Anweisung an den Compiler. Der Compiler ist eine
Software, welche den C-Code des Arduino in Maschinencode übersetzt.

Um genau zu sein, es veranlasst den Compiler die Variable aus dem RAM zu laden, und nicht aus einem
Speicher-Register. Ein Register ist ein Speicherbereich, wo Variablen normalerweise
zwischengespeichert und bearbeitet werden. Unter bestimmten Bedingungen kann der Wert einer im
Register abgelegten Variable ungenau sein.
Eine Variable sollte immer dann als „volatile“ deklariert werden, wenn ihr Wert durch ein Ereignis
beeinflusst werden kann, welches außerhalb des Codes stattfindet, in dem sie sich befindet. Das kann z.B.
eine gleichzeitig aufgerufene Funktion sein. Im Arduino – die einzige Funktion, die so etwas kann, ist
eine Interrupt-Funktion, genannt Interrupt Service Routine.

Beispiel
// toggled LED wenn ein Interrupt-Pin seinen Zustand ändert

int pin = 13;
volatile int state = LOW;

void setup()
{
pinMode(pin, OUTPUT);
attachInterrupt(0, blink, CHANGE); //springt in Funktion „blink“
}
void loop()
{
digitalWrite(pin, state);
}
void blink() //Funktion (= Unterprogramm) blink
{
state = !state; // state wird negiert
}


const
Das Schlüsselwort const steht für Konstante. Es ist ein Variablem-Kriterium und ändert das Verhalten der
Variable in „read-only“, d. h. die Variable kann ganz normal benutzt werden, aber NICHT geändert! Sie
bekommen einen Compiler-Fehler, wenn Sie versuchen eine const-Variable im Programm zu ändern.

Konstanten, die mit dem const-Schlüsselwort erstellt werden, folgen den Regeln von anderen Variablen
(siehe oben  Geltungsbereich von Variablen, etc.)
Diese Tatsache, und die Fallstricke beim Benutzen von #define, machen das const-Schlüsselwort zu einer
vorzüglichen Möglichkeit um Konstanten zu definieren und sollte auf jeden Fall dem #define bevorzugt
werden.

Beispiel
const float pi = 3.14;
float x; // Variable x mit dem Datentyp float

// ....

x = pi * 2; // eine schöne Sache, und gut zu lesen mit Konstanten

pi = 7; // NICHT erlaubt! Sie können keine Konstante ändern!

#define oder const?
Sie können entweder const oder #define benutzen, um numerische oder String-Konstanten zu definieren.
Für Arrays ist die Benutzung von const erforderlich. Im Allgemeinen ist const der Vorzug zu geben.
#define ist eine Präprozessor-Anweisung, d.h. die hinter #define stehende Zahl wird durch den Compiler
eingesetzt, ohne das irgendeine Prüfung durch den Compilers stattfinden kann (z.B. richtiger Datentyp)
Danke an Gregor und Quelle [11
.
Trigonometrie
(Dreiecksberechnungen)

sin(rad)
Beschreibung
Berechnet den Sinus eines Winkels (in Radiant / Bogenmaß). Das Ergebnis bewegt sich zwischen -1 und
+1.

Parameter
rad: der Winkel im Bogenmaß (float-Datentyp)

Rückgabewerte
Der Sinus des Winkels (double-Datentyp)


cos(rad)
Beschreibung
Berechnet den Cosinus eines Winkels (in Radiant / Bogenmaß). Das Ergebnis bewegt sich zwischen -1
und +1.

Parameter
rad: der Winkel im Bogenmaß (float-Datentyp)

Rückgabewerte
Der Cosinus des Winkels (double-Datentyp)


tan(rad)
Beschreibung
Berechnet den Tangens eines Winkels (in Radiant / Bogenmaß). Das Ergebnis bewegt sich zwischen –
unendlich und +unendlich.
Parameter
rad: der Winkel im Bogenmaß (float-Datentyp)

Rückgabewerte
Der Tangens des Winkels (double-Datentyp)
Zeichen (Character-) Funktionen
Im folgenden Kapitel geht es um Zeichen-Funktionen. Als „Zeichen“ werden hier alle eingehenden
Zeichen genannt, welche z.B. über die serielle Schnittstelle empfangen werden können. Zeichen sind
dabei nicht nur Buchstaben, sondern auch Ziffern, Sonderzeichen und Steuerzeichen. In gewissen
Situationen kann es erforderlich sein, zu erkennen, ob eingegangene Zeichen zum Beispiel ein
Sonderzeichen enthalten, oder ein ganz bestimmtes Zeichen. Oder auch, ob das Zeichen eine Ziffer oder
ein Buchstabe ist. Genau das können die folgenden Funktionen für uns erledigen.

isAlphaNumeric(thisChar)
Beschreibung
Stellt fest, ob ein Zeichen entweder ein Buchstabe ist oder eine Ziffer.

Syntax
ergebnis = isAlphaNumeric(thisChar)

Parameter
thisChar Das Zeichen, welches analysiert werden soll
ergebnis Wert der Prüfung, boolean (true / false)

Rückgabewert
true (wahr; 1) oder false (nicht wahr; 0)

Beispiel
ergebnis = isAlphaNumeric(thisChar);
Serial.print("Zeichen ist Buchstabe/Ziffer (1) oder nicht (0): ");
Serial.println(ergebnis);

isAlpha(thisChar)
Beschreibung
Stellt fest, ob ein Zeichen ein Buchstabe ist.

Syntax
ergebnis = isAlpha(thisChar)

Parameter
thisChar Das Zeichen, welches analysiert werden soll
ergebnis Wert der Prüfung, boolean (true / false)

Rückgabewert
true (wahr; 1) oder false (nicht wahr; 0)

Beispiel
ergebnis = isAlpha(thisChar);
Serial.print("Zeichen ist Buchstabe (1) oder nicht (0): ");
Serial.println(ergebnis);



isAscii(thisChar)
Beschreibung
Stellt fest, ob ein Zeichen ein ASCII-Zeichen ist

Syntax
ergebnis = isAscii(thisChar)

Parameter
thisChar Das Zeichen, welches analysiert werden soll
ergebnis Wert der Prüfung, boolean (true / false)

Rückgabewert
true (wahr; 1) oder false (nicht wahr; 0)

Beispiel
ergebnis = isAscii(thisChar);
Serial.print("Zeichen ist ASCII-Zeichen (1) oder nicht (0): ");
Serial.println(ergebnis);


isWhiteSpace(thisChar)

Beschreibung
Stellt fest, ob ein Zeichen eine Leerstelle ist. Der Unterschied zwischen Leerstelle und Leerzeichen ist mir
nicht ganz klar (Ich bin Elektroniker, kein Computer-Nerd). Vielleicht kann mal ein IT-Fachmann hier
eine Hilfestellung geben. Bei Bedarf einfach ausprobieren, ob isWhiteSpace(thisChar) oder
isSpace(thisChar) zum gewünschten Ergebnis führt. Siehe auch: isSpace(thisChar)

Syntax
ergebnis = isWhiteSpace(thisChar)

Parameter
thisChar Das Zeichen, welches analysiert werden soll
ergebnis Wert der Prüfung, boolean (true / false)

Rückgabewert
true (wahr; 1) oder false (nicht wahr; 0)

Beispiel
ergebnis = isWhiteSpace(thisChar);
Serial.print("Zeichen ist Leerstelle (1) oder nicht (0): ");
Serial.println(ergebnis);


isControl(thisChar)

Beschreibung
Stellt fest, ob ein Zeichen ein Steuerzeichen ist. Steuerzeichen sind nichtdruckbare Zeichen, wie z.B.
Linefeed(Zeilenvorschub), Neue Zeile(CarriageReturn), Formfeed(Seitenvorschub) etc. Siehe hierzu z.B.
Wikipedia.

Syntax
ergebnis = isControl(thisChar)

Parameter
thisChar Das Zeichen, welches analysiert werden soll
ergebnis Wert der Prüfung, boolean (true / false)

Rückgabewert
true (wahr; 1) oder false (nicht wahr; 0)

Beispiel
ergebnis = isControl(thisChar);
Serial.print("Zeichen ist Steuerzeichen (1) oder nicht (0): ");
Serial.println(ergebnis);


isDigit(thisChar)

Beschreibung
Stellt fest, ob ein Zeichen eine Ziffer ist

Syntax
ergebnis = isControl(thisChar)

Parameter
thisChar Das Zeichen, welches analysiert werden soll
ergebnis Wert der Prüfung, boolean (true / false)

Rückgabewert
true (wahr; 1) oder false (nicht wahr; 0)

Beispiel
ergebnis = isDigit(thisChar);
Serial.print("Zeichen ist eine Ziffer (1) oder nicht (0): ");
Serial.println(ergebnis);


isGraph(thisChar)

Beschreibung
Stellt fest, ob ein Zeichen ein druckbares Zeichen ist. Diese Funktion ist quasi das Gegenteil von
isControl(thisChar). Hier wird ein „true“ zurückgegeben, wenn das Zeichen KEIN Steuerzeichen ist.
Unterschied zu isPrintable(thisChar) nicht klar. Vielleicht kann mal ein IT-Fachmann hier eine
Hilfestellung geben.

Syntax
ergebnis = isGraph(thisChar)

Parameter
thisChar Das Zeichen, welches analysiert werden soll
ergebnis Wert der Prüfung, boolean (true / false)

Rückgabewert
true (wahr; 1) oder false (nicht wahr; 0)

Beispiel
ergebnis = isGraph(thisChar);
Serial.print("Zeichen ist ein druckbares Zeichen (1) oder nicht (0): ");
Serial.println(ergebnis);


isLowerCase(thisChar)

Beschreibung
Stellt fest, ob ein Zeichen ein klein geschriebenes Zeichen (Buchstabe) ist.

Syntax
ergebnis = isLowerCase(thisChar)

Parameter
thisChar Das Zeichen, welches analysiert werden soll
ergebnis Wert der Prüfung, boolean (true / false)

Rückgabewert
true (wahr; 1) oder false (nicht wahr; 0)

Beispiel
ergebnis = isLowerCase(thisChar);
Serial.print("Zeichen ist ein klein geschriebenes Zeichen (1) oder nicht (0): ");
Serial.println(ergebnis);


isPrintable(thisChar)

Beschreibung
Stellt fest, ob ein Zeichen ein druckbares Zeichen ist. Unterschied zu isGraph(thisChar) nicht getestest
und mir (noch) nicht klar. Vielleicht kann mal ein IT-Fachmann hier eine Hilfestellung geben.

Syntax
ergebnis = isPrintable(thisChar)

Parameter
thisChar Das Zeichen, welches analysiert werden soll
ergebnis Wert der Prüfung, boolean (true / false)

Rückgabewert
true (wahr; 1) oder false (nicht wahr; 0)

Beispiel
ergebnis = isPrintable(thisChar);
Serial.print("Zeichen ist druckbar (1) oder nicht (0): ");
Serial.println(ergebnis);


isPunct(thisChar)

Beschreibung
Stellt fest, ob ein Zeichen eine Interpunktion ist. Interpunktionen sind Satzzeichen wie z.B. Punkt,
Doppelpunkt, Ausrufezeichen, Fragezeichen, Komma etc.

Syntax
ergebnis = isPunct(thisChar)

Parameter
thisChar Das Zeichen, welches analysiert werden soll
ergebnis Wert der Prüfung, boolean (true / false)

Rückgabewert
true (wahr; 1) oder false (nicht wahr; 0)

Beispiel
ergebnis = isPunct(thisChar);
Serial.print("Zeichen ist Interpunktion (1) oder nicht (0): ");
Serial.println(ergebnis);


isSpace(thisChar)

Beschreibung
Stellt fest, ob ein Zeichen ein Leerzeichen ist. Der Unterschied zwischen Leerstelle und Leerzeichen ist
mir nicht ganz klar (Ich bin Elektroniker, kein Computer-Nerd). Vielleicht kann mal ein IT-Fachmann
hier eine Hilfestellung geben. Bei Bedarf einfach ausprobieren, ob isWhiteSpace(thisChar) oder
isSpace(thisChar) zum gewünschten Ergebnis führt. Siehe auch: isWhiteSpace(thisChar)


Syntax
ergebnis = isSpace(thisChar)

Parameter
thisChar Das Zeichen, welches analysiert werden soll
ergebnis Wert der Prüfung, boolean (true / false)

Rückgabewert
true (wahr; 1) oder false (nicht wahr; 0)

Beispiel
ergebnis = isSpace(thisChar);
Serial.print("Zeichen ist Leerzeichen (1) oder nicht (0): ");
Serial.println(ergebnis);


isUpperCase(thisChar)

Beschreibung
Stellt fest, ob ein Zeichen ein groß geschriebenes Zeichen (Buchstabe) ist.


Syntax
ergebnis = isUpperCase(thisChar)

Parameter
thisChar Das Zeichen, welches analysiert werden soll
ergebnis Wert der Prüfung, boolean (true / false)

Rückgabewert
true (wahr; 1) oder false (nicht wahr; 0)

Beispiel
ergebnis = isUpperCase(thisChar);
Serial.print("Zeichen ist groß geschrieben (1) oder nicht (0): ");
Serial.println(ergebnis);

isHexadecimalDigit(thisChar)

Beschreibung
Stellt fest, ob ein Zeichen eine gültige, herxadezimale Zahl ist.


Syntax
ergebnis = isHexadecimalDigit(thisChar)

Parameter
thisChar Das Zeichen, welches analysiert werden soll
ergebnis Wert der Prüfung, boolean (true / false)

Rückgabewert
true (wahr; 1) oder false (nicht wahr; 0)

Beispiel
ergebnis = isHexadecimalDigit(thisChar);
Serial.print("Zeichen ist hexadezimal (1) oder nicht (0): ");
Serial.println(ergebnis);

Hilfsfunktionen

sizeof
Beschreibung
Der sizeof Operator ermittelt die Anzahl Bytes in einem Variablentyp, oder die Anzahl von Bytes, welche
durch ein Array belegt werden.

Syntax
sizeof(variable)

Parameter
Variable: jeder Variablentype oder Array (z.B. int, float, byte)

Beispiel
Der sizeof-Operator ist nützlich, wenn man mit Arrays arbeitet (wie z.B. Strings) wo es komfortabel ist,
die Größe des Arrays zu ändern, ohne andere Teile des Programms zu zerstören oder zu unterbrechen.
Das folgende Programm druckt einen Textstring, immer einen Buchstaben einzeln. Versuchen sie, die
Textphrase zu verändern…

char myStr[
int i;

void setup(){
Serial.begin(9600);
}

void loop() {
for (i = 0; i < sizeof(myStr) - 1; i++){
Serial.print(i, DEC);
Serial.print(" = ");
Serial.write(myStr[i
Serial.println();
}
delay(5000); // slow down the program
}


PROGMEM
Beschreibung
Dieses Schlüsselwort sorgt dafür, dass Daten im Flash des ARDUINO anstatt im SRAM abgespeichert
werden. Wie wir wissen, ist der SRAM begrenzt: bei ATMega328-basierten Boards, wie dem Uno, Nano,
Micro sind das 2kB. Der Flash (dort wo auch das Programm gespeichert wird) hat bei diesen ARDUINOs
32kB.
Durch die Benutzung von PROGMEM kann man also SRAM sparen, wenn dieser im Programm knapp
wird. Die PROGMEM-Funktion ist mittlerweile in der IDE implementiert, es ist keine Lib mehr zu laden.

PROGMEM modifiziert eine Variable und funktioniert mit den meisten Datentypen, die beim ARDUINO
verwendet werden. Nutzer haben aber herausgefunden, das aufgrund der Version des GCC-Compilers
manche Anwendungen des PROGMEM-Keywords funktioniert haben, andere wiederum nicht.

Syntax
const dataType variableName[ PROGMEM = {data0, data1, data3...};

Parameter
datatype: Wert beliebiger Datentyp
variableName: der Name des Datenarrays

Hinweis
Aufgrund der o.g. möglichen Unterschiede, je nach Compiler-Version, können unterschiedliche
Schreibweisen funktionieren. Die folgenden funktionieren:

const dataType variableName[ // so geht’s
const PROGMEM dataType variableName[
const dataType PROGMEM variableName[ // aber NICHT so

Auch, wenn es theoretisch möglich ist, diese Schreibweise für nur eine einzige Variable zu benutzen,
macht es wirklich nur Sinn bei großen Datenmengen, welche in Arrays gespeichert werden müssen. Ich
persönlich habe es noch nie benutzt, nur einmal, um es zu testen. Ich denke, für Anfänger ist es einfach zu
kompliziert…
Die Benutzung von PROGMEM ist etwas umständlich und auch eine zweistufige Arbeitsweise. Nachdem
die Daten mit der Funktion in den Flash gelangt sind, müssen sie zur Benutzung auch dort wieder heraus
in den SRAM geholt werden.

Beispiel

// save some unsigned ints
const PROGMEM uint16_t charSet[

// save some chars
const char signMessage[
THE UNITED STATES DEPART"};

unsigned int displayInt;
int k; // counter variable
char myChar;


void setup() {
Serial.begin(9600);
while (!Serial);

// put your setup code here, to run once:
// read back a 2-byte int
for (k = 0; k < 5; k++)
{
displayInt = pgm_read_word_near(charSet + k);
Serial.println(displayInt);
}
Serial.println();

// read back a char
int len = strlen_P(signMessage);
for (k = 0; k < len; k++)
{
myChar = pgm_read_byte_near(signMessage + k);
Serial.print(myChar);
}

Serial.println();
}

void loop() {
// put your main code here, to run repeatedly:

}

Es ist zu beachten, dass die Variablen, welche mit PROGMEM benutzt werden sollen, global definiert
werden müssen. Oder aber mit dem Keyword static, damit sie mit PROGMEM arbeiten.

Der folgende Ausdruck wird innerhalb einer Funktion nicht gehen:

const char long_str[\n";

Dieser hier geht, auch wenn man ihn lokal in einer Funktion definiert:

const static char long_str[I would like to tell you a bit about
myself.\n"


F()-Makro
In diesem Zusammenhang sei auch noch auf das F()-Makro verwiesen. Man kann es benutzen, wenn viele
Text-Ausgaben auf den seriellen Monitor erfolgen. Damit kann man sehr schnell den SRAM füllen und
hat nicht mehr genügend für den Rest des Programms. Vermeiden lässt sich das mit der folgenden
Schreibweise:

Serial.print(F("Etwas auf dem Serial Monitor anzeigen…"));

Siehe hierzu auch „RAM sparen bei Serial.print“ im Abschnitt „Kleine hilfreiche Programm-Teile“
Bits und Bytes

lowByte()
Beschreibung
Ermittelt das niederwertige Byte einer Variablen (z.B. Word-Datentyp)

Syntax
lowByte(x)

Parameter
x: Wert beliebiger Datentyp

Rückgabewerte
byte

highByte()
Beschreibung
Ermittelt den höherwertigen Byte eines Word, oder den zweitniedrigsten eines noch größeren Datentypes.

Syntax
highByte(x)

Parameter
x: Wert beliebiger Datentyp

Rückgabewerte
byte

bitRead()
Beschreibung
Liest ein bestimmtes Bit einer Zahl.

Syntax
bitRead(x, n)

Parameter
x: die Zahl, von der ein Bit ermittelt werden soll
n: welches Bit gelesen werden soll, beginnend mit 0 für das niedrigstwertige Bit (das am meisten rechts
befindliche Bit)

Rückgabewerte
Der Wert des Bit’s, also 0 oder 1

bitWrite()
Beschreibung
Schreibt ein bestimmtes Bit einer numerischen Variable (also keine Strings)

Syntax
bitWrite(x, n, b)

Parameter
x: die numerische Variable, in der das Bit geschrieben werden soll
n: welches Bit geschrieben werden soll, beginnend mit 0 für das niedrigstwertige Bit (das am meisten
rechts befindliche Bit)
b: der Wert des Bit’s, der geschrieben werden soll (0 oder 1)

Rückgabewerte
keine

bitSet()
Beschreibung
Setzt (schreibt eine 1) eines bestimmten Bit’s einer numerischen Variablen.

Syntax
bitSet(x, n)

Parameter
x: die numerische Variable, in der ein Bit gesetzt werden soll
n: welches Bit gesetzt werden soll, beginnend mit 0 für das niedrigstwertige Bit (am meisten rechts
befindlich)

Rückgabewerte
keine
bitClear()
Beschreibung
Löscht (schreibt eine 0) ein bestimmtes Bit einer numerischen Variablen.

Syntax
bitClear(x, n)

Parameter
x: die numerische Variable, in der ein Bit gelöscht werden soll
n: welches Bit gelöscht werden soll, beginnend mit 0 für das niedrigstwertige Bit (am meisten rechts
befindlich)

Rückgabewerte
Keine

bit()
Beschreibung
Ermittelt den Wert eines bestimmten Bits (Bit 0 ist 1, Bit 1 ist 2, Bit 2 ist 4, etc.).
Hier bedarf es einer kurzen Erklärung: Ein Byte besteht aus acht Bits, also z.B. die Zahl 9 entspricht in
Binärschreibweise &B00001001:

Binärzahl (Bits) &B 0 0 0 0 1 0 0 1
Wert der Bits 128 64 32 16 8 4 2 1

Wie man sieht, für die Zahl 9 ist das Bit für die „1“ und die „8“ gesetzt, 1+8=9! Einfach, oder?
Die Bits werden folgendermaßen gezählt:

Nummer des Bits 7 6 5 4 3 2 1 0

Syntax
bit(n)

Parameter
n: das Bit, dessen Wert berechnet werden soll

Rückgabewerte
Der Wert des Bits

Serielle Kommunikation (UART)

Allgemeines

Serielle Schnittstellen werden benutzt, damit der Arduino mit einem Computer oder anderer Hardware
kommunizieren kann. Alle Arduino-Boards haben mindestens eine serielle Schnittstelle, auch bekannt
unter der Bezeichnung UART oder USART. Die Datenübertragung geschieht an bestimmten Pins: RX
und TX, wie auch über USB mit dem Computer oder auch z.B. Tastatur, Maus etc.
Wenn Sie die serielle Schnittstelle benutzen, dann können diese o.g. Pins nicht für andere Funktionen,
wie Eingang oder Ausgang genutzt werden.

In der Arduino-IDE (Das Programm, um Arduino-Sketche zu schreiben), ist ein serielles Terminal
eingebaut. Dieses kann benutzt werden, um mit dem Arduino-Board über USB zu kommunizieren.
Klicken Sie auf den Button für den seriellen Monitor in der Toolbar und wählen sie dieselbe Baudrate wie
in der Definierung mit dem Befehl begin().

Bei allen ARDUINO’s ist die serielle Schnittstelle (welche an die USB-Buchse geht) an den Digital-Pins
Pin0 (RX) und Pin1 (TX) angeschlossen.

Der Arduino MEGA hat drei zusätzliche serielle Schnittstellen: Serial1 an Pin19 (RX) und Pin18 (TX),
Serial2 an Pin17 (RX) und Pin16 (TX), Serial3 an Pin15 (RX) und Pin14 (TX).
Um diese Pins zu nutzen zur Kommunikation mit einem Computer wird ein weiterer USB-zu-Seriell-
Konverter benötigt. Die zusätzlichen seriellen Schnittstellen des MEGA haben keinen USB-Adapter
eingebaut.
Soll mit einem externen Gerät über TTL-Pegel kommuniziert werden, muss der RX-Pin des Arduino mit
dem TX-Pin des externen Gerätes verbunden werden sowie der TX-Pin des Arduino mit dem RX-Pin des
externen Gerätes. Weiterhin ist natürlich die Verbindung der Masse (GND) notwendig.
Die Pins können NICHT direkt an RS232-Schnittstellen angeschlossen werden, dass würde das Arduino-
Board zerstören (wegen der -12V und +12V Pegel der RS232).

Der Arduino DUE hat drei zusätzliche 3,3V-TTL serielle Schnittstellen: Serial1 an Pin19 (RX) und
Pin18 (TX), Serial2 an Pin17 (RX) und Pin16 (TX), Serial3 an Pin15 (RX) und Pin14 (TX).
Zusätzlich ist hier noch ein nativer USB-Seriell-Port mit dem SAM3X-Chip vorhanden: SerialUSB.

Der Arduino LEONARDO benutzt Serial1 um mit TTL-Pegel an Pins Pin0 (RX) und Pin1 (TX) zu
kommunizieren. Serial ist reserviert für USB CDC Kommunikation.

Falls gewünscht, müssen weitere Infos im Netz nachgelesen werden.

Hier folgen nun kurze Beschreibungen der fünf wichtigsten Befehle für die serielle Kommunikation.
Aktuell ist keine detaillierte Beschreibung im Netz zu finden, also immer mal nachschauen: Vielleicht
gibt es mittlerweile etwas. Das kann dann auch noch in dieses Buch aufgenommen werden.
Alle Funktionen (Befehle) für die serielle Kommunikation beginnen mit dem ‚Serial‘, gefolgt von der
entsprechenden Funktion. Es sind die folgenden Funktionen verfügbar:

 if (Serial)
 available () Beschreibung verfügbar, siehe nächste Seiten
 begin () Beschreibung verfügbar, siehe nächste Seiten
 end ()
 find ()
 findUntil ()
 flush () Beschreibung verfügbar, siehe nächste Seiten
 parseFloat ()
 parseInt ()
 peek ()
 print () Beschreibung verfügbar, siehe nächste Seiten
 println () Beschreibung verfügbar, siehe nächste Seiten
 read () Beschreibung verfügbar, siehe nächste Seiten
 readBytes ()
 readBytesUntil ()
 setTimeout ()
 write ()
 serialEvent()

Serial.begin(speed)
Beschreibung
Initialisiert die serielle Kommunikation mit der Geschwindigkeit speed. Für gewöhnlich wird man hier
9600 Baud benutzen, es sind aber auch andere Werte möglich, maximal aber 115200 Baud.

Syntax
Serial.begin(speed)

Parameter
Speed: die gewünschte Geschwindigkeit in Baud ( 9600, etc.)

Rückgabewerte
Keine

Beispiel:
Serial.begin(9600); // initialisiert mit 9600 Baud


Serial.print(data) Serial.print(data, encoding)
Beschreibung
Sendet Daten an den seriellen Port. Encoding ist optional, wenn es weggelassen wird, dann wird der
Arduino versuchen zu viel wie möglich einfachen Text zu verwenden. Dieser wird von den meisten
externen Komponenten richtig wiedergegeben.

Beispiel:
Serial.print (var); // druckt den Wert der Variable var
Serial.print(75); // druckt "75"
Serial.print(75, DEC); // wie oben.
Serial.print(75, HEX); // "4B" (75 in hexadecimal)
Serial.print(75, OCT); // "113" (75 in octal)
Serial.print(75, BIN); // "1001011" (75 in Binärcode)
Serial.print(75, BYTE); // "K" (Rowbyte entspricht 75 in ASCII Code)

Serial.println(data) Serial.println(data, encoding)
Beschreibung
Identisch mit Serial.print, AUSSER das ein Carriage Return und Linefeed (\r \n) angefügt wird. Das ist
etwa so, als wenn man in MSWord eine Zeile Text schreibt, und dann RETURN oder ENTER drückt.

Beispiel:
Wie oben, aber es wird nach dem Drucken in eine neue Zeile gesprungen


Serial.available()
Beschreibung
Ermittelt, wie viele ungelesene Bytes am seriellen Port verfügbar sind, um mit der read()-Funktion
gelesen zu werden. Nachdem alles mit read() gelesen wurde, dann ergibt Serial.available den Wert 0,
solange, bis wieder Daten über den seriellen Port empfangen wurden.

Rückgabewert
Anzahl Variable Datentyp int, welche der Anzahl verfügbarer Datenbytes entspricht

Beispiel
int Anzahl = Serial.available();


Serial.read()
Beschreibung
Holt ein hereingekommenes Byte aus der seriellen Schnittstelle ab

Rückgabewert
data Variable (Byte), die dem empfangenen Zeichen entspricht (ASCII-Code)

Beispiel
int data = Serial.read();

Serial.flush
Über den seriellen Port können Daten schneller reinkommen, als sie vom Arduino verarbeitet werden.
Diese werden in einem Zwischenspeicher gespeichert. Um diesen Speicher zu löschen, damit er mit
neuen Daten gefüllt wird, können wir die flush() Funktion benutzen.

Beispiel
Serial.flush();
String Objects
Allgemeines
Die String objects erlauben die Auswertung und Manipulation von Strings in einer wesentlich
komplexeren Art, als das mit char-Array‘s möglich ist. Sie können Strings verbinden, andere Strings
anhängen, suchen und ersetzen von Unter-Strings und vieles mehr. Es braucht mehr Speicher, ist aber
auch wesentlich leistungsfähiger.
Zur Unterscheidung: Strings in Arrays werden mit einem kleinen s geschrieben, wenn es um String
objects geht wird String mit einem großen S geschrieben. Beachten Sie, dass String-Konstanten, die in
doppelten Anführungszeichen geschrieben werden, immer ein String-Array sind.

Bei den String Objects gibt es die folgenden Funktionen (Befehle):

 String()
 charAt()
 compareTo()
 concat()
 endsWith()
 equals()
 equalsIgnoreCase()
 getBytes()
 indexOf()
 lastIndexOf()
 length()
 replace()
 setCharAt()
 startsWith()
 substring()
 toCharArray()
 toLowerCase()
 toUpperCase()
 trim()
Diese Funktionen werden auf den nächsten Seiten näher beschrieben.
String()
Beschreibung
Erstellt ein String-Objekt. Es gibt mehrere Versionen, ein String zu erstellen, aus verschiedenen
Datentypen. Hier z.B., wenn man sie formatiert hat als einzelne Sequenzen von Buchstaben. Das
beinhaltet:

- Eine String-Konstante, bestehend aus Buchstaben, in doppelten Anführungszeichen (z.B. ein
Char-Array)
- Eine String-Konstante, bestehend aus EINEM Buchstaben, in einfachen Anführungszeichen
- Ein weiteres String-Objekt
- Eine Integer- oder long-integer-Konstante
- Eine Integer- oder long-integer-Konstante, die eine bestimmte Basis benutzt
- Eine Integer- oder long-integer-Variable
- Eine Integer- oder long-integer-Variable, die eine bestimmte Basis benutzt

Wenn ein String aus einer Zahl erstellt wird, dann enthält dieser das ASCII-Zeichen, das dieser Zahl
entspricht, die Standard-Basis ist 10, also

String thisString = String(13)

Erstellt den String mit den Zeichen „13“ (Die 13 ist hier eine Zeichenkette, keine Zahl!) Man kann auch
eine andere Basis benutzen, z.B. HEX

String thisString = String(13, HEX)

Das erstellt den String “D“, was der hexadezimalen Darstellung der Zahl „13“ entspricht. Oder wenn Sie
Binärcode bevorzugen:

String thisString = String(13, BIN)

Erstellt den String “1101”, was der binären Darstellung der Zahl 13 entspricht.

Syntax
String(val)
String(val, base)

Parameter
val: eine Variable, die als String formatiert (umgewandelt in String) werden soll. Datentypen: string,
char, byte, int, long, unsigned int, unsigned long
base: (optional) Die Basis der Variable val (also DEZ, HEX, BIN, OCT)

Beispiel:
Alle folgenden Ausdrücke sind gültige String-Deklarationen

String stringOne = "Hello String"; // using a constant String
String stringOne = String('a'); // converting a constant char into a String
String stringTwo = String("This is a string"); // converting a constant string into
a String object
String stringOne = String(stringTwo + " with more"); // concatenating two strings
String stringOne = String(13); // using a constant integer
String stringOne = String(analogRead(0), DEC); // using an int and a base
String stringOne = String(45, HEX); // using an int and a base (hexadecimal)
String stringOne = String(255, BIN); // using an int and a base (binary)
String stringOne = String(millis(), DEC); // using a long and a base




charAt()

Beschreibung
Greift auf einen bestimmten Buchstaben eines Strings zu.

Syntax
string.charAt(n)

Parameter
string: eine Variable vom Datentyp String
n: der n’te Buchstabe, welcher ermittelt werden

Rückgabewert
Das n’te Zeichen des Strings

Beispiel
char x = string.charAt(5); // gibt das 5. Zeichen des Strings an die Variable x


compareTo()
Beispiel-Sketch verfügbar: compareTo.ino

Beschreibung
Vergleicht zwei Strings. Testet, ob einer vor oder hinter dem anderen kommt, oder ob sie identisch sind.
Die Strings werden Zeichen für Zeichen verglichen, indem die ASCII-Werte der Zeichen benutzt werden.
Das bedeutet, z.B. das ‚a‘ vor ‚b‘ kommt, aber nach ‚A‘. Ziffern kommen vor Buchstaben.

Syntax
string.compareTo(string2)

Parameter
string: eine Variable vom Datentyp String
string2: eine weitere Variable vom Typ String

Rückgabewert
eine negative Zahl: wenn string VOR string2 kommt
0 wenn string GLEICH string2 ist
eine positive Zahl: wenn string NACH string2 kommt

Beispiel
String string1 = "Hans";
String string2 = "Peter";
String string3 = "Hans";
int x = 0;

x= string1.compareTo(string2);
Serial.println(x); // negative Zahl, wenn string1 VOR string2 ist

x= string2.compareTo(string1);
Serial.println(x); // positive Zahl, wenn string1 NACH string2 ist

x= string3.compareTo(string1);
Serial.println(x); // Null, wenn beide Strings identisch sind

concat()
Beispiel-Sketch verfügbar: concat.ino

Beschreibung
Hängt einen String an einen anderen hinten dran.

Syntax
String1.concat(string2);

Parameter
String1: eine Variable vom Datentyp String
string2: eine weitere Variable vom Typ String

Rückgabewert
Ein neuer String, der aus den beiden Einzelstrings besteht.

Beispiel
String string1 = "Hans";
String string2 = "Peter";
string1.concat(string2); // string2 an string1 anhängen
// Ergebnis: HansPeter

endsWith()
Beispiel-Sketch verfügbar: endsWith.ino

Beschreibung
Testet, ob oder ob nicht ein String mit dem Zeichen eines anderen Strings endet.

Syntax
string.endsWith(string2)

Parameter
string: eine Variable vom Datentyp String
string2: eine weitere Variable vom Typ String

Rückgabewert
true: wenn string mit dem Zeichen von string2 endet
false: wenn nicht

Beispiel
String string1 = "Hans";
String string2 = "s";
String string3 = "r";
boolean x;

x= string1.endsWith(string3);
Serial.println(x); // false, wenn string1 NICHT mit dem Zeichen von string2 endet
x= string1.endsWith(string2);
Serial.println(x); // true, wenn string1 mit dem Zeichen von string2 endet

equals()
Beispiel-Sketch verfügbar: equals.ino

Beschreibung
Vergleicht zwei Strings, ob diese gleich sind. Der Vergleich ist „case-sensitive“. Das bedeutet, der String
„hello“ ist nicht identisch mit dem String „HELLO“ oder „Hello“. Es wird die exakte Schreibweise
verglichen!

Syntax
string.equals(string2)

Parameter
string: eine Variable vom Datentyp String
string2: eine weitere Variable vom Typ String

Rückgabewert
true: string ist identisch mit string2
false: wenn nicht

Beispiel
String string1 = "Hans";
String string2 = "Hans";
String string3 = "hans";
boolean x;

x= string1.equals(string3);
Serial.println(x); // false, wenn string1 NICHT identisch mit string3
x= string1.equals(string2);
Serial.println(x); // true, wenn string1 identisch mit string2

equalsIgnoreCase()
Beispiel-Sketch verfügbar: equalsIgnoreCase.ino

Beschreibung
Vergleicht zwei Strings, ob diese gleich sind. Der Vergleich ist NICHT „case-sensitive“. Das bedeutet,
der String „hello“ ist identisch mit dem String „HELLO“ oder „Hello“.

Syntax
string.equalsIgnoreCase(string2)

Parameter
string: eine Variable vom Datentyp String
string2: eine weitere Variable vom Typ String

Rückgabewert
true: string ist identisch mit string2
false: wenn nicht

Beispiel
String string1 = "Hans";
String string2 = "HANS";
String string3 = "hans";
boolean x;

x= string1.equalsIgnoreCase(string3);
Serial.println(x); // true, weil 'hans' = 'Hans' ist
x= string1.equals(string2);
Serial.println(x); // auch true, NICHT case-sensitive


getBytes()
Beispiel-Sketch verfügbar: getBytes_length.ino

Beschreibung
Kopiert die Zeichen des Strings als ASCII-Wert in den bereitgestellten Pufferspeicher

Syntax
string.getBytes(buf, len)

Parameter
string: eine Variable vom Datentyp String
buf: der Pufferspeicher, in den der ASCII-Wert kopiert werden sollen (byte[-Array)
len: die Größe des Puffers (unsigned int Datentyp)

Rückgabewert
keine

Beispiel
String nachricht = "Dies ist ein Test";

byte bytes[nachricht.length() + 1-Array ermitteln (mit 0-Term.)
nachricht.getBytes(bytes, nachricht.length() + 1); // Bytes extrahieren

for (int i = 0; i < nachricht.length(); i++){
if (i > 0){Serial.print(" ");} // Leerzeichen einfügen
Serial.print(bytes[i // anzeigen
// Ausgabe: 68 105 101 115 32 105 115 116 32 101 105 110 32 32 84 101 115 116

Das heißt, es ist im Byte-Array so hinterlegt:
Bytes[0] = 68, Bytes[1] = 105, Bytes[2] = 101 … usw.

indexOf()
Beschreibung
Lokalisiert ein Zeichen / String innerhalb eines anderen Strings. Standardmäßig wird vom Anfang des
Strings begonnen, es kann aber auch vorwärts von einer bestimmten Stelle aus gesucht werden. Das
erlaubt das Feststellen von mehrfach vorhandenen Zeichen / Strings innerhalb des vorhandenen Strings.

Syntax
string.indexOf(val)
string.indexOf(val, from)

Parameter
string: eine Variable vom Datentyp String
val: nach was soll gesucht werden (Zeichen oder String)
from: der Punkt, an dem die Suche vorwärts gestartet werden soll

Rückgabewert
Eine Zahl, welche der Stelle entspricht, an dem die gesuchten Zeichen oder Strings gefunden worden
sind. Oder -1, wenn das Zeichen oder String NICHT gefunden wurde.

Beispiel
String string1 = "- Hallo! Hallo! Hier ist DL1AKP.";

int erstesAusrufezeichen = string1.indexOf('!');
Serial.println(erstesAusrufezeichen);
int zweitesAusrufezeichen = string1.indexOf('!', erstesAusrufezeichen + 1 );
Serial.println(zweitesAusrufezeichen);
int fragezeichen = string1.indexOf('?'); // Wo ist Fragezeichen?
Serial.println(fragezeichen); // Wert ausgeben (Negativ, weil nicht vorhanden)

Als Ergebnis werden die Zahle 7, 14 und -1 ausgegeben. Da die Zählung bei Null beginnt, ist das erste
Zeichen die 0. Stelle. Wird das Zeichen nicht gefunden ist der Wert negativ. Man kann also damit
feststellen, ob ein Zeichen oder String in einem anderen enthalten ist und wo, vom Anfang beginnend.

lastIndexOf()
Beschreibung
Lokalisiert ein Zeichen oder String innerhalb eines anderen Strings. Standardmäßig wird vom Ende
des Strings begonnen, es kann aber auch rückwärts von einer bestimmten Stelle aus gesucht werden. Das
erlaubt das Feststellen von mehrfach vorhandenen Zeichen oder Strings innerhalb des vorhandenen
Strings.

Syntax
string.lastIndexOf(val)
string.lastIndexOf(val, from)

Parameter
string: eine Variable vom Datentyp String
val: nach was soll gesucht werden (Zeichen oder String)
from: der Punkt, an dem die Suche rückwärts gestartet werden soll

Rückgabewert
Eine Zahl, welche der Stelle entspricht, an dem die gesuchten Zeichen oder Strings gefunden worden
sind. Oder -1, wenn das Zeichen oder String NICHT gefunden wurde.

Beispiel
String string1 = "- Hallo! Hallo! Hier ist DL1AKP.";

int erstesAusrufezeichen = string1.lastIndexOf('!'); // Wo ist 1. Ausr.Z. ?
Serial.println(erstesAusrufezeichen); // Wert ausgeben
// Wo ist zweites Ausrufezeichen? Beginne 1 Zeichen hinter dem ersten zu suchen!
int zweitesAusrufezeichen = string1.lastIndexOf('!', erstesAusrufezeichen - 1 );
Serial.println(zweitesAusrufezeichen); // Wert ausgeben
int fragezeichen = string1.lastIndexOf('?'); // Wo ist Fragezeichen?
Serial.println(fragezeichen); // Wert ausgeben (Negativ, weil nicht vorhanden)

Hier werden als Ergebnis die Zahlen 14, 7 und -1 ausgegeben. Von hinten beginnend ist an Position 14
das erste Ausrufezeichen. (Achtung! Das Ergebnis gibt die Position von vorn aus gezählt wieder und
NICHT wie gedacht von hinten aus!)
Das zweite Ausrufezeichen ist an Stelle 7 von vorn aus gesehen und das Fragezeichen nicht vorhanden
(negativer Wert)

length()
Beispiel-Sketch verfügbar: getBytes_length.ino

Beschreibung
Ermittelt die Länge eines Strings in Anzahl der Zeichen. Hierbei wird ein angehängter Null-Charakter
(siehe Erklärung bei String-Arrays) nicht mitgezählt.

Syntax
string.length()

Parameter
string: eine Variable vom Datentyp String

Rückgabewert
Die Länge des Strings in Anzahl der Zeichen

Beispiel
String string1 = "Hans";
String string2 = "Hans-Dieter";

x= string1.length();
Serial.println(x); // Ergebnis: 4

x= string2.length();
Serial.println(x); // Ergebnis: 11

replace()
Beschreibung
Die Stringfunktion replace() erlaubt es, ALLE in einem String vorhandenen Zeichen mit einem
gewünschten Zeichen zu ersetzen. Dies funktioniert auch mit Teilstrings, welche durch einen anderen
Teilstring ersetzt werden sollen.

Syntax
string.replace(substring1, substring2)

Parameter
string: eine Variable vom Datentyp String
substring1: eine Variable vom Datentyp String
substring2: eine Variable vom Datentyp String

Rückgabewert
Ein neuer String, welcher den alten String mit den ersetzten Zeichen oder Teilstrings enthält

Beispiel
String string1 = "- Hallo! Hallo! Hier ist DL1AKP.";

string1.replace("Hallo", "Hoh");
Serial.println(string1); // Ausgabe Hallo ist durch Hoh ersetzt



setCharAt()
Beschreibung
Setzt ein bestimmtes Zeichen eines Strings. Ist wirkungslos, wenn der String kürzer ist, als die
gewünschte Stelle, an der ein Zeichen gesetzt werden soll.

Syntax
string.setCharAt(index, c)

Parameter
string: eine Variable vom Datentyp String
index: die Stelle (Index), an der ein Zeichen gesetzt werden soll (beginnend bei 0)
c: das Zeichen, welches an der Stelle gesetzt werden soll

Rückgabewert
keine

Beispiel
String string1 = "Hallo";

string1.setCharAt(1, 'e');
Serial.println(string1); // aus Hallo wird Hello

startsWith()
Beschreibung
Ermittelt, ob oder ob nicht ein String mit dem Zeichen eines anderen Strings beginnt.

Syntax
string.startsWith(string2)

Parameter
string: eine Variable vom Datentyp String
string2: eine Variable vom Datentyp String


Rückgabewert
true: wenn string mit dem Zeichen von string2 beginnt
false: wenn nicht

Beispiel
String string1 = "Hallo";
String string2 = "Ha";
String string3 = "Ho";
boolean x;

x = string1.startsWith(string2);
Serial.println(x); // Ausgabe "1", weil string1 mit string2 beginnt

x = string1.startsWith(string3);
Serial.println(x); // Ausgabe "0", weil string1 nicht mit string3 beginnt

substring()
Beschreibung
Findet einen Teilstring innerhalb eines Strings. Die Startzahl (beginnend bei 0) ist inklusive (d.h. das
entsprechende Zeichen gehört schon zum Teilstring), aber die optionale Endzahl ist exclusive (d.h. das
entsprechende Zeichen gehört nicht mehr zum Teilstring). Wenn die Endzahl weggelassen wird, dann
geht der Teilstring bis zum Ende des Strings.

Syntax
string.substring(from)
string.substring(from, to)

Parameter
string: eine Variable vom Datentyp String
from: die Startposition, an welcher der Teilstring beginnt
to: (optional) die Endposition, bevor dieser der Teilstring endet

Rückgabewert
Den Teilstring

Beispiel
String string1 = "Heute ist kein schoenes Wetter";
String string2 = "";

string2 = string1.substring(10); // beginne an Stelle 10
Serial.println(string2); // Ausgabe: "kein schoenes Wetter"

string2 = string1.substring(10,23); // von Stelle 10 bis Stelle 22
Serial.println(string2); // Ausgabe: "kein schoenes"

toCharArray()
Beschreibung
Kopiert die Zeichen des Strings in einen bereitgestellten Pufferspeicher.
Achtung: Ist das Char-Array (buf) nicht groß genug, um alle Zeichen aufzunehmen, dann wird gar nichts
in buf gespeichert!

Syntax
string.toCharArray(buf, len)

Parameter
string: eine Variable vom Datentyp String
buf: der Puffer, in den die Zeichen gespeichert werden sollen (char [)
len: die Größe des Puffers (unsigned int)

Rückgabewert
keine

Beispiel
String string1 = "Heute ist schoenes Wetter";
char buf[50
+ null-Terminator)

string1.toCharArray(buf, 50);
Serial.print(buf);

toInt()
Beschreibung
Konvertiert einen gültigen String in einen long (Integer). Der Quell-String muss mit einer gültigen
Integer-Zahl beginnen. Ist das nicht der Fall, stoppt die Umwandlung.

Syntax
string.toInt()

Parameter
string: eine Variable vom Datentyp String

Rückgabewert
long
Wenn der String NICHT mit einer Integerzahl beginnt, dann wird als Ergebnis 0 zurückgegeben.

Beispiel
String string1 = "495 Hunde warten im Hof";
long zahl = 0;

zahl = string1.toInt();
Serial.println(zahl); // ausgegeben wird: 495

toFloat()
Beschreibung
Konvertiert einen gültigen String in einen float-Wert (Fliesskommazahl). Der String muss dafür mit einer
Ziffer beginnen. Wenn die Funktion keine Ziffern mehr findet, endet die Umwandlung. Die Strings „
45.87“ und „650“ und „650klaus“ ergeben die Fliesskommazahlen 45,87 und 650,00 und 650,00.
Zu beachten ist auch, dass z.B. der String „50.786“ im float den gerundeten Wert 50,77 ergibt.
Das ist bei etwaigen genauen Berechnungen zu beachten, weil dadurch ein Fehler entstehen kann.

Syntax
string.toFloat()

Parameter
string: eine Variable vom Datentyp String

Rückgabewert
float
Wenn der String NICHT mit einer Ziffer beginnt, dann wird als Ergebnis 0 zurückgegeben.

Beispiel
String string1 = "169.51 Grad Celsius";
float wert;

wert = string1.toFloat();
Serial.println(wert); // Ausgabe: 169.51

toLowerCase()
Beschreibung
Modifiziert einen String dahingehend, dass er in Kleinbuchstaben umgewandelt wird.

Syntax
string.toLowerCase()

Parameter
string: eine Variable vom Datentyp String

Rückgabewert
Der Originalstring, nur aus Kleinbuchstaben bestehend

Beispiel
String string1 = "HALLO LEUTE";

string1.toLowerCase();
Serial.print(string1); // Ausgabe "hallo leute"

toUpperCase()
Beschreibung
Modifiziert einen String dahingehend, dass er in Großbuchstaben umgewandelt wird.

Syntax
string.toUpperCase()

Parameter
string: eine Variable vom Datentyp String

Rückgabewert
Der Originalstring, nur aus Großbuchstaben bestehend

Beispiel
String string1 = "hallo LEute";

string1.toUpperCase();
Serial.print(string1); // Ausgabe "HALLO LEUTE"

trim()
Beispiel-Sketch verfügbar: temp_MCP9700.ino

Beschreibung
Entfernt alle bestehenden Leerräume (Leerzeichen) vor und nach dem String.

Syntax
string.trim()

Parameter
string: eine Variable vom Datentyp String

Rückgabewert
Der bearbeitete Originalstring

Beispiel
String string1 = " speicher ";

Serial.print("Programm");
string1.trim();
Serial.print(string1);
Serial.println("platz"); // Ausgabe: Programmspeicherplatz
String Operatoren
[

(Z
ug
ri
ff auf
Z
ei
chen)
Beschreibung
Erlaubt den Zugriff auf die einzelnen Zeichen eines Strings

Syntax
char meinZeichen = string1[n

Parameter
char meinZeichen Variable (Datentyp char)
string1 ein String
int n die Stelle, auf die zugegriffen werden soll (beginnend mit 0)

Rückgabewert
Das n-te Zeichen eines Strings. Ergibt das gleiche Ergebnis wie der Befehl ‚charAt()‘

Beispiel
String string1 = "Programmspeicher";

char mychar = string1[5
Serial.print(mychar); // Ausgabe: a (5.Zeichen bei 0 zählend)


+ (Operator „Anhängen“)
Beschreibung
Verbindet, bzw. („hängt an“) zwei Strings zu einem neuen String. Der zweite String wird an den ersten
angehängt, das Ergebnis wird in einen neuen String ausgegeben. Funktioniert auf die gleiche Art wie der
Befehl string.concat().

Syntax
string3 = string1 + string 2;
string3 += string2;

Parameter
string, string2, string3: String-Variablen

Rückgabewert
Ein neuer String, der eine Kombination der beiden Original-Strings ist.

Beispiel
String string1 = "Programm";
String string2 = "speicher";
String string3 = "";

string3 = string1 + string2;
Serial.println(string3);


== (Operator „Vergleich“)
Beschreibung
Vergleicht zwei Strings auf Gleichheit. Der Vergleich ist „case-sensitive“, d.h. „hello“ ist nicht identisch
mit „Hello“. Funktioniert auf die gleiche Art wie der Befehl string.equals().

Syntax
String1 == string2 Achtung! Zwei = hintereinander!

Parameter
string1, string2: String-Variablen

Rückgabewert
true wenn beide Strings identisch sind
false wenn nicht

Beispiel
String string1 = "Programm";
String string2 = "Klaus";
String string3 = "Programm";
boolean x;

x= string1 == string2;
Serial.println(x); // Ausgabe 0, weil string1 nicht gleich string2 ist

x= string1 == string3;
Serial.println(x); // Ausgabe 1, weil string1 gleich string3 ist

LCD-Anzeigen und deren Benutzung

Allgemeines
LCD-Anzeigen zählen mit zu den faszinierendsten Bauteilen bei einem Mikrocontroller-Projekt. Sie
vermitteln Informationen und sehen einfach super aus, speziell die blauen. Deshalb hier eine Einführung
zu LCDs und deren Benutzung, Anschlussbelegung und die dazu erforderlichen Befehle (Funktionen).
Die folgende Passage inklusive des Bildes wurde aus [4 übernommen:

Dank der Library „LiquidCrystal“ ist es sehr einfach ein LCD mit dem Arduino zu verwenden: Die
blauen Leitungen entsprechenden Datenleitungen (4 im 4bit-Modus, sonst 8), rot/schwarz auf der linken
Seite sind die Versorgungsspannung des Chips und rot/schwarz auf der rechten Seite dienen der LED-
Hintergrundbeleuchtung. Das orangene Kabel dient zur Einstellung des Kontrastes, wobei das Potenzial
am mittleren Pin eines 10 kΩ-Poti‘s abgegriffen wird. Die beiden grünen Kabel (register select und
enable) dienen der Kommunikation zwischen Arduino und LCD, das mittlere schwarze legt fest, dass wir
das LCD nur zur Ausgabe ("Schreiben") benutzen wollen.

Tipp: Die Kontrasteinstellung soll eigentlich mit einem Potenzial zwischen 0 und 1,5 V erfolgen. Wenn
man lediglich einen Poti verwendet, spielt sich die Kontrastveränderung in einem sehr kleinen
Drehbereich ab. Zur Abhilfe kann ein großer Widerstand (z.B. 20 kΩ) zum Poti in Reihe (oberhalb von
+5V ausgehend, A.N.) geschaltet werden. Damit ist die Potenzialdifferenz am Poti selbst deutlich
geringer.
Auf den folgenden Seiten werden die Befehle zur Arbeit mit LCD’s beschrieben, und auch an Beispielen
erklärt. Wichtig ist es, dem ARDUINO die Verwendung der verschiedenen Leitungen (Verbindungen)
zum Display mitzuteilen. Die Benutzung des 4bit-Bus-Modus ist ausreichend, welchem Zweck der 8bit-
Bus-Modus dient, ist mir persönlich bisher im Verborgenen geblieben.

LiquidCrystal()
Beispiel-Sketch verfügbar: LCD.ino

Beschreibung
Erzeugt eine Variable vom Typ LiquidCrystal. Das dient dazu, dem ARDUINO die Pinbelegung zur
Verbindung mit dem Display mitzuteilen. Die nichtbenutzten Anschlüsse D0 bis D3 des Displays können
einfach unbeschaltet bleiben. RW kann direkt mit GND verbunden werden.

Syntax
LiquidCrystal(rs, enable, d4, d5, d6, d7) / 4bit-Mode (bevorzugt!!)
LiquidCrystal(rs, rw, enable, d4, d5, d6, d7) / 4bit-Mode mit RW
LiquidCrystal(rs, enable, d0, d1, d2, d3, d4, d5, d6, d7) / 8bit-Mode
LiquidCrystal(rs, rw, enable, d0, d1, d2, d3, d4, d5, d6, d7) 78bit-Mode

Parameter
rs: der Arduino-Pin, welcher mit RS des Displays verbunden ist
rw: der Arduino-Pin, welcher mit RW des Displays verbunden ist (optional, unnütz! A.N.)
enable: der Arduino-Pin, welcher mit enable (E) des Displays verbunden ist
d0…d7: Die Pins des Arduino, welche mit den entsprechenden Datenleitungen D0 bis D7 des
Displays verbunden sind

Rückgabewert
keine

Beispiel
#include // binden Bibliothek LiquidCrystal ein
LiquidCrystal lcd(12, 11, 5, 4, 3, 2); // initialisieren Bibliothek LCD-Pins

void setup()
{
lcd.print("Hello, world!");
}

begin()
Beispiel-Sketch verfügbar: LCD.ino

Beschreibung
Beschreibt die Dimensionen des Displays, also Breite (Anzahl der Zeichen) und Höhe (Zeilen)

Syntax
lcd.begin(cols, rows)

Parameter
lcd: eine Variable vom Typ LiquidCrystal
cols: Anzahl der Zeichen (16, 20, 40…)
rows: Anzahl der Zeilen (1, 2, 4…)

Rückgabewert
keine

Beispiel
void setup()
{
lcd.begin(16, 2); // Display hat 16 Zeichen x 2 Zeilen
}
clear()
Beispiel-Sketch verfügbar: LCD.ino

Beschreibung
Löscht das Display und setzt den Cursor in die obere linke Ecke.

Syntax
lcd.clear()

Parameter
lcd: eine Variable vom Typ LiquidCrystal

Rückgabewert
keine

Beispiel
lcd.clear(); /Display löschen


home()
Beschreibung
Setzt den Cursor in die obere linke Ecke. Wird benutzt, um folgenden Text oben links beginnend
anzuzeigen. Soll das Display auch gelöscht werden, dann benutzen Sie den Befehl clear() stattdessen.

Syntax
lcd.home()

Parameter
lcd: eine Variable vom Typ LiquidCrystal

Rückgabewert
keine

Beispiel
lcd.home(); /Cursor links oben setzen


setCursor()
Beispiel-Sketch verfügbar: LCD.ino

Beschreibung
Setzt den Cursor an eine gewünschte Position. Also nicht links oben, wie beim Befehl home(), sondern an
eine beliebige Position. Dort wird der folgende Text beginnend angezeigt.

Syntax
lcd.setCursor(col, row)

Parameter
lcd: eine Variable vom Typ LiquidCrystal
col: Die Zeichen-Stelle, an welcher der Cursor gesetzt werden soll
row: die Zeile, in welcher der Cursor gesetzt werden soll

Rückgabewert
keine

Beispiel
lcd.setCursor(0, 1); // Cursor auf Position 1, Zeile 2 (0, 1) setzen

write()
Beschreibung
Schreibt ein Zeichen auf das Display.

Syntax
lcd.write(data)

Parameter
lcd: eine Variable vom Typ LiquidCrystal
data: das Zeichen, welches geschrieben werden soll

Rückgabewert
Eine Byte-Zahl: Wird NUR der Befehl write() ohne data benutzt, dann gibt er die Anzahl geschriebener
Bytes zurück. Aber das Lesen dieser Anzahl Bytes ist optional. Der Befehl dient primär dazu, Zeichen an
das Display zu senden.

Beispiel
void loop() //Hauptprogramm
{
if (Serial.available()) { //wenn Daten über die serielle Schnittstelle da sind
lcd.write(Serial.read()); // dann zeige sie an!
}
}

print()
Beschreibung
Druckt Text auf das Display

Syntax
lcd.print(data)
lcd.print(data, BASE)

Parameter
lcd: eine Variable vom Typ LiquidCrystal
data: die Daten, welche gedruckt werden sollen (Datentypen: char, byte, int, long, string)
BASE: optional, Die Basis, in welcher die Daten gedruckt werden sollen (BIN=binär,
DEC=dezimal, OCT=oktal, HEX=hexadezimal)

Rückgabewert
Eine Byte-Zahl: Wird NUR der Befehl print() ohne data benutzt, dann gibt er die Anzahl geschriebener
Bytes zurück. Aber das Lesen dieser Anzahl Bytes ist optional. Der Befehl dient primär dazu, Zeichen an
das Display zu senden.

Beispiel
lcd.print("hello, world!"); //…



cursor()
Beschreibung
Zeigt den Cursor an. Ein Unterstrich erscheint an der Stelle, an welcher dann der Text erscheint.
Das Gegenteil ist noCursor().

Syntax
lcd.cursor()

Parameter
lcd: eine Variable vom Typ LiquidCrystal

Rückgabewert
keine

Beispiel
lcd.cursor(); //Cursor anzeigen

noCursor()
Beschreibung
Versteckt den Cursor. Das Gegenteil ist cursor().

Syntax
lcd.noCursor()

Parameter
lcd: eine Variable vom Typ LiquidCrystal

Rückgabewert
keine

Beispiel
lcd.noCursor(); //Cursor verstecken

blink()
Beschreibung
Zeigt den blinkenden Cursor an. Wenn es benutzt wird in Verbindung mit cursor(), dann hängt das
Ergebnis von dem jeweils benutzten Displaytyp ab.

Syntax
lcd.blink()

Parameter
lcd: eine Variable vom Typ LiquidCrystal

Rückgabewert
keine

Beispiel
lcd.blink(); //Cursor anzeigen und blinken lassen



noBlink()
Beschreibung
Schaltet den blinkenden Cursor ab.

Syntax
lcd.noBlink()

Parameter
lcd: eine Variable vom Typ LiquidCrystal

Rückgabewert
keine

Beispiel
lcd.noBlink(); //Cursor blinken abschalten


display()
Beschreibung
Schaltet das Display ein, nachdem es durch noDisplay() abgeschaltet wurde. Es wird der Text und Cursor
wiederhergestellt, wie er vorher war.

Syntax
lcd.display()

Parameter
lcd: eine Variable vom Typ LiquidCrystal

Rückgabewert
keine

Beispiel
lcd.display(); //LCD einschalten


noDisplay()
Beschreibung
Schaltet das Display ab, ohne das der angezeigte Text verloren geht. Mit display() kann es wieder
eingeschaltet werden, und der vorher dargestellte Inhalt wird wieder angezeigt.

Syntax
lcd.noDisplay()

Parameter
lcd: eine Variable vom Typ LiquidCrystal

Rückgabewert
keine

Beispiel
lcd.noDisplay(); //LCD abschalten



scrollDisplayLeft()
Beschreibung
Schiebt den Inhalt des Displays (Text UND Cursor) um eine Stelle nach links

Syntax
lcd.scrollDisplayLeft()

Parameter
lcd: eine Variable vom Typ LiquidCrystal

Rückgabewert
keine

Beispiel
lcd.scrollDisplayLeft; // eine Stelle nach links


scrollDisplayRight()
Beschreibung
Schiebt den Inhalt des Displays (Text UND Cursor) um eine Stelle nach rechts

Syntax
lcd.scrollDisplayRight()

Parameter
lcd: eine Variable vom Typ LiquidCrystal

Rückgabewert
keine

Beispiel
lcd.scrollDisplayRight; // eine Stelle nach rechts


autoscroll()
Beschreibung
Schaltet das automatische Scrollen des Displays an. Diese Funktion erzwingt das Weiterschieben der
vorhergehenden Zeichen auf dem Display um eine Stelle, wenn ein neues Zeichen ausgegeben wird.
Wenn die aktuelle Textrichtung links-nach-rechts ist (Standardeinstellung), dann wird der Text um eine
Stelle nach links geschoben (gescrollt). Ist die Textrichtung rechts-nach-links, dann wird der Text um
eine Stelle nach rechts geschoben. Dadurch wird jedes neue Zeichen, welches an das Display gesendet
wird, an genau derselben Stelle angezeigt.

Syntax
lcd.autoscroll()

Parameter
lcd: eine Variable vom Typ LiquidCrystal

Rückgabewert
keine

Beispiel
lcd.autoscroll(); // Autoscroll einschalten


noAutoscroll()
Beschreibung
Autoscroll abschalten (siehe oben)

Syntax
lcd.noAutoscroll()

Parameter
lcd: eine Variable vom Typ LiquidCrystal

Rückgabewert
keine

Beispiel
lcd.noAutoscroll // Autoscroll aus



leftToRight()
Beschreibung
Setzt die Schreibrichtung des Displays auf links-nach-rechts, das ist die Standardeinstellung. Das
bedeutet, dass alle nachfolgend auf das Display gesendeten Zeichen von links nach rechts erscheinen. Es
hat keinen Einfluss auf bereits an das Display gesendete Zeichen.

Syntax
lcd.leftToRight()

Parameter
lcd: eine Variable vom Typ LiquidCrystal

Rückgabewert
keine

Beispiel
lcd.leftToRight(); //


rightToLeft()
Beschreibung
Setzt die Schreibrichtung des Displays auf rechts-nach-links. Das bedeutet, dass alle nachfolgend auf das
Display gesendeten Zeichen von rechts nach links erscheinen. Es hat keinen Einfluss auf bereits an das
Display gesendete Zeichen.

Syntax
lcd.rightToLeft()

Parameter
lcd: eine Variable vom Typ LiquidCrystal

Rückgabewert
keine

Beispiel
lcd.rightToLeft(); //


createChar()
Beschreibung
Erzeugt ein frei selbst zu erstellendes Zeichen. Bis zu maximal 8 verschiedene Zeichen (0 bis 7) von 5x8
Pixeln jeweils sind möglich. Das Aussehen jedes einzelnen Zeichens wird festgelegt durch ein Datenarray
von 8 Bytes, eines für jede Reihe von Pixeln.

Syntax
lcd.createChar(num, data)

Parameter
lcd: eine Variable vom Typ LiquidCrystal
num: welches Zeichen soll erstellt werden (0 bis 7)
data: die Pixeldaten des neuen Zeichens

Rückgabewert
keine

Beispiel
#include //LCD-Library einbinden

LiquidCrystal lcd(12, 11, 5, 4, 3, 2); // Pinbelegung LCD und Arduino

byte smiley[8 //erstellt Zeichen Smiley
B00000,
B10001,
B00000,
B00000,
B10001,
B01110,
B00000,
};

void setup() { //Setup, wird einmal durchlaufen.
lcd.createChar(0, smiley); //erstelltes Zeichen benutzen
lcd.begin(16, 2); //LCD definieren mit 16zeichen, 2 Zeilen
lcd.write(byte(0)); //Zeichen anzeigen
}

void loop() {} //Hauptprogramm


Sonderzeichen, Symbole und Umlaute
Beispiel-Sketch verfügbar: LCD_Char.ino

Allgemeines
Die LCD-Anzeigen können mehr, als nur einfachen Text anzuzeigen. Im Speicher des LCD-Moduls ist
ein ganzes Arsenal an zusätzlichen Zeichen abgespeichert. Das sind z.B. die deutschen Umlaute,
Sonderzeichen wie { } ° µ Ohm-Zeichen, und weitere Symbole etc. Um die Benutzung dieser Zeichen,
wie man sie darstellt und anzeigt, geht es in diesem Abschnitt. Danke hierfür an Gregor Hebeker (via E-
Mail), der mir diese Infos und auch ein .ino-File zur Verwendung in dieser Referenz zur Verfügung
stellte.

So ohne weiteres kann man keine Sonderzeichen oder Symbole mit lcd.print auf das Display bringen.
Man muss sich hierfür die integrierten Zeichen zu Nutze machen. Sie sind in einer Art Tabelle im LCD-
Display abgelegt und können über ihren hexadezimalen Code angezeigt werden.
Die nachfolgende Kurzübersicht zeigt die wichtigsten Sonderzeichen und ihren HEX-Code:

ä : \xE1
ö : \xEF
ü : \xF5
ß : \xE2
° : \xDF z.B. in °C (Grad Celsius)
μ : \xE4 z. B. in μF (Mikrofarad) oder μC (Mikrocontroller)
Ω : \xF4 das große Omega steht für die Einheit des Widerstandes (Ohm)
π : \xF7 Zahl PI (3,14…)
√ : \xE8 Quadratwurzel
∞ : \xF3 unendlich
∑ : \xF6 Summensymbol

Benutzung im Sketch
Nun wollen wir die Zeichen bei Bedarf auch korrekt auf dem Display anzeigen lassen.
Zur Anzeige des Grad-Zeichens bei einer Temperatur kann man es wie folgt machen:

lcd.print("Temp: " myTemp "\xDF" "C"); // °C mit Variable myTemp

Eine weitere Möglichkeit ist es, das gewünschte Zeichen vorher zu definieren. Das macht den Code auch
gleich einfacher lesbar. Hier am Beispiel des Ohm-Zeichens:

#define OHM "\xF4" // vor setup() einfügen
lcd.print( "480" OHM ); // Anzeige: 480 Ω

Das Wort "Datenübertragung" enthält ein ü.
ein Umlaut, der nicht ohne weiteres auf das LCD hingeschrieben werden kann.
Die Lösung wäre z. B. eine sogenannte Escape-Sequenz mit der Hexadezimalzahl F5:

lcd.print("Daten");
lcd.print("\xF5"); // das ist ein ü
lcd.print("bertragung");

oder kürzer und eleganter so:

lcd.print("Daten" "\xF5" "bertragung"); // Datenübertragung

Dieses seltsame "\xF5" ist wie folgt aufgebaut:

"": Anführungszeichen, da es sich um einen String handelt
\ : Backslash, da es sich um eine Escapesequenz handelt
x : wegen Hexadezimalzahl
F5: diejenige Hexadezimalzahl, die ein ü repräsentiert


EEPROM schreiben und lesen
Allgemeines
Im Programmfluss hat sicher schon jeder berechnete Werte, ausgelesene Sensoren, Zustand von
Eingangspins, Zeichen über den RS232-Port oder anderes im SRAM des ARDUINO zwischengespeichert, um ihn
später wieder zu verwenden. Oder etwas damit zu berechnen. Das geht prima, der SRAM ist auch mit 2048 Byte
bei einem Uno recht umfangreich. Das Speichern geht einfach von der Hand, man merkt davon nichts, der
Comiler kümmert sich darum. Es gibt nur einen Haken: Mit dem Wegfall der Versorgungsspannung verschwinden
diese gespeicherten Daten.
Was aber, wenn etwas dauerhaft gespeichert werden soll: Soll z.B. ein bestimmter Zustand, der nach
einschalten eingenommen werden soll bei einer Steuerung, eine ganz bestimmte Schaltstellung verschiedener
Relais, oder ein beim letzten Mal ausgelesener Wert soll nach Einschalten wieder weiterverarbeitet werden?
Eine solche dauerhafte Speicherung, auch ohne Betriebsspannung, ist unter Nutzung des sogenannten
EEPROM möglich. EEPROM heisst „elektrisch löschbarer und programmierbarer Nur-Lese-Speicher“ Seine
besondere Eigenschaft ist, das die gespeicherten Informationen auch ohne Spannungsversorgung erhalten
bleiben.
Sein Nachteil ist eine endliche Lebensdauer. Es kann jede Speicherzelle etwa 100.000-mal beschrieben
werden. Das garantiert der Hersteller. Danach geht es immer noch, aber nicht garantiert. Wen das näher
interessiert, der findet sicher Massen Infos im Netz. Aber man muss sich nicht mit unnützem Wissen belasten, bei
einigermaßen sinnvoller Programmierung werden wir die Lebensdauer des EEPROM nicht ausreizen.
Das klingt erst mal extrem viel… Ist es aber nicht. Wenn man eine solche Speicherung des EEPROM in die
loop() schreibt, sind die 100.000 Schreibzyklen nach wenigen Minuten verbraucht. Es ist also eine kluge
Programmierung erforderlich, sodass die Werte dort wirklich nur gespeichert werden, wenn es nötig ist. Und
nicht einfach immer wieder. Auch ist es sinnvoll, nicht immer alle Werte auf eine bestimmte Speicherstelle zu
schreiben, sondern eventuell diese Speicherstelle zu variieren, wenn sehr oft Werte geschrieben werden. So kann
man die Lebensdauer auch optimieren, falls erforderlich. Bei wenigen Werten und geringer Speicherrate ( selbst
einmal pro Stunde wäre kein Problem, eine garantierte Lebensdauer von mindestens 11 Jahren ist so drin)
Weiterhin dauert das Speichern der Werte im EEPROM relativ „lange“, etwa 3 Millisekunden. Das ist bei der
Programmierung zeitkritischer Anwendungen zu beachten.

Die EEPROM-Library
Es gibt natürlich eine Library zum Schreiben und Lesen des EEPROM, was die Benutzung relativ einfach macht.
Weitere Erklärungen zur Library gibt es bei [2 englischer Sprache. Besonders interessant finde ich den
Operator EEPROM[
. K
an
n
do
ch d
ies
er
g
enau
s
o
beha
n
d
elt
w
erden
w
i
e
ein
D
a
te
n-Array. Das macht es meiner
Meinung nach besonders einfach. Zum Datentyp Array siehe hier.
EEPROM.read()
Beschreibung
Liest ein Byte aus dem EEPROM. Speicherstellen, die niemals vorher beschrieben worden sind, haben den Wert
255.

Syntax
EEPROM.read(addresse);

Parameter
addresse: die Speicherstelle, von der gelesen werden soll, beginnend bei 0. (Datentyp int)

Rückgabewert
Der in der Speicherstelle “adresse” hinterlegte Wert (Datentyp byte) 0…255

Beispiel
#include
int x = 0; // Speicherzelle
int wert; // ausgelesener Wert

void setup()
{
Serial.begin(9600); // ser. Schnittstelle initialisieren
}

void loop(){
wert = EEPROM.read(x); // Wert aus Speicherzelle x an Variable wert geben

Serial.print("Speicherzelle Nr.: "); Serial.print(x); // alles anzeigen
Serial.print("\t"); Serial.print("Wert: "); Serial.print(wert); Serial.println();

x = x + 1; // nächste Speicherzelle
delay(50);
if (x == 255) while(1); // bei Speicherzelle 255 Programm stoppen
}

EEPROM.write()
Beschreibung
Schreibt ein Byte in eine Speicherzelle des EEPROM

Syntax
EEPROM.write(addresse, wert);

Parameter
adresse die Speicherzelle, in die geschrieben werden soll, beginnend mit 0 (Datentyp int)
wert der Wert, welcher in die Speicherzelle geschrieben werden soll (Datentyp byte)

Rückgabewert
Keiner

Beispiel
#include // Lib einbinden

void setup(){
for (int x = 0; x < 255; x++) // Speicherzelle 0...254 auswählen
EEPROM.write(x, x); // Speicherzelle 0...254 mit Wert 0...254 schreiben
}

void loop(){
// weiterer Code
}

EEPROM.update()
Beschreibung
Schreibt ein Byte in den EEPROM. Der Wert wird nur geschrieben, wenn er von dem bereits an dieser
Speicherzelle abgelegten Wert abweicht.

Syntax
EEPROM.update(addresse, wert);

Parameter
adresse die Speicherzelle, in die geschrieben werden soll, beginnend mit 0 (Datentyp int)
wert der Wert, welcher in die Speicherzelle geschrieben werden soll (Datentyp byte)

Rückgabewert
Keiner

Beispiel
EEPROM.update(5, 128); // schreibt den Wert 128 in Zelle 5 nur, wenn er
// nicht schon 5 ist.


EEPROM.put()
Beschreibung
Schreibt jeden beliebigen Datentyp oder Object (struct) in den EEPROM. Man muss sich nicht darum kümmern,
wieviele Speicherzellen belegt werden. Diese Methode funktioniert ähnlich der update()-Methode. Das heisst, der
Wert wird nur geschrieben, wenn er vom vorher geschriebenen abweicht.

Syntax
EEPROM.put(addresse, wert);

Parameter
adresse die Speicherzelle, in die geschrieben werden soll, beginnend mit 0 (Datentyp int)
wert der Wert, welcher geschrieben werden soll (jeder Datentyp, oder auch Object

Rückgabewert
Keiner

Beispiel
#include // Lib einbinden

void setup() {
Serial.begin(9600);

float x = 56.8453; // Variable zum Speichern
int addresse = 0; // Speicherstelle, wo gespeichert werden soll
EEPROM.put(addresse, x); // schreibt (updated) den Wert in Speicherstelle
addresse += sizeof(float); // eine Speicherstelle hinter das Ende von float x
springen
EEPROM.put(addresse, "Hallo Hans");
}

void loop(){
// weiterer Code
}


EEPROM[
Beschreibung
Mit dieser Methode können EEPROM-Speicherzellen beschrieben werden, als wären sie ein Daten-Array.

Syntax
EEPROM[addresse

Parameter
adresse die Speicherzelle, in die geschrieben werden soll, beginnend mit 0 (Datentyp int)

Rückgabewert
Der Wert der Speicherzelle

Beispiel
wert = EEPROM[ 0 // Liest den Wert aus Speicherzelle 0
EEPROM[ 0 wert; // Schreibt wert in Speicherzelle 0

Timer-Interrupts und deren Benutzung
Allgemeines
Quelle: [6
Die hier beschriebene Verfahrensweise basiert auf der Library „Timer1“. Diese wie auch die
Beschreibung in Englisch, kann von [6

he
runte
rg
e
l
a
de
n
w
e
rde
n.
Die
se

Anle
it
ung

e
ntst
a
nd
d
a
he
r,
we
il

ich von BASCOM her diese Herangehensweise kenne. Durch Verwendung des Timers1 können einfach
Programmanweisungen nach einer genau definierten Zeit ausgeführt werden.
Beispiele hier sind das Blinken von Anzeige-LEDs, Sekunden-Timer, etc.

Die Library ist eine Sammlung von Routinen zur Einrichtung des 16Bit-Hardware-Timers, genannt
Timer1 beim ATMega 168/328. Es gibt 3 verschiedene Hardware-Timer bei diesem Chip. Diese können
auf verschiedene Art konfiguriert werden, um eine ganze Reihe von Funktionen zu erreichen. Die
Entwicklung dieser Library begann ursprünglich, um die PWM-Periodendauer oder PWM-Frequenz
einfach und schnell zu verändern. Sie ist aber immer mehr gewachsen und beinhaltet nun auch Timer-
overflow-Interrupts und andere Features.

Die Genauigkeit der Zeiten des Timers hängen vom Prozessortakt (beim ARDUINO 16MHz) und des
Vorteilers ab. Dieser Vorteiler, genannt Prescaler, kann auf die Werte 1, 8, 64, 256 oder 1024 eingestellt
werden.

Für 16MHz:
Prescaler Time per Counter-Tick Max. Dauer
1 0.0625 uS 8.192 mS
8 0.5 uS 65.536 mS
64 4 uS 524.288 mS
256 16 uS 2097.152 mS
1024 64uS 8388.608mS
Berechnung:
 Max. Dauer = (Prescaler)*(1/Frequenz)*(2^17)
 Time per Tick = (Prescaler)*(1/Frequenz)

Verwendung des Timer1
Als erstes muss die folgende Zeile an den Programmanfang eingefügt werden:

#include //Library einbinden

Dann muss im Setup() der Timer1 konfiguriert werden:

Timer1.initialize(100000); // Timerlänge 100.000µsek (0,1 sek)
Timer1.attachInterrupt( timerIsr ); // ISR aufrufen

Hinter Timer1.initialize muss die Zeit in Mikrosekunden angegeben werden. Das ist das Intervall,
indem die Interrupt-Service-Routine (ISR) aufgerufen wird. Diese wird dann als Funktion aufgerufen und
muss den unter Timer1.attachInterrupt angegebenen Namen haben.


Beispiel:

#include

void setup()
{
pinMode(13, OUTPUT); // LED auf dem Board
Timer1.initialize(100000); // Timerlänge 0,1sek
Timer1.attachInterrupt( timerIsr ); // ISR aufrufen
}

void loop()
{
// Haupprogrammschleife
// TODO: Eigenes Programm hier rein
}

/// ------------------------------------
/// Eigene ISR Timer Routine
/// ------------------------------------
void timerIsr()
{
digitalWrite( 13, digitalRead( 13 ) ^ 1 ); // Toggle LED
}


Hinweise:
Die Benutzung dieser Library kann die Benutzung der Servo-Library unmöglich machen. (gemäß Quelle
[6
,
von
mi
r
nicht
g
e
te
stet).
Die
se

L
ibra
r
y

ha
t

noc
h
we
it
e
r
e

F
unkti
on
e
n,
be
i
I
nter
e
sse
bit
te
se
lbst

nachschauen.

Auch erzeugt die Benutzung der Library zusätzlichen Code (genannt „Overhead“). Dies gilt übrigens für
jegliche Libraries. Die Funktionen einer Library, welche man nicht benutzt, belegen dennoch
Speicherplatz im ARDUINO. Wenn der Speicherplatz knapp ist, kann das eventuell ein Problem werden.
Also nur einsetzen, wenn es auch gebraucht wird. Profis entfernen in so einem Fall die zusätzlichen, nicht
benötigten Funktionen in einer Library, oder benutzen erst gar keine.

Die erzielbare Genauigkeit ist für die meisten Funktionen ausreichend. Eine genaue Uhr kann man aber
hiermit nicht programmieren. Dafür sollte dann eine temperaturkompensierte RTC (DS3231), DCF77,
GPS oder NTP verwendet werden. Man kann aber die Genauigkeit durch anpassen des Wertes bei
Timer1.initialize noch erhöhen. Über die Notwendigkeit muss jeder selbst entscheiden, ich empfehle
eine temperaturkompensierte RTC mit dem Chip DS3231. Diese arbeitet sehr zuverlässig, hochgenau und
ohne Empfangsprobleme wie bei einer DCF77-Uhr

Taster und deren Benutzung

Anschließen von Tastern
Beim Anschließen von Tastern gibt es zwei verschiedene Möglichkeiten. Möglichkeit eins wäre vom ARDUINO-Pin
nach Masse (GND) und Variante zwei vom ARDUINO-Pin nach +5V. Beide Varianten führen zum Ziel. Beim
Programmieren muss man lediglich wissen, welche der beiden Varianten man in seiner Schaltung verwendet.
Sonst kann die Funktion genau umgekehrt sein, als man erwartet…

Taster nach GND
Ich persönlich (und die meisten Elektroniker) bevorzugen diese Variante. Dies hat unter Umständen Vorteile, man
kann den einen Anschluss des Tasters direkt an ein (metallisches) Gehäuse klemmen und auch gegenüber
Störungen ist diese Variante besser. Vom ARDUINO-Pin sollte auch noch ein sogenannter Pullup-Widerstand nach
+5V geschaltet werden. Der Wert ist unkritisch und kann zwischen 5kOhm und 20kOhm liegen.
Es können auch die internen Pullup-Widerstände des ARDUINO verwendet werden. Jedoch haben nicht alle Pins
diese Möglichkeit. Man umgeht durch den geringen Mehraufwand eines externen Widerstandes etwaige
Probleme oder unerwartete Schaltfunktionen, damit Ärger und Frust. Die Verwendung des internen Pullup wird
hier, hier und hier in der Referenz behandelt.
Drückt man nun diesen Taster, dann geht der Pegel am ARDUINO-Pin von HIGH nach LOW. Das nennt der
Elektroniker „low-aktiv“. Im Programm muss also gehandelt werden, wenn der Pin auf LOW geht.
Das ist absolut wichtig und muss im Programm bedacht werden.

Taster nach +5V
Bei dieser Variante ist der Taster vom ARDUINO-Pin nach +5V geschaltet. Der Widerstand ist demzufolge vom
ARDUINO-Pin nach Masse und nennt sich hier logischerweise Pulldown-Widerstand. Eine Benutzung des internen
Pullup-Widerstandes ist bei dieser Variante nicht möglich.
Der Vorteil ist für den Elektronik-Laien der, das die Schaltlogik positiv ist. Das heißt, beim Drücken des Tasters
geht der Pegel von LOW nach HIGH am ARDUINO-Pin, man nennt das „high-aktiv“. Vielen Anfängern erscheint das
einfacher. Hier muss im Programm gehandelt werden, wenn der ARDUINO-Pin auf HIGH geht.
Das ist absolut wichtig und muss im Programm bedacht werden.
Ich empfehle die Benutzung der ersten Variante.

Benutzung von Tastern mit Interrupts
In einigen Fällen kann es erforderlich sein, SOFORT auf das Drücken eines Tasters zu reagieren. Bei sehr
einfachem Programmablauf reicht dafür das Abfragen des Tasters im loop(). Oft sind aber Programme länger,
haben zeitintensive Vorgänge (z.B. das Auslesen eines DS18B20-Sensors), oder springen in Unterprogramme.
Dann kann das Abfragen des Tasters schwierig werden. Das äussert sich darin, das auf einen Tasterdruck keine,
oder nur eine verspätete Reaktion erfolgt.
Um diese Probleme zu umgehen, kann man sich der Interruptfunktion bedienen. Klingt erst mal kompliziert, ist es
aber gar nicht.
Der ARDUINO UNO und auch der NANO (auch andere haben sowas, gegebenenfalls nachlesen) haben digitale
Pins, welche fähig sind, als externe Interruptquelle zu dienen. Das sind ganz bestimmte Pins, hier die digitalen Pin
2 und Pin 3. Andere Pins funktionieren dafür nicht! Es ist also ratsam, beim Entwurf eines Projektes mit ARDUINO,
wenn Taster verwendet werden sollen, von vorn herein diese schon an die Pins 2 und 3 anzuschliessen. Wenn es
mehr als zwei Taster sind, dann auf jeden Fall die beiden Pins mit nutzen. Wenn man ein Interrupt braucht, muss
man nicht erst alles umändern, sondern braucht einfach nur das Programm danach anpassen.

Aber wie gehen wir nun vor? Die Taster werden gemäß der vorhergehenden beiden Kapiteln „Taster nach GND“
oder „Taster nach +5V“ angeschlossen. Entsprechend der beiden, komplett verschiedenen, Varianten muss nun
die entsprechende Variante für das Interrupt gewählt werden. Diese Anweisung kommt in das setup():

attachInterrupt(0, interruptRoutine, HIGH); // INT0 für Taster nach +5V an Pin 2
oder
attachInterrupt(0, interruptRoutine, LOW); // INT0 für Taster nach GND an Pin 2

Für den anderen Interruptpin Pin 3 sind die Anweisungen so:

attachInterrupt(1, interruptRoutine, HIGH); // INT1 für Taster nach +5V an Pin 2
oder
attachInterrupt(1, interruptRoutine, LOW); // INT1 für Taster nach GND an Pin 2


Entprellen von Tastern
Allgemeines
Quelle: [8
Tasten sind wichtige Eingabeorgane an Mikrocontrollern. So auch an ARDUINO’s. Allerdings haben
mechanische Tasten ein gravierendes Problem, bekannt als „Prellen“. Dieses Prellen äußert sich darin,
das beim einmaligen Drücken eines Tasters dieser in Wahrheit mehrfach, unvorhersehbar oft, geöffnet
und geschlossen wird. Dieses passiert sehr schnell und ist nach wenigen Millisekunden vorbei. Der
Bediener bemerkt davon nichts. Aber der Mikrocontroller ist viel schneller und registriert jede „Pseudo-
Betätigung“ des Tasters. So kommt es zu unvorhersehbaren Funktionen, die nicht gewollt sind.
Daher muss der Taster entprellt werden. Dies kann mittels zusätzlichen Bauteilen oder auch per Software
geschehen.

Um das Entprellen per Software in diesem Fall durchzuführen, ist die Library „Bounce2“ erforderlich,
welche auch bei [8

he
runte
rge
lade
n

we
rde
n
k
a
nn
.
S
ie
ist

in
de
n
L
ib
ra
r
y-Ordner zu installieren, oder per
ARDUINO-DIE einzubinden.

Die Library hat mehrere Funktionen. Ich beziehe mich hier nur auf die einfache Entprellung eines Tasters.
Gegebenenfalls die Beispiele anschauen, um die anderen Funktionen kenn zu lernen. Aber die Benutzung
eines Tasters stellt eigentlich die Standard-Anwendung dar.


Verwendung der Debounce-Library
Als erstes ist es nötig, die Bounce-Library zu initialisieren. Dies geschieht VOR der setup()-Funktion:

Bounce debouncer = Bounce(); // Lib Init

Die weiteren wichtigen Dinge geschehen in der setup()-Funktion, entnommen aus Beispiel:

void setup() {
pinMode(BUTTON_PIN,INPUT); // Taster einbinden
digitalWrite(BUTTON_PIN,HIGH); // internen PullUp-Widerstand aktivieren

debouncer.attach(BUTTON_PIN); // Debouncer dem Taster zuordnen
debouncer.interval(5); // Entprellzeit in msec (5 Milli-Sek.)

pinMode(LED_PIN,OUTPUT); // LED einbinden
}

Um den Taster verwenden zu können, muss er natürlich regelmäßig (oft genug) abgefragt werden.
Ansonsten entstehen unschöne Verzögerungen und Verwirrung, wenn der Taster nicht reagiert beim
Drücken. Also die folgenden Befehle am besten im loop() unterbringen, damit er immer wieder
durchlaufen wird.

debouncer.update(); // Debouncer updaten

int value = debouncer.read(); // Wert abfragen

Nun ist der aktuelle Wert des Tasters (logisch HIGH oder LOW) bekannt. Jetzt kann mit dem Programm
darauf reagiert werden, was gemacht werden soll.

if ( value == HIGH) {
digitalWrite(LED_PIN, HIGH );
}
else {
digitalWrite(LED_PIN, LOW );
}

Entprellen mit zusätzlichen Bauteilen
Ich komme ursprünglich aus der analogen Elektronik.
Warum nicht auch einen Taster mittels herkömmlicher
Elektronik entprellen? Bauteile kosten heutzutage fast
nichts mehr…
So kam es zu dieser kleinen Zusatzschaltung, die mit
drei weiteren Bauteilen auskommt, plus des natürlich
notwendigen Tasters. Es wird ein sogenannter
Schmitt-Trigger eingesetzt, einfach ausgedrückt ein
Schwellwertschalter. Ich möchte komplizierte
Erklärungen weglassen, wen es interessiert kann im
Netz alles finden. Nur soviel: Durch Drücken des
Tasters wird ein Zeitglied aus Kondensator und
Widerstand entladen oder geladen. Bei einem
bestimmten Ladezustand des Kondensators schaltet
der Schwellwertschalter schlagartig von LOW auf
HIGH oder umgekehrt. Diese zeitabhängige Funktion
nutzen wir zum Entprellen.

Der verwendete Schaltkreis ist ein 7414, welcher für ein paar Cent zu erwerben ist. Er enthält sechs
Schmitt-Trigger, kann also auch maximal sechs Taster bedienen! Er ist so billig, dass sein Einsatz auch
bei nur einem Taster gut ist. Die anderen fünf Schmitt-Trigger nutzt man eben nicht.

Ich benutze immer diese Variante, meine Projekte haben genug Platz für drei zusätzliche Bauteile (oder
eben 13, wenn man alle sechs Schmitt-Trigger benutzt). Die Schaltung ist absolut betriebssicher, und man
braucht keinen Speicherplatz für die Debounce-Library.
Eine einfache Abfrage des entsprechenden Tasters mittels analogRead oder per Interrupt reicht völlig aus,
auch die Benutzung mit Mehrfachfunktionen (nächstes Kapitel) geht einwandfrei.

Mehrfachfunktionen mit Tastern (Doppelklick, langer
Klick etc.)
Ein Taster ist sicher das am meisten benutzte Eingabe-Organ am ARDUINO. Es gibt noch andere, gute Eingabe-
Organe, z.B. den Dreh-Encoder. Aber Taster sind einfach, billig und vielseitig anwendbar.
Noch besser werden sie, wenn man Mehrfachfunktionen benutzen kann. Hier kommen im Speziellen der einfache
Klick, der Doppelklick und der lange Klick zur Anwendung. Beim langen Klick gibt es die Möglichkeit, wiederholte
Aktionen auszuführen, so lang der Taster gedrückt ist, oder nur eine am Ende des Klickes.

Am einfachsten geht das wieder mit einer Library…
Ein Entprellen ist hier nicht extra notwendig.

Benutzung der Library OneButton
Quelle: [13
Die oben beschriebenen Tasterfunktionen lassen sich sehr einfach mit der Library „OneButton“ realisieren.
Ich habe diese Library schon mehrfach in eigenen Projekten benutzt, es macht richtig Spaß mit so wenig
Programmieraufwand tolle Funktionen zu realisieren.
Als erstes muss die Library natürlich in die IDE eingebunden werden, dies geschieht am besten mit dem
Bibliotheksverwalter der IDE. Danach kann die Library mit den folgenden Befehlen in den Sketch eingefügt
werden und alle Funktionen stehen dann zur Verfügung.

#include "OneButton.h" // Lib einbinden
OneButton button1(A1, true); // Taster an Pin A1 anschliessen

In diesem Fall wird der Taster vom Pin A1 nach GND (Masse) angeschlossen. Zusätzlich sollte noch ein Widerstand
etwa 5k bis 10k nach +5V geschalten werden. Das wird hier genau erklärt.

Im setup(); ist noch zu deklarieren, welche Tasterfunktionen wir nutzen wollen und welches Unterprogramm dann
angesprungen werden soll. Dies geschieht so:

button1.attachClick(click);
button1.attachDoubleClick(doubleclick);
button1.attachDuringLongPress(longPress);
button1.attachLongPressStop(longPressStop);

Damit der (oder auch mehrere) Taster regelmäßig abgefragt wird, muss im loop(); der Befehl

button1.tick(); // Abfrage Taster

eingefügt werden. Erkennt diese Funktion ein Drücken des Tasters, dann wird durch die Library analysiert, welche
Funktion der Taster ausführt, also einfacher Klick, Doppelklick etc. Dies geschieht ohne unser Zutun automatisch.
Die von uns gewünschten Programmfunktionen bei dem entsprechenden Klick müssen dann in die von der Library
vorgegebenen Methoden eingefügt werden:

Einfacher kurzer Klick
In die folgende Methode wird unser gewünschter Code eingefügt, was bei einem kurzen Klicken des Tasters
ausgeführt werden soll:

void click() {
Serial.println("Button 1 einfacher Klick.");
digitalWrite(led, HIGH); // LED an
// weiterer Code
} // end click

Doppelklick
Ein Doppelklick sind zwei kurz hintereinander durchgeführte Klicks, ähnlich wie beim Computer ein Doppelklick
mit der Maus. Der auszuführende Code kommt in diese Methode:

void doubleclick() {
Serial.println("Button 1 Doppelklick.");
digitalWrite(led_gruen, HIGH); // grüne LED an
// weiterer Code
} // end doubleclick

Langer Klick wiederholte Funktion
Wird der Taster gedrückt und gehalten, so wird diese Funktion immer wieder aufgerufen, solange man den Taster
gedrückt hält. Das kann sehr vorteilhaft genutzt werden, um einen Zähler hoch- oder runter zu zählen.

void longPress() {
Serial.println("Button 1 langer Klick mehrfach...");
zaehler ++; // Zähler um eins erhöhen
if zaehler == 100 then zaehler = 0;
} // end longPress


Langer Klick einfach
Wird der Taster lang gedrückt und gehalten, dann wird NACH dessen Loslassen die folgende Funktion ausgeführt.
Es gibt auch eine Funktion, die arbeitet ähnlich, nur wird hier die Funktion schon ausgeführt, wenn die Zeit für
einen langen Klick abgelaufen ist. Bei ersterer wird lediglich noch gewartet, bis der Taster wieder losgelassen
wird. Welche der Funktionen man nutzt, ist den eigenen Vorlieben überlassen, ich benutzte immer diese hier:

void longPressStop() {
Serial.println("Button 1 langer Klick einfach");
digitalWrite(led2; HIGH); // LED2 an
} // end longPressStop


RTC-Uhr und deren Benutzung
Allgemeines
Quelle: [14
Vielfach besteht im fertigen Gerät oder Projekt das Erfordernis, eine Uhrzeit zu haben, anzuzeigen oder zu
bestimmten Uhrzeiten eine Funktion auszuführen. Beispiele wären automatische Alarmanlagen,
Türverriegelungen, Hühnerstall-Steuerungen usw. …
Nun gibt es mehrere Möglichkeiten, die Uhrzeit zu gewinnen, jeweils mit Vor- und Nachteilen. Eine von mir
bevorzugte Variante ist das Benutzen einer sogenannten temperaturkompensierten „Real Time Clock“, kurz RTC
genannt. Sie besteht aus einer kleinen Platine, auf dieser befinden sich der RTC-Schaltkreis, ein paar Bauteile
sowie eine Batterie. Diese Batterie versorgt die Platine über viele Jahre mit Strom, die typische Lebensdauer einer
solchen Batterie ist zwischen 5 Jahren und mehr als 10 Jahren. Dies dürfte für die meisten Fälle ausreichen. Und
wenn nicht, kann man die Batterie immer noch wechseln. Manche RTC-Platinen besitzen auch einen Akku, sodass
mit jedem Benutzen des Gerätes dieser aufgeladen wird. Das verlängert die Lebensdauer noch weiter.

Weitere Möglichkeiten für die Gewinnung der Uhrzeit:

1. Prozessortakt  extrem ungenau, Uhrzeit bei Abschalten der Stromversorgung weg
2. DCF77  oft Empfangsprobleme, Code umfangreich, hochgenau
3. NTP  Netzwerkanschluss erforderlich, hochgenau
4. GPS  Empfangsprobleme in Gebäuden, Stromverbrauch hoch, hochgenau
5. Billige RTC  keine Temperaturkompensation, daher extrem ungenau

Ich habe schon alle Varianten ausprobiert, geblieben bin ich bei der temperaturkompensierten RTC mit dem
Schaltkreis DS3231. Sie ist sehr genau, spottbillig aus Fernost zu beziehen und einfach zu programmieren. Um die
Benutzung dieser RTC geht es hier.

Die RTC DS3231
Die Genauigkeit ist sicher als erstes von Interesse. Wir neigen ja immer dazu, alles so genau wie möglich zu
machen, obwohl das meistens mit Problemen behaftet ist. Laut Datenblatt hat dieser Chip eine Gangabweichung
von +/- 2 Minuten pro Jahr im Temperaturbereich von -40°C bis +85°C. Vier Minuten Abweichung im Jahr klingt
erst mal „unakzeptabel viel“… Damit kann man ja GAR NICHT leben!

ABER: Dieser Wert bezieht sich auf den gesamten Temperaturbereich und ist der schlechteste garantierte Wert!
Die realen Werte sind viel besser. Und in welchem Gerät herrschen schon solche Temperaturunterschiede.
Meistens bewegen sich die Temperaturen so zwischen 20°C und 35°C, ein Bruchteil des Datenblattes. Dadurch
wird die Genauigkeit wesentlich besser, deutlich unter einer Minute pro Jahr.
Ich habe es mal bei einem Gerät über 5 Monate beobachtet und konnte KEINE Abweichung feststellen, jedenfalls
keine messbare. Und weil der normale ARDUINO-Bastler vermutlich kein Atom-Physiker ist, wird er wohl mit der
Abweichung von einigen Sekunden im Jahr leben können, oder? Wenn nicht, dann siehe „weitere Möglichkeiten“.

Das RTC-Modul DS3231 besitzt wie schon erwähnt eine Batterie zum Betrieb der Schaltung auch dann, wenn das
Gerät abgeschaltet ist. Es werden das Datum, Uhrzeit in 12h/24H-Format, der Wochentag, Schaltjahr-Automatik
und auch zwei Alarmzeiten bereitgestellt. Das erfüllt alle Wünsche.
Die Sommerzeit und Winterzeit wird im Programm durch ein paar Codezeilen korrekt dargestellt.

Wie schon fast vermutet, arbeite ich wieder mit einer Library. Der Mensch ist bequem, und bequemer geht es
kaum. Ich verwende die Library aus Quelle [14

D
e
s W
eite
ren
w
ird
die
Time-Library benötigt und die Wire-
Library zum abfragen des I2C-Busses, welche die RTC benutzt. Diese können mit dem Bibliotheksverwalter der IDE
eingepflegt werden, wenn dies nicht schon geschehen ist.
Beschaltung
Das wichtigste hierbei ist die korrekte Beschaltung der kleinen RTC-Platine, welche durchaus einen Fallstrick
beinhalten kann. Also aufpassen. Im schlimmsten Fall geht es nicht, zerstören kann man die Platine nur bei
groben Fehlern, etwa Falschpolung der Betriebsspannung.

Auf der RTC-Platine gibt es meistens einen vierpoligen Steckverbinder. Dieser hat die folgenden Anschlüsse:

+5V DC Versorgungsspannung, wird mit wenigen mA belastet
GND Masse
SDA Datenleitung
SCL Clock-Leitung

SDA und SCL sind die wichtigen Leitungen, mit denen die Kommunikation mit dem Chip erfolgt. Die Schnittstelle
heißt „I2C“. Bei Interesse kann hier im Netz gelesen werden. Die richtige Kommunikation wird durch die Library
„wire“ sichergestellt. Diese beiden Leitungen brauchen einen sogenannten Pullup-Widerstand jeweils nach +5V.
Auf den meisten RTC-Platinen ist dieser Widerstand schon drauf, also mal schauen oder lesen ob das der Fall ist.
Kann man diese Info nicht herausfinden, einfach das Modul anschließen und schauen, ob es geht. Wenn nicht,
dann je einen Widerstand 4,7kOhm von SDA nach +5V und einen von SCL nach +5V schalten.

Die beiden Leitungen SDA und SCL müssen auch an einen festgelegten Pin des ARDUINO, sonst geht nichts!
SDA an A4 und SCL an A5. Natürlich GND mit GND des ARDUINO verbinden, genauso wie auch die +5V.
Dann steht der Uhrzeit im ARDUINO nichts mehr im Wege…

Benutzung der Library
Als erstes müssen diese drei Zeilen in den Sketch oberhalb setup(); eingefügt werden:

#include
#include
#include

Damit werden die benötigten Libraries eingebunden. Im setup(); ist dann die folgende Zeile notwendig. Damit
wird durch die Library alle 5 Minuten die RTC ausgelesen und die time-Variable aktualisiert. So ist eine sehr
genaue Zeit immer gewährleistet.

setSyncProvider(RTC.get); // time alle 5 Minuten mit RTC syncen

Nun steht jederzeit die aktuelle Uhrzeit und Datum in den Variablen stunde, minute(), second(), day(), month(),
year(), weekday() zur Verfügung und kann im eigenen Programm verwendet werden. Je nach Anzeigevariante
(seriell, LCD, 7-Segment, Grafikdisplay mit den entsprechenden Codezeilen. Auch eine Weiterverarbeitung zwecks
Funktionen zu einer bestimmten Zeit ist einfach möglich. Hier nur mal exemplarisch ein paar Beispiele:

lcd.print(stunde); // Anzeige auf LCD
lcd.print(":");
lcd.print(minute());
lcd.print(":");
lcd.print(second()); // Achtung! Noch Formatierung (Vornull) erforderlich

if (stunde == 10 && minute() == 15) // tue etwas um 10:15 Uhr

Weitere Infos zu den verfügbaren Variablen der Time-Funktion des ARDUINO sind unter
http://playground.arduino.cc/Code/time zu finden.


Sommer- / Winterzeit Berechnung
Die RTC speichert nur eine Uhrzeit, sinnvollerweise benutzt man hierzu die Winterzeit.
Doch was ist bei der Sommerzeit? Kein Problem, dafür gibt es eine Formel, mit der man berechnen kann, wann
Sommerzeit aktiv ist. Im Internet findet man unzählige Beispiele dazu, auch in ARDUINO oder C/C++.
(Genaue Quelle unbekannt, weil an vielen Stellen im Netz zu finden)

boolean sommerzeit() // gibt TRUE (Sommerzeit) oder FALSE (Winterzeit) zurück
{
if (month()<3 || month()>10) return false; // keine Sommerzeit in Jan, Feb, Nov, Dez
if (month()>3 && month()<10) return true; // Sommerz. in Apr, Mai, Jun, Jul, Aug, Sep
if (month()==3 && day()<25) return false; // keine Sommerzeit bis 25.Maerz
if (month()==10 && day()<25) return true; // Sommerzeit bis 25.Okt.
if (month()==3 && (hour() + 24 * day())>=(1 + 24*(31 - (5 * year() /4 + 4) % 7))
|| month()==10 && (hour() + 24 * day())<(1 + 24*(31 - (5 * year() /4 + 1) % 7)))
return true;
else
return false;
}

Diese Funktion einfach im Programm außerhalb loop(); eingefügt, kann benutz werden, um abzufragen, ob
Sommerzeit oder Winterzeit ist. Mit dem folgenden Code im Programm, wenn die Zeit ermittelt oder angezeigt
werden soll, kann einfach darauf reagiert werden, ob die Stunde korrigiert werden muss oder nicht.

if (sommerzeit() == true) {
stunde = hour() + 1;
if(stunde == 24) stunde = 0; // damit korrekt 0 Uhr angezeigt wird
}
else{ Stunde = hour(); }


Temperatursensoren und deren
Benutzung
Allgemeines
Die Messung und Anzeige von Temperaturen gehört sicher zu den interessantesten Anwendungen, die
man in seine Programme einfügen möchte. Ebenso kann man dann, wenn man erst mal die Temperatur
kennt, im Programm in geeigneter Weise darauf reagieren. Zum Beispiel einen Lüfter einschalten, eine
Warn-LED oder Pieper, oder auch das zu warme Teil abschalten. Ich selbst habe schon mehrere Uhren
mit großen LED-7-Segmentanzeigen gebaut, die auch die Temperatur alle 40 Sekunden für 10 Sekunden
anzeigen.

Nun kommen wir zum „WIE“… Es gibt etliche, teilweise grundverschiedene Sensoren, die man
verwenden kann. Sie sind von ganz billig bis teuer zu haben, von weniger genau bis hochpräzise.
Ich beschränke mich hier auf drei Typen: Einmal einen Sensor (DS18B20 / DS18S20 / DS1820), der mit
einem Eindraht-Bus arbeitet und wo dadurch mehrere Sensoren an einem einzigen ARDUINO-Pin
angeschlossen werden können. Zum anderen auf einen Typ (MCP9700), welcher eine der Temperatur
proportionale, lineare Gleichspannung ausgibt. Der dritte ist der LM75, er arbeitet mit dem I2C-Bus.
Alle sind sehr preiswert, die letzten beiden im Centbereich, und einfach anzuwenden. Wir werden die
beiden ersten hier in diesem Kapitel behandeln.
Den letzten, den Sensor LM75, welcher mit dem I2C-Bus arbeitet, werde ich im Kapitel „Der I2C-Bus
und seine Benutzung“ behandeln.

DS18B20 / DS18S20 (1wire-Bus-Sensor)
Bei diesem Sensor handelt es sich um einen komfortabel anzuwendenden Temperatursensor der Fa.
Dallas, dessen Datenblatt unter Quelle [16
a
nz
use
he
n ist
, ode
r e
infa
c
h se
lb
st i
m Ne
tz
suc
he
n.

Die großen Vorteile dieser Sensoren sind:

- Großer Temperaturbereich -55°C bis +125°C
- Kein Abgleich erforderlich
- Einfach zu verdrahten dank Eindrahtbus
- Viele Sensoren gleichzietig an einem einzigen ARDUINO-Pin benutzbar

Der Sensor arbeitet mit dem sogenannten 1wire-Bus. Zur Benutzung dessen gibt es eine komfortable
Library, oder besser zwei. Wer hätte das gedacht…? Die beiden Libraries, auf die ich mich hier beziehe,
sind OneWire und DallasTemperature. Beide sind komfortabel über den Bibliotheksverwalter der IDE
einzubinden.
Anschliessen des Sensors
Ist das geschehen, muss nur noch der Sensor (oder mehrere) korrekt an den ARDUINO
angeschlossen werden. Hier ist etwas zu beachten, sonst geht es nicht: Es muß ein
sogenannter „PullUp-Widerstand“ vom Data-Pin des Sensors nach +5V geschaltet
werden. Das ist schon alles. Das sieht dann so aus, siehe meine künstlerische Skizze.
Möchte man mehrere dieser Sensoren gleichzeitig nutzen, so sind diese einfach parallel
zu schalten. Einen weiteren Widerstand 4,7k braucht man dann nicht! Einfach die
weiteren Sensoren parallel zu dem ersten anschliessen. Das wars! Kommen wir nun zur Programmierung.


Programmierung
Hierzu sei der Beispiel-Sketch „Simple“ aus der Library DallasTemperature zum ersten Testen
empfohlen. Auf diesen beziehe ich mich hier größtenteils.
Im eigenen Sketch müssen natürlich die beiden Libraries eingebunden werden.

#include
#include

Als nächstes wird dem Compiler mitgeteilt, an welchem digitalen Pin der Sensor angeschlossen ist:

#define ONE_WIRE_BUS 2 // Sensor DS18B20 an digitalem Pin 2

Nun werden die Libraries intialisiert mit den folgenden beiden Anweisungen:

OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);

Im setup() muss die Library gestartet werden.

sensors.begin();

So, das war eigentlich alles, damit das Programm vorbereitet ist zum erfolgreichen Abfragen der
Temperaturen. Wann dieses geschieht, liegt in den Vorlieben des Programmierers. Mir persönlich reicht
es, wenn maximal 1mal pro Minute die Temperatur abgefragt wird.
Weiterhin ist zu bedenken, das die Sensoren relativ lange brauchen, um die Temperatur abzufragen und
zu verarbeiten: bis zu 750ms. Das ist in ARDUINO-Programmen eine halbe Ewigkeit! Wenn man
zeitkritische Dinge im Programm laufen hat, z.B. Tasterabfragen, sind diese dann per Interrupt zu lösen
(siehe hier). Sonst erfolgt unter Umständen keine Reaktion auf den Tastendruck. Auch bei anderen
Programmfunktionen ist diese lange Zeit eventuell ein Problem und man muss sich genau überlegen, wie
man das Problem löst.
An geeigneter Stelle (oder auch in einer separaten Funktion) wird nun die Abfrage mit dem folgenden
Befehl vorbereitet:

sensors.requestTemperatures(); // Temperatur holen

Der folgende Befehl übergibt den Wert des Sensors an eine float-Variable:

float temp = sensors.getTempCByIndex(0);

Die Zahl (0) bedeutet, dass der erste Sensor ausgelesen wird, wenn es mehrere sind. Will man den
zweiten auslesen, kann man das mit (1) machen usw. Auch eine for-Schleife ist denkbar, bei vielen
Sensoren.
Meine maximale Anzahl von Sensoren an einem Projekt waren bisher 2 Stück, da ist es am einfachsten,
man macht es so:

float temp0 = sensors.getTempCByIndex(0);
float temp1 = sensors.getTempCByIndex(1);

Dann stehen die beiden Werte als Fliesskommazahl in den Variablen temp0 und temp1 zur weiteren
Verarbeitung zur Verfügung. Man kann sie anzeigen, auf bestimmte Wert reagieren, zu hoch, zu tief…

MCP9700 (analoger Sensor)
Beispiel-Sketch verfügbar: temp_MCP9700.ino

Der MCP9700 ist ein analoger Sensor der Firma Microchip. Dieser liefert am Ausgang eine der
Temperatur direkt proportionale Gleichspannung mit einer Auflösung von 10mV/°C. Bei 0°C beträgt die
Ausgangsspannung 500mV, bei 20°C demzufolge 700mV, 30°C entsprechen 800mV, -20°C entsprechen
300mV usw. Diese Spannung muss also mit einem analogen Eingang des ARDUINO verarbeitet werden.

Die Eigenschaften des Sensors in Kurzform:

- Hoher Temperaturbereich -40°C bis +150°C
- Geringer Stromverbrauch
- Sehr günstig
- Simple Programmierung ohne Library

Nachteile:
- Jeder Sensor belegt einen analogen Eingang
- Genauigkeit nicht so gut mit +-4°C
- Anfällig gegen Schwankungen der Referenzspannung des ARDUINO (meist die +5V Betriebsspannung)

Anschliessen des Sensors

Das Anschliessen dieses Sensors ist besonders einfach. Einfach die Betriebsspannung
5V DC und GND anschliessen. Der Ausgang wird nun an einen beliebigen
Analogeingang gelegt. Das war es auch schon.



Programmierung

Zum Messen der Temperatur muss der Wert des AD-Wandlers (z.B. A0) in eine für den Menschen
nützliche Form gebracht werden. Da der AD-Wandler lediglich einen Wert von 0…1024 entsprechend
der anliegenden Spannung von 0…5V zurück gibt, ist etwas Mathematik nötig, um daraus eine
Temperatur zu bekommen.
Diese Berechnung ist für den ARDUINO aber keine Schwierigkeit.
Wir definieren uns erst mal eine float-Variable, um den errechneten Wert der Temperatur dort zu
speichern.

float temp = 0.0; // errechnete Temperatur

Im Programm bringen wir nun an geeigneter Stelle unseren Code unter, um den 10bit-AD-Wert des AD-
Wandlers in eine Temperatur umzuwandeln. Hier sollte auch wieder bedacht werden, wie oft man die
Temperatur neu berechnet, es reicht sicher einmal pro Minute aus.

temp = (analogRead(A0) * 5.0 / 1024.0) - 0.5;
temp = temp / 0.01;

Allerdings geht diese Berechnung deutlisch schneller als das Auslesen der 1wire-Sensoren.

Hinweis

Ein ähnlicher Sensor ist der LM35. Er hat auch eine Auflösung von 10mV/°C, liefert aber bei 25°C eine
Ausgangsspannung von 250mV. Durch Anpassung der obigen Formel kann er genauso angewendet
werden.

LM75 (I2C-Sensor)
Siehe hier im Kapitel für I2C

Der I2C-Bus und seine Benutzung

Allgemeines
Allgemeines ist z.B. unter Quelle: [17 zu finden.
Der I2C-Bus – wozu brauchen wir ihn…? Gute Frage. Nehmen wir als Beispiel ein LCD-Display, eines
der beliebtesten Ausgabegeräte. Schliessen wir es dem Standard entsprechend an, brauchen wir ausser
GND und +5V noch vier Datenleitungen, sowie E, und RW. Das macht insgesamt sechs (!) ARDUINO-
Pins, die nur zur Ansteuerung des Displays verwendet sind. Ganz schön viel, speziell, wenn man einen
kleinen ARDUINO benutzt, oder noch viel weitere Dinge, wie Taster, Relais oder LED’s anschliessen
will.

Wäre es da nicht schön, wenn man die verbrauchten Pins in so einem Fall einschränken könnte, sagen
wir, auf nur zwei Pins anstatt sechs? Genau das macht der I2C-Bus. Eine tolle Sache! Der I2C-Bus hat
zwei Leitungen: SDA und SCL.

Hinweis
Wenn man mehrere I2C-Geräte benutzt, können dieses alle an diesen dafür verwendeten ARDUINO-Pins
angeschlossen werden. Es werden also keine weiteren Pins verbraucht, nur diese beiden.
Unterschieden werden die „Teilnehmer“ am Bus durch ihre Adresse. Diese ist ein HEX-Wert im Format
0x68. Im Sketch muss also immer „gesagt“ werden, welcher Teilnehmer bei dem entsprechenden Befehl
gemeint ist.

Es können nicht beliebige Pins benutzt werden! Bei den ATMega328-basierten ARDUINO’s, also z.B. UNO, NANO
sind die Pins die folgenden: SDA an A4 SCL an A5

Beschaltung

Wie in dem Bild zu sehen, ist von SDA und SCL je ein sogenannter
„PullUp-Widerstand“ nach + Versorgungsspannung nötig. Dieses aber
nur einmal, egal wie viele Teilnehmer am Bus sind. Die I2C-Geräte
benötigen selbst natürlich auch noch jeweils GND und +5V als
Betriebsspannung. Mehr gibt es nicht zu beachten, dann kann es schon
losgehen.



I2C-LCD-Displays
Bei einem LCD-Display kann man durch Verwendung des I2C-Busses ganze fünf von sieben
ARDUINO-Pins einsparen. Anzuschliessen ist es gemäß obiger Grafik. Die Adresse hängt vom
verwendeten I2C-Modul ab, welches verbaut wurde. Im Idealfall steht die Adresse auf dem Modul. Bei
einigen kann man auch die Adresse wählen durch Einbringen einer Lötbrücke. Hier hilft gegebenenfalls
das Datenblatt oder Informationen des Anbieters.
Ist beides nicht verfügbar, gibt es einen kleinen Sketch, welcher den Bus nach I2C-Teilnehmern absucht
und die Adresse auf dem seriellen Port ausgibt. Dieser Sketch kann unter [18 heruntergeladen werden.


Programmierung
Zum Betreiben des Displays verwenden wir wieder eine Library, welche unter [19
he
runte
rge
lade
n
werden kann.
Weiterhin ist noch die prinzipielle Library für die Benutzung des I2C-Busses notwendig. Wir binden
beide Libraries in unseren Sketch ein:

#include // erforderlich
#include // erforderlich

Nun kann die Programmierung ganz normal mit den bekannten Befehlen des Kapitels „LCD-Anzeigen und deren
Benutzung“ fortgesetzt werden. Es gibt aber noch ein paar extra Befehle, welche man bei Bedarf in den Beipielen
sieht und anwenden kann.
Damit es losgehen kann, muß das Display noch initialisiert werden:

LiquidCrystal_I2C lcd(0x3F, 16, 2);

Hier handelt es sich um ein Display mit der Adresse 0x3F und 16 Zeichen auf zwei Zeilen.
Im Setup muß das Display genau so behandelt werden wie ein normales Display mit dem folgenden Befehl:

lcd.begin(); // LCD starten

Ist es ein beleuchtetes Display, kann nun die Beleuchtung wie gewünscht an- oder ausgeschaltet werden. Das
geschieht mit den folgenden Befehlen:

lcd.backlight(); // Backlight an
lcd.noBacklight(); // Backlight aus

Im laufenden Programm ist es auch möglich, abzufragen, ob die Beleuchtung gerade an ist oder nicht.
Das ist ganz einfach möglich mit der folgenden Codezeile:

boolean state = lcd.getBacklight();

Das Ergebnis der Variable „state“ ist entweder „0“ (Beleuchtung aus) oder „1“ (Belechtung an).

LM75 Temperatursensor
Der LM75 ist ein Temperatursensor für den I2C-Bus mit einem Temperaturbereich von -55°C bis +125°C
und wartet mit einer interessanten zusätzlichen Funktion auf. Zusätzlich zur Möglichkeit, die Temperatur
über I2C abzufragen, hat der LM75 noch einen Übertemperatur-Alarm-Ausgang. Hier handelt es sich um
einen Open-Drain-Ausgang (bitte mal nachlesen, was das bedeutet, falls unbekannt), welcher aktiviert
wird, wenn die Temperatur einen bestimmten Wert überschreitet.
Dieser Ausgang hat zwei verschiedene Betriebsarten, die am meisten genutzte ist als Standard (Default)
aktiviert. Der Schaltpunkt beträgt 80°C, der Schwellwert, also der Rückschaltpunkt 75°C. Beide Werte
können über I2C programmiert werden. Die Standardfunktion arbeitet folgendermaßen: Übersteigt die
Temperatur den Schaltwert (TOS) von 80°C, wird der Ausgang OS aktiviert (niedrige Impedanz, also
nahe null Ohm – ähnlich wie „Schalter geschlossen“). Unterschreitet die Temperatur den Wert der
Schaltschwelle (THYST) von 75°C, dann wird der Ausgang OS wieder deaktiviert (hohe Impedanz –
ähnlich wie „Schalter geöffnet“).
Die andere Betriebsart erwähne ich hier nicht, wen das näher interessiert, sei auf das Datenblatt
verwiesen.

Da der Schaltkreis selbst ein SMD-Bauteil ist, besorgt man sich am besten eines dieser kleinen
Leiterplatten, auf denen alles bereits bestückt und beschriftet ist. Sie sind für minmales Geld übers
Internet zu beziehen.


Programmierung
Man kann zur Programmierung wieder auf Libraries zugreifen, oder es mit meist kryptischen Befehlen
selbst programmieren. Ich benutze die Library der Quelle [20 und mache es mir so leicht wie möglich.
Bei der Library ist auch ein Beispiel dabei, welches selbsterklärend ist. Ich beziehe mich hier auf genau
jenes Beispiel.
Zuerst müssen mal wieder zwei Libraries eingebunden werden:

#include // I2C-Lib
#include // LM75-Lib

Auf dem Board des LM75 befinden sich drei Lötbrücken oder Jumper zur Festlegung der I2C-Adresse.
Belässt man das Board im Lieferzustand und will nur eines einsetzen, kann man die Standardadresse von
0x48 beibehalten. Dann wird der Sensor mit dem folgenden Befehl initialisiert:

LM75 sensor; // Sensor initialisieren

Hat man mit den Jumpern eine andere I2C-Adresse eingestellt, muss diese der Library mitgeteil werden.
Das geschieht in der folgenden Art und Weise:

LM75 sensor(LM75_ADDRESS | 0b001); // Adresse 0x4C zugewiesen

In dieser Zeile wurde auf dem Modul der Jumper A0 auf GND, A1 auf GND und A2 auf +5V gelegt. Auf
diese Art kann man insgesamt 8 verschiedene Adressen vergeben, somit 8 verschiedene Sensoren
anschliessen und auch abfragen.
Im setup() ist nun die wire-Library zu starten mit:

Wire.begin(); // I2C-Library starten

Nun kann an geeigneter Stelle im Programmcode die Temperatur abgefragt werden.
Entweder wie im Beispiel zur direkten Ausgabe auf den seriellen Monitor:

Serial.print("Aktuelle Temperatur: ");
Serial.print(sensor.temp());
Serial.println(" C");

Oder aber (das ist sicher eher der Fall) an eine Fliesskommavariable übergeben werden:

float temperatur = sensor.temp();

Will man den float-Wert mit einer Kommastelle auf einem LCD ausgeben, kann man das so machen:

lcd.print(temperatur,1); // anzeigen, mit einer Kommastelle


Portexpander
In Bearbeitung…. Lib auf Quelle 21

Der Watchdog-Timer und seine
Benutzung
Allgemeines
Quelle: [7
Haben Sie schon mal eine Situation gehabt, wo der Arduino hängt, abgestürzt ist? Ja? Dafür kann es viele
Gründe geben. Zum Beispiel eine defekte Leitung zu einem Sensor im Freien, falsche Programmabläufe
etc. Aber was, wenn der Arduino weit abgesetzt, schlecht zugänglich, oder ohne Überwachung durch den
Menschen arbeitet? Diese Situationen sollten also vermieden werden. Oder wollen Sie Ihre geliebten
Pflanzen, welche automatisch bewässert werden, nach ein paar Tagen vertrocknet oder verfault
wiederfinden? Sicher nicht…

Die meisten Controller, so auch die AVR’s im Arduino haben eine spezielle Funktion integriert, den
sogenannten Watchdog Timer (deutsch: Wachhund). Ein schöner Name, genau das ist die Aufgabe dieses
Hundes. Er überwacht das laufende Programm und bei Fehlfunktionen „beißt“ er!
Wenn er einmal konfiguriert ist, dann wartet er auf sogenannte „Heartbeat-Signals“. Sollten diese nicht in
einer vorher festgelegten Zeit erscheinen, wird der Prozessor einen RES ausführen.
Das ist sehr komfortabel und stellt sicher, dass der Arduino niemals länger als diese festgelegte
Zeitschwelle im Programm hängen bleibt.

Über diese Dinge werden kein Wort verloren in den bekannten Arduino Dokumentationen. Es ist aber
wichtig und spart wirklich eine Menge Zeit und Ärger.

Aber Vorsicht: Es gibt auch Fallstricke! Also unbedingt lesen!

Benutzung des Watchdog-Timers
Als erstes muss die folgende Zeile an den Programmanfang eingefügt werden:

#include

Im nächsten Schritt wird der Watchdog aktiviert und konfiguriert:

Wdt_enable (WDTO_4S); // Watchdog-Zeit 4 Sekunden

Diese Zeile sollte in den Setup-Teil des Programmes eingefügt werden. Der Watchdog kann aber
prinzipiell zu jeder Zeit aktiviert werden.

WDTO_4S ist eine Konstante und bedeutet eine Zeitschwelle von 4 Sekunden. Diese Zeitschwellen sind
vorprogrammiert, Sie können nicht jeden beliebigen Wert verwenden. Wenn der Wachhund innerhalb
dieser Zeit nicht „gestreichelt“ (zurückgesetzt) wird, dann „beißt“ er: Der Controller führt einen RESET
aus! Der Controller darf also für seine normale, bestimmungsgemäße Arbeit im Programm nie länger als
diese Zeit (4Sek. In diesem Fall) brauchen! Gegebenenfalls diese Zeit erhöhen, oder den Programmlauf
optimieren. Aber welches Programm braucht schon 4 Sekunden für einen Durchlauf – das ist eine
Ewigkeit für einen Controller.

Die folgenden Zeitschwellen sind möglich, siehe Tabelle:

Schwellwert Konstanten-Name Verfügbar bei
15 ms WDTO_15MS ATMega 8, 168, 328, 1280, 2560
30 ms WDTO_30MS ATMega 8, 168, 328, 1280, 2560
60 ms WDTO_60MS ATMega 8, 168, 328, 1280, 2560
120 ms WDTO_120MS ATMega 8, 168, 328, 1280, 2560
250 ms WDTO_250MS ATMega 8, 168, 328, 1280, 2560
500 ms WDTO_500MS ATMega 8, 168, 328, 1280, 2560
1 s WDTO_1S ATMega 8, 168, 328, 1280, 2560
2 s WDTO_2S ATMega 8, 168, 328, 1280, 2560
4 s WDTO_4S ATMega 168, 328, 1280, 2560
8 s WDTO_8S ATMega 168, 328, 1280, 2560

Zum Schluss muss dem Watchdog noch gesagt werden, dass alles OK ist („Streicheln“):

wdt_reset(); // Watchdog Zeit zurücksetzen

Natürlich muss dieser Reset-Befehl öfter als die in der Konfiguration angegebene Zeit (hier 4 Sekunden)
aufgerufen werden. Am besten gleich am Anfang der void loop()!
Aber es hängt auch vom Programm ab. Wenn das Programm sehr lang in einer Funktion
(Unterprogramm) hängt, dann kann es auch nötig sein, den wdt_reset() dort an geeigneter Stelle
unterzubringen. Hier ist also Aufmerksamkeit erforderlich, um immer den Watchdog Timer rechtzeitig
zurück zu setzen.
In allen zeitraubenden Funktionen muss dieser Reset eingefügt werden! Also auch z.B. bei
Datenübertragungen, Warteschleifen, Auslesen von Sensoren etc.

Bei der Auswahl der Reset-Zeitschwelle müssen alle zeitbrauchenden Funktionen mit beachtet werden,
also delay(), auszuführende Funktionen, Bus-Timeouts (wenn vorhanden) und Arbeitsgeschwindigkeit.
Weiterhin sollte man im Auge behalten, das nur der ARDUINO zurückgesetzt wird. Alle andere eventuell
angeschlossene Hardware nicht, wie GSM-Shield, Network-Shield usw. Sollen diese auch zurückgesetzt
werden, ist dieses eventuell zu verdrahten oder anders vorzusehen.

Die Zeitschwelle sollte nicht zu klein gewählt werden! Ansonsten kann es vorkommen, das der
ARDUINO nicht aus dem Bootloader rauskommt, weil schon vorher ein Reset erzeugt wird! Dann
geht nichts mehr, auch nicht das neuprogrammieren!! Nur ein erneutes Aufbrennen des
Bootloaders mit einem geeigneten AVR-Brenner oder einem anderen Arduino als
Programmieradapter ist dann noch möglich!
Also lieber eine längere Zeit wählen, nicht unter 2 Sekunden. Ich benutze 4 Sekunden oder 8
Sekunden, da ist man auf der sicheren Seite.

Kleine hilfreiche Programm-Teile

Freien RAM anzeigen
Quelle: unbekannt, Internet
Mit dieser Funktion kann der noch im ARDUINO verfügbare freie RAM-Speicher angezeigt werden.
Die Funktion muß vorerst in den eigenen Code, wie ein „Unterprogramm“ eingefügt werden, also NICHT
in setup() oder loop(). Am besten dahinter.

int freeRam () {
extern int __heap_start, *__brkval;
int v;
return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval);
}

Die Abfrage des freien RAM erfolgt dann wo es gewünscht ist im Programm zum Beispiel durch den
Befehl:

Serial.print(freeRam()); // Ausgabe seriell USB
LCD.print(freeRam()); // Ausgabe LCD


Programm anhalten (für immer)
Manchmal möchte man die komplette Programmausführung für immer (bis die Spannung abgeklemmt
wird) anhalten, sodass der Prozessor absolut nichts mehr machen kann. Fragt vielleicht der ein oder
andere: Warum? Nun, ich habe eine Überwachung der Spannung eines Bleiakkus programmiert. Damit
dieser nicht tiefentladen wird, soll der Verbraucher per Relais getrennt werden. Und auch nie wieder
angehen, bis ich mich um den Akku kümmere. Nach Abschalten durch das Relais soll also der Controller
„anhalten“. Dies kann man mit diesem einfachen kurzen Befehl machen:

while(1);

Software-Reset
Manchmal möchte man definiert eine Reset des ARDUINO durchführen, also so, als hätte man gerade
eben die Spannung angelegt und das Programm beginnt.
Das kann man mit Hardware realisieren, also z.B. einen Transistor an einen digitalen Ausgang und den
Kollektor des Transistors an den Reset-Pin anschließen. Den Reset erreicht man dann durch einen HIGH-
Pegel am Ansteuerpin mit digitalWrite.

Es gibt aber auch eine einfache Software-Möglichkeit. Hier braucht man keine zusätzlichen Bauteile.
Der Befehl ist ein simpler Assembler-Befehl, welcher ins Programm als Funktion eingefügt werden kann
(siehe „Freien RAM anzeigen“):

void software_Reset()
{
asm volatile (" jmp 0");
}

Der Aufruf der Funktion geschieht dann an gewünschter Stelle mit dem Befehl:

software_Reset(); // Software-Reset ausführen

RAM sparen bei Serial.print
Wenn man viele String-Ausgaben macht mit dem Befehl Serial.print, kann man RAM-Speicher sparen,
indem diese Strings im Flash abgespeichert werden. Das ist ganz einfach zu erreichen durch folgende
Vorgehensweise:

Serial.println(F("Hallo Welt!")); // speichert den String im Flash

Siehe auch hier in der Referenz
Digital-Ausgang (z.B. LED) togglen
Will man den Zustand eines Digital-Ausgangs umkehren, also von HIGH nach LOW oder umgekehrt, so
kann man dazu den folgenden Ausdruck verwenden:

digitalWrite(LED, !(digitalRead(LED))); // Pin togglen

Binaerausgabe 8bit, 16bit, 32bit auf seriellem Port
Die folgenden drei Programmteile erzeugen die Ausgabe eines byte, int, long-Wertes als Binärwert auf
den seriellen Port. Dies kann nützlich sein, um den Code bei Fehlfunktionen mit Bitoperationen o.ä. zu
debuggen. So muss man nicht erst die dezimale Zahl z.B. 17 umständlich in das Format B00010001
umrechnen. Danke hierfür ardu_arne vom deutschen ARDUINO-Forum.

Binärausgabe 8bit

void binout8 (byte wert) { // Binaerausgabe 8 Bit
Serial.print("B ");
for (int i = 7; i >= 0; i--) {
if ( i == 3 ) Serial.print(" ");
if (bitRead(wert, i)) Serial.print("1");
else Serial.print("0");
}
Serial.println();
}

Um nun einen Wert als Binärzahl auf den seriellen Port auszugeben, ist folgende Programmzeile nötig:

binout8(170); // liefert "B 1010 1010" der dez. Zahl 170


Binärausgabe 16bit

void binout16 (unsigned int wert) { // Binaerausgabe 16 Bit
Serial.print("B ");
for (int i = 15; i >= 0; i--) {
if ( i == 3 || i == 11) Serial.print(" ");
if ( i == 7) Serial.print(" ");
if (bitRead(wert, i)) Serial.print("1");
else Serial.print("0");
}
Serial.println();
}

Um nun einen Wert als Binärzahl auf den seriellen Port auszugeben, ist folgende Programmzeile nötig:

binout16(43690); // liefert "B 1010 1010 1010 1010" der dez. Zahl


Binärausgabe 32bit

void binout32 (unsigned long wert) { // Binaerausgabe 32 Bit
Serial.print("B ");
for (int i = 31; i >= 0; i--) {
if ( i == 3 || i == 11 || i == 19 || i == 27) Serial.print(" ");
if ( i == 7 || i == 15 || i == 23) Serial.print(" ");
if (bitRead(wert, i)) Serial.print("1");
else Serial.print("0");
}
Serial.println();
}

Um nun einen Wert als Binärzahl auf den seriellen Port auszugeben, ist folgende Programmzeile nötig:

binout32(2863311530); // liefert "B 1010 1010 1010 1010 1010 1010 1010 1010"


String nach char kopieren
Quelle: deutsches Arduino-Forum, Member Tommy56
Manchmal besteht die Notwendigkeit, eine Variable vom Typ String in eine Variable vom Typ char-
Array zu kopieren. Das geht so ohne weiteres nicht. Mit diesem kleinen Codeschnipsel ist es schnell
erledigt:

String Text = "Hallo Welt"; // der String, welcher kopiert werden soll
char mychar[20 // das char-Array, in welches kopiert werden soll

strcpy(mychar,Text.c_str());



Stichwortverzeichnis
#
#define ................................................................................. 16, 71
#include ..................................................................................... 17
7
7414 ......................................................................................... 123
A
Abfragen .................................................................................... 13
abs(x) ......................................................................................... 65
Addition ..................................................................................... 34
analogRead() .............................................................................. 39
analogReference() ..................................................................... 39
analogWrite() ............................................................................. 40
Anführungszeichen .................................................................... 23
Array‘s ........................................................................................ 20
attachInterrupt() ........................................................................ 61
B
Befehle ....................................................................................... 11
Bibliotheken ............................................................................... 13
Binaerausgabe ......................................................................... 139
bit() ............................................................................................ 85
bitClear() .................................................................................... 84
Bitoperatoren ............................................................................ 56
bitRead() .................................................................................... 83
bitSet() ....................................................................................... 84
Bitweises links schieben ............................................................ 56
Bitweises NICHT ......................................................................... 57
Bitweises ODER .......................................................................... 57
Bitweises rechts schieben .......................................................... 56
Bitweises UND ........................................................................... 57
Bitweises XOR ............................................................................ 58
bitWrite() ................................................................................... 84
boolean ...................................................................................... 20
Boolsche Operatoren ................................................................. 36
break .......................................................................................... 31
byte ............................................................................................ 18
byte() ......................................................................................... 47
C
char ............................................................................................ 21
charAt() ...................................................................................... 90
compareTo() .............................................................................. 91
concat() ...................................................................................... 91
const .......................................................................................... 71
constrain(x, a, b) ........................................................................ 66
continue ..................................................................................... 32
cos(rad) ...................................................................................... 72
D
Datenkonvertierung................................................................... 47
Datentypen ................................................................................ 18
Datentypen-Bezeichner ............................................................. 24
dekrement -- .............................................................................. 55
delay() ........................................................................................ 50
delayMicroseconds() ................................................................. 51
detachInterrupt() ....................................................................... 62
Digital In / Out ............................................................................ 37
digitalRead() ............................................................................... 38
digitalWrite() .............................................................................. 37
Division ...................................................................................... 34
do – while................................................................................... 31
double ........................................................................................ 20
Dreiecksberechnungen ................................. Siehe Trigonometrie
DS18B20 / DS18S20 ................................................................. 129
DS3231 .................................................................... Siehe RTC-Uhr
E
EEPROM ................................................................................... 115
EEPROM.put() .......................................................................... 117
EEPROM.read() ........................................................................ 115
EEPROM.update() .................................................................... 116
EEPROM.write() ....................................................................... 116
EEPROM[ ................................................................................. 117
else ............................................................................................. 29
endsWith() ................................................................................. 92
equals() ...................................................................................... 92
equalsIgnoreCase() .................................................................... 93
Erweitertes Analoges In / Out .................................................... 43
EXKLUSIV ODER, bitweise..................................................... 58
Externe Interrupts ...................................................................... 61
F
F()-Makro ................................................................................... 82
false ............................................................................................ 25
float ............................................................................................ 19
float() ......................................................................................... 48
Floating point Konstanten .......................................................... 27
Freien RAM anzeigen ............................................................... 138
G
Geltungsbereich von Variablen .................................................. 69
geschweifte Klammern ........................................................ 15, 16
Bedingungsabfrage ............................................................... 16
Funktionen ............................................................................ 16
Schleifen ............................................................................... 16
getBytes() ................................................................................... 94
Gleichspannung, analog ausgeben............................................. 41
globale Variable......................................................................... 69
goto ............................................................................................ 32
Grundlegendes Analog In / Out ................................................. 39
Grundrechenarten ..................................................................... 34
H
HIGH ........................................................................................... 25
highByte() ................................................................................... 83
Hilfsfunktionen........................................................................... 80
I
I2C-Bus ..................................................................................... 133
I2C-LCD-Displays ...................................................................... 133
if 28, 29
indexOf() .................................................................................... 94
inkrement ++ .............................................................................. 55
INPUT ......................................................................................... 26
INPUT_PULLUP ........................................................................... 26
int 18
int() ............................................................................................ 47
Integer Konstanten .................................................................... 27
Interrupts (global) ...................................................................... 63
interrupts() ................................................................................ 63
isAlpha(thisChar) ....................................................................... 73
isAlphaNumeric(thisChar) .......................................................... 73
isAscii(thisChar) ......................................................................... 74
isControl(thisChar) ..................................................................... 75
isDigit(thisChar) ......................................................................... 75
isGraph(thisChar) ....................................................................... 76
isHexadecimalDigit(thisChar) ..................................................... 79
isLowerCase(thisChar) ............................................................... 76
isPrintable(thisChar) .................................................................. 77
isPunct(thisChar)........................................................................ 77
isSpace(thisChar) ....................................................................... 78
isUpperCase(thisChar) ............................................................... 78
isWhiteSpace(thisChar).............................................................. 74
K
Kommentare .............................................................................. 15
Konstanten ................................................................................ 25
L
lastIndexOf() .............................................................................. 95
lcd.autoscroll() ......................................................................... 111
lcd.backlight() ............................................................. 134
lcd.begin() ................................................................................ 105
lcd.blink() ................................................................................. 109
lcd.clear() ................................................................................. 106
lcd.createChar() ....................................................................... 112
lcd.cursor() ............................................................................... 108
lcd.display() .............................................................................. 109
lcd.getBacklight() ...................................................... 134
lcd.home()................................................................................ 106
lcd.leftToRight() ....................................................................... 112
lcd.noAutoscroll() .................................................................... 111
lcd.noBacklight() ......................................................... 134
lcd.noBlink() ............................................................................. 109
lcd.noCursor() .......................................................................... 108
lcd.noDisplay() ......................................................................... 110
lcd.print() ................................................................................. 107
lcd.rightToLeft() ....................................................................... 112
lcd.scrollDisplayLeft() ............................................................... 110
lcd.scrollDisplayRight() ............................................................ 110
lcd.setCursor() ......................................................................... 106
lcd.write() ................................................................................ 107
LCD-Anzeigen ........................................................................... 104
length() ...................................................................................... 96
Library OneButton ................................................................... 124
LiquidCrystal() .......................................................................... 105
LiquidCrystal_I2C ......................................................... 134
LM35 ....................................................................................... 132
LM75 ........................................................................................ 134
Logische Pegel ........................................................................... 25
logisches oder ............................................................................ 36
logisches und ............................................................................. 36
Lokale Variablen ........................................................................ 69
long ............................................................................................ 19
long().......................................................................................... 48
loop() ................................................................................... 11, 14
LOW ..................................................................................... 25, 26
lowByte() ................................................................................... 83
M
map() ......................................................................................... 66
Mathematische Funktionen ....................................................... 65
max(x, y) .................................................................................... 65
MCP9700 .................................................................................. 131
Mehrfachfunktionen mit Tastern ............................................. 123
Doppelklick .......................................................................... 124
Einfacher kurzer Klick .......................................................... 124
Langer Klick einfach............................................................. 125
Langer Klick wiederholte Funktion ...................................... 125
Methoden .................................................................................. 11
micros() ...................................................................................... 50
millis() ........................................................................................ 51
Richtige Benutzung des millis() – Befehles ............................ 52
min(x, y) ..................................................................................... 65
Modulo....................................................................................... 35
Multiplikation ............................................................................. 34
N
nicht ........................................................................................... 36
noInterrupts() ............................................................................ 63
noTone()..................................................................................... 43
null character ............................................. Siehe null termination
null termination ......................................................................... 22
O
ODER, bitweise zusammengesetzt ............................................. 54
Operationsverstärker ................................................................. 41
Operatoren ................................................................................ 12
Arithmetische Operatoren .................................................... 12
Boolesche Operatoren .......................................................... 13
Vergleichsoperatoren ............................................................ 13
OUTPUT...................................................................................... 26
P
pinMode ..................................................................................... 26
pinMode() .................................................................................. 37
Pin-Zustände .............................................................................. 25
Portexpander ........................................................................... 135
pow() .......................................................................................... 67
PROGMEM ................................................................................. 80
Programm anhalten ................................................................. 138
pulseIn() ..................................................................................... 46
Pulsweitenmodulation ................................................................ 40
PWM ................................................ Siehe Pulsweitenmodulation
R
RAM sparen ............................................................................. 139
random() .................................................................................... 59
randomSeed(seed) ..................................................................... 59
Rechenoperationen ................................................................... 34
replace() ..................................................................................... 96
return ......................................................................................... 32
RTC-Uhr .................................................................................... 126
S
Schleifen............................................................................... 13, 28
for-Schleifen .......................................................................... 28
Semikolon .................................................................................. 15
Serial.available() ......................................................................... 88
Serial.begin(speed) .................................................................... 87
Serial.flush ................................................................................. 88
Serial.print ................................................................................. 87
Serial.println............................................................................... 88
Serial.read()................................................................................ 88
Serielle Kommunikation (UART) ................................................. 86
setCharAt() ................................................................................. 97
setup() .................................................................................. 11, 14
shiftIn() ....................................................................................... 45
shiftOut() ................................................................................... 44
short .......................................................................................... 19
sin(rad) ....................................................................................... 72
sizeof .......................................................................................... 80
Software-Reset ........................................................................ 138
Sommer- / Winterzeit Berechnung .......................................... 128
Sonderzeichen im LCD-Display ................................................ 113
sqrt(x) ........................................................................................ 67
startsWith() ................................................................................ 97
static .......................................................................................... 69
string .......................................................................................... 21
String nach char kopieren ........................................................ 140
String Objects ............................................................................ 89
String Operatoren .................................................................... 102
String() ....................................................................................... 89
String-Array‘s ............................................................................. 23
String-Objects ............................................................................ 23
String-Operatoren
[

Zu
g
ri
ff
au
f Ze
i
c
h
e
n
) ........................................................ 102
+ (Operator „Anhängen“) ................................................. 102
== (Operator „Vergleich“) ................................................ 103
substring() .................................................................................. 98
Subtraktion ................................................................................ 34
switch / case .............................................................................. 30
Symbole im LCD-Display .......................................................... 113
T
tan(rad) ...................................................................................... 72
Taster ....................................................................................... 121
Anschliessen von Tastern .................................................... 121
Entprellen von Tastern ........................................................ 122
Taster mit Interrupts ........................................................... 121
Taster nach +5V .................................................................. 121
Taster nach GND ................................................................. 121
Verwendung der Debounce-Library .................................... 122
Temperatursensoren und deren Benutzung ............................ 129
Timer-Interrupts ...................................................................... 119
toCharArray() ............................................................................. 98
toFloat() ..................................................................................... 99
togglen, Digitalausgang ........................................................... 139
toInt() ......................................................................................... 99
toLowerCase() .......................................................................... 100
tone() ......................................................................................... 43
toUpperCase().......................................................................... 100
Trigonometrie ............................................................................ 72
trim() ........................................................................................ 100
true ............................................................................................ 25
U
Umlaute im LCD-Display .......................................................... 113
UND, bitweise zusammengesetzt .............................................. 54
unsigned char ............................................................................. 21
unsigned int ............................................................................... 19
unsigned long ............................................................................. 19
V
Variablen .................................................................................... 11
Vergleichsoperatoren .......................................................... 28, 29
Verknüpfungsoperationen ................. Siehe Boolsche Operatoren
Verwendung des Timer1 .......................................................... 119
Verzweigungen .......................................................................... 28
void ............................................................................................ 18
volatile ....................................................................................... 70
W
Watchdog-Timer ...................................................................... 136
while .......................................................................................... 30
while(1) .............................................................................. 138
word ........................................................................................... 19
word() ........................................................................................ 48
Z
Zeichen (Character-) Funktionen ............................................... 73
Zeit ............................................................................................. 50
Zufallszahlen .............................................................................. 59
Zusammengesetzte mathematische Operationen ..................... 54
Zusammengesetzte Operatoren ................................................ 54
Zuweisungsoperator = ............................................................... 34
Μ
μ-Zeichen im LCD-Display ..................................................... 114
Π
π Zahl PI im LCD-Display ....................................................... 114
Ω
Ω (Ohm-Zeichen im LCD-Display) ......................................... 114


Log der Änderungen & Ergänzungen

Version vom 20.07.2017
- Taster mit Interrupts
- Temperatursensoren und deren Benutzung
..1wire-Sensor DS18B20 / DS18S20
..analoger Sensor MCP9700

Version vom 11.08.2017
- DOWNLOAD: angepasste Beispiele zu bestimmten Kapiteln und Libraries
- PROGMEM aktualisiert, keine Lib mehr nötig
- float-Datenkonvertierung Hinweise ergänzt
- Datentyp double ergänzt
- Datentyp short ergänzt
- LCD-Anzeigen aktualisiert, neuer Unterprunkt "Sonderzeichen, Symbole, Umlaute"
- Entprellen von Tastern mittels zusätzlicher Bauteile
- String Object toInt() ergänzt
- String Object toFloat() ergänzt
- Neues Kapitel "Zeichen- (Character-) Funktionen" eingefügt
alle Befehle gemäß ARDUINO.cc zugefügt
- I2C LCD-Displays
- I2C Temperatursensor LM75