Hallo zur Webseite von
DL1DMW






<- Bild 1: Arduino IDE mit dem geladenen Sketch ohmsches-gesetz_normal.ino. Basierend auf diesen Sketch wird eine kleine Bibliothek entwickelt.


Arduino:
Eigene Bibliotheken erstellen

Arduino-Programme werden in einer einfachen Form der Sprache „C“ formuliert. Fallen sie länger aus, wird es schnell unübersichtlich. Um den Quellcode übersichtlich zu gestalten und doppelte Arbeit bei der Programmierung zu vermeiden, fasst man wiederkehrende Codeabschnitte, etwa die Funktionen zum Auslesen eines Sensors oder zur Ansteuerung eines Funkgerätes in eine sogenannte „Klasse“ zusammen und macht sie als Auduino-Bibliothek verfügbar..

Die Ardiono IDE kommt mit einer Vielzahl von Bibliotheken daher. Sie ermöglichen eine einfache Programmierung, ohne in die Tiefen der Bits und Bytes von Schrittmotor, Sensoren oder der Ansteuerung eines Funkmoduls einzutauchen. Doch nicht für alle Fälle steht eine Bibliothek parat. Also muss man sie selbst programmieren. Hier erfahren Sie Schritt für Schritt, wie Sie eine Bibliothek für Arduino schreiben und anwenden. Als einfaches Beispiel dient ein Programm (ein „Sketch“) für die Berechnung des Ohmschen Gesetzes. Dabei kommt es nicht auf die elegante Programmierung an – es geht ums Prinzip! Ausgehend von einem herkömmlichen Berechnungsprogramm (Ohne Bibliothek) werden im weiteren Verlauf die Funktionen in eine Bibliothek eingepflegt. Vorteile einer Arduino-Bibliothek: Andere Leute können den von Ihnen geschriebenen Code leicht verwenden und bei Bedarf weiter entwickeln. Wir starten mit einem Sketch, der auf einfachste Weise U (Spannung), R (Widerstand) oder I (Strom) berechnet:

float u;
float r;
float i;

void setup()
{
Serial.begin(9600);
}

void loop()
{

r = 1500.0; i = 0.002;
u = r * i;
Serial.print("U ="); Serial.println(u);
// U sollte 3 sein!

u = 12.0; i = 0.002;
r = u / i;
Serial.print("R ="); Serial.println(r);
// R sollte 6000 sein

u = 12.0; r = 470.0;
i = u / r;
Serial.print("I ="); Serial.println(i);
// I sollte 0,03 sein

Serial.println();
delay(3000);
}


<- Bild 2: Der serielle Monitor zeigt das Resultat der Berechnungen.


Starten Sie diesen Sketch auf einem Arduino UNO, wird jeweils das Ohmsche Gesetz auf die gegebenen Variablen angewandt Der Sketch läuft natürlich auf beliebigen anderen Arduinos. Anfangs werden drei Variablen für Spannung, Strom und Widerstand definiert. In der Funktion Setup() wird die serielle Ausgabe von Texten und Variablen vorbereitet und eine Baudrate von 9600 Baud festgelegt, um später die Resultate der Berechnungen auf dem seriellen Monitor der Arduino IDE anzuzeigen. In der Programmschleife Loop() werden die Variablen mit Werten belegt, die Berechnung ausgeführt und mittels Print-Anweisung zum seriellen Monitor geschickt. Der Sketch weist ein paar wichtige Zeilen auf, die wir in unsere Bibliothek aufnehmen müssen. Zunächst sind das natürlich die Zeilen, in denen der benötigte Wert berechnet wird.


Ab in die Lib!

Für eine Bibliothek (engl.: library) benötigt man mindestens zwei Dateien: eine Header-Datei mit der Endung .h und die Quelldatei mit der Endung .cpp. Die Header-Datei enthält Definitionen für die Bibliothek, im Grunde eine Auflistung von allem, was in der Klasse enthalten ist, während die Quelldatei den eigentlichen Code enthält. Wir werden unsere Bibliothek "OhmschesGesetz" nennen, also wird unsere Header-Datei "OhmschesGesetz.h" heißen. Schauen wir uns einmal an, was darin enthalten ist. Es mag auf den ersten Blick etwas seltsam erscheinen, später werden Sie den Sinn erkennen, wenn Sie die dazugehörige Quelldatei sehen.

Der Kern der Header-Datei besteht aus einer Zeile für jede Funktion in der Bibliothek, eingepackt in eine Klasse zusammen mit allen benötigten Variablen:


class OhmschesGesetz
{
public:
OhmschesGesetz();
float getU(float R,float I);
float getR(float U, float I);
float getI(float U, float R);

private:
float _spannung;
float _strom;
float _widerstand;
};

Eine Klasse ist eine Sammlung von Funktionen und Variablen, die alle an einem Ort zusammengefasst sind. Diese können öffentlich sein, d.h. sie sind für die Benutzer Ihrer Bibliothek zugänglich (public), oder privat (private), d.h. sie sind nur innerhalb der Klasse selbst nutzbar. Jede Klasse besitzt einen speziellen Konstruktor (hier: OhmschesGesetz();). Der Konstruktor besitzt denselben Namen wie die Klasse und kennt keinen Rückgabetyp, hier also OhmschesGesetz(). Beachten Sie bitte, dass die Klasse mit einem Großbuchstaben beginnt. Dazu später mehr.
In der Header-Datei werden noch ein paar andere Dinge benötigt. Eine davon ist eine #include-Anweisung, die den Zugriff auf die Standardtypen und -konstanten der Arduino-Sprache ermöglicht (diese wird von der Arduino IDE automatisch zu normalen Sketches hinzugefügt, leider aber nicht zu Bibliotheken). Das sieht wie folgt aus (und steht oberhalb der zuvor angegebenen Klassendefinition):

#include "Arduino.h"

Schließlich ist es üblich, die gesamte Header-Datei in ein seltsam aussehendes Konstrukt zu verpacken:

#ifndef OhmschesGesetz_h
#define OhmschesGesetz_h

// #include-Befehl und der Code kommen hier hinein...

#endif

Dadurch werden Probleme vermieden, wenn jemand Ihre Bibliothek versehentlich mehrfach per #include-Kommando einfügt. Das funktioniert so: Bevor ein Sketch kompiliert wird, schaut sich ein Präprozessor den Text des Sketches an. Befehle, die mit '#' beginnen, sind Kommandos an den Präprozessor. Wenn man z.B. #define LED 5 schreibst, ersetzt der Präprozessor im Sketch jedes „LED“ im Code durch „5“ und gibt ihn an den Compiler zur Verarbeitung weiter. Abschnitte, die von #ifdef und #endif umgeben sind, werden nur an den Compiler weitergereicht, wenn wie hier ein Text (auch makro genannt) vorher durch #define definiert wurde (ifdef ist die Kurzform von if defined, ifndef die von if not defined). Wenn eine Headerdatei eingebunden werden soll, wird überprüft, ob ein Makro (hier: OhmschesGesetz_h) bereits definiert wurde. Falls nicht (#ifndef), wird es definiert und die Headerdatei wird eingebunden. Wurde das Makro zuvor schon definiert, die Headerdatei ist also bereits eingebunden, dann geschieht das nicht ein zweites Mal.
Zu guter Letzt setzen Sie normalerweise einen Kommentar an den Anfang der Bibliothek mit ihrem Namen, einer kurzen Beschreibung ihrer Funktion, dem Autor, dem Datum und den Nutzungsbestimmungen (Weitergabelizenz). Werfen wir einen Blick auf die vollständige Header-Datei:

/*
OhmschesGesetz.h – Berechnungen.
Created by Michael, August 2022.
Released into the public domain.
*/


#ifndef OhmschesGesetz_h
#define OhmschesGesetz_h

#include "Arduino.h"

class OhmschesGesetz
{
public:
OhmschesGesetz();
float getU(float R,float I);
float getR(float U, float I);
float getI(float U, float R);

private:
float _spannung;
float _strom;
float _widerstand;
};

#endif

Gehen wir nun die verschiedenen Teile der Quelldatei OhmschesGesetz.cpp durch. Zuerst sehen Sie zwei #include-Anweisungen. Diese geben dem Rest des Codes Zugriff auf die Standard-Arduino-Funktionen und auf die Definitionen in Ihrer Header-Datei:

#include "Arduino.h"
#include "OhmschesGesetz.h"

Danach kommt der Konstruktor dieser Klasse. Er legt fest, was passieren soll, wenn jemand eine Instanz Ihrer Klasse erstellt. In diesem Fall gibt der Benutzer an, welchen Pin er verwenden möchte. Wir konfigurieren den Pin als Ausgang und speichern ihn in einer privaten Variable zur Verwendung in den anderen Funktionen:

// Konstructor
OhmschesGesetz::OhmschesGesetz()
{
_spannung = 0;
_strom = 0;
_widerstand = 0;
}
In diesem Code gibt es einige merkwürdige Dinge. Das erste ist das OhmscheGesetz:: (mit zwei Doppelpunkten) vor dem Namen der Funktion. Dies besagt, dass die Funktion Teil der Klasse OhmschesGesetz ist. Sie werden dies in den anderen Funktionen der Klasse wiederfinden. Die zweite Besonderheit ist der Unterstrich im Namen der privaten Variablen. Diese Variablen könnten jeden beliebigen Namen haben, solange er mit der Definition in der Header-Datei übereinstimmt. Das Hinzufügen eines Unterstrichs am Anfang des Namens ist eine übliche Konvention, um zu verdeutlichen, dass es sich um private Variablen handelt, die nur innerhalb der Klasse gültig sind. Private Variablen wie _strom sollten also mit einem Untersprich beginnen.

Als nächstes finden wir die Berechnungen aus dem Sketch wieder. Wir definieren drei Funktionen, um Spannung, Strom und Widerstand zu berechnen, aber mit OhmschesGesetz:: vor den Namen jeder Funktionen. Betrachten wir die Funktion zum Berechnen der Spannung im Detail:

float OhmschesGesetz::getU(float R,float I)
{
// U = R * I;
_widerstand = R;
_strom = I;
_spannung = _widerstand * _strom;
return _spannung;
}

Es werden die Variablen R und I der Funktion getU übergeben; sie gibt einen float-Wert zurück. In der Funktion werden die von außen kommenden Variablen auf private Variablen (die wie gesagt nur innerhalb der Klasse zugänglich sind) umkopiert. Schließlich wird die Spannung berechnet und mit dem return-Kommando die Spannung zurückgegeben.

Schließlich ist es üblich, auch den Kommentar-Header am Anfang der Quelldatei einzufügen. Schauen wir uns das Ganze einmal an:

/*
OhmschesGesetz.cpp - Library for U/R/I.
Released into the public domain.
*/

#include "Arduino.h"
#include "OhmschesGesetz.h"

// Konstructor
OhmschesGesetz::OhmschesGesetz()
{
_spannung = 0;
_strom = 0;
_widerstand = 0;
}

float OhmschesGesetz::getU(float R,float I)
{
// U = R * I;
_widerstand = R;
_strom = I;
_spannung = _widerstand * _strom;
return _spannung;
}

float OhmschesGesetz::getR(float U, float I)
{
// R = U / I
_spannung = U;
_strom = I;
_widerstand = _spannung / _strom;
return _widerstand;
}

float OhmschesGesetz::getI(float U, float R)
{
// I = U / R
_spannung = U;
_widerstand = R;
_strom = _spannung / _widerstand;
return _strom;
}

Und das ist schon alles, was Sie für Ihre kleine Bibliothek brauchen. Betrachten wir, wie Sie die Bibliothek verwenden.


<- Bild 3: Korrekt angelegte Bibliothek OhmschesGesetz im Verzeichnis Arduino/libraries der Arduino-Installation mit dem Unterordnern examples.


Zuerst erstellen Sie ein Verzeichnis OhmschesGesetz innerhalb des libraries-Unterverzeichnisses Ihres Sketch-Verzeichnisses (Dokumente\Arduino\libraries\OhmschesGesetz). Kopieren oder verschieben Sie die Dateien OhmschesGesetz.h und OhmschesGesetz.cpp in dieses Verzeichnis. Starten Sie nun die Arduino-Umgebung. Wenn Sie das Menü Sketch -> Import Library öffnen, sollten Sie den Ordner OhmschesGesetz darin sehen. Die Bibliothek wird mit den Sketches, die sie verwenden, kompiliert. Wenn sich die Bibliothek nicht kompilieren lässt, vergewissern Sie sich, dass die Dateien wirklich auf .cpp und .h enden (ohne zusätzliche .txt-Erweiterung).

Schauen wir uns an, wie unser alter Sketch unter Verwendung der neuen Bibliothek aussieht:

#include <OhmschesGesetz.h>

OhmschesGesetz uri;

float u;
float r;
float i;

void setup()
{
Serial.begin(9600);

}

void loop()
{
r = 1500.0; i = 0.002;
u = uri.getU(r, i);
Serial.print("U ="); Serial.println(u);
// U sollte 3 sein!

u = 12.0; i = 0.002;
r = uri.getR(u, i);
Serial.print("R ="); Serial.println(r);
// R sollte 6000 sein

u = 12.0; r = 470.0;
i = uri.getI(u, r);
Serial.print("I ="); Serial.println(i);
// I sollte 0,0255 sein

Serial.println();
delay(3000);
}

Es gibt ein paar Unterschiede zum alten Sketch. Zunächst sehen Sie eine #include-Anweisung am Anfang. Dadurch wird die Bibliothek für den Sketch verfügbar gemacht und in den an das Arduino-Board gesendeten Code aufgenommen. Das bedeutet, sollten Sie eine Bibliothek nicht mehr in einem Sketch benötigen, ist die entsprechende #include-Anweisung zu löschen, um Platz zu sparen.

Danach erstellen wir nun eine Instanz der Klasse mit der Bezeichnung uri. Der Name kann frei gewählt werden, sollte jedoch einen Bezug zur Klasse aufweisen:

OhmschesGesetz uri;

Wenn diese Zeile ausgeführt wird, was sogar noch vor der Setup()-Funktion geschieht, wird der Konstruktor für die Klasse OhmschesGesetz aufgerufen. Mit einem Konstruktor kann man auch Werte an die Klasse übergeben, was hier jedoch nicht nötig ist. Wir haben die Klasse bewusst mit einem anfänglichen Großbuchstaben genannt. Die hier entstehende Instanz dieser Klasse heißt uri. Klassen sollten mit einem Großbuchstaben beginnen und die Instanzen der Klasse sollte man mit Kleinbuchstaben benennen!
Beachten Sie, dass sich bei Setup() nicht viel verändert hat. Um die Funktionen getU () und weitere aufzurufen, müssen wir ihnen die Bezeichnung der Instanz voranstellen (uri.getU(…);).


Kleiner Exkurs:

Es ist durchaus gestattet, mehrere Instanzen einer Klasse zu bilden, beispielsweise um zwei gleichartige Sensoren auszulesen:

SensorXY sensor1();
SensorXY sensor2();

Die Klasse hat die Bezeichnung SensorXY und die Instanzen der Klasse sensor1 und sensor2. Um einen Sensorwert zu lesen würde man beispielsweise sensor1.lesen() für den ersten Sensor schreiben und sensor2.lesen() für den zweiten Sensor. Ende des Exkurses.

Wenn Sie den neuen Sketch ausprobiert haben, ist Ihnen vielleicht aufgefallen, dass bei Anzeige des Sketches im Editor kein Text aus unserer Bibliothek farblich gekennzeichnet wird. Leider kann Arduino nicht automatisch herausfinden, was Sie in Ihrer Bibliothek definiert haben, also müssen Sie ein wenig helfen: Erstellen Sie eine Datei mit der Bezeichnung keywords.txt im Verzeichnis OhmschesGesetz. Sie sollte wie folgt aussehen:

OhmschesGesetz KEYWORD1
getU KEYWORD2
getI KEYWORD2
getR KEYWORD2

Jede Zeile enthält den Namen des Schlüsselworts, gefolgt von einem Tabulator (keine Leerzeichen!), gefolgt von der Art des Schlüsselworts. Klassen gehören zu KEYWORD1 und sind orange gefärbt; Funktionen werden mit KEYWORD2 markiert und werden im Editor braun dargestellt.

Werden in einer Klasse Konstanten definiert, werden diese wie folgt in keywords.txt eingetragen. Das Beispiel wurde einer anderen Klasse entnommen::

######################
# Constants (LITERAL1)
######################
PRESSED LITERAL1
RELEASED LITERAL1

Wie man sieht, darf man Kommentare in die Datei schreiben, wenn sie mit einem „#” beginnen. Konstanten werden als LITERAL1 gekennzeichnet. Nachdem die Arduino IDE neu gestartet wurde, werden die neuen Schlüsselwörter erkannt und farblich gekennzeichnet.


<- Bild 4: Wurde die Bibliothel korrekt angelegt, erscheint der Beispiel-Sketch im Menü Datei -> Beispiele -> OhmschesGesetz der Arduino IDE.





Besser mit Beispiel-Sketch!

Es ist gängige Praxis, den Benutzern ihrer Bibliothek ein Beispiel-Sketch zur Verfügung zu stellen, welche die Anwendung Ihrer Bibliothek erläutert. Erstellen Sie dazu ein Verzeichnis examples innerhalb des Verzeichnisses OhmschesGesetz. Verschieben oder kopieren Sie dann das Verzeichnis, das den Sketch (ohmsches_gesetz.ino) enthält, den wir oben geschrieben haben, in das examples-Verzeichnis. Sie finden den Ordner mit dem Befehl Sketch -> Sketch Ordner anzeigen. Nach einem erneuten Start der Arduino IDE finden Sie das Beispielprogramm im Menü Datei -> Beispiele -> OhmschesGesetz (Bild 4).

Die Sketches sowie die Bibliothek finden Sie in der Datei arduinolib.zip unten zum Download.

Literatur/Verweise:
[1] Arduino-Homepage:
arduino.cc

Datei arduinolib.zip laden






Mehr Zeugs
  • Schaun mer mal
  • Moin
  • Bast scho

Hier gibt es was zu lesen

Adresse etc.

  • Op: Michael, DL1DMW
  • ITU Region 1, Zone 14, DL, JO41CO
  • Bad Sassendorf
  • NRW / Germany