Kitabı oku: «Android mit Arduino™ Due»

Manuel di Cerbo, Andreas Rudolf
Yazı tipi:

1 Einleitung

1.1 Android

Android ist ein Betriebssystem, das besonders im Smartphone- und Tablet-Bereich eingesetzt wird. Entwickelt wird es hauptsächlich von der sogenannten Open Handset Alliance, die von Google angeführt wird.

Im Kern von Android befindet sich der Linux-Kernel, der gänzlich unter der Open-Source-Lizenz General Public License (GPL) entwickelt wird. Der Linux-Kernel ist ein Stück Software, um unter anderem Hardware anzusteuern und Speicher zu verwalten. Außerdem werden Prozesse und Rechte zur Verfügung gestellt. Generell kann der Linux-Kernel als »Fundament« des Betriebssystems aufgefasst werden. Bis vor Kurzem wurde Linux vor allem in Server- und Embedded-Systemen verwendet. Dies änderte sich aber schlagartig in den letzten Jahren mit der rasanten Verbreitung von Android.

Linux

Linux ist ein Betriebssystemkern, der vom Hacker und Bastler Linus Torvalds in seiner Studienzeit entwickelt wurde. Mit der Lizenzierung unter GPL ermöglichte er die Verbreitung seines Systems ohne Restriktionen, weil er Entwicklern am System möglichst viel Freiraum geben wollte. Heute verbessern tausende Entwickler den Linux-Source-Code. Der »Vanilla-Kernel«, ein Referenz-Kernel von Linux, wird in regelmäßigen Abständen von Linus Torvalds veröffentlicht. Auch führende Technologiekonzerne wie Intel, ARM, Microsoft und IBM arbeiten am Linux-Kernel und tragen mit »Patches« zu dessen Weiterentwicklung bei.

Wie der Kernel ist der Android-Source-Code auch als »Open Source« lizensiert. Allerdings wird für die Bestandteile von Android, die außerhalb des Kernels liegen, eine weniger restriktive Lizenz (zumeist Apache oder LGPL) verwendet. Dies erlaubt es den Hardware-Vertreibern, Modifikationen vorzunehmen, ohne dazu verpflichtet zu sein, den dazugehörigen Source-Code zu offenbaren. Primär hat dies zum Ziel, den Wettbewerb zwischen den einzelnen Vertreibern anzukurbeln und die Plattform wirtschaftlich für Hardware-Hersteller (meist auch Mitglieder der Open Handset Alliance) interessant zu machen.

GPL

GPL ist eine »Copyleft«-Lizenz. Bei der Erweiterung von GPL-lizenziertem Source-Code muss dieser mit der gleichen GPL-Lizenz weitergegeben werden. Dies führt dazu, dass alle Änderungen, die am Source-Code vorgenommen werden, dem originalen Verfasser mitgeteilt werden müssen. Bei einer Apache-Lizenz ist das nicht nötig, allerdings muss bei Weiterentwicklungen eine Notiz vorhanden sein, dass der Source-Code auf einem Apache-lizenzierten Ausgangsprojekt beruht.

Das Hauptinteresse von Google ist es, die Android-Plattform zu verbreiten, sodass Endbenutzer in Zukunft möglichst viele Dienstleistungen über den Suchmaschinengiganten in Anspruch nehmen. Zusätzlich bemüht sich Google, ein »Entwickler-Ökosystem« zu pflegen, das als zentralen Bestandteil den Google Play Store hat. Entwickler sollen in der Lage sein, gewinnbringend Applikationen – die bekannten Android-Apps – zu vermarkten, und Google ist dabei am Erfolg beteiligt (30 Prozent des Preises einer App gehen beim Kauf an Google).

Die »Google Play«-App selbst ist – wie auch die Apps »GMail« und »Google Maps« – nicht Open Source und wird dem Kunden nur zur Verfügung gestellt, wenn die Hardware und die Android-Implementierung den Standards der Open Handset Alliance entsprechen. Dies erfolgt aus Gründen der Qualitätssicherung.

Android ist für Entwickler interessant, da es statt klassischer Softwareentwicklung eine nahezu geniale Einbettung von Applikationen in das Betriebssystem erlaubt. Mit akribisch genauer Dokumentation und guten Tutorials für das Android Software Development Kit (Android SDK) motiviert Google Entwickler, das Betriebssystem als Basis für ihre nächste große App zu verwenden.

Android SDK

Das SDK ist zentraler Bestandteil der Android-Philosophie. Auch mitgelieferte Apps wie »Telefon«, »E-Mail« und »Browser« basieren auf dem SDK. Regelmäßig veröffentlicht Google neue Versionen des SDKs, die es den Entwicklern erlauben, neue Features in ihre Apps einzubauen.

Als Programmiersprache für Android-Apps wird überwiegend Java verwendet. Mit der Möglichkeit, nativen Code in C/C++ zu schreiben und diesen via Java Native Interface (JNI) einzubinden, existiert zusätzlich die Option, zeitkritische Komponenten einer App auszulagern. In diesem Buch werden wir uns allerdings auf die klassische Android-Entwicklung mit Java konzentrieren.

Der Open-Source-Charakter des Betriebssystems zieht sehr viele Entwickler an. Allein schon die Möglichkeit, in den Source-Code des Betriebssystems Einblick zu nehmen, um Software-Patterns zu lernen und Bestandteile eines modernen Systems zu erkunden, begeistert viele Software-Entwickler. Auch der Bestandteil Linux ist ein Faktor, warum Bastler und Hobbyisten gerne mit Android arbeiten. Denn für Linux gibt es Hardware-Treiber wie Sand am Meer – und alle sind frei verfügbar.

1.2 Arduino

Die Marke Arduino hat vieles gemeinsam mit Android. Arduino ist eine Entwicklerplattform für Hardware. Neben den Hardware-Boards, die mit leistungsfähigen Mikrocontrollern ausgestattet sind, ist auch die Softwareplattform Arduino IDE (IDE = Integrated Development Environment) als Entwicklungsumgebung ein wichtiger Teil des Projekts. Beide Bestandteile, Hardware und Software, sind als Open Source verfügbar. Der Name Arduino ist allerdings als Marke eingetragen und geschützt.

Arduino-Boards

Originale Arduino-Boards werden in Italien hergestellt und weltweit vertrieben. Die Erfinder von Arduino arbeiten konstant an Verbesserungen bestehender Boards und an neuen Shields, die es ermöglichen, die Arduinos mit Peripherie zu erweitern.

Während der letzten zwei Jahre erlebte die Hardware-Branche mit Arduino etwas Unvorstellbares. Open-Source-Hardware, die jeder kopieren und vertreiben kann, bricht als Geschäftskonzept alle Regeln der Betriebswirtschaft. Mit einem Mix aus Markenstärke, durchdachtem Vertrieb und Weiterentwicklung der Arduino-Plattform schaffte es das Produkt in praktisch jedes Zimmer und jede Garage der passionierten Hobbytüftler. Wenn man heute einen Arduino kauft, dann kauft man Qualität sowie Kompatibilität, und dafür steht die Marke Arduino.

Für dieses Buch werden wir uns mit dem Arduino Due befassen. Er ist ein Entwicklerboard, das mit einem Cortex-M3 als Mikrocontroller bestückt ist und Aus- und Eingänge für Peripherie besitzt, z. B. serielle Schnittstelle, SPI, D/A-Wandler, A/D-Wandler und CAN.

Die Kommunikation mit Android ist ohne Zukauf von Modulen über USB möglich. Dies kann beim Arduino Due auf zwei Arten geschehen:

1. Arduino als USB-Device

Der Arduino wird über den USB-Seriell-Wandler (USB-Serial-Konverter) von Android angesprochen, dazu übernimmt Android die Rolle des USB-Hosts; je nach Gerät erfolgt dies mit einem USB-OTG-Konverter (USB On-The-Go). Gewisse Tablets verfügen über einen herkömmlichen USB-A-Port, wie er vom Desktop-PC bekannt ist. Der Arduino wird dabei vom Android-Gerät mit Strom versorgt und muss nicht extern gespeist werden.

2.  Arduino als USB-Host

Der Arduino übernimmt die Rolle des USB-Hosts und versorgt das Android-Gerät mit Energie. Hierzu wird auf der Seite von Android die Android Accessory API verwendet und der Arduino als sogenanntes »Accessory« betrieben.

Auf beide Varianten wird in den kommenden Teilen des Buchs näher eingegangen.

Der Arduino kann so die Schnittstelle zur »realen Welt« werden und externe Hardware ansteuern. Vom Toaster-Regulator bis zur Rasenmäher-Steuerung sollte so alles möglich sein.

Tipp

Auf der Webseite von Arduino werden regelmäßig die neuesten Erfindungen präsentiert: http://arduino.cc/en/Tutorial/HomePage. Suchen Sie hier z. B. unter dem Punkt Examples.

In Verbindung mit einem Arduino kann ein Android-Tablet oder ein Smartphone also in eine »Controller-Steuerung« verwandelt werden. Im Speziellen können dazu die Vorteile des Android-Betriebssystems ausgenutzt werden, z. B. Wi-Fi und Bluetooth oder Beschleunigungssensoren und Touchscreen.

Bluetooth und Wi-Fi

Natürlich könnte man auch den Arduino mit einen Bluetooth- oder Wi-Fi-Modul ausstatten. Allerdings ist es wesentlich einfacher, diese Bestandteile dem schon konfigurierten Smartphone zu übergeben und sich nicht um das Debuggen dieser Kommunikationsprotokolle auf niedriger Ebene kümmern zu müssen. Gerade wenn es darum geht, einen Netzwerk-Stack zu implementieren, greift man gerne auf Embedded-Systeme zurück, welche bereits Kernel-Treiber zur Verfügung haben.

Der Universal Serial Bus (USB) ist zentraler Bestandteil der Kommunikation zwischen Android und Arduino. In diesem Buch werden die zwei verschiedenen Varianten Accessory API und USB Serial genauer unter die Lupe genommen. Die Variante USB Serial ermöglicht übrigens auch die Kommunikation mit anderen Boards, die eine serielle Schnittstelle haben, wie z. B. dem Arduino Uno.

Seit Sommer 2011 und Android 3.1 (Honeycomb) ist es möglich, über das Android SDK via USB-Host mit Peripherie zu kommunizieren. Dies ermöglicht den Anschluss von allerlei Hardware an Android-Geräte. Dazu gehören z. B. Maus oder Tastatur, das kann aber auch bis hin zu USB-Spielzeug wie Mini-Raketenwerfern gehen. Von den Autoren wird beispielsweise das Open-Source-USB-Oszilloskop »OsciPrime« entwickelt, welches via USB-High-Speed Gebrauch von der neuen USB-Host-API macht. Damit wird das Android-Gerät in ein Oszilloskop inklusive Multitouch-Funktionalität verwandelt.

Viele Arduino-Boards besitzen einen USB-Serial-Konverter. Das ist ein Mikrocontroller, der die Aufgabe hat, USB in »klassische« serielle UART-Kommunikation zu verwandeln. Diese serielle Schnittstelle wird dazu verwendet, den Haupt-Mikrocontroller auf dem Arduino-Board zu programmieren, oder während der Laufzeit mit dem Haupt-Mikrocontroller zu kommunizieren. Die serielle Schnittstelle (RS 232) stellt eines der meistverwendeten Protokolle in der Welt der Mikrocontroller dar. Ihre Einfachheit und Universalität sind Kernfaktoren für die heutige Verbreitung. Da USB wesentlich komplexer ist und spezielle Hardware bei Mikrocontrollern voraussetzt, ist bei vielen Controllern auch heute noch die klassische serielle Schnittstelle anzutreffen.

USB hat einen Host, der Ursprung aller Kommunikation ist, und bis zu 127 Devices. Dabei diktiert der Host, welches Device gerade etwas senden darf. USB erlaubt den Bezug von maximal 500 mA und läuft bei einer Spannung von 5 V. Maximal werden bei USB-High-Speed Datenraten von 480 Mbit/s erreicht. Dies sind allerdings nur theoretische Werte – in der Praxis ist, je nach Host-Controller, nur etwa die Hälfte erreichbar.

USB-Devices haben eine hierarchische Struktur. So besitzt ein USB-Device verschiedene »Configurations«, welche wiederum verschiedene »Interfaces« zur Verfügung stellen können. Jedes Interface enthält eine gewisse Anzahl »Endpoints«, die jeweils die Richtung »in« (vom Device zum Host) oder »out« (vom Host zum Device) vorschreiben. Die Richtungen in und out sind also mit Bezug auf den USB-Host definiert. Ausnahme dabei ist der Endpoint »0«, welcher bidirektional betrieben werden kann. Den Endpoints ist jeweils eine Adresse zugeordnet, welche vom Host zum Absenden oder Empfangen von Daten verwendet wird. So kann der Host einen Endpoint eines Device adressieren, welcher dem Interface der aktuellen Konfiguration zugewiesen ist.

Der USB-Standard definiert Geräteklassen. Darunter fallen z. B. Audio, Drucker oder Human Interface Device (HID; wie Maus und Tastatur). Eine Geräteklasse ist auch die »serielle« CDC-Klasse, welche eine virtuelle serielle Schnittstelle emuliert. Das USB-Device kommuniziert jeweils die Geräteklasse, und der USB-Host lädt daraufhin den entsprechenden Treiber. So wird zum Beispiel beim Anschließen einer Maus der passende Maustreiber geladen. Das USB-Device kommuniziert daher auch, um welchen »Typen« es sich handelt, mittels der Parameter »Vendor ID« (VID) und »Product ID« (PID). Für unsere Versuche filtern wir die VID/PID vom USB-Serial-Konverter des Arduinos, um von Android her kommunizieren zu können.

Tipp

»USB in a Nutshell« (http://www.beyondlogic.org/usbnutshell/usb1.shtml) bietet eine detaillierte Übersicht des USB-Standards. Hier werden u. a. alle vorhandenen »Geräte-Profile« besprochen.

Ein weiteres wichtiges Feature von USB ist USB On-The-Go (OTG). Falls vom Betriebssystem unterstützt, ermöglicht OTG es, ein USB-Device in einen USB-Host umzuwandeln. So ist es auch möglich, bei gewissen Android-Geräten eine Maus oder Tastatur anzuschließen.

Eine Standard-Typ-A-USB-Buchse wie bei einem Computer gibt es bei Android-Geräten äußerst selten. Deswegen muss für das Anschließen einer Maus oder ähnlicher Geräte in den meisten Fällen ein sogenannter USB-OTG-Adapter verwendet werden. Mit USB OTG ist es auch möglich, externe USB-Devices mit Energie zu versorgen. USB OTG wird allerdings nicht von allen Geräten automatisch unterstützt.

Zwar ist USB OTG hardwaremäßig bei fast allen verbauten Mikrocontrollern für Smartphones und Tablets vorhanden, aber es hängt allein vom Hardware-Vertreiber ab, ob die Software USB OTG unterstützt. Besitzt man ein Android-Gerät, das USB OTG nicht unterstützt, kann man dem immer noch mit einem »Custom ROM« entgegenwirken. Speziell das CyanogenMod-Projekt (http://www.cyanogenmod.org/) ist bestrebt, dem Benutzer eine Alternative zur vorinstallierten »Interpretation« von Android zu geben.

USB OTG

Galaxy Nexus, Motorola Xoom, Nexus 7 und Galaxy S3 unterstützen USB OTG und auch die Android-USB-Host-API. Zum jetzigen Zeitpunkt sieht es so aus, als würde das Nexus 4 USB OTG nicht unterstützen. Dies kann sich jedoch mit einem Softwareupdate noch ändern – allerdings scheinen weder der Hersteller noch Google daran interessiert zu sein, da kein Statement zur Abwesenheit dieses Features vorhanden ist. Das Projekt http://usbhost.chainfire.eu/ versucht mit »user-reports«, USB-Host-Support experimentell ausfindig zu machen. Auf der Webseite kann man also nachschauen, ob ein Gerät USB OTG bzw. USB-Host unterstützt.

Dank des Android-ADK (Accessory Development Kit) ist es allerdings möglich, mit Android über USB zu kommunizieren, ohne einen USB-Host-Mode vorauszusetzen. Alle Android-Geräte, die einen »Play Store« haben, sind dazu verpflichtet, einen USB-Device-Port zu besitzen. Darüber findet nicht nur Debugging von Apps und Datenaustausch zwischen PC und Android-Gerät statt, sondern auch Kommunikation zu Android-»Accessories«.

Der Arduino Due kann dank modernem Mikrocontroller einerseits die Rolle des USB-Hosts übernehmen (mit einem USB-OTG-Adapter) und andererseits auch für ein Android-Gerät mit USB-Host-Support als »serielles« Device verwendet werden. Wird der Arduino an einen USB-Host angeschlossen, so wird er mit Strom versorgt. Unser Android-Tablet oder Android-Smartphone kann also auch als portable Batterie für den Arduino betrachtet werden. Da mit dem Arduino Due beide Varianten (USB-Host und USB-Device) möglich sind, werden wir uns in den Programmierbeispielen jeweils mit zwei Lösungsansätzen beschäftigen.

2 Arduino

Arduino ist eine Open-Source-Entwicklungsplattform. Diese Entwicklungsplattform besteht zum einen aus vielen verschiedenen Hardware-Boards und zum anderen aus der Arduino IDE, einer Softwareplattform (Entwicklungsumgebung) für die Programmierung der Mikrocontroller. Für dieses Buch verwenden wir das Ende 2012 erschienene Arduino Due als Mikrocontroller-Board.

2.1 Installieren der Arduino IDE

Die Arduino IDE kann von der offiziellen Website www.arduino.cc heruntergeladen werden. Unter dem Reiter Download wählen Sie die entsprechende Version (Windows, Mac OS X, Linux 32/64-bit). Da wir für den Arduino Due entwickeln werden, brauchen wir die Arduino IDE mindestens in der Version 1.5.1. Zur Zeit der Erstellung dieses Buches befindet sich diese Version noch offiziell in Beta-Phase. Entpacken Sie das heruntergeladene Archiv an einen passenden Ort und starten Sie die Applikation. In Ubuntu/Linux könnte dies folgendermaßen geschehen:

user@host:~$ cd Downloads

user@host:~/Downloads$ tar -xvf arduino-1.5.1-linux32.tgz

user@host:~/Downloads$ mv arduino-1.5.1 ..

user@host:~/Downloads$ cd ..

user@host:~$ arduino-1.5.1/arduino

Auf der Rückseite des Arduino Due sehen wir, dass zwei unterschiedliche USB-Buchsen zur Verfügung stehen. Das ist zum einen der native USB (NATIVE USB -> SAM3X) und zum anderen die Programmierschnittstelle (PROGRAMMING -> ATMEGA16U2). Der native USB-Anschluss ist eine Neuheit des Arduino Due. Dieser native USB-Port ist direkt mit dem Haupt-Mikrocontroller (SAM3X) verbunden. Er kann als USB-Host oder als USB-Device fungieren. Bisherige Arduino-Boards hatten meist nur die Programmierschnittstelle. Dabei handelt es sich um einen USB-Port, der mit einem kleineren Mikrocontroller verbunden ist. Beim Arduino Due ist das der ATMEGA16U; frühere Arduino-Boards verwendeten auch den FTDI232-Chip. Auf diesem kleinen Mikrocontroller läuft eine USB-zu-Seriell-Firmware und die Pins sind mit dem UART-Interface (RX/TX-Pins) des Haupt-Mikrocontrollers verbunden.

Bild 2.1: Die beiden USB-Buchsen am Arduino-Due-Board.


Verbinden Sie Ihren Host-Computer mit der Programmierschnittstelle (PROGRAMMING -> ATMEGA16U2) via USB-Kabel. Starten Sie auch die Arduino IDE, falls sie noch nicht ausgeführt wird.

2.2 Ein erster Sketch

In der Arduino-Entwicklungsumgebung wird ein Programm auch »Sketch« genannt. Standardmäßig sind bereits einige Sketches vorhanden. Wählen Sie deshalb File > Examples > Basics > Blink, um einen vordefinierten Sketch zu laden. Am Anfang der Datei steht kurz beschrieben, welche Funktion der Sketch hat:

/*

Blink

Turns on an LED on for one second,

then off for one second, repeatedly.

This example code is in the public domain.

*/

Dieses Programm schaltet also die LED periodisch an und ab, jeweils für eine Sekunde.


Bild 2.2: Den ersten Sketch in der Arduino-Entwicklungsumgebung laden.


Nun möchten wir diesen Sketch auf dem Arduino Due laufen lassen. Dafür muss der Source-Code zuerst für den ARM-Mikrocontroller kompiliert werden und anschließend die generierte Binärdatei transferiert und in dessen Flash geschrieben werden. Diese Arbeit nimmt uns die Arduino IDE glücklicherweise ab. Wir müssen lediglich unter Tools > Board das richtige Board auswählen. Da wir den Arduino über die Programmierschnittstelle angeschlossen haben, wählen wir Arduino Due (Programming Port). Der angeschlossene Arduino wird auf dem Host-Computer einen virtuellen COM-Port generieren. Je nach Betriebssystem ist dieser unterschiedlich benannt. Unter Windows könnte er zum Beispiel »COM4« heißen. Unter Linux hingegen »/dev/ttyACM0« oder ähnlich. Damit die Arduino IDE das Programm auf das Arduino-Board transferieren kann, muss noch der verwendete COM-Port eingestellt werden. Das machen wir über Tools > Serial Port. Die Arduino IDE ist übrigens so clever, dass nur diejenigen Ports zur Auswahl stehen, die auch im System verfügbar sind. Den richtigen Port kann man ansonsten auch über den Geräte-Manager (Windows) herausfinden. In Linux verwenden wir den Befehl dmesg kurz nach dem Einstecken des Arduino Due. Im folgenden Beispiel wurde der COM-Port »/dev/ttyACM0« erstellt.

user@host:~$ dmesg

…

[13113.208429] usb 1-2.4.1: new full-speed USB device number 29 using ehci_hcd

[13113.303141] cdc_acm 1-2.4.1:1.0: ttyACM0: USB ACM device

user@host:~$ ls -l /dev/ttyA*

crw-rw– 1 root dialout 166, 0 Dec 4 16:37 /dev/ttyACM0

Bild 2.3: Wählen Sie als Board Arduino Due (Programming Port).


Bild 2.4: Unter Linux wählen Sie den Serial Port > /dev/ttyACM0.


Nachdem Sie den Serial Port eingestellt haben, klicken Sie nun auf das Verify-Symbol. Sie können auch über das Menü Sketch > Verify/Compile anwählen oder direkt die Tastenkombination CTRL + R verwenden. Somit wird der Kompilierungsvorgang gestartet. Anschließend laden wir die Programmdatei auf den Mikrocontroller mit Klick auf das Upload-Symbol. Alternativ dazu wählen Sie File > Menu oder die Tastenkombination CTRL + U.


Bild 2.5: Hier finden Sie die Buttons zum Kompilieren und zum Upload.


Falls alles geklappt hat, sollte die kleine LED auf dem Arduino Due nun periodisch blinken!

Wenn Sie eine Linux-Distribution verwenden, kann es vorkommen, dass Sie eine Fehlermeldung »Permission denied« erhalten, welche aufgrund unzureichender Benutzerrechte ausgegeben wird. Dies können wir schnell beheben, indem wir die Rechte des erstellten Device-Nodes ändern:

user@host:~$ ls -l /dev/ttyA*

crw-rw– 1 root dialout 166, 0 Dec 4 16:37 /dev/ttyACM0

user@host:~$ sudo chmod 666 /dev/ttyACM0

Damit erteilen wir Schreibe- und Leserechte für alle Benutzer des Betriebssystems, und ein Upload aus der Arduino IDE sollte nun funktionieren. Nachdem der Arduino allerdings vom Computer entfernt und erneut einsteckt wurde, sind diese modifizierten Rechte nicht mehr gespeichert.

Für eine permanente Lösung betrachten wir den erstellten Device-Node und stellen fest, dass dieser zum Benutzer »root« und zur Gruppe »dialout« gehört. Sowohl der Benutzer »root« als auch Mitglieder der Gruppe »dialout« haben Schreibe- und Leserechte. Damit auch wir in Zukunft Zugriffsrechte haben, fügen wir unseren Benutzer der Gruppe »dialout« hinzu. Gleichermaßen hat dann auch die Arduino IDE die benötigten Zugriffsrechte, weil wir sie unter unserem Benutzer gestartet haben. Beachten Sie, dass wir in diesem Buch von einem Benutzer »user« ausgehen, ersetzen Sie also die entsprechenden Vorkommnisse von »user« durch ihren eigenen Benutzernamen.

user@host:~$ ls -l /dev/ttyA*

crw-rw– 1 root dialout 166, 0 Dec 4 16:37 /dev/ttyACM0

user@nexwork:~$ groups user

user adm cdrom plugdev lpadmin admin sambashare

user@nexwork:~$ sudo adduser user dialout

user@nexwork:~$ groups user

user adm dialout cdrom plugdev lpadmin admin sambashare

2.3 Änderungen am Blink-Sketch

Bis jetzt haben wir noch gar nichts selbst programmiert. Nun werden wir das Blink-Programm etwas abändern und schauen, ob sich das Verhalten ändert. Dazu vergrößern wir die beiden Zeitintervalle auf jeweils 3 Sekunden. Danach laden wir den Sketch erneut auf das Arduino Due. Die loop()-Funktion sollte also folgendermaßen aussehen:

void loop() {

digitalWrite(led, HIGH);

delay(3000); // wait for three seconds

digitalWrite(led, LOW);

delay(3000); // wait for three seconds

}

Nachdem der Mikrocontroller neu beschrieben wurde, blinkt die LED nun deutlich langsamer als zuvor.

2.4 Die Arduino-Programmiersprache

Arduino besitzt eigentlich keine eigene Programmiersprache. Vielmehr versteht man unter der Arduino-Programmiersprache ein Framework, das eine Sammlung von Funktionen und Bibliotheken zur Verfügung stellt. Die Programmierung erfolgt in C und/oder C++, wobei die Arduino-spezifischen Funktionen verwendet werden können. Eine Übersicht der Arduino-Programmiersprache findet man auf der offiziellen Arduino-Webseite unter dem Reiter Reference (http://arduino.cc/en/Reference/HomePage). Erwähnenswert ist insbesondere auch, dass es sich um eine »Cross-Plattform«-Programmiersprache handelt. Ein Programm, welches für ein spezifisches Board mit dazugehörigem Mikrocontroller geschrieben wurde, kann also grundsätzlich auch für einen anderen Mikrocontroller verwendet werden. Der Source-Code muss dabei nicht verändert werden.

Nachdem wir nun unseren ersten Sketch, das Blink-Beispiel aus Abschnitt 2.2, auf den Arduino Due geladen haben, wollen wir dessen Source-Code studieren.


Bei den ersten Zeilen handelt es sich um Kommentarzeilen. Wie in C/C++ üblich, sind mehrzeilige Kommentare durch die Zeichen /* (zu Beginn) bzw. */ (am Ende) und einzeilige Kommentare durch // gekennzeichnet. Im Kommentar der ersten Zeilen wird die Funktion des Programms kurz erläutert.

Die erste für das Programm entscheidende Zeile

int led = 13;

wird verwendet, um den Mikrocontroller-Pin mit der On-board-LED zu definieren. Die LED ist in unserem Fall verbunden mit dem Arduino-Pin Nummer 13. Diese Information entnehmen wir zum Beispiel der Produktwebseite (http://arduino.cc/en/Main/ArduinoBoardDue). Dort finden wir unter Input und Output die folgende Beschreibung:

»L« LED: 13

There is a built-in LED connected to digital pin 13. When the pin is HIGH, the LED is on, when the pin is LOW, it's off. It is also possible to dim the LED because the digital pin 13 is also a PWM output.


Hinweis

Bitte beachten Sie: Als Arduino-Pin Nummer 13 wird derjenige Mikrocontroller-Pin bezeichnet, welcher oben auf dem Board mit der Nummer 13 angeschrieben ist. Es handelt sich nicht etwa um den 13ten Pin des SAM3X-Mikrocontrollers. Die Zuordnung zwischen Arduino und SAM3X-Pins findet man ebenfalls auf der Produktwebseite (http://arduino.cc/en/Hacking/PinMappingSAM3X). Aus der Tabelle entnehmen wir, dass der Arduino-Due-Pin 13 dem SAM3X-Pin PB27 entspricht. Im Datenblatt des SAM3X steht außerdem, dass sich der Pin PB27 am physikalischen Mikrocontroller-Pin mit Nummer 68 befindet. Mit dieser Begebenheit müssen wir uns nicht weiter beschäftigen. Es sollte bloß im Hinterkopf behalten werden, dass es Unterschiede bei der Nummerierung von Arduino-Pins und physikalischen Mikrocontroller-Pins gibt. Insbesondere wenn bereits bestehender C-Code mit Arduino-Source-Code vermischt wird (oder umgekehrt), kann dies eine Stolperfalle darstellen.

Als Nächstes betrachten wir die Funktionen setup() und loop(). Wie die Namen schon vermuten lassen, werden alle Anweisungen innerhalb von loop() in einer Endlos-Schleife ausgeführt. Der Inhalt von setup() hingegen wird nur ein einziges Mal ausgeführt, und zwar ganz zu Beginn des Programmablaufs, noch bevor loop() das erste Mal ausgeführt wird. Bei den Funktionen setup() und loop() handelt es sich um eine Besonderheit von Arduino. Falls Sie schon Erfahrungen mit C-Programmierung haben, fragen Sie sich bestimmt, wo die main()-Funktion geblieben ist. Da Arduino unter der Haube auch nur C/C++ verwendet, gibt es intern natürlich auch eine main()-Funktion. Darin werden dann unsere Methoden setup() und loop() an den entsprechenden Stellen aufgerufen, gemäß folgendem Muster:

int main(void){

…

setup();

// loop forever

for(;;){

loop();

}

return 0; // never reached

}

Die genaue Implementierung der main()-Funktion für den Arduino Due finden Sie übrigens im Arduino-Ordner unter ./hardware/arduino/sam/cores/arduino/main.cpphttp://arduino.cc/en/Reference/HomePage.

Falls Sie noch keine Erfahrungen mit C/C++ haben, merken Sie sich einfach, dass die Funktion setup() nur ein einziges Mal zu Programmbeginn ausgeführt wird. Die Funktion loop() hingegen wird endlos und periodisch aufgerufen. Die Funktionen setup() und loop() sind auch in der offiziellen Language Reference (http://arduino.cc/en/Reference/HomePage) beschrieben.

Innerhalb von setup() sollten also im Idealfall alle Initialisierungen stattfinden, wie zum Beispiel Pin-Konfigurationen. Die Pins eines Mikrocontrollers können grundsätzlich als Eingänge oder Ausgänge konfiguriert werden. Intern speichert ein Mikrocontroller diese Konfiguration in speziellen Registern ab. Das Ändern einer Pin-Konfiguration erfordert also das Schreiben von Registern, und dies wiederum verbraucht kostbare Rechenzeit. Um ehrlich zu sein, in den meisten Fällen würde man kaum eine Performance-Einbuße feststellen können. Dennoch lohnt es sich, dieses Pattern korrekt anzuwenden.

Im Blink-Sketch wird der LED-Pin (Arduino-Pin Nummer 13) als Ausgang konfiguriert. Dies geschieht mit der Funktion pinMode().

void setup() {

// initialize the digital pin as an output.

pinMode(led, OUTPUT);

}

Bei pinMode() handelt es sich ebenfalls um eine spezifische Arduino-Funktion. Der erste Parameter bestimmt die Arduino-Pin-Nummer (vorher wurde led gleich 13 gesetzt). Der zweite Parameter legt fest, ob es sich um einen Eingang oder einen Ausgang handelt. Anstatt OUTPUT könnte zum Beispiel auch INPUT verwendet werden. Wie bereits erwähnt, ist die Arduino-Programmiersprache eine »Cross-Plattform«-Programmiersprache. Die Funktion pinMode() kann für unterschiedliche Arduino-Boards bzw. Mikrocontroller verwendet werden. Je nach Mikrocontroller braucht es dann natürlich eine andere Implementation der pinMode()-Funktion. Bei Interesse findet man die Implementation für den SAM3X des Arduino Due im Arduino-Ordner unter ./hardware/arduino/sam/cores/arduino/wiring_digital.c

Nun betrachten wir die Anweisungen innerhalb der loop()-Funktion.



Die Funktionen sind grundsätzlich selbsterklärend. Mit digitalWrite() wird ein Ausgang gesetzt (HIGH) oder gelöscht (LOW). Mit delay(1000) wird 1000 Millisekunden, also 1 Sekunde, gewartet.

2.5 Serielle Verbindung: Host-Computer und Arduino

In einem ersten Schritt stellen wir eine serielle Verbindung zwischen unserem Host-Computer und dem Arduino Due her. Unser Host-Computer dient dabei als USB-Host, der Arduino ist das USB-Device. Später können wir dann anstatt unseres Computers ein USB-Host-fähiges Android-Gerät verwenden.

Die serielle Verbindung wird aufgrund ihrer Einfachheit sehr häufig zur Kommunikation mit Mikrocontrollern verwendet. Dazu muss der Mikrocontroller mindestens zwei dedizierte Pins RX und TX zur Verfügung stellen. Der RX-Pin (»Receive«) dient dem Mikrocontroller zum Empfangen von Daten; der TX-Pin (»Transmit«) zum Versenden von Daten. Diese Struktur wird je nach Ausführung auch UART (Universal Asynchronous Receiver Transmitter) oder USART (Universal Synchronous Asynchronous Receiver Transmitter) genannt. Der Mikrocontroller des Arduino Due verfügt sogar über vier serielle Schnittstellen. Sie sind auf der Oberseite jeweils mit TX0/RX0, TX1/RX1, TX2/RX2 und TX3/RX3 beschriftet. Die Anschlüsse CANRX/CANTX ermöglichen übrigens eine Kommunikation über den sogenannten CAN(Controller Area Network)-Bus. Die Anschlüsse SDA und SCL werden ihrerseits für das Two-wire Interface (TWI) beziehungsweise I²C verwendet.

Eine serielle Schnittstelle, oft auch COM-Port genannt, gehörte früher praktisch zur Grundausstattung eines jeden Computers. Der meist verwendete RS-232-Standard benutzt neben den zwei RX- und TX-Pins noch sieben weitere Leitungen. Darunter zum Beispiel RTS (Request to Send) und DSR (Data Set Ready). Diese 9-poligen Stecker sind heutzutage größtenteils verschwunden, stattdessen können aber auch USB-zu-seriell-Adapter mit den entsprechenden Treibern verwendet werden. Für eine serielle Verbindung zwischen unserem Host-Computer und dem Arduino brauchen wir allerdings keinen physikalischen Adapter, sondern lediglich ein USB-Kabel. Der USB-Programming-Port des Arduino Due ist direkt mit einem kleinen Mikrocontroller, dem ATMega16U2, verbunden. Dieser ist seinerseits wieder mit den RX0/TX0-Pins des Haupt-Mikrocontrollers SAM3X verbunden. Auf dem ATMega16U2 läuft also eine USB-zu-seriell-Firmware. Diese wandelt das USB-Protokoll auf der Computer-Seite in serielle Kommunikation auf der Mikrocontroller-Seite um, und umgekehrt.


Bild 2.6: Die schematische Darstellung der USB-Verbindung zwischen Computer und Arduino Due


Bild 2.7: Die USB-Verbindung mit dem USB-serial converter.


Zum Testen der seriellen Verbindung schreiben wir ein kleines Programm, welches die Groß- und Kleinschreibung aller eingehenden Buchstaben umkehrt und die veränderten Symbole wieder an den Computer zurückschickt. Dabei ist zu beachten, dass die Symbole im ASCII-Format codiert sind. Es wird jeweils ein Byte übertragen, welches einen Wert zwischen 0 und 255 haben kann. Der Wert 65 entspricht dabei einem groß geschriebenen »A«. Ein großes »B« hat den Wert 66 und so weiter bis »Z« (90). Die klein geschriebenen Buchstaben starten mit »a« bei 97. Eine vollständige ASCII-Tabelle findet man zum Beispiel unter http://www.asciitable.com im Internet.


Tabelle 2.1: Dezimale ASCII-Werte der Buchstaben von A bis Z

int input;

int output;

void setup()

{

Serial.begin(9600);

}

void loop()

{

if(Serial.available() > 0){

input = Serial.read();

if(64 <= input && input <= 90 ){ // upper case input

output = input + 32;

Serial.write(output);

} else if(97 <= input && input <= 122) { // lower case

// input

output = input – 32;

Serial.write(output);

} else if(input == 32){ // space bar

output = input;

Serial.write(output);

}

else {

Serial.println();

}

}

}

Kompilieren Sie das obige Programm und laden Sie es auf den Arduino. Nun starten wir den Serial Monitor durch Klick auf das Lupen-Symbol oben rechts in der Arduino IDE.


Bild 2.8: Das Lupen-Symbol zum Start des Serial Monitor.


Es öffnet sich ein neues Fenster mit dem Serial Monitor. Beachten Sie, dass die verwendete Baudrate unten rechts auf 9600 eingestellt ist (vgl. Bild 2.9), da wir diese Geschwindigkeit auch im obigen Programm mit Serial.begin(9600) konfiguriert haben. Schreiben Sie nun ein paar Buchstaben und bestätigen Sie mit Enter oder durch Klick auf Send. Als Antwort erhalten Sie dieselben Wörter mit invertierter Groß- und Kleinschreibung.


Bild 2.9: Hello World im Serial Monitor.


Ein Serial Monitor eignet sich übrigens auch sehr gut zum Debuggen von Programmen, indem einfach an den entsprechenden interessanten Stellen Nachrichten herausgeschrieben werden. Neben dem integrierten Serial Monitor gibt es noch eine Menge anderer sogenannter Terminal-Programme. Einige davon bieten nützliche Zusatzfunktionen, wie zum Beispiel die Darstellung der erhaltenen Daten im Dezimal-, Hex- oder Binärformat. Der integrierte Serial Monitor von Arduino versucht die empfangenen Daten immer als ASCII-Symbole darzustellen. Sehr zu empfehlen ist zum Beispiel das frei erhältliche Terminal-Programm HTerm für Windows/Linux (www.der-hammer.info/terminal/). Im folgenden Bild ist die gleiche Ausgabe in HTerm dargestellt. Das kleine »h« am Anfang entspricht dem Hexadezimalwert »0x68« beziehungsweise dem Dezimalwert »104« oder dem Binärwert »01101000«. Beachten Sie bei der Verwendung von externen Terminal-Programmen, dass jeweils nur ein Computer-Programm mit dem virtuellen COM-Port verbunden sein kann. Trennen Sie also die Verbindung im Terminal-Programm, bevor Sie einen neuen Sketch auf den Arduino laden. Als Verbindungsparameter verwenden Sie natürlich die entsprechende Baudrate. Die Konfiguration ist standardmäßig »8 data bits, no parity, one stop bit«, was manchmal auch als 8N1 bezeichnet wird.


Bild 2.10: Ein empfehlenswertes Terminal-Programm für den Arduino: HTerm.


2.6 LED-Intensität steuern über serielle Konsole

Das vorherige Arduino-Programm hat gezeigt, wie man zwischen Arduino Due und einem Host-Computer kommunizieren kann. In einem weiteren Schritt soll nun abhängig von den empfangenen Daten die Helligkeit der On-board-LED eingestellt werden.

Der benötigte Sketch ist erstaunlich einfach.

#define LED 13

void setup()

{

pinMode(LED, OUTPUT);

Serial.begin(9600);

}

void loop(){

char cmd = 0;

if(Serial.available()){

cmd = Serial.read();

analogWrite(LED,cmd);

}

}

Dieser Sketch empfängt einzelne Bytes über die serielle Verbindung und setzt den LED-Pin mit der Funktion analogWrite(). Mit analogWrite() wird an den entsprechenden Pin ein PWM-Signal gesetzt. Unter der Bezeichnung »PWM« verbirgt sich die Pulsweitenmodulation. Bei der Pulsweitenmodulation wird ein Signal für eine gewisse Zeit eingeschaltet und auch für eine gewisse Zeit ausgeschaltet. Dies wiederholt sich periodisch und meistens mehrere hundert Mal pro Sekunde. Die PWM-Frequenz des Arduino ist zum Beispiel 490 Hz. Also wiederholt sich diese Sequenz 490 Mal pro Sekunde und dauert 1/490 Hz = 2,04 ms oder ungefähr 2 Millisekunden. Die Funktion analogWrite() erwartet nebst der Pin-Nummer auch einen »value«-Parameter zwischen 0 und 255. Dieser Parameter legt fest, wie lange das Signal während der 2 Millisekunden eingeschaltet ist. Ein Wert von 0 bedeutet, dass es nie eingeschaltet ist, die LED ist also komplett dunkel. Mit einem Wert von 255 bleibt sie immer eingeschaltet, die LED leuchtet also mit voller Kraft. Ein Wert von 128 bedeutet, dass die LED die Hälfte der Zeit eingeschaltet ist, sie leuchtet also mit halber Kraft. Diese Beziehung ist auch in Bild 2.11 dargestellt. Im Zusammenhang mit PWM-Signalen kommt häufig auch der Begriff Duty-Cycle zum Einsatz. Ein Duty-Cycle von 50 % zum Beispiel bedeutet, dass das PWM-Signal im Mittel 50 % der Zeit eingeschaltet ist. Dies wird mit einem Aufruf von analogWrite(LED, 128) erreicht. Wie bereits erwähnt, hat die PWM-Frequenz des Arduino, welche durch die Funktion analogWrite() erzeugt wird, einen festen Wert von ca. 490 Hz. Um eine LED zu steuern, ist diese Frequenz gut geeignet. Obwohl die LED in Tat und Wahrheit viele Male ein- und ausgeschaltet wird, können wir kein Flackern feststellen. Je nach Anwendung muss die PWM-Frequenz aber angepasst werden. Ein herkömmlicher Servo zum Beispiel erwartet eine Frequenz von 50 Hz, welche mit Hilfe der Arduino Servo Library in einem späteren Beispiel (vgl. Kapitel 8 Servo mit Android ansteuern) erzeugt werden kann.


Bild 2.11: Die Pulsweitenmodulation zur Steuerung der LED-Intensität.


Wenn Werte über die serielle Verbindung von einem Host-Computer gesendet werden, dann sollte beachtet werden, dass die empfangenen Bytes auf dem Arduino »roh« gelesen und als Zahl zwischen 0 und 255 interpretiert werden. Mit dem integrierten Serial Monitor (Tools > Serial Monitor oder CTRL+SHIFT+M) werden alle Daten in ASCII codiert. Ein großes »A« entspricht dabei dem Wert 65, und ein kleines »z« entspricht dem Wert 122. Senden Sie also abwechselnd diese zwei Buchstaben. Es sollte ein Unterschied in der Lichtstärke der On-board-LED erkennbar sein. Achten Sie auch darauf, dass unten rechts No line encoding eingestellt ist. Sonst wird nach jedem Senden noch ein konstantes Sonderzeichen (New Line und/oder Carriage Return) geschickt, und die Intensität der LED würde sich nicht ändern. Etwas komfortabler kann man rohe Byte-Daten mit dem Hammer-Terminal (http://www.der-hammer.info/terminal/) versenden. Dazu wählt man als Type »DEC« und kann nun Zahlen zwischen 0 und 255 eingeben.

Genau dieser Sketch kann später auch zusammen mit einem Android-Gerät verwendet werden, vorausgesetzt das Android-Gerät verfügt über USB-Host-Funktionalität. Damit die Kommunikation auch über Android Accessory Mode funktioniert, wird der Sketch noch etwas erweitert.

2.7 LED-Intensität steuern über serielle Konsole und Android Accessory Mode

Der nachfolgende Sketch wurde erweitert, damit die Lichtintensität auch über den Android USB Accessory Mode eingestellt werden kann.

#include <adk.h>

#include <Scheduler.h>

#define LED 13

#define RCVSIZE 128

char model[] = "HelloWorldModel";

char description[] = "A Hello World Accessory";

char company[] = "Hello Inc";

char versionNumber[] = "1.2";

char serialNumber[] = "1";

char url[] = "http://www.osciprime.com";

USBHost Usb;

ADK adk(&Usb, company, model, description,versionNumber,url,serialNumber);

void setup()

{

cpu_irq_enable();

pinMode(LED, OUTPUT);

Serial.begin(9600);

delay(200);

Scheduler.startLoop(adkLoop);

Scheduler.startLoop(serialLoop);

}

void loop(){

yield();

}

void serialLoop(){

uint8_t cmd = 0;

if(Serial.available()){

cmd = Serial.read();

analogWrite(LED,cmd);

}

yield();

}

void adkLoop()

{

uint8_t buf[RCVSIZE];

uint32_t nbread = 0;

uint8_t cmd = 0;

Usb.Task();

if (adk.isReady()){

adk.read(&nbread, RCVSIZE, buf);

if (nbread > 0){

cmd = buf[0];

analogWrite(LED,cmd);

}

}

yield();

}

Die Definitionen zu Beginn wie model, description, company etc. dienen dazu, das Android Accessory zu beschreiben. Besonders bei diesem Sketch ist, dass zwei Loops gleichzeitig ausgeführt werden. In der setup()-Funktion sieht man, dass zwei Loops gestartet werden mit Scheduler.startLoop(). Die Scheduler Library ist eine Besonderheit des Arduino Due, andere Boards mit AVR-Mikrocontrollern unterstützen diese Funktionalität (noch) nicht. Die beiden Loops laufen quasi unabhängig voneinander. Der serialLoop kümmert sich um die serielle Kommunikation und der adkLoop um den Android Accessory Mode. Es fallen die yield()-Aufrufe auf. Die Funktion yield() gibt die Kontrolle zwischenzeitlich an andere Tasks bzw. Loops ab und sollte im Zusammenhang mit dem Scheduler mehrfach gebraucht werden.

Die Anweisungen innerhalb des adkLoop sind quasi analog zu serialLoop. Ein Beispiel zum Android Accessory Mode findet man übrigens auch unter File > Examples > USBHost > ADKTerminalTest.

Der obige Sketch wird später für die Kommunikation zwischen Android-Gerät und Arduino Due verwendet. Sowohl für Kommunikation via Android-USB-Host als auch via Android Accessory Mode.

3 Android

3.1 Betriebssystem Android

Um alle Bestandteile dieses Buches zu verstehen, macht es Sinn, zuerst einen Überblick über Android zu erhalten. Android ist ein Betriebssystem, das Gebrauch vom Linux-Kernel macht.

Android ist für mobile Systeme ausgelegt. Insbesondere heißt das, es ist für Energieeffizienz und beschränkte Ressourcen (niedrige CPU-Taktfrequenz, niedrige Speicherkapazität, kleines RAM etc.) konzipiert worden. Da Android für den mobilen Einsatz gedacht ist, wurde auch an das Verwalten von Batterie, Wi-Fi, Bluetooth, Kamera etc. schon von Anfang an gedacht, speziell auch daran, dass gewisse Teile, wie Grafik- und Kamera-Treiber, »Closed Source« vom Hardware-Hersteller (OEM) geliefert werden.

Dies bringt uns wieder auf einen sehr spannenden Punkt:Android ist Open Source!

Open Source heißt, der Source-Code von Android kann von jedem inspiziert und modifiziert werden. Die Weiterentwicklung des Systems findet allerdings zum größten Teil bei Google intern statt, dabei werden »Major Releases« (größere Versionen) von Android dann wieder für die Öffentlichkeit freigegeben.

Um eine bessere Übersicht über das System zu bekommen, studieren wir Bild 3.1. In dieser Illustration sehen wir, aus welchen Schichten das Betriebssystem zusammengesetzt ist. Architektonisch bietet Android nämlich so einige Einzigartigkeiten und unterscheidet sich stark von seinen »nächsten« Verwandten (Embedded Linux, iOS, Windows Mobile). Das Modell veranschaulicht hardwarenahe Teile des Systems (im unteren Bereich des Modells) und eher hardwareferne Elemente (oben).


Bild 3.1: Der Aufbau des Android-Betriebssystems.


Ücretsiz ön izlemeyi tamamladınız.

Manuel di Cerbo
v.s.
Metin
4,0
1 puan
₺1.110,61