Einführung Arduino mit PlatformIO
Dieser Artikel ist die Aufzeichnung eines Arduino-Einführungsworkshop inkl. aller Beispielprogramme und einiger kurzer Erklärungen.
Im Maker Space haben wir verschiedene Bauformen von Microcontrollern vorrätig. Jeder hat seine eigenen Besonderheiten und Einsatzgebiete.
- Arduino Uno – Einsteigermodel, Relativ viele Pins
- Arduino Mega – Sehr viele Pins, sehr große Bauform
- Lillipad – Wasserfest, für den Einsatz in Textilien
- Arduino Nano – klein und günstig
- ESP32 – WLAN und Bluetooth
Für den Workshop wird der Arduino Nano eingesetzt. Grund dafür ist, dass dieser Microcontroller verhältnismäßig günstig ist (China ca. 1€, Deutschland ca. 10€).
Als Entwicklungsumgebung wird im Workshop Visual Studio Code (Download) mit dem Plugin PlatformIO (Dokumentation) verwendet. Gegenüber der Arduino IDE (Download) bieten sich verschiedene Vorteile. Zum einen ist die Unterstützung inklusive Treiber auch für günstige Boards direkt mitgeliefert. Autokorrektur und übliche IDE-Features wie Code-Vervollständigung, Syntax-Highlighting, markieren von Syntaxfehlern werden direkt von VSCode übernommen. Einfaches uploaden und automatische Portauswahl bringt PlatformIO mit.
Installation und Einrichtung
Die Installation von Visual Studio Code ist über den Installer von der Website und wird hier nicht groß erklärt.
PlatformIO ist ein Plugin für VSCode und wird innerhalb des Editors installiert. Dazu muss zuerst Visual Studio Code gestartet werden.
Danach muss zuerst das Plugin installiert werden. Dazu öffnen wir links im Menü den Bereich Extensions.
Danach müssen wir das Plugin suchen und installieren. Dazu oben in die Suche den Begriff “PlatformIO” eingeben und beim Plugin “PlatformIO IDE” auf install klicken.
Jetzt müssen wir warten, bis das Plugin fertig installiert ist. Anschließend Visual Studio Code neu starten. Nach dem Neustart werden noch einige Dinge installiert. Sobald alles abgeschlossen ist und der PlatformIO Startbildschirm angezeigt wird können wir loslegen.
Wenn die Installation erfolgreich war, wird in der unteren linken Ecke ein kleines Haus-Symbol angezeigt. Dieses Symbol öffnet auch den PlatformIO-Startbildschirm.
Projekt anlegen
In dem PlatformIO Startbildschirm haben wir unterschiedliche Werkzeuge zur Auswahl. Wir können zuerst ein neues Projekt anlegen. Dazu klicken wir auf “New Project”. Im folgenden müssen wir einen Projektname festlegen, unser Board und das Framework auswählen und den Speicherort bestimmen. Für den Workshop ist das Board der “Arduino Nano ATmega328” und als Framework setzen wir Arduino ein. Das Projekt wird standardmäßig im Benutzerverzeichnis unter Dokuments/PlatformIO/Projects gespeichert.
Sobald das erledigt ist und der Projektwizard das Projekt fertig initialisiert hat können wir uns im Explorer das Projekt ansehen. Der Explorer ist im linken Menü zu finden und zeigt alle Dateien des Projekts in einer Baumstruktur an. Für den Einstieg interessiert uns der Ordner “src” in dem wir die Datei “main.cpp” finden. Diese Datei können wir durch Doppelklick öffnen.
Beispielprogramme
In die main.cpp kommt unser Programmcode. Im Folgenden sind die drei Beispielprogramme aus dem Workshop. Jedes Arduino-Programm beginnt mit zwei Funktionen.
Die Setup-Funktion wird beim starten des Arduino ausgeführt. In dieser Funktion werden alle Definitionen und Initialisierungen ausgeführt. Viele Bibliotheken bringen Setupfunktionen mit, die hier aufgerufen werden müssen z.B. FastLed mit FastLED.addLeds<NEOPIXEL, 6>(leds, 1);
Die Loop-Funktion wird endlos lange immer wieder nacheinander aufgerufen. Immer wenn die Loop beendet wurde beginnt ein neuer Aufruf. Alle Logik, die wir von unserem Microcontroller ausgeführt haben wollen werden wir in diese Funktion implementieren.
Blinkende LED
Auf dem Arduino Nano ist eine LED direkt auf dem Board verbaut. Diese kann für einfache Funktionstests und kleine Beispiele verwendet werden. Die Konstante LED_BUILTIN enthält den Pin dieser LED. Das Programm setzt im Setup diesen Pin als output um dann in der Loop den Pin abwechselnd auf High und Low, also an und aus, zu setzen.
#include
void setup() {
pinMode(LED_BUILTIN, OUTPUT);
}
void loop() {
digitalWrite(LED_BUILTIN, HIGH);
delay(100);
digitalWrite(LED_BUILTIN, LOW);
delay(100);
}
Debug mit Serial
Um zu überwachen, was unser Arduino tut gibt es verschiedene Optionen. Eine sehr einfache ist die Ausgabe von Daten über den Serial-Port. Diese Daten können wir am Computer über den Serial Monitor anzeigen. Der Serial Monitor wird mit dem Stecker-Icon unten links gestartet.
Der folgende Sketch zählt in der Loop immer weiter nach oben und gibt den Wert über Serial aus. Dazu wird zuerst eine Variable vom Typ “int” mit dem Name “tick” definiert. Im Setup wird die Geschwindigkeit der Serial-Kommunikation auf 9600 Baud festgelegt. In der Loop wird dann tick immer weiter hochgezählt und über Serial an den Computer gesendet.
#include
int tick = 0;
void setup() {
Serial.begin(9600);
}
void loop() {
Serial.println(tick);
tick++;
}
Ampel
Als drittes Beispiel programmieren wir eine kleine Ampel. Neben der Programmierung kommen hier noch einige elektronische Komponenten ins Spiel. Für das Beispiel werden Vorwiderstände und LEDs in drei Farben benötigt. Aufgebaut wird alles auf einem Breadboard.
Der Code ist eine sehr einfache Variante einer Ampel. Mithilfe des Befehl “delay” wird die Ausführung pausiert und die Ampelphasen nach einer kurzen Wartezeit umgeschaltet.
#include
#define D3 3
#define D4 4
#define D5 5
void setup() {
Serial.begin(9600);
pinMode( D3, OUTPUT);
pinMode( D4, OUTPUT);
pinMode( D5, OUTPUT);
}
void loop() {
digitalWrite( D3, HIGH);
digitalWrite( D4, LOW);
digitalWrite( D5, LOW);
delay(5000);
digitalWrite( D3, HIGH);
digitalWrite( D4, HIGH);
digitalWrite( D5, LOW);
delay(2000);
digitalWrite( D3, LOW);
digitalWrite( D4, LOW);
digitalWrite( D5, HIGH);
delay(10000);
digitalWrite( D3, LOW);
digitalWrite( D4, HIGH);
digitalWrite( D5, LOW);
delay(2000);
digitalWrite( D3, HIGH);
digitalWrite( D4, LOW);
digitalWrite( D5, LOW);
delay(10000);
}
Abstandssensor mit Servo
Über PlatformIO lassen sich Bibliotheken installieren, auf die wir in unserem Projekt zurück greifen können. Dazu müssen wir auf PlatformIO Home gehen (das kleine Haus-Icon unten links) und dort auf den Punkt “libraries” wechseln. Dort können wir dann in die Suche das Wort Servo eintragen. Unter den Treffern sollte, recht weit oben, die Bibliothek von Michael Margolis sein. Auf diese können wir klicken.
Über den Button “Add to project” können wir diese Bibliothek zu unserem Projekt hinzufügen. Außerdem können wir uns direkt den Beispielcode aus der Bibliothek kopieren und lernen, wie wir damit arbeiten können.
In diesem Code hier, sind ein Ultraschall-Abstandssensor und ein Servo gekoppelt. Das Servo wird bewegt, wenn wir dem Sensor näher kommen.
#include
#include
#define PIN_TRIGGER 7
#define PIN_ECHO 6
#define PIN_SERVO 9
Servo myservo;
int pos = 0;
long dauer = 0;
long entfernung = 0;
void setup()
{
Serial.begin(9600);
myservo.attach(9);
pinMode(PIN_TRIGGER, OUTPUT);
pinMode(PIN_ECHO, INPUT);
}
void loop()
{
digitalWrite(PIN_TRIGGER, LOW);
delay(5);
digitalWrite(PIN_TRIGGER, HIGH);
delay(10);
digitalWrite(PIN_TRIGGER, LOW);
dauer = pulseIn(PIN_ECHO, HIGH);
entfernung = (dauer / 2) * 0.03432;
if (entfernung >= 500 || entfernung <= 0)
{
Serial.println("Kein Messwert");
}
else
{
Serial.print(entfernung);
Serial.println(" cm");
pos = map(entfernung, 5, 20, 0, 180);
myservo.write(pos);
}
delay(150);
}
#include
#include
Servo karl;
void setAmpel(uint8_t green, uint8_t yellow, uint8_t red) {
digitalWrite(11, green);
digitalWrite(12, yellow);
digitalWrite(13, red);
}
// C++ code
//
void setup()
{
pinMode(11, OUTPUT);
pinMode(12, OUTPUT);
pinMode(13, OUTPUT);
karl.attach(5);
}
int last = 0;
int pos = 0;
int dir = 1;
void loop()
{
karl.write(pos);
pos += dir;
dir = pos < 1 || pos > 179 ? dir * -1 : dir;
delay(10);
setAmpel(HIGH, LOW, LOW);
if (last < millis() - 2000) {
setAmpel(HIGH, HIGH, LOW);
}
if (last < millis() - 3000) {
setAmpel(LOW, LOW, HIGH);
}
if (last < millis() - 5000) {
setAmpel(LOW, HIGH, LOW);
}
if (last < millis() - 6000) {
last = millis();
}
}
Servo steuern über Serial und Button auf D2
#include
#include
Servo myservo;
int pos = 0;
void setup()
{
Serial.begin(9600);
myservo.attach(9);
myservo.write(90);
pinMode(2, INPUT_PULLUP);
}
int run = 1;
int incomingByte = 0;
int lastButtonPressed = 0;
void loop()
{
if (digitalRead(2) == LOW)
{
if (lastButtonPressed < millis() - 100)
{
lastButtonPressed = millis();
myservo.write(90);
}
}
if (Serial.available() > 0)
{
incomingByte = Serial.read();
if (incomingByte == 108)
{
myservo.write(120); // tell servo to go to position in variable 'pos'
}
if (incomingByte == 114)
{
myservo.write(70); // tell servo to go to position in variable 'pos'
}
if (incomingByte == 48)
{
myservo.write(90); // tell servo to go to position in variable 'pos'
}
}
}
LEDs und Servo über Serial kontrollieren
#include
#include
#define pin_r 4
#define pin_y 3
#define pin_g 2
Servo myservo;
int servo_states[] = {0, 90, 180};
void setup() {
Serial.begin(9600);
myservo.attach(5);
pinMode(pin_r, OUTPUT);
pinMode(pin_y, OUTPUT);
pinMode(pin_g, OUTPUT);
Serial.println("Hallo Welt");
}
int state_r = 0;
int state_y = 0;
int state_g = 0;
int state_servo = 1;
void loop() {
if (Serial.available() > 0) {
int incomingByte = Serial.read();
if (incomingByte == 103) {
state_g = (state_g + 1) % 2;
}
if (incomingByte == 121) {
state_y = (state_y + 1) % 2;
}
if (incomingByte == 114) {
state_r = (state_r + 1) % 2;
}
// DAS IST DAS SERVO
if (incomingByte == 115) {
state_servo = (state_servo + 1) % 3;
}
if (incomingByte == 116) {
state_r = (state_r + 1) % 2;
state_y = (state_y + 1) % 2;
state_g = (state_g + 1) % 2;
}
}
digitalWrite(pin_r, state_r);
digitalWrite(pin_y, state_y);
digitalWrite(pin_g, state_g);
myservo.write(servo_states[state_servo]);
}
Von Joni, Mai 2019