• 1 Vorwort
  • 2 Einführung in C
  •   2.1 Datentypen
  •     2.1.1 Arrays
  •     2.1.2 Strings
  •     2.1.3 Strukturen
  •     2.1.4 Aufzählungstyp
  •     2.1.5 Konstanten
  •   2.2 Operatoren
  •     2.2.1 Arithemtische Operatoren
  •     2.2.2 Vergleichsoperatoren
  •     2.2.3 Logische Operatoren
  •     2.2.4 Bitorientierte Operatoren
  •   2.3 Kontrollstrukturen
  •     2.3.1 Verzweigung
  •     2.3.2 for-Schleife
  •     2.3.3 while-Schleife
  •     2.3.4 do-while-Schleife
  •     2.3.5 break and continue
  •     2.3.6 switch-Anweisung
  •   2.4 Zeiger (Pointer)
  •   2.5 Funktionen
  •     2.5.1 call-by-value
  •     2.5.2 call-by-pointer
  •     2.5.3 call-by-reference
  •     2.5.4 Default-Parameter
  •     2.5.5 Funktionen überladen
  •   2.6 Formatierung
  • 3 Einführung in Arduino
  •   3.1 Software und Installation
  •   3.2 Programmieren
  •   3.2.1 Sketch
  •    3.2.2 Digital I/O
  •    3.2.3 Analog I/O
  •    3.2.4 Zeit
  •    3.2.5 Kommunikation
  •    3.2.6 Mathe
  •    3.2.7 Externe Interrupts
  •   3.3 Boards
  •    3.3.1 Arduino Uno
  •    3.3.2 Arduino Mega
  •   3.4 Beispiele
  • 1 Vorwort

    Diese Einführung entstand im Rahmen eines Semester Praktikums in China. Bei einem Projekt das über die Programmierung und den Aufbau eines Quadrocopters ging wurde mit einem Arduino gearbeitet. Um alle Projektmitglieder auf einen gemeinsamen Wissensstand zu bringen brauchte ich ein speziell für Arduino und C ausgelegte Einführung. Alle die ich im Internet dazu gefunden habe waren nicht vollständig und deckten nur kleine Teilgebiete ab. Gleichzeitig war das schreiben dieser Einführung eine gute Wiederholung für mich. Es soll für all-diejenigen sein, die etwas eingerostet sind in der Sprache C oder den Umgang mit einem Arduino lernen möchten. Wobei der Arduino schon sehr benutzerfreundlich ist und für Einsteiger im Mikrocontroller Bereich gilt, finden dennoch viele die ersten Schritte schwierig. Weil es sehr knapp gehalten wurde kann es auch als Nachschlagewerk für die Syntax genutzt werden.

    2 Einführung in C

    Es gibt immer mehr als eine Möglichkeit, eine Aufgabe in einem Computerprogramm abzubilden. Finde deinen eigenen Programmierstil und verbessere ihn. Ablauf eines Programms:

    1. Präprozessing: Headerfiles(*.h) werden zum Quellfile hinzugefügt
    2. übersetzen in Assemblercode: Hier wird ein Quelltextfile in der prozessorspezifischen Programmiersprache Assembler erzeugt.
    3. Objektcode erzeugen: Hier wird aus dem Assemblerfile ein Hex-File generiert, welches die direkten Steuerbefehle für den Prozessor beinhaltet.
    4. Linken: Alle Objektfiles und notwendigen Bibliotheken werden miteinander zum ausführbaren Programm verbunden.

    2.1 Datentypen

    Die Größe der Datentypen ist System abhängig und besonders bei Mikrocontroller sehr wichtig, da der Speicher begrenzt ist. Ein Bool ist eigentlich nur ein Bit groß dennoch wird dafür ein ganzes Byte reserviert, weil kleinere Datentypen nicht verarbeitet werden können.

    Type Vorzeichen Anzahl Bit Wertebereich
    char mit 8 Character-Zeichen 'A'
    bool ohne 8 false, true
    byte ohne 8 0-255
    short mit 16 -32 768 bis 32 767
    word ohne 16 0 bis 65 535
    int mit 16 -32 768 bis 32 767
    unsigned int ohne 16 0 bis 65 535
    long mit 32 -2 147 483 648 bis 2 147 483 647
    unsigned long ohne 32 0 bis 4 294 967 295
    float mit 32 6-7 Stellen insgesamt
    double mit 32 wie float

    2.1.1 Arrays

    In einem Array werden Daten gleichen Datentyps zusammengefasst. 

    int x[3]; // Deklaration
    x[0] = 1; // 1. Element
    x[1] = 2; // 2. Element
    x[2] = 3; // 3. Element
    
    int y[3] = {1, 2, 3}; // Kann auch bei der Deklaration festgelegt werden
    for(int i = 0; i < 3; i++) // array durchlaufen
      x[i] = y[i]; // vorsicht: Element muss existieren!

    2.1.2 Strings

    Ein String ist nichts anderes als ein char-Array.

    char str1[5] = {’T’, ’e’, ’s’, ’t’, ’\0’}; // \0 beendet den String
    char str2[] = "Test"; // nach der Deklaration ist das Array 5 lang
    char str3[5] = "Test";
    char str4[15] = "Test"; // platz halten für einen größeren String

    2.1.3 Strukturen

    Die Struktur definiert einen neuen Datentyp, welcher Komponenten unterschiedlicher Datentypen beinhaltet

    struct Auto // neue Struktur
    {
      int gewicht;
      int maxGeschwindigkeit;
    };
    
    Auto bmw;
    bmw.gewicht = 1600;
    bmw.maxGeschwindigkeit = 290;

    2.1.4 Aufzählungstyp

    Der Aufzählungstyp wird verwendet, wenn man Werte gruppieren möchte, aber ein Array zu unübersichtlich ist.

    enum Tag
    {
      montag, dienstag, mittwoch, donnerstag, freitag
    };
    
    Tag arbeitstag; // neue Variable Deklarieren
    arbeitstag = montag; // Variable zuweisen
    if (arbeitstag == montag)
    {
      // schlechte Laune
    }

    2.1.5 Konstanten

    Es gibt Konstanten mit Variablennamen. Dabei wird eine Variable zusätzlich mit dem Schlüsselwort const gekennzeichnet, so kann sie später im Programm nicht mehr verändert werden. Es gibt auch symbolische Konstanten. Hier wird zu Beginn ein Name festgelegt, der später beim Kompilieren durch den dazugehörigen Wert ersetzt wird.

    // Symbolische Konstanten
    #define NL ’\n’
    #define Number 5
    #define Hello "Hello World\n"
    
    //Konstanten mir Variablennamen
    const int N = 5;

    2.2 Operatoren

    2.2.1 Arithemtische Operatoren

    Zu jeder arithmetischen Operation gibt es auch eine Kurzschreibweise, die aber mit bedacht verwendet werden sollte (führt aber zu schlecht lesbarem Code).

    a = a + b; // Addition
    a += b;
    a = a - b; // Subtraktion
    a -=b;
    a = a * b; // Multiplikation
    a *=b;
    a = a / b; // Division (Vorsicht bei Integer)
    a /=b;
    a = a % b; // Modulo (Rest bei Division)
    a %= b;
    a = b++; // Post Inkrement
    a = ++b // Pre Inkrement
    a = b--; // Post Dekrement
    a = --b; // Pre Dekrement

    2.2.2 Vergleichsoperatoren

    Alle Operationen geben true oder false zurück.

    int a = 3, b = 6;
    a < b; // a kleiner b
    a <= b; // a kleiner gleich b
    a > b; // a größer b
    a >= b; // a größer gleich b
    a == b; // a gleich b (Vorsicht bei Gleitkommazahlen)
    a != b; // a ungleich b (Vorsicht bei Gleitkommazahlen)
    
    if(a == b) // wenn erfüllt
    {
      //..dann tue das
    }

    2.2.3 Logische Operatoren

    Alle Operationen geben true oder false zurück.

    bool a = true;
    a = !a; // jetzt hat a den wert false
    a = a && true // logisches UND
    a = a || true // logisches ODER

    2.2.4 Bitorientierte Operatoren

    Alle Operatoren werden bitweise angewandt.

    short int n = 6 // 0..000110 entspricht 6
    n = ~n; // Complement, d.h. jede 0 wird eine 1 und jede 1 eine 0
    n = n & 1 // bit-AND
    n = n | 1 // bit-OR
    n = n ^ 1 // bit-XOR
    n = n << 2 // shift left by 2
    n = n >> 2 // shift right by 2
    
    if ((n | 1) == n) // 10101 OR 00001 = 10101
    {
      // zahl n ist ungerade
    }

    2.3 Kontrollstrukturen

    2.3.1 Verzweigung

    Es wird überprüft, ob eine Bedingung erfüllt ist. Je nach dem wird ein anderer Code ausgeführt.

    bool a = true;
    if(a == true)
    {
      // wenn a == true
    }
    else
    {
      // wenn a == false
    }
    
    int c = (a > b) ? a : b // Kurzschreibweise ist aber offiziell ein Ternärer Operator

    2.3.2 for-Schleife

    Der Code im Block wird eine bestimmte Anzahl durchlaufen. Auf die Zählvariable kann innerhalb des Blocks zugegriffen werden.

    for(int i=0; i<10; i++)
    {
      // dieser Code wird 10 mal ausgeführt
    }

    2.3.3 while-Schleife

    Der Code innerhalb des Blocks wird solange ausgeführt, wie die Bedingung im Kopf erfüllt ist.

    while(a == true)
    {
      // dieser Code wird solange ausgeführt wie a gleich true ist
    }

    2.3.4 do-while-Schleife

    Dies ist die fußgesteuerte while-Schleife. Sie funktioniert wie die normale while-Schleife nur, dass die Bedingung am Schluss kommt. Der Vorteil ist, dass der Code unabhängig von der Bedingung mindestens einmal ausgeführt wird.

    do {
      // dieser Code wird mindestens einmal ausgeführt
    } while(a == true); // nicht das Semikolon vergessen!

    2.3.5 break and continue

    Diese beiden Anweisungen werden im Zusammenhang mit Schleifen verwendet. Vorsicht bei der Anwendung. break: der Aufruf dieser Anweisung beendet die gesamte Schleife. continue: Der Aufruf beendet nur den aktuellen Durchlauf an dieser Stelle und setzt die Codeausführung an dem Schleifenkopf fort.

    int i = 0;
    for(;;)
    {
      i++; // i um 1 hochzählen
      if(i % 2 == 0) // alle geraden Zahlen überspringen
        continue; // den Rest vom Programmteil überspringen und beim Schleifen Kopf starten
    
      if(i>1000) // nach 1000 durchläufen Schleife beenden
        break;
    }

    2.3.6 switch-Anweisung

    Falls man einen Wert einer Variablen auf verschiedene Werte überprüfen möchte, ist die switch-Anweisung die beste Wahl.

    int n = 7;
    switch(n)
    {
      case 3:
        // falls n gleich 3 ist
      break; // die Anweisung break beendet die switch-Anweisung
      case 7:
        // falls n gleich 7 ist
      break;
      default:
        // Falls es auf kein Fall zu trifft
      break;
    }

    2.4 Zeiger (Pointer)

    Zeiger zeigen auf ein Objekt eines jeden beliebigen Datentyps. Mit einem Sternchen vor dem Namen wird ein Zeiger beim Deklarieren gekennzeichnet. Er muss vom gleichen Datentyp sein, wie der, auf den er späte zeigen soll.

    int n = 5 // Deklaration einer normalen Variablen
    int *ip; // Deklaration eines Zeigers der auf Integer zeigen kann
    ip = &n; // Pointer wird initialisiert mit der Adresse der Variablen
    *ip = *ip + 2; // n wird mithilfe des Zeigers um 2 erhöht
    
    struct Auto // Struktur erstellen
    {
      int maxGeschwindigkeit;
    };
    
    Auto bmw, *pBmw; // Anlegen einer Variablen und einem Pointer
    pBmw = &bmw; // Pointer bekommt die Adresse von bmw
    (*pBmw).maxGeschwindigkeit = 290; // zugriff auf die Variable
    pBmw->maxGeschwindigkeit = 290; // bessere alternative

    2.5 Funktionen

    Wenn Programmabschnitte meist öfter als einmal benötigt werden, oder einfach nur der übersichtlichkeit halber, bietet sich eine Funktion an. Sie besteht aus dem Datentyp, welchen sie zurückgibt, dem Namen und der übergabeparameter. Doch zuerst muss man sie, wie auch bei den Variablen, bekannt geben.

    int add(int a, int b); // Deklaration der Funktion meist außerhalb in einem Header File
    int add(int a, int b) // Definition der Funktion
    {
      return (a + b);
    }
    int c = add(1, 2); // Aufruf der Funktion

    2.5.1 call-by-value

    void calcY(int y) // Definition der Funktion. Void bedeutet das diese Funktion nichts zurückgibt
    {
      y = y + 2;
    }
    
    int y1 = 2;
    calcY(y1); // nach dem Aufruf hat die lokale Variable y1 immer noch den Wert 2

    2.5.2 call-by-pointer

    Falls die Übergabeparameter durch den Aufruf der Funktion verändert werden sollen, gibt es die Möglichkeit sie per Zeiger zu übergeben.

    void swap (int *a, int *b)
    {
      int *tmp = a; // Variable wird temporär zwischen gespeichert
      a = b;
      b = tmp;
      *tmp = (*a) + (*b); // Falls man auf die Werte zugreifen will
    }
    
    int x = 1, y = 2;
    swap(&x, &y); // nachdem Aufruf besitzt x den Wert 2, y den Wert 1

    2.5.3 call-by-reference

    ähnlich wie call-by-pointer, funktioniert call-by-reference. Man gibt nur die Speicheradresse der Variablen an die Funktion weiter.

    void swap (int &a, int &b)
    {
      int tmp = a; // Variable wird temporär zwischen gespeichert
      a = b;
      b = tmp;
    }
    
    int x = 1, y = 2;
    swap(x, y); // nachdem Aufruf hat x den Wert 2 und y den Wert 1

    2.5.4 Default-Parameter

    Um bei einem Funktionsaufruf nicht alle Parameter angeben zu müssen, kann man die Variablen vor belegen.

    int add(int a, int b, int c=0, int d=0); // muss bei der Deklaration geschehen
    
    add(1, 2, 3, 4); // man muss nicht alle Parameter angeben, für die fehlenden wird der Defaultwert 0 übergeben
    add(1, 2, 3);
    add(1, 2);

    2.5.5 Funktionen überladen

    Man kann den gleichen Namen einer Funktion verwenden, solange sie sich in der Parameterliste unterscheiden. Der Compiler entscheidet dann welche Funktion er verwenden muss.

    int add(int a, int b); // Deklaration der add Funktion mit zwei Integer Parameter
    int add(int a, int b, int c); // Deklaration mit drei Parameter

    2.6 Formatierung

    Ein wichtiges Thema wird meist vergessen, die Formatierung.

    • Bei der Benennung der Variablen werden wir dem CamelCase Style folgen. D.h. der Anfangsbuchstabe ist jeweils klein und jedes weitere Wort wird groß geschrieben.
    • Wichtig ist es auch sein Code zu kommentieren. Zu Beginn eine kurze Beschreibung, welche Funktion diese Datei hat, den Autor und das Datum, sowie Kommentare im Code. Ein gut kommentierter Code ist zu 50% Grün.
    • Außerdem ist es wichtig den Code übersichtlich zu gestalten und bei zu langen Ausdrücken in einer Zeile in mehrere Zeilen aufzuteilen.
    • Bitte auch darauf achten, dass der Code einer Funktion keinen größeren Umfang als eine Seite hat.
    • Jede neue Klasse sollte in einer neuen Datei geschrieben werden.
    int meineZahl = 5;
    Auto einObjectDerKlasseAuto;
    
    x = 1/2(b^2 * sin(angle/PI)) // dies ist ein Kommentar
    /* ein Kommentar..
    .. über mehrere Zeilen */
    
    if(a == true){b*=(a-b)%2} // kein Spaghetticode erzeugen

    3 Einführung in Arduino

    Arduino ist eine Open-Source-Plattform, basierend auf einem Mikrocontroller-Board und einer Entwicklungsumgebung. Warum Arduino? Arduino ist viel günstiger als so manches Entwickler Board. Sie sind leichter zu Programmieren als zum Beispiel die Atmel AVR Controller und es gibt eine große aktive Community.

    3.1 Software und Installation

    Arduino liefert eine eigene kleine Software die Ihr hier herunterladen könnt. Es existieren auch Plugins für Microsoft Visual Studio und Eclipse. Nach der Installation könt ihr auch schon gleich loslegen. Geht auf neuen Sketch erstellen (Programme in Arduino heißen Sketch). Dann wählt ihr noch den richtigen USB Port aus, unter Tools -> Serial Port. Nun muss noch das richtige Arduino Modell ausgewählt werden, unter Tools -> Board. Zum Schluss könnt ihr den Sketch hochladen.

    // Beispiel Sketch - Blinkende LED
    void setup() 
    {               
      pinMode(13, OUTPUT);     
    }
    
    void loop() 
    {
      digitalWrite(13, HIGH);
      delay(1000);            
      digitalWrite(13, LOW); 
      delay(1000);  
    }
    

    3.2 Programmieren

    Man kann den Arduino in C und teilweise in C++ programmieren, wobei man bei C++ auf den begrenzten Speicher acht geben muss. Zusätzlich gibt es noch spezielle mikrocontroller-typische Befehle, wie zum Beispiel das Einlesen und Ausgeben eines Pins. Für eine detaillierte Erklärung bitte hier nachlesen.

    3.2.1 Sketch

    Als Sketch wird ein Programm bezeichnet. Es beinhaltet immer zwei Funktionen, nämlich setup und loop. Setup wird genau einmal ausgeführt und dient zur Deklarationen von Variablen. Loop ist wie eine endlos-Schleife. Sie wird nach jedem Durchlauf wieder von neuem aufgerufen.

    void setup() 
    {
       // wird einmalig ausgeführt
    }
    void loop()  
    {
      // Endlos-Schleife
    }
    

    3.2.2 Digital I/O

    Folgendes dient zur Manipulierung der Digitalen Pins. Zuerst muss man im setup bekanntgeben, ob der Pin als Eingang oder als Ausgang fungiert.

    int val = 0;
    void setup()
    {
      pinMode(13, OUTPUT);  // setzt den Pin 13 als Ausgang
      pinMode(12, INPUT);  // setzt den Pin 12 als Eingang 
    }
    
    void loop()
    {
      val = digitalRead(12);  // einlesen des Digitalen Wert
      digitalWrite(13, val);  // macht den Ausgang HIGH  
      delay(1000);  // 1s warten
      digitalWrite(13, LOW);  // schaltet den Ausgang wieder auf LOW       
    }
    

    3.2.3 Analog I/O

    Für die Analogen Pins gilt fast das gleiche, wie bei den Digitalen Pins. Bei analogWrite wird der Wert in ein Rechtecksignal (PWM ca. 490Hz) umgewandelt, dass im Mittelwert dem gewünschten Analogen Wert entspricht.

    void setup()
    {
      pinMode(9, OUTPUT);   // Pin 9 unterstützt analogWrite()
    }
    
    void loop()
    {
      int val = analogRead(3);   // Potentiometer einlesen
      analogWrite(9, val >> 2);  // val muss von 0-1023 auf 0-255 angepasst werden
    }
    

    3.2.4 Zeit

    Für die Zeitgebung und die Verzögerung gibt es einige fertige Funktionen.

    // 1 s = 1 000 ms = 1 000 000 us
    t = millis();  // gibt die Millisekunden zurück seit der Mikrocontroller läuft. (Datentyp läuft in 50 Tagen über)
    t = micros();  // gibt die zeit in Mikrosekunden zurück. Die Auflösung beträgt 4 us bei 16MHz (Datentyp läuft in 70 Minuten über)
    delay(t);  // verzögert das Programm um ms
    delayMicroseconds(t);  // verzögert um us
    

    3.2.5 Kommunikation

    Die Kommunikation mit dem Arduino erfolgt meist über einen Seriellen Port. Zum einen wird der Arduino darüber programmiert, zum anderen kann man auch mit ihm kommunizieren. Zum Beispiel Sensorwerte auslesen und direkt anzeigen. Um dies zu machen muss man zuerst den Serial Monitor aktivieren und die richtige Baudrate auswählen. Für weitere Funktionen bitte hier entnehmen.

    void setup() 
    {
      Serial.begin(9600);  // Neue Kommunikation einrichten mit einer Baudrate von 9600
    }
    
    void loop() 
    {
      Serial.println(analogRead(0));  // den Analogen Pin0 einlesen und auf dem Serial Monitor ausgeben
      delay(100);  // verzögerung von 100 ms
    }   
    

    3.2.6 Mathe

    In der Standard Bibliothek gibt es schon vorhandene Funktionen für die Berechnung. Bei der Verwendung immer darauf achten, dass der Mikrocontroller nicht viel Leistung hat.

    minX = min(x1, x2);  // bestimmt die kleiner Zahl
    maxX = max(x1, x2);  // bestimmt die größere zahl
    x = abs(a);  // berechnet den Absolutwert
    x = constrain(x, a, b);  // wird überprüft ob x innerhalb des Wertebereich liegt. Wenn x kleiner als a ist wird a zurückgegeben und wenn x größer als b ist wird b zurückgegeben.
    value= map(value, fromLow, fromHigh, toLow, toHigh);  // Wertebereich wird angepasst
    a = pow(base, exponent);  // berechnet die Potenz einer Zahl
    a = sqrt(x);  // berechnet die Wurzel
    a = sin(a);  // berechnet den Sinus (Radiant)
    a = cos(a);  // der Rückgabewert ist auch Radiant
    a = tan(a);
    randomSeed(analogRead(0));  // Den Zufallsgenerator abhängig von einem Eingang machen. Der Funktionsaufruf muss im setup erfolgen
    x = random(300);  // eine Zufallszahl zwischen 0 und 299 generieren
    x = random(10, 100);  // Zufallszahl liegt zwischen 10 und 99);
    

    3.2.7 Externe Interrupts

    Ein Interrupt ist wenn ein wichtiges Ereignis eintritt und das Hauptprogramm unterbrochen wird, um das Ereignis zu verarbeiten. Bei dem Arduino Uno gibt es zwei Externe Interrupts an Pin 2 und Pin 3. Man kann den Interrupt auslösen, wenn der Eingang auf LOW ist, sich ändert ( CHANGE ), wechselt auf high ( RISING ) oder auf low wechselt ( FALLING ). Die Interrupt Service Routine ist die Funktion, die den Interrupt verarbeitet. Sie sollte so knapp wie möglich geschrieben werden. Manche Funktionen werden nicht mehr weiterverarbeitet, wenn ein Interrupt aufgerufen wird (serielle Kommunikation). Falls Interrupts bei kritischen Sachen nicht erwünscht sind, kann man sie mit noInterrupts() deaktivieren und mit interrupts() wieder aktivieren.

    volatile int state = LOW;  // falls die Funktion durch ein Interrupt verändert werden soll muss volatile angegeben werden
    void setup()
    {
      pinMode(13, OUTPUT);  // Pins 13 ist ein Ausgang
      attachInterrupt(0, blink, CHANGE);  // Interrupt 0, Interrupt Service Routine, soll auf ein Wechsel reagieren
      delay(60000);  // 60 s warten
      detachInterrupt(0);
    }
    
    void loop()
    {
      digitalWrite(13, state);
    }
    
    void blink()  // Interrupt Service Routine
    {
      state = !state;
    }
    

    3.3 Boards

    3.3.1 Arduino Uno

    Das meist verwendete Board heißt Arduino Uno. Aktuell in der dritten Revision ist es für fast jedes Projekt denkbar. Im Internet kursieren etliche Projekte und Anleitungen im Bezug auf den Arduino Uno. Es gibt zusätzlich einige Shields für dieses Board um die Funktionalität zu erweitern.

    Spezifikation Arduino Uno R3

    Microcontroller ATmega328
    Operating Voltage 5V
    Digital I/O Pins 14 (6 davon haben PWM)
    Analog Input Pins 6
    Strom maximal I/O Pin 40 mA
    Flash Memory 32 KB (0.5 KB Bootloader)
    SRAM 2 KB
    EEPROM 1 KB
    Clock Speed 16 MHz

    3.3.2 Arduino Mega

    Wenn einem die Anschlüsse doch mal nicht reichen sollten dann ist die bessere Wahl der Arduino Mega. Mit zusätzlichem Speicher ist er gut für die großen Projekte ausgerüstet.

    Spezifikation Arduino Mega R3

    Microcontroller ATmega1280
    Operating Voltage 5V
    Digital I/O Pins 54 (15 davon haben PWM)
    Analog Input Pins 16
    Strom maximal I/O Pin 40 mA
    Flash Memory 128 KB (4 KB Bootloader)
    SRAM 8 KB
    EEPROM 4 KB
    Clock Speed 16 MHz

    3.4 Beispiele

    Nun macht es hier wenig Sinn die gleichen Beispiele die es schon genügend im Internet gibt hier noch einmal auszutreten. Unter folgendem Link findet Ihr etliche gut beschriebene Tutorials die sich meist auf den Arduino Uno beziehen aber ohne Probleme auch mit dem Mega realisierbar sind.