Arduino-Programmierung

Aus LinuxUser 05/2013

Arduino-Programmierung

© Medialinx AG

Denken und Fühlen

Der Arduino lockt mit Offenheit und Portabilität: Die Schaltung des Minirechners ist ebenso frei lizenziert wie die zugehörige Entwicklungsumgebung. Grund genug, sich näher mit der Programmierung zu beschäftigen.

Mit dem Slogan “Ein Arduino fühlt und steuert die physische Welt besser als ein Desktop-PC” bewirbt der Hersteller [1] seine preisgünstige Mikroprozessor-Plattform. Das Aufmacherbild zeigt die Basisvariante Arduino Uno, das 53 x 68 Millimeter große Einsteigermodell der Minicomputer-Serie. Es kostet nur etwa 30 Euro [2] und basiert auf einem programmierbaren ATmega328-Prozessor.

Sechs analoge Eingänge (0 bis 5 Volt) und vierzehn Ausgangs-Pins (bis zu 40 mA Leistung) für Verbraucher prädestinieren den SBC als Ersatz für den bei aktuellen PCs meist fehlenden programmierbaren Parallelport. Die mit 16 MHz getaktete CPU überwacht und steuert diese Schnittstellen zur Außenwelt. Im Betrieb nimmt der Arduino nur rund 50 mA Strom bei 7 bis 12 Volt auf [3].

Mit dem PC kommuniziert der Winzling via USB, was auch unter Linux reibungslos funktioniert. Dies gilt auch für die unter der GPL vertriebene Entwicklungsumgebung [4], die auf Knopfdruck C- oder C++-Code in den 32 KByte großen Flash-Speicher des Arduino hochlädt und startet.

Die Baupläne aller Arduino-Modelle stehen ebenfalls unter einer freien Lizenz [5]. Sie dürfen sich ihren Minicomputer also auch selbst zusammenlöten, wenn Sie die nötige Fingerfertigkeit für den Umgang mit winzigen Mikroprozessor-Pins mitbringen.

Einfach anklicken

Auch wenn viele mit C oder C++ etwas anderes verbinden: Neben dem günstigen Preis macht gerade die einfache Programmierung den Arduino für den Einstieg in die Mikroprozessor-Programmierung interessant. Von der üblichen Komplexität der Embedded-Programmierung ist hier nichts zu spüren: Ein Knopfdruck in der Arduino-IDE compiliert den Quellcode, lädt ihn auf den Minirechner hoch und startet ihn.

TIPP

Falls die IDE sich beklagt, dass sie den am USB-Port angeschlossenen Arduino nicht findet, kann das am Modem-Manager liegen, der versucht, das Gerät als Modem anzusprechen. Beenden Sie dann den Modem-Manager – oder warten Sie einfach ein halbe Minute, bis er aufgibt.

Tief gehendes C- oder gar C++-Know-how brauchen Sie für die Arduino-Programmierung nur sehr selten. Auch die beiden Beispielprogramme, die dieser Artikel vorstellt, kommen ohne manuelle Speicherverwaltung mit malloc() und C++-Klassen aus.

Das erste Schaltungs- und Programmierexempel lässt sechs helle LEDs im von der Shell aus frei programmierbaren Rhythmus blinken. Die Schaltung eignet sich auch gut, um Zustände auf einem über USB angeschlossenen Computer oder von Serverdiensten optisch darzustellen. Einmal programmiert, blinkt der Minicomputer ohne Verbindung zum PC weiter.

Im zweiten Beispiel lauscht der Arduino auf den über einen Taster eingegebenen Morsecode und vergleicht ihn mit einer Punkt-Strich-Zeichenfolge. Am Klingelknopf angeschlossen, könnte der Arduino damit den Türöffner steuern und nur solchen Besuchern Zugang gewähren, die einen (bis zu 100 Zeichen langen) geheimen Rhythmus läuten.

Mehr Licht

Ohne angeschlossene externe Bauteile kann der Arduino bloß mit einer winzigen LED in der Nähe des USB-Anschlusses blinken. Sie können ein simples Blink-Programm von der Arduino-Homepage [1] auf ihr Gerät laden, um es damit zu testen.

Zu mehr Leuchtkraft verhelfen dem Minicomputer in der Beispielschaltung sechs High-Power-LEDs (Abbildung 1). Bei dem eingesetzten Typ des Herstellers Luckylight verkraften Blau und Grün zwischen 2,8 und 4 Volt, lassen sich also ohne Vorwiderstand paarweise hintereinander direkt an die 7,5 Volt des spannungsstabilisierten Arduino-Schaltnetzteils anschließen. Anders die roten LEDs: Bei einer zulässigen Eingangsspannung zwischen 1,6 und 2,4 Volt würden sie ohne vorgeschalteten Widerstand zwar nicht sofort durchbrennen, aber nach kurzer Zeit ausfallen.

Abbildung 1: Eine einfache, 10 x 10 Zentimeter große Rasterplatine bietet genug Platz für unsere Schaltung. Diese besteht aus einem Taster, den über Power-Feldeffekt-Transistoren angesteuerten helle LEDs sowie den aufmontierten Arduino.

Abbildung 1: Eine einfache, 10 x 10 Zentimeter große Rasterplatine bietet genug Platz für unsere Schaltung. Diese besteht aus einem Taster, den über Power-Feldeffekt-Transistoren angesteuerten helle LEDs sowie den aufmontierten Arduino.

Der Vorwiderstand muss beim roten Kanal also gut 3 Volt verbraten. Beim einem Stromverbrauch der LED von 35 mA gilt es nach dem Ohmschen Gesetz grob 100 Ohm vorzuschalten. Das entspricht Pi mal Daumen einem etwas weniger als halb geöffneten 250-Ohm-Poti. Damit sich die Helligkeit aller Kanäle regeln lässt, schalten wir diesen Poti auch vor die grünen und blauen LEDs.

Verstärkung gefragt

Die Ausgangspins des Arduino schaffen maximal 40 mA, was für die High-Power-LEDs knapp ausreicht. Für eine universell erweiterbare Schaltung steuern wir sie indirekt über einen Feldeffekt-Transistor des Typs IRLIZ44N, der im Elektronikhandel leicht zu bekommen ist. Er schaltet zwischen seinen Drain und Source genannten Pins – Sie sehen diese in Abbildung 2 rechts – Lasten bis zu 30 Ampere bei 55 Volt. Die FET-Schaltung könnte also wesentlich mehr verkraften als einfache Blinklichter.

Abbildung 2: Die Analogschaltung mit Bauteilen, die alle im einschlägigen Elektronikhandel leicht zu bekommen sind, hat den Autor trotz lange Jahre zurückliegender Löterfahrung nicht überfordert.

Abbildung 2: Die Analogschaltung mit Bauteilen, die alle im einschlägigen Elektronikhandel leicht zu bekommen sind, hat den Autor trotz lange Jahre zurückliegender Löterfahrung nicht überfordert.

Die Source des FETs verschalten wir direkt mit Masse, den Drain-Pin verbinden wir mit der Kathode der LEDs. Das LED-Pinout zeigt Abbildung 2 auf der rechten Seite. Zwischen LED-Anode und Pluspol liegt noch der schon erwähnte 250-Ohm-Poti als Vorschaltwiderstand.

Verbleiben noch zwei Widerstände pro Kanal: Ein 10-kOhm-Widerstand schließt den Transistor trotz eventueller Einstreuung zuverlässig, wenn der Arduino-Ausgangspin 0 Volt liefert. Der 1-kOhm-Widerstand schützt den Arduino vor Überlastung, falls mit der Schaltung dahinter etwas nicht stimmen sollte.

Wir haben die mit DIGITAL bezeichnet Pins 3, 5 und 6 als Ausgänge gewählt. Diese am Arduino mit ~ markierten Pins sind nicht nur als einfache Schalter ausgelegt, sie dimmen die LEDs auch durch Ein- und Ausschalten im KHz-Bereich (Pulse Width Modulation, PWM). Unsere Beispielprogramme machen davon allerdings keinen Gebrauch.

Für das zweite Beispiel fehlt noch ein einfacher Taster. Ist er geöffnet, zieht ein 10-kOhm-Widerstand Pin 8 auf 0 Volt. Bei geschlossenem Taster liegen die 5 Volt aus dem mit 5V gekennzeichneten Ausgang am Arduino-Board an. Verbinden Sie den Taster nicht mit den 7,5 Volt der LED-Schaltung: Das würden den Arduino zerstören.

Arduino-Programmierung: Basics

Jedes Arduino-Programm muss die Funktionen void setup(){} und void loop(){} enthalten. Wie die Namen schon andeuten, läuft setup() beim Start des Programms einmal, loop() hingegen anschließend pausenlos als Endlosschleife.

Wer seine Programmiererfahrung mit Skriptsprachen gesammelt hat, wird über das Schlüsselwort void in der Definition von setup() stolpern. Anders als bei Skriptsprachen muss man in C stets den Rückgabewert einer Funktion explizit angeben – zum Beispiel int für Ganzzahlen, boolean für wahr/falsch oder void für Funktionen ohne Rückgabewert.

Die für C eigentlich obligatorische Trennung der oft in Header-Dateien (*.h) ausgelagerten Funktionsdeklarationen und der endgültigen Implementierung fällt innerhalb der Arduino-Laufzeitumgebung weg. Die IDE (Abbildung 3) erzeugt die Header beim Klick auf die Schalter Kompilieren oder Upload stillschweigend, ohne dass Sie das Ergebnis zu sehen bekommen.

Eine Funktion, die zwei Integer-Zahlen addiert und wieder einen Ganzzahlwert zurück gibt, definieren Sie also in folgender Form:

int add(int Zahl1, int Zahl2){ //C-Code }

Den Rest erledigt die Arduino-Umgebung. Jedoch gilt es zumindest Variablen vor ihrer Verwendung mit Typenangabe zu deklarieren: int Ganzzahl;, char Einzelzeichen; oder float Fließkommazahl;.

Abbildung 3: Die dank Java systemübergreifend lauffähige, GPL-lizenzierte Arduino-IDE verbirgt die Komplexität der Mikroprozessor-Programmierung. Rot hervorgehoben sind der <code srcset=

Upload-Button und die Anzeige des Arduino-Geräts im Verzeichnis /dev.” width=”275″ height=”300″ /> Abbildung 3: Die dank Java systemübergreifend lauffähige, GPL-lizenzierte Arduino-IDE verbirgt die Komplexität der Mikroprozessor-Programmierung. Rot hervorgehoben sind der Upload-Button und die Anzeige des Arduino-Geräts im Verzeichnis /dev.

Blinkrhythmus

Das komplette Listing zur Blinkschaltung finden Sie auf der Heft-DVD sowie unter http://www.linux-user.de/Downloads/2013/05. Im Folgenden stellen wir Ihnen kurz die wesentlichsten Abschnitte des Codes vor.

Der Inhalt von setup() lässt sich mithilfe der Referenz zur Arduino-Programmierumgebung [6] einfach verstehen: Er initialisiert den seriellen Port mit dem für unsere Zwecke ausreichenden Tempo von 9600 Bit pro Sekunde (Serial.begin(9600)) und schaltet die Pins 3, 5 und 6 vom hochohmigen Input-Modus in den niederohmigen Output-Modus (pinMode(int Pin, OUTPUT)). Details zu pinMode() und Serial liefert wie immer das Handbuch.

Zeitschleife

Den Kern der sich endlos wiederholenden Hauptschleife loop() bildet der Aufruf der benutzerdefinierten Funktion rhythmCycle(). Eine Verzögerungsschleife am Ende der Schleife (Listing 1) sorgt dafür, dass diese Funktion nur alle 10?000 Mikrosekunden aufgerufen wird.

Listing 1

while((micros() - lastTimeSlot ) < (timeSlot) && (micros() > lastTimeSlot)) {}
lastTimeSlot = micros();
@KE

Die in der Arduino-Laufzeitumgebung vordefinierte Funktion micros() liefert die Mikrosekunden seit dem Programmstart. Die While-Schleife “hängt” daher so lange, bis entweder timeSlot Mikrosekunden vergangen sind oder der Zeitzähler überläuft, was etwa alle 70 Minuten passiert. Vorher übergibt loop()an rhythmCycle(), das für das Ein- und Ausschalten der LEDs verantwortlich ist (Listing 2).

Listing 2

void rhythmCycle(){
  // alle Farben durchzählen
  for(int color = 0; color <= 2; color++){
        [...]
    if(RhythmCounter[color] > 0){
      RhythmCounter[color]--;
    } else {
      toggleState(color);
      RhythmCounter[color] =
        Rythm[color][RythmPointer[color]];
      if(RythmPointer[color] <
       RythmMaxIndex[color]){
        RythmPointer[color]++;
      } else {
        RythmPointer[color] = 0;
      }
    }
  }
}

Die äußerste Schicht von Listing 2 bildet eine Schleife über die color-Werte von 0 bis 2, die für Rot, Grün und Blau stehen. Die LEDs jeder Farbe sollen eine definiert Anzahl von Zyklen, sprich: rhythmCycle()-Aufrufen, im gleichen Zustand verharren. Dazu zählt der If-Zweig den Inhalt des Arrays RhythmCounter[color] bis auf null herunter. Dieses Array mit Integerwerten wurde außerhalb jeder Funktion, also mit globaler Gültigkeit, folgendermaßen definiert:

int RhythmCounter[3] = {Wert,Wert,Wert};

Sie hängen also bei der Definition lediglich die Zahl der Array-Elemente in eckigen Klammern an den Variablennamen an. Die Werte eines Arrays initialisieren Sie mit einer Liste in geschweiften Klammern. In C ist die Länge eines Arrays nach der Deklaration unveränderlich, der Lesezugriff auf RhythmCounter[4] würde ohne Fehlermeldung einen undefinierten Wert liefern, ein Schreibzugriff sogar zum Absturz führen.

Es tut sich was

Spannender als der einfache Zähler im If-Zweig fallen die von else{} umschlossenen Zeilen aus: Sie laden einen neuen Wert mit den Zeitzyklen bis zum nächsten Blinken nach RhythmCounter[color]. Zuvor schaltet toggleState(color) aber erst einmal den Zustand der color entsprechenden LED um. Dazu invertiert es den Bool-Wert im Array LEDState[color] und setzt den Ausgabepin mit:

digitalWrite(Pins[color], LEDState[color]);

Die Zyklen für die An/Aus-Zeiten einer Leuchtdiode stehen im zweidimensionalen Array Rythm[color][i], das global zu Beginn des Codes definiert ist (Listing 3)

Listing 3

int Rythm[3][MaxRhythmLength] = {
        {100,100,50,50},
        {50,50,100,100},
        {50,100,100,50},
};

Zweidimensionale Arrays versteht C als Arrays aus Arrays. Die Zahlenwerte in den eckigen Klammern stehen dabei für die Anzahl der maximal enthaltenen Arrays (hier drei) und der maximalen Länge dieser Arrays vom Typ int. Statt einer Zahl ist bei den Längenwerten aus eine Konstante erlaubt, in unserem Fall const int MaxRhythmLength = 254.

Ungenierte Verschwendung

Obwohl die inneren Arrays bei der Initialisierung nur vier Elemente lang sind, bleibt Speicherplatz für 254 Ganzzahlenwerte reserviert, um entsprechend lange Rhythmusfolgen eingeben zu können.

Die Länge eines Array muss in C aber bereits beim Kompilieren feststehen, sodass sich diese verkraftbare Speicherverschwendung nur mit einigem Aufwand vermeiden ließe. Neulinge in der C/C++-Welt dürfen aber nicht vergessen, vor dem Schreiben nach Rhythm[color][i] zu prüfen, dass i nicht größer ist als MaxRhythmLength, denn sonst stürzt der Arduino ab.

Zum Auslesen der Sequenzen aus Rhythm brauchen wir noch den Zeiger RythmPointer[color], ein Integer-Array. Er durchläuft die Werte von null bis RythmMaxIndex[color], wo anders als in MaxRhythmLength nicht die maximal erlaubte, sondern die tatsächliche Elementzahl des Arrays in Rythm[color] steht.

Nach dem Auslesen erhöht eine zweite If/Else-Verzweigung innerhalb des else-Blocks den Pointer RythmPointer[color], außer er ist bereits bei RythmMaxIndex[color] angelangt. Dann erhält er den Wert null und das Auslesen der Verzögerungswerte aus Rhythm beginnt wieder bei null.

Heiße Rhythmen

Der fest programmierte Anfangsrhythmus aus nur vier An/Aus-Sequenzen für die drei LEDs ist recht langweilig. Doch wie schon angeklungen können Sie Blinkfolgen aus bis zu 254 Zeitwerten eingeben. Der Arduino lässt sich über das in der Statuszeile der Arduino-IDE genannte TTY, normalerweise /dev/ttyACM0, von der Konsole aus ansprechen.

Für den Anfang ist jedoch der in die IDE eingebaute Serial-Monitor bequemer. Öffnen Sie ihn mit [Umschalt]+[Strg]+[M] und stellen Sie sicher, dass in den beiden Ausklapplisten unten im sich öffnenden Fenster für das Zeilenende Neue Zeile (NL) sowie die Übertragungsgeschwindigkeit 9600 baud ausgewählt sind.

Geben Sie nun rh 31,5 10,28,19,5,25,10,10,10,10,25 ein und drücken Sie [Eingabe] oder klicken Sie auf Senden. Der Arduino meldet sich mit Pattern (188 Zyklen) für Farbe Rot, und die rote LED blinkt von nun an einen wilden Rumba.

Die erste Stelle der Eingabe (r, g oder b) steht für die Farbe. Damit sich die Blinksequenzen gegeneinander versetzen lassen, wählt das nun folgende l– oder h-Zeichen, ob die Folge mit eingeschalteter (h) oder ausgeschalteter LED (l) startet.

Darauf folgen mit Kommas oder Leerzeichen getrennte paarweise Zahlenwerte: An/Aus oder Aus/An-Sequenzen, je nachdem, ob das zweite Zeichen h oder l gelautet hat. Die Einheit für die Schaltzeitwerte ist nach dem Start auf 1/100-tel Sekunden gesetzt, lässt sich aber durch Eingabe von t Mikrosekunden an der Konsole umstellen, damit man einen bereits programmierten Grundrhythmus beschleunigen oder verlangsamen kann.

Kontakt zur Außenwelt

Für das Lauschen an der seriellen Schnittstelle, die über das USB-Kabel mit dem PC verbunden ist, zeichnet die gegen Ende von loop() aufgerufene Funktion evaluateInput() zuständig.

Der Aufruf erfolgt – unabhängig vom Tempo, mit dem die Hauptverzögerungsschleife durchlaufen wird – nur jede Viertelsekunde. Jeder Zugriff auf die serielle Schnittstelle löscht nämlich alle dort anliegenden, aber noch nicht übertragenen Zeichen und darf daher nicht in zu kurzen Abständen erfolgen.

In evaluateInput() sorgt die Schleife while (Serial.available() > 0) dafür, dass die Funktion alle verfügbaren Zeichen abgreift. Sie prüft zunächst auf den Buchstaben t und leitet gegebenenfalls an setTempo() zur Neujustierung der Zeitbasis weiter.

Ist das erste Zeichen kein t, folgt eine Umsetzung der Zeichen r, g oder b in den im Programm durchgängig verwendeten Integer-Farbcode zwischen 0 und 2. Dazu kommt das in der Laufzeitumgebung vordefinierte C++-Objekt String zum Einsatz. Dabei handelt es sich um ein String-Objekt variabler Länge, das die für Anfänger schwierige Arbeitsspeicherverwaltung kapselt.

Aber darum geht es an dieser Stelle noch nicht. Hier hilft uns seine Methode String.indexOf(char) weiter: Sie gibt zurück, an welcher Stelle das Farbcode-Zeichen im String rgb steht. So dürfen Sie den intuitiveren Buchstabencode für eine Farbe eingeben, obwohl das Programm mit einem numerischen Array-Index arbeitet.

Als Nächstes gilt es auf das Zeichen l oder h zu prüfen und das Ergebnis nach LEDStartState[color] zu schreiben. Dann folgt das Einlesen der An/Aus-Werteliste, das die FunktionreadRythmString(color) erledigt (Listing 4).

Listing 4

void readRythmString(char color){
  int readValuesCount = 0;
  int PatternLength = 0;
  int Value;
  while (readValuesCount < MaxRhythmLength
    && Serial.peek() != '\n' ){
    Value = Serial.parseInt();
    Rythm[color][readValuesCount] = Value;
    readValuesCount++;
    PatternLength += Value;
  }
  RythmMaxIndex[color] = readValuesCount -1;
  [...]
}

Die Hauptarbeit nimmt uns die vordefinierte C++-Methode Serial.parseInt() ab, denn sie schreibt die auf <Farbcode><l|h> folgende Zahlenreihe in einer While-Schleife direkt als Integer-Wert in das Array Rythm. Die Schleifenbedingung überwacht dazu auf das Zeichen \n (Newline) als Sequenzschluss sowie gleichzeitig auf die Maximallänge von MaxRhythmLength. So entsteht ein neuer Rhythmus für color.

Damit rhythmCycle ihn auslesen kann, muss RythmMaxIndex[color] den größten vorkommenden Array-Index für Rythm[color][n] enthalten. Weil das Inkrement mit readValuesCount++ nach dem Schreiben in Rythm[color][readValuesCount] erfolgt, ist readValuesCount-1 der richtige Wert.

Bildhaft dargestellt

Das serielle Device auf dem Arduino ist nach Anschluss des USB-Kabels an den PC über das Character-Device /dev/ttyACM0 erreichbar. Um mit dem Minirechner zu kommunizieren, genügt es dennoch nicht, es einfach mit echo "xxx" > /dev/ttyACM0 zu beschreiben oder mit cat /dev/ttyACM0 auszulesen, denn jeder Zugriff auf die Gerätedatei bootet den Arduino neu. So startet ein von der Arduino-IDE über die serielle Schnittstelle hochgeladenes neues Programm ohne Druck auf den Reset-Taster.

Leiten Sie also für einen Zugriff von der Shell aus das Character-Device mit exec 3<> /dev/ttyACM0 (oder das am unteren Fensterrand der IDE angezeigte Device) auf das File-Handle Nummer drei um, das Linux selbst nicht benutzt. Auch dabei startet der Arduino neu, jedoch nicht mehr bei Schreib- und Lesezugriffen auf das File-Handle mit echo "xxx" >&3 oder cat <&3 . Nach dem Reboot in knapp einer Sekunde funktioniert der Zugriff via &3 also genau so bequem wie der Serial-Monitor der Arduino-IDE.

Das Bash-Skript cpulast.sh aus Listing 5 nutzt die Device-Umleitung, um die Blinkgeschwindigkeit der roten LED im Sekundentakt der CPU-Last anzupassen. Der Befehl vmstat 1 2 gibt nach einer Sekunde zwei Zeilen mit Systemlastwerten aus. Das per Pipe angehängte sed -n '4p' filtert die vierte Zeile der Vmstat-Ausgabe heraus: In den ersten zwei Zeilen stehen Spaltenüberschriften, die dritte Zeile listet Durchschnittslastangaben seit dem Systemstart. Darum stehen die gesuchten Werte erst in der vierten Zeile.

Listing 5

while(true); do
  idle=$(vmstat 1 2|sed -n '4p'|awk '{print $15}')
  echo "rh 1,$(( ($idle/3)+1 ))">&3
  cat <&3 > /dev/null
done

Es folgt eine weitere Pipe auf den Kommandozeilentextprozessor Awk, der die fünfzehnte Spalte herauslöst. Dort steht der Leerlaufprozentsatz, den die im Skript folgende Zeile durch drei teilt und in die Zeichenfolge rh 1,xx \n einbaut, wie wir sie schon bei der Programmierung des ersten Beispielprogramms über den Serial-Monitor kennengelernt haben. Sie steht für “Rot 1 ms an, xx ms aus”. Da der Vmstat-Befehl ohnehin schon eine Sekunde läuft, ist in der nur mit [Strg]+[C] zu beendenden Endlosschleife keine weitere Verzögerung nötig.

Weil der Arduino auf die gesendete Zeichenfolge mit einer Meldung antwortet, müssen wir diese auch mit cat <&3 > /dev/null abholen, sonst läuft der Puffer der seriellen Schnittstelle voll. Um dies zu vermeiden, könnten Sie alternativ alle Aufrufe von Serial.print() aus dem Programm auf dem Minirechner entfernen.

Um das Skript auszuprobieren, laden Sie das erste Beispielprogramm auf dem Arduino, starten die Umleitung des Arduino-Devices mit exec 3<> /dev/ttyACM0 und rufen Sie das Skript auf, sobald die LEDs im vorprogrammierten Rhythmus blinken. Solange das Skript läuft, ändert sich die Blinkgeschwindigkeit der roten LED mit der CPU-Last.

Mit dem Verfahren, per Bash Zeichenfolgen zum Setzen des Blinkrhythmus über &3 an den SBC zu senden, lässt sich jeder Wert auf dem PC optisch darstellen, auf den die Shell Zugriff hat.

Die vom Arduino über die serielle Schnittstelle versandten Daten lassen sich mit tail -f <&3 anzeigen, statt sie nach /dev/null zu entsorgen. Dank des Puffers auf dem Minicomputer genügt eine einfache Schleife, die &3 in angemessenen Abständen ausliest als Basis für eine Analogmesswerte-Schaltung mit Auswertung auf dem PC.

Elektronischer Türsteher

Mit dem im vorigen Beispiel erworbenen Wissen über die Arduino-Laufzeitumgebung lässt sich leicht ein einfacher Morsemuster-Erkenner umsetzen. Insbesondere die String-Klasse für Zeichenketten variabler Länge inklusive Methoden zum Vergleich erleichtert hier die Programmierung. Auch hier finden Sie das komplette Listing auf der Heft-DVD sowie unter http://www.linux-user.de/Downloads/2013/05. Die wichtigsten Teile gibt Listing 6 wieder.

Die Hauptschleife des Programmsloop() wartet zunächst, bis digitalRead(pushButton) mit dem Wert HIGH einen Tastendruck erkennt. Dann übernimmt die Funktion readInput().

Dort misst eine Schleife, die erst endet, wenn mehr als inputFinished (750 Millisekunden) kein weiterer HIGH-Impuls folgt, wie lange die Taste zwischen LOW-Phasen gedrückt bleibt. Liegt die Dauer über shortLongThreshold (100 Millisekunden), erweitert sie das String-Objekt inputPattern um einen Strich, bei kurzen Tastendrücken um einen Punkt.

Nach dem Ablauf von readInput() muss die Hauptschleife nur noch den zurückgegeben String mit dem vorgegebenen pattern vergleichen. Dafür stellt des String-Objekt die Methode equals() zur Verfügung. War das Muster richtig, schaltet das Programm die grüne LED ein, sonst die rote. Danach startet loop() von vorne.

Wer sich den Code nach if(captured.equals(pattern)){ genau ansieht, stellt fest, dass die grüne LED im Erfolgsfalls buzzerOn Millisekunden (7 Sekunden) an bleibt und dann wieder aus geht. Ist der grüne Kanal mit dem Türöffner verbunden (Abbildung 4), genügt das bequem, um einzutreten. Die rote LED bleibt nach einer fehlerhaften Eingabe bis zum Reset des Arduino mittels des roten Tasters neben dem USB-Port an.

Abbildung 4: Die Mustererkennungsschaltung aus Listing 6 verwandelt den Klingelknopf in einen Morsetaster. Nur beim Klingeln im als Punkt-Strich-Folge im Programmcode hinterlegten geheimen Rhythmus öffnet sich die Tür.

Abbildung 4: Die Mustererkennungsschaltung aus Listing 6 verwandelt den Klingelknopf in einen Morsetaster. Nur beim Klingeln im als Punkt-Strich-Folge im Programmcode hinterlegten geheimen Rhythmus öffnet sich die Tür.

Noch nicht erwähnt wurde, dass readInput() den blauen Kanal einschaltet, solange die Klingel ohne längere Pause betätigt wird. Trennt man das Läutwerk vom Klingelknopf und hängt es an den blauen Kanal, dann verrät das Klingeln nicht den geheimen Rhythmus.

Listing 6

// Konstanten für Pin-Nummern
  (...)
// Morsemuster
String pattern = "...---...";
// LED-Pins als Output
void setup(){
  (...)
}
// Hauptschleife
void loop(){
  // sobald Input HIGH, lese Muster ein
  if(digitalRead(pushButton) == HIGH) {
    String captured = readInput();
    // eingeg. Muster richtig
    if(captured.equals(pattern)){
      // grün für buzzerOn ms an
      digitalWrite(green, HIGH);
      delay(buzzerOn);
      digitalWrite(green, LOW);
      // eingeg. Muster falsch
    } else {
      digitalWrite(red, HIGH);
    }
  }
}
// Muster einlesen
String readInput(){
  boolean keepReading = true;
  (...)
  digitalWrite(blue, HIGH);
  do{
    // Länge von "gedrückt" messen ...
    (...)
    // ... und entsprechend
    // "." oder "-" zum Muster hinzufg.
    if(pressLength > shortLongThreshold){
      inputPattern += "-";
    } else {
      inputPattern += ".";
    }
    (...)
  } while(keepReading);
  digitalWrite(blue, LOW);
  return inputPattern;
}

Fazit

Dreierlei bietet der Arduino für unter 30 Euro: Analogfühler, die Spannungen zwischen 0 und 5 Volt messen; Ausgabepins, die bis zu 40 mA schalten; sowie einen 16-MHz-Mikroprozessor, der sich dank der unter Linux, Windows und Mac OS lauffähigen quelloffenen IDE und der auch für Anfänger verständlichen Dokumentation [6] einfach programmieren lässt.

Die Baupläne des Minirechners sind nach dem sympathischen Open-Hardware-Prinzip lizenziert. Wer nicht selbst den Lötkolben in die Hand nehmen möchte, kann zahlreiche aufsteckbare Erweiterungsboards (“Shields”) erstehen [7]. Von der Arduino-Homepage können Sie zahlreiche Beispielschaltungen und Programme abrufen [8]

Glossar

SBC

Single Board Computer. Gängige Bezeichnung für Rechnersysteme, die alle zum Betrieb notwendigen Komponenten auf einer Platine zusammenfassen.

TTY

Teletype Interface, serielle Schnittstelle.

Infos

[1] Arduino-Homepage: http://arduino.cc

[2] Arduino-Bezugsquellen: http://arduino.cc/en/Main/Buy

[3] Arduino Uno: http://arduino.cc/en/Main/ArduinoBoardUno

[4] IDE unter Linux installieren: http://playground.arduino.cc/Learning/Linux

[5] Schaltplan Arduino Board: http://arduino.cc/en/Main/ArduinoBoardSerialSingleSided3

[6] Referenz zur Arduino-Programmierung: http://arduino.cc/en/Reference/

[7] Arduino-Produktpalette: http://arduino.cc/en/Main/Products

[8] Tutorials: http://arduino.cc/en/Tutorial

DIESEN ARTIKEL ALS PDF KAUFEN
EXPRESS-KAUF ALS PDF
LinuxUser 05/2013 KAUFEN
EINZELNE AUSGABE
ABONNEMENTS
TABLET & SMARTPHONE APPS
E-Mail Benachrichtigung
Benachrichtige mich zu:

Hinweis: Dieser Artikel ist älter als ein Jahr, enthaltene Informationen sind möglicherweise veraltet.

0 Kommentare
Älteste
Neuste Beste Bewertung
Nach oben