Sisor
05.07.2014, 22:00
Dieses Tutorial beschäftigt sich mit dem Erstellen einer Arduino-Bibliothek
1. Vorwort
Bibliotheken sind ja für viele etwas, was man reinladen muß, damit irgendein Sensor, Motor, Display etc angesprochen werden kann. Bibliotheken sind aber kein Hexenwerk. Im Gegenteil, sie sind sehr nützlich, um Programme übersichtlicher zu machen. Außerdem kann man sie leicht mit anderen teilen, sodass nicht jeder Programierer ein bestimmtes Problem neu enträtseln muss. Darum werden wir hier mal ein bischen genauer hinschauen.
Dazu nehmen wir ein einfaches Arduino-Programm und lagern die Funktion in mehreren Schritten in eine Bibliothek aus. Diese sind nicht unbedingt alle nötig, dienen aber der Verauschaulichung, was zu tun ist und warum.
Wer die Programmbeispiele am eigenen Rechner nachvollziehen will, benötigt eine installierte Arduino-IDE ab Version 1.
2. Das Programm
Programmbeschreibung:
Das Programm steuert eine RGB-Led. Diese Led kann man sich vorstellen wie 3 verschiedenfarige Leds in einem Gehäuse. Sie besitzt 4 Anschlüsse: Masse und 3 Anschlüsse für die einzelnen Steuerspannungen, mit denen die Helligkeit der jeweiligen Farbe (Rot, Grün, Blau) gesteuert wird.
RGB_LED.ino:
#define RED_PIN 4
#define GRN_PIN 3
#define BLU_PIN 2
void setRGB(byte r, byte g, byte b) {
analogWrite(RED_PIN, r);
analogWrite(GRN_PIN, g);
analogWrite(BLU_PIN, b);
}
void blink(char color, byte times, unsigned int ms) {
byte r=0, g=0, b=0;
if(color == 'r') r = 255;
else if(color == 'g') g = 255;
else if(color == 'b') b = 255;
else return ;
for (byte i = 0; i < times; i++) {
setRGB(r, g, b);
delay(ms);
setRGB(0, 0, 0);
delay(ms);
}
}
void setup() {}
void loop() {
blink('r', 5, 500); // rot, 5 Widerholungen, jeweils 500 Millisekunden an
blink('b', 10, 250);
blink('g', 15, 167);
}
'setRGB' setzt die einzelnen Steuerspannungen, und damit Farbe und Helligkeit der RGB-Led. Sie nimmt je Farbe Werte zwischen 0 (aus) und 255 (volle Helligkeit) entgegen.
'blink' lässt die Led naja blinken. Farbe der Led, Anzahl der Blinkwiderholungen und Dauer eines An-Aus-Intervalls sind der Funktion zu übergeben.
'loop' lässt die RGB-Led nun in erst rot und langsam, dann blau und schneller, dann grün und schnell blinken. Dann beginnt es von vorn.
3. Auslagern der Funktionalität in ein Modul
Motivation:
- Die Übersichtlichkeit wird verbessert. Im Hauptprogramm sind nur noch die Funtionsaufrufe sichtbar.
- Die Funktionalität kann so sehr einfach in andere Programme integriert werden. Dazu muss nur das Modul geladen werden.
Dazu wird im Sketch-Ordner eine zusätzliche Datei erstellt. Wir nennen sie 'RGBLed.h'.
'.h' identifiziert die Datei als Header-Datei. Hier werden nun die Funtionen eingefügt. Dem vorangestellt steht die Zeile: #include <Arduino.h>. Die ist erforderlich, weil dem Linker die Arduino-Befehlsumgebung zu diesem Zeitpunkt noch nicht bekannt ist. (Der Linker ist Programm, dass die einzelnen Programmteile zu eine einem Gesamtprogramm zusammensetzt, damit es vom Compiler in einen vom Arduino verständlichen Maschinencode übersetzt werden kann).
RGBLed.h
#include <Arduino.h>
void setRGB(byte r, byte g, byte b) {
analogWrite(RED_PIN, r);
analogWrite(GRN_PIN, g);
analogWrite(BLU_PIN, b);
}
void blink(char color, byte times, unsigned int ms) {
byte r=0, g=0, b=0;
if(color == 'r') r = 255;
else if(color == 'g') g = 255;
else if(color == 'b') b = 255;
else return ;
for (byte i = 0; i < times; i++) {
setRGB(r, g, b);
delay(ms);
setRGB(0, 0, 0);
delay(ms);
}
}
Im Hauptprogramm muß dann dem Kompiler angezeigt werden, dass wir die frisch erzeugte Datei verwenden wollen. Dies macht die Anweisung #include "RGBLed.h".
RGB_LED.ino
#define RED_PIN 4
#define GRN_PIN 3
#define BLU_PIN 2
#include "RGBLed.h"
void setup() {}
void loop() {
blink('r', 5 , 500);
blink('b', 10, 250);
blink('g', 15, 167);
}
4. Objekt bauen
Motivation:
- Objekte fassen Funtionalität und Daten unter einem Dach zusammen
- bessere Lesbarkeit des Codes
- Kapselung, Sicherheit
Bis hierhin haben wir reinen C-Code verwendet. Es ist jetzt an der Zeit einen der Vorzüge von C++ zu verwenden: Objekt-Orientierung. Objekte werden nach einem Bauplan erstellt. Dieser Bauplan wird allgemein als Klasse bezeichnet. Die Beschreibung einer Klasse geschieht in einem class-Block. Unsere bekommt den Namen RGBLed.
Das Schlüsselwort public gibt an, dass die Funktionen (die in der Objekt -Orientierung auch Methoden genannt werden) ausserhalb der Klasse ansprechbar sind. Dies wollen wir, da ja später aus dem Hauptprogramm diese Methoden aufrufen werden sollen.
RGBLed.h
#include <Arduino.h>
class RGBLed {
public:
void setRGB(byte r, byte g, byte b) {
analogWrite(RED_PIN, r);
analogWrite(GRN_PIN, g);
analogWrite(BLU_PIN, b);
}
void blink(char color, byte times, unsigned int ms) {
byte r=0, g=0, b=0;
if(color == 'r') r = 255;
else if(color == 'g') g = 255;
else if(color == 'b') b = 255;
else return ;
for (byte i = 0; i < times; i++) {
setRGB(r, g, b);
delay(ms);
setRGB(0, 0, 0);
delay(ms);
}
};
Im Hauptprogramm erzeugen wir zuerst ein RGBLed-Objekt mit dem Namen 'rgb'. Die Methoden des Objekts werden über den '.'-Operator angesprochen.
RGB_LED.ino
#define RED_PIN 4
#define GRN_PIN 3
#define BLU_PIN 2
#include "RGBLed.h"
RGBLed rgb;
void setup() {}
void loop() {
rgb.blink('r', 5 , 500);
rgb.blink('b', 10, 250);
rgb.blink('g', 15, 167);
}
5. Weitere Bearbeitung
- verhindern, dass die Bibliothek mehrfach geladen werden kann (und so zu Compiler-Fehlermeldungen führt)
Dies wird mit folgendem Code erreicht:
#ifndef __RGB_LED__
#define __RGB_LED__
//...
#endif
- Daten im Objekt speichern
Dazu benutzen wir einen Konstruktor: RGBLed (byte redPin, byte greenPin, byte bluePin)
Dieser soll die PIN-Nummern, an denen die RGB-Led angeschlossen wird, beim sofort beim Erstellen des Objekts speichern.
Das Schlüsselwort 'private' gibt an, dass die Variablen nur innerhalb des Objekts angesprochen werden können.
RGBLed.h:
#ifndef __RGB_LED__
#define __RGB_LED__
#include <Arduino.h>
class RGBLed {
private:
byte redPin;
byte greenPin;
byte bluePin;
public:
RGBLed (byte redPin, byte greenPin, byte bluePin){
this->redPin = redPin;
this->greenPin = greenPin;
this->bluePin = bluePin;
}
void setRGB(byte r, byte g, byte b) {
analogWrite(redPin, r);
analogWrite(greenPin, g);
analogWrite(bluePin, b);
}
void blink(char color, byte times, unsigned int ms) {
byte r=0, g=0, b=0;
if(color == 'r') r = 255;
else if(color == 'g') g = 255;
else if(color == 'b') b = 255;
else return ;
for (byte i = 0; i < times; i++) {
setRGB(r, g, b);
delay(ms);
setRGB(0, 0, 0);
delay(ms);
}
}
};
#endif
Im Hauptprogramm benutzen wir nun den neuen Konstruktor.
RGB_LED.ino
#include "RGBLed.h"
RGBLed rgb(4, 3, 2); //Pins: red =4, green =3, blue =2
void setup() {}
void loop() {
rgb.blink('r', 5 , 500);
rgb.blink('b', 10, 250);
rgb.blink('g', 15, 167);
}
6. Finale Bearbeitung
Jetzt werden wir eine weitere Datei hinzufügen: RGBLed.cpp
Diese cpp-Datei wird die gesamte Funktionalität beinhalten, während wir diese aus der h-Datei verbannen. Dort werden nur noch Deklarationen stehen. Dies dient wiederum der Übersichtlichkeit. Falls ein fremder Programmieren sich den Code anschaut, kann er in der h-Datei sehen, was die Bibliothek kann. In der cpp-Datei kann er sehen, wie die Bibliothek das umsetzt.
Außdem werden wir nun einen neuen Ordner im Ordner '..Arduino/libraries' erstellen. Diesen nennen wir 'RGBLed' und packen unsere h-Datei und cpp-Datei dort hinein.
RGBLed.h:
#ifndef __RGB_LED__
#define __RGB_LED__
#include <Arduino.h>
class RGBLed {
private:
byte redPin;
byte greenPin;
byte bluePin;
public:
RGBLed (byte redPin, byte greenPin, byte bluePin);
void setRGB(byte r, byte g, byte b) ;
void blink(char color, byte times, unsigned int ms);
};
#endif
'RGBLed::' ordnet die in der cpp-Datei definierten Funktionen der Klasse 'RGBLed' zu.
RGBLed.cpp:
#include "RGBLed.h"
RGBLed::RGBLed (byte redPin, byte greenPin, byte bluePin) {
this->redPin = redPin;
this->greenPin = greenPin;
this->bluePin = bluePin;
}
void RGBLed::setRGB(int r, int g, int b) {
analogWrite(redPin, r);
analogWrite(greenPin, g);
analogWrite(bluePin, b);
}
void RGBLed::blink(char color, byte times, unsigned int ms) {
byte r=0, g=0, b=0;
if(color == 'r') r = 255;
else if(color == 'g') g = 255;
else if(color == 'b') b = 255;
else return ;
for (byte i = 0; i < times; i++) {
setRGB(r, g, b);
delay(ms);
setRGB(0, 0, 0);
delay(ms);
}
}
Das Hauptprogramm hat nur eine Änderung:
#include <RGBLed.h> statt #include "RGBLed.h"
Diese Änderung trägt der Migration in den Ordner '..Arduino/libraries' Rechnung. Dort sucht die Arduino-IDE beim Programmstart automatisch nach Bibliotheken.
RGB_LED.ino
#include <RGBLed.h>
RGBLed rgb(4, 3, 2); //Pins: red =4, green =3, blue =2
void setup() {}
void loop() {
rgb.blink('r', 5 , 500);
rgb.blink('b', 10, 250);
rgb.blink('g', 15, 167);
}
Als letztes fügen wir in unseren Ordner eine weitere Datei:
keywords.txt
RGBLed KEYWORD1
setRGB KEYWORD1
blink KEYWORD1
Diese sorgt für ein buntes Hervorheben unserer Schlüsselwörter und dient somit der nocheinmal der besseren Lesbarkeit.
--
Viel Spass beim Schreiben (und Veröffentlichen;)) eurer eigenen Arduino-Bibliotheken!!!
Sisor
1. Vorwort
Bibliotheken sind ja für viele etwas, was man reinladen muß, damit irgendein Sensor, Motor, Display etc angesprochen werden kann. Bibliotheken sind aber kein Hexenwerk. Im Gegenteil, sie sind sehr nützlich, um Programme übersichtlicher zu machen. Außerdem kann man sie leicht mit anderen teilen, sodass nicht jeder Programierer ein bestimmtes Problem neu enträtseln muss. Darum werden wir hier mal ein bischen genauer hinschauen.
Dazu nehmen wir ein einfaches Arduino-Programm und lagern die Funktion in mehreren Schritten in eine Bibliothek aus. Diese sind nicht unbedingt alle nötig, dienen aber der Verauschaulichung, was zu tun ist und warum.
Wer die Programmbeispiele am eigenen Rechner nachvollziehen will, benötigt eine installierte Arduino-IDE ab Version 1.
2. Das Programm
Programmbeschreibung:
Das Programm steuert eine RGB-Led. Diese Led kann man sich vorstellen wie 3 verschiedenfarige Leds in einem Gehäuse. Sie besitzt 4 Anschlüsse: Masse und 3 Anschlüsse für die einzelnen Steuerspannungen, mit denen die Helligkeit der jeweiligen Farbe (Rot, Grün, Blau) gesteuert wird.
RGB_LED.ino:
#define RED_PIN 4
#define GRN_PIN 3
#define BLU_PIN 2
void setRGB(byte r, byte g, byte b) {
analogWrite(RED_PIN, r);
analogWrite(GRN_PIN, g);
analogWrite(BLU_PIN, b);
}
void blink(char color, byte times, unsigned int ms) {
byte r=0, g=0, b=0;
if(color == 'r') r = 255;
else if(color == 'g') g = 255;
else if(color == 'b') b = 255;
else return ;
for (byte i = 0; i < times; i++) {
setRGB(r, g, b);
delay(ms);
setRGB(0, 0, 0);
delay(ms);
}
}
void setup() {}
void loop() {
blink('r', 5, 500); // rot, 5 Widerholungen, jeweils 500 Millisekunden an
blink('b', 10, 250);
blink('g', 15, 167);
}
'setRGB' setzt die einzelnen Steuerspannungen, und damit Farbe und Helligkeit der RGB-Led. Sie nimmt je Farbe Werte zwischen 0 (aus) und 255 (volle Helligkeit) entgegen.
'blink' lässt die Led naja blinken. Farbe der Led, Anzahl der Blinkwiderholungen und Dauer eines An-Aus-Intervalls sind der Funktion zu übergeben.
'loop' lässt die RGB-Led nun in erst rot und langsam, dann blau und schneller, dann grün und schnell blinken. Dann beginnt es von vorn.
3. Auslagern der Funktionalität in ein Modul
Motivation:
- Die Übersichtlichkeit wird verbessert. Im Hauptprogramm sind nur noch die Funtionsaufrufe sichtbar.
- Die Funktionalität kann so sehr einfach in andere Programme integriert werden. Dazu muss nur das Modul geladen werden.
Dazu wird im Sketch-Ordner eine zusätzliche Datei erstellt. Wir nennen sie 'RGBLed.h'.
'.h' identifiziert die Datei als Header-Datei. Hier werden nun die Funtionen eingefügt. Dem vorangestellt steht die Zeile: #include <Arduino.h>. Die ist erforderlich, weil dem Linker die Arduino-Befehlsumgebung zu diesem Zeitpunkt noch nicht bekannt ist. (Der Linker ist Programm, dass die einzelnen Programmteile zu eine einem Gesamtprogramm zusammensetzt, damit es vom Compiler in einen vom Arduino verständlichen Maschinencode übersetzt werden kann).
RGBLed.h
#include <Arduino.h>
void setRGB(byte r, byte g, byte b) {
analogWrite(RED_PIN, r);
analogWrite(GRN_PIN, g);
analogWrite(BLU_PIN, b);
}
void blink(char color, byte times, unsigned int ms) {
byte r=0, g=0, b=0;
if(color == 'r') r = 255;
else if(color == 'g') g = 255;
else if(color == 'b') b = 255;
else return ;
for (byte i = 0; i < times; i++) {
setRGB(r, g, b);
delay(ms);
setRGB(0, 0, 0);
delay(ms);
}
}
Im Hauptprogramm muß dann dem Kompiler angezeigt werden, dass wir die frisch erzeugte Datei verwenden wollen. Dies macht die Anweisung #include "RGBLed.h".
RGB_LED.ino
#define RED_PIN 4
#define GRN_PIN 3
#define BLU_PIN 2
#include "RGBLed.h"
void setup() {}
void loop() {
blink('r', 5 , 500);
blink('b', 10, 250);
blink('g', 15, 167);
}
4. Objekt bauen
Motivation:
- Objekte fassen Funtionalität und Daten unter einem Dach zusammen
- bessere Lesbarkeit des Codes
- Kapselung, Sicherheit
Bis hierhin haben wir reinen C-Code verwendet. Es ist jetzt an der Zeit einen der Vorzüge von C++ zu verwenden: Objekt-Orientierung. Objekte werden nach einem Bauplan erstellt. Dieser Bauplan wird allgemein als Klasse bezeichnet. Die Beschreibung einer Klasse geschieht in einem class-Block. Unsere bekommt den Namen RGBLed.
Das Schlüsselwort public gibt an, dass die Funktionen (die in der Objekt -Orientierung auch Methoden genannt werden) ausserhalb der Klasse ansprechbar sind. Dies wollen wir, da ja später aus dem Hauptprogramm diese Methoden aufrufen werden sollen.
RGBLed.h
#include <Arduino.h>
class RGBLed {
public:
void setRGB(byte r, byte g, byte b) {
analogWrite(RED_PIN, r);
analogWrite(GRN_PIN, g);
analogWrite(BLU_PIN, b);
}
void blink(char color, byte times, unsigned int ms) {
byte r=0, g=0, b=0;
if(color == 'r') r = 255;
else if(color == 'g') g = 255;
else if(color == 'b') b = 255;
else return ;
for (byte i = 0; i < times; i++) {
setRGB(r, g, b);
delay(ms);
setRGB(0, 0, 0);
delay(ms);
}
};
Im Hauptprogramm erzeugen wir zuerst ein RGBLed-Objekt mit dem Namen 'rgb'. Die Methoden des Objekts werden über den '.'-Operator angesprochen.
RGB_LED.ino
#define RED_PIN 4
#define GRN_PIN 3
#define BLU_PIN 2
#include "RGBLed.h"
RGBLed rgb;
void setup() {}
void loop() {
rgb.blink('r', 5 , 500);
rgb.blink('b', 10, 250);
rgb.blink('g', 15, 167);
}
5. Weitere Bearbeitung
- verhindern, dass die Bibliothek mehrfach geladen werden kann (und so zu Compiler-Fehlermeldungen führt)
Dies wird mit folgendem Code erreicht:
#ifndef __RGB_LED__
#define __RGB_LED__
//...
#endif
- Daten im Objekt speichern
Dazu benutzen wir einen Konstruktor: RGBLed (byte redPin, byte greenPin, byte bluePin)
Dieser soll die PIN-Nummern, an denen die RGB-Led angeschlossen wird, beim sofort beim Erstellen des Objekts speichern.
Das Schlüsselwort 'private' gibt an, dass die Variablen nur innerhalb des Objekts angesprochen werden können.
RGBLed.h:
#ifndef __RGB_LED__
#define __RGB_LED__
#include <Arduino.h>
class RGBLed {
private:
byte redPin;
byte greenPin;
byte bluePin;
public:
RGBLed (byte redPin, byte greenPin, byte bluePin){
this->redPin = redPin;
this->greenPin = greenPin;
this->bluePin = bluePin;
}
void setRGB(byte r, byte g, byte b) {
analogWrite(redPin, r);
analogWrite(greenPin, g);
analogWrite(bluePin, b);
}
void blink(char color, byte times, unsigned int ms) {
byte r=0, g=0, b=0;
if(color == 'r') r = 255;
else if(color == 'g') g = 255;
else if(color == 'b') b = 255;
else return ;
for (byte i = 0; i < times; i++) {
setRGB(r, g, b);
delay(ms);
setRGB(0, 0, 0);
delay(ms);
}
}
};
#endif
Im Hauptprogramm benutzen wir nun den neuen Konstruktor.
RGB_LED.ino
#include "RGBLed.h"
RGBLed rgb(4, 3, 2); //Pins: red =4, green =3, blue =2
void setup() {}
void loop() {
rgb.blink('r', 5 , 500);
rgb.blink('b', 10, 250);
rgb.blink('g', 15, 167);
}
6. Finale Bearbeitung
Jetzt werden wir eine weitere Datei hinzufügen: RGBLed.cpp
Diese cpp-Datei wird die gesamte Funktionalität beinhalten, während wir diese aus der h-Datei verbannen. Dort werden nur noch Deklarationen stehen. Dies dient wiederum der Übersichtlichkeit. Falls ein fremder Programmieren sich den Code anschaut, kann er in der h-Datei sehen, was die Bibliothek kann. In der cpp-Datei kann er sehen, wie die Bibliothek das umsetzt.
Außdem werden wir nun einen neuen Ordner im Ordner '..Arduino/libraries' erstellen. Diesen nennen wir 'RGBLed' und packen unsere h-Datei und cpp-Datei dort hinein.
RGBLed.h:
#ifndef __RGB_LED__
#define __RGB_LED__
#include <Arduino.h>
class RGBLed {
private:
byte redPin;
byte greenPin;
byte bluePin;
public:
RGBLed (byte redPin, byte greenPin, byte bluePin);
void setRGB(byte r, byte g, byte b) ;
void blink(char color, byte times, unsigned int ms);
};
#endif
'RGBLed::' ordnet die in der cpp-Datei definierten Funktionen der Klasse 'RGBLed' zu.
RGBLed.cpp:
#include "RGBLed.h"
RGBLed::RGBLed (byte redPin, byte greenPin, byte bluePin) {
this->redPin = redPin;
this->greenPin = greenPin;
this->bluePin = bluePin;
}
void RGBLed::setRGB(int r, int g, int b) {
analogWrite(redPin, r);
analogWrite(greenPin, g);
analogWrite(bluePin, b);
}
void RGBLed::blink(char color, byte times, unsigned int ms) {
byte r=0, g=0, b=0;
if(color == 'r') r = 255;
else if(color == 'g') g = 255;
else if(color == 'b') b = 255;
else return ;
for (byte i = 0; i < times; i++) {
setRGB(r, g, b);
delay(ms);
setRGB(0, 0, 0);
delay(ms);
}
}
Das Hauptprogramm hat nur eine Änderung:
#include <RGBLed.h> statt #include "RGBLed.h"
Diese Änderung trägt der Migration in den Ordner '..Arduino/libraries' Rechnung. Dort sucht die Arduino-IDE beim Programmstart automatisch nach Bibliotheken.
RGB_LED.ino
#include <RGBLed.h>
RGBLed rgb(4, 3, 2); //Pins: red =4, green =3, blue =2
void setup() {}
void loop() {
rgb.blink('r', 5 , 500);
rgb.blink('b', 10, 250);
rgb.blink('g', 15, 167);
}
Als letztes fügen wir in unseren Ordner eine weitere Datei:
keywords.txt
RGBLed KEYWORD1
setRGB KEYWORD1
blink KEYWORD1
Diese sorgt für ein buntes Hervorheben unserer Schlüsselwörter und dient somit der nocheinmal der besseren Lesbarkeit.
--
Viel Spass beim Schreiben (und Veröffentlichen;)) eurer eigenen Arduino-Bibliotheken!!!
Sisor