Grundstruktur einer myAVR C++ Anwendung

Die Grundstruktur einer objektorientierten Anwendung erfordert eine Applikationsklasse oder auch Hauptklasse, welche als erstes gestartet wird. Das ist vergleichbar mit der Hauptfunktion in strukturierten Programmiersprachen. Bei Mikrocontrolleranwendungen repräsentiert die Instanz dieser Hauptklasse letztlich die Firmware des Controllers. Dieser Sachverhalt wird in myAVR C++ wie folgt abgebildet:

// Deklaration der Hauptklasse
class Application {
   // innere Struktur
   // Attribute und Methoden
} app;  // Anwendungsinstanz

Das Schlüsselwort class ist nötig, um dem Kompiler anzuweisen, eine Klasse zu erstellen. Der Name der Klasse wird vom Programmierer festgelegt. In unserem Fall heißt die Hauptklasse Application. Was so viel wie Anwendungsprogramm bedeutet. Wenn man cool sein will erzählt man abends beim Bier, dass man gerade eine Äpp baut. Klassennamen sollten immer mit einem Großbuchstaben beginnen. Daran erkennt der Programmierer später beim Schreiben oder Lesen des Programmcodes jeweils, ob ein Typ oder eine Instanz gemeint ist. Umlaute, Sonderzeichen, Leerzeichen und Zahlen am Wortanfang sind in Klassennamen nicht zulässig. Die Klasse selbst beginnt und endet mit geschweifter Klammer { } . Innerhalb dieser Klammer werden als nächstes die Attribute und Operationen der Klasse programmiert. Von der Hauptklasse muss es auch noch eine Instanz geben. Diese wird durch den Bezeichner app am Ende der Klassendeklaration repräsentiert. Dieser Name kann in unserem Fall nicht frei gewählt werden. Wir werden ein vorgefertigtes Framework (Klassenbibliothek) verwenden, welches zwingend eine Hauptklasse mit dem Namen app erwartet. Das Semikolon signalisiert dem Compiler, dass die Deklaration abgeschlossen ist.

Weil Programmierer von Natur aus faul sind gern auf Zeiteffizienz achten, möchten sie möglichst viel wiederverwenden was sie selbst oder auch andere schon programmiert haben.

// Deklaration der Hauptklasse
class Application : public Controller {
   // innere Struktur
   // Attribute und Methoden
} app;  // Anwendungsinstanz

Der Ausdruck : public weist den Kompiler an, das die Klasse Applikation alle Merkmale der Klasse Controller öffentlich, also für alle sichtbar, erben soll. Diese Klasse ist im myAVR C++ Framework schon vorhanden. Besonders interessant ist jetzt, was die Klasse Controller bereits kann. Dazu eine kurze Übersicht.

Nicht gruseln! Das ist nur ein etwas vereinfachter Ausschnitt aus dem entsprechenden UML Klassendiagramm des myAVR C++ Framework. Was wir dort sehen ist, das die Klasse Controller offensichtlich alle Eigenschaften des ATmega8 besitzt und einen AppKernel realisiert. Das Klassetemplate AppKernel stellt wesentliche Basisfunktionalitäten zur Verfügung. Diese finden sich als Operationen, wie zum Beispiel onStart, onWork oder onTimer10ms, in der Klasse Controller wieder. Wir erkennen Funktionen für das Hochfahren und den Betrieb des Controllers. An diese Funktionen werden wir uns sehr bald „ranhängen“, indem wir selber gleichnamige Operationen schreiben. Der Fachmann bezeichnet das, wie bereits erwähnt, als überschreiben der Operationen. Interessant ist auch die Schnittstellenklasse AppModul. Der Controller kennt eine Liste von AppModulen und diese verfügen auch über die gleichen Basisfunktionen. Die AppModule können ihrerseits Ereignisse an den Controller melden.

Das erste myAVR C++ Programm

Für diesen Schritt müssen Sie SiSy installiert und ein myAVR-Board mit ATmega8 an Ihrem PC angeschlossen haben. Starten Sie SiSy und legen Sie ein neues Projekt mit dem Namen „Tutorial“ an. Wählen Sie das AVR-Vorgehensmodell Dann laden Sie bitte keine Vorlagen sondern legen ein kleines Programm mit dem Namen „test1“ an, indem sie das entsprechende Objekt per Drag & Drop aus der Objektbibliothek in das Diagramm ziehen. Beachten Sie die korrekten Einstellungen für das myAVR Board.

Für das kleine Programm ist es wichtig, dass Sie als Zielsprache AVR C++ ausgewählt haben. Sind die Board- und Spracheinstellungen korrekt, könnnen Sie im Dialog zum kleinen Programm die Grundstruktur für ein AVR C++ Programm laden. Dazu wählen Sie im Dialog Programmgerüst die entsprechende Vorlage und die Schaltfläche „Struktur laden“.

Ihnen sollte jetzt ein kleines Programm mit geladenem Programmgerüst vorliegen. Der Bildschirm von SiSy teilt sich in Navigator (links, im Bild unten ausgeblendet), Diagrammfenster mit Objektbibliothek (unten) und den Quelltexteditor (oben). Im Quelltexteditor können Sie den Programmcode des im Diagrammfenster jeweis selektierten Elementes bearbeiten. Alle Übungen dieses Tutorials können in ein und demselben Projekt bearbeitet werden. Es ist lediglich nötig, die Schritte für das Anlegen eines neuen kleinen Programms durchzuführen.

Die geladene Vorlage enthält folgende Quelltextteile:

  • Programmkopfdokumentation
  • Klassendeklaration
  • Attributsektion mit Beispielattribut
  • Methodensektion mit den Operationen
    • onStart() und
    • onWork()
//----------------------------------------------------------------------
// Titel     : Grundgerüst einer AVR C++ Anwendung
//----------------------------------------------------------------------
// Funktion  : ...
// Schaltung : ...
//----------------------------------------------------------------------
// Prozessor : ...
// Takt      : ...
// Sprache   : AVR C++
// Datum     : ...
// Version   : ...
// Autor     : ...
//----------------------------------------------------------------------
class Application : public Controller
{
    // Bausteine und Attribute .........................................
    // Sichtbarkeit: Typ name;
    protected: uint8_t wert;
 
    // Funktionen ......................................................
    // Sichtbarkeit: Typ name (Parameter) { Befehle }
    public: void onStart()
    {
        // hier Initialisierungen durchführen
        wert=0;
    }
    // Sichtbarkeit: Typ name (Parameter) { Befehle }
    public: void onWork()
    {
        // hier 
        // Eingabe
        // Verarbeitung
        // Ausgabe
    }
} app;  // Anwendungsinstanz

Das Programm hat bis jetzt keine Funktionalität, nur vorbereitete Strukturelemente für eine einfache Anwendung. Schauen wir uns kurz die Attribute und Operationen näher an.

Attribute müssen zwar nicht, aber sollten als Erstes in der Applikation deklariert werden. Dabei ist empfehlenswert diszipliniert die Schreibweise einzuhalten und jedes Attribut in der Operation onStart zu initialisieren. Ein Attribut wird korrekt deklariert, indem die Sichtbarkeit gefolgt von einem Doppelpunkt, der Typ und ein Name für das Attribut festgelegt werden. Die Deklaration wird mit einem Semikolon abgeschlossen. Der Name des Attributes sollte klein geschrieben werden.

    // Sichtbarkeit: Typ name;
    protected: uint8_t wert;

Ähnliches gilt für die Schreibweise von Operationen. Diese besitzen ebenfalls eine Sichtbarkeit, einen Typ, einen Namen, der klein beginnen sollte, zusätzlich eine Parameterliste in runden Klammern und den eigentlichen Funktionskörper in geschweifter Klammer. Wenn die Operation keinen Rückgabewert liefert, wird der Typ als void (leer) angegeben. Wenn keine Parameter übergeben werden, sind in C und C++ trotzdem die leeren Klammern zu notieren oder eben auch als void zu deklarieren.

    // Sichtbarkeit: Typ name ( Parameter ) { Funktionskörper }
    public: bool meineOperationX ( char parameter1, int parameter2 ) 
    {
        /*Funktionskörper*/ 
        return true;
    }
    // eine Operation ohne Typ und ohne Parameter
    public: void meineOperationY ( ) 
    {
        /*Funktionskörper*/ 
    }

Die Operationen onStart() und onWork() sind genau dieselben wie die in der Basisklasse bereits vorhandenen. Sie wurden durch uns überschrieben, was soviel bedeutet wie dem Kompiler mitzuteilen, dass unsere Operationen und nicht die der Basisklasse die gültigen sind. Diese auf den ersten Blick etwas eigenwillige Vorgehensweise dient dazu, vorweg vereinbarte bzw. definierte Namen von Operationen (Nachrichten) zur Verfügung zu haben. Da die Namen der Operationen schon bekannt sind bevor wir als Programmierer diese überschrieben haben, kann der Entwickler von anderen Klassen, zum Beispiel aus einem anderen Teilprojekt oder wie in unserem Fall der Entwickler des myAVR Frameworks, diese Operationen aufrufen bevor sie programmiert wurden. Diese vorab vereinbarten Operationen bilden die Schnittstelle zwischen dem Entwickler des Framework und uns. Im Framework wurde so programmiert, dass die Operation onStart genau einmal nach dem Einschalten des Controllers und die Operation onWork ständig wiederholend, so lange der Controller arbeitet, aufgerufen wird. Vergleichen Sie dazu das folgende Sequenzdiagramm.

Obwohl das Programm noch gar nichts tut wollen wir erst einmal sehen, ob die Programmierung des Controllers funktioniert. Dazu lösen wir über die Schaltflächen im oberen Bereich des Quelltextfensters nacheinander folgende Aktionen aus:

  • Komilieren, die Quelltextdatei (*.cc) wird erzeugt und in eine Objekt-Datei (*.o) übersetzt
  • Linken, die Objekt-Datei (*.o) wird mit der myAVR Bibliothek (*.a) zum lauffähigen Programm (*.elf) verbunden
  • Brennen, Das lauffähige Programm (*.elf) wird über den Programmer oder den Bootloader in den Programmspeicher (FLASH) des Controllers übertragen

Sie können das Protokoll für die ausgeführten Aktionen im Ausgabefenster einsehen. Sollten Fehler aufgetreten sein, werden diese hier angezeigt.

Glückwunsch! Sie haben das erste AVR C++ Programm auf ihren Controller geflasht.

Videozusammenfassung

Und weil es so schön war hier das Ganze noch mal als Video.

Nächstes Thema