Hallo PEC
Die erste eigene Funktionalität die wir mit den Mitteln des PEC-Framework realisieren wollen ist, wie kann es anders sein, ein Blinky. Vorraussetzung ist, dass wir ein Projekt mit den PEC-Bibliotheken angelegt und ein Klassendiagramm mit dem Grundgerüst einer PEC-Anwendung erstellt haben.
Das so erstellte Klassendiagramm sieht in etwas wie folgt aus:
Wir halten kurz verbal fest was dieses Klassenmodell als Konstruktionszeichnung und Realisierungsvorschrift die vom Codegenerator umgesetzt wird festlegt:
- es gibt eine Klasse Controller diese verfügt über die Operationen
- onStart
- onWork
- Die Klasse Controller realisiert ein PecAppKernel
- das Objekt app ist die Instanz der Klasse Controller
- es werden die Pakete Pec und MCU_ATmega_xxx verwendet
die Aufgabe besteht darin, die rote LED auf dem MK2-Board blinken zu lassen. Dazu benötigen wir im Klassenmodell den entsprechenden Baustein. Im folgenden wird eine von verschiedenen Möglichkeiten aufgezeigt wie der Systemdesinger einen benötigten Baustein in sein Klassenmodell aufnehmen kann. Dazu sind folgende Überlegungen vorausgegangen:
- das System hat eine rote LED
- die rote LED ist mit dem Controller über Port B Bit 0 verbunden
- wenn das System instanziiert (angelegt und hochgefahren) wird soll die LED automatisch verfügbar sein
- die LED ist solange verfügbar wie das System läuft
Diese Überlegungen führen zunächst dazu, dass der Systemdesiner sich dafür entscheidet die rote LED als Attribut in der Klasse Controller zu aggregieren. Hierbei hat er auch wieder verschiedene Möglichkeit. Er entschließt sich eine Klasse mit dem namen RoteLED anzulegen und diese über einer Aggregationsbeziehung mit dem Controller zu verbinden. Dabei wird die Aggregation vom Codegenerator als Attribut der Klasse Controller abgebildet. Der Attributname wird als sogenannter Rollenbezeicher +roteLED an der Aggregationsbeziehung mit dessen Sichtbarkeit notiert. Beachten Sie die Unterscheidung in der Schreibweise zwischen dem Typ RoteLED und der Instanz roteLED.
Aus diesem Modell erstellt der Codgenerator vereinfacht folgenden Quelltext für die Klassen Controller und RoteLED.
/////////////////////////////////////////////////////////// class Controller : public PecAppModul { // Attribute public: RoteLED roteLED; // Operationen public: Controller(); public: ~Controller(); public: void onStart(); public: void onWork(); }; /////////////////////////////////////////////////////////// class RoteLED { // inline public: RoteLED() { } // Konstruktor public: ~RoteLED() { } // Destruktor };
Diese Vorgehensweise für die Abbildung eines Systembausteins im Klassenmodell kann für die Arbeit mit den PEC-Bibliotheken durchaus als typisch angesehen werden. Zusätzlich wird diese Variante der Modellierung durch das Angebot zahlreicher PEC-Templates gefördert. Es liegt jetzt am Systemdesiner, dem Architekten in Ihnen eine geeignete Basisklasse oder ein geeignetes Template aus den Bibliotheken herauszusuchen. In der folgenden Darstellung wird die Realisierung mit dem Template PecPinOutput gezeigt. Dabei ist zu beachten, dass der Teil aus den eigentlichen PEC-Paketen lediglich festlegungen der Signatur der Klassen und Schnittstellen darstellt also portable und damit nicht spezifischen Code für AVR-Controller enthält. Diesen Umstand erkennen Sie am Präfix pec. Es ist notwendig zusätzlich controllerspezifische Informationen an die zu realisierende Klasse anzubinden. Das geschieht über die Zuweisung des betreffenden plattformspezifischen Pins.
Aus diesem Modell erstellt der Codgenerator wiederum den plattformspezifischen Code der im Folgenden vereinfacht abgebildet ist.
// Defines from Templates #define PinOutput_HighActive #define PinOutput_PushPull #define PinOutput_NoPull class RoteLED // implements PecDigitalOut { // Attribute from PecDigitalOut protected: volatile uint8_t* port; protected: uint8_t bitmask; // Operationen from PecDigitalOut public: virtual bool getState(); public: void setState(bool newState); public: virtual void config(port_t port, pinMask_t bitmask); public: void on(); public: void off(); public: void toggle(); // inline public: RoteLED() {config( PORTB, BIT0 );} public: ~RoteLED(){ } };
Bis hier haben wir uns in der Adlerperspektive wir können auch sagen auf Architekturebene bewegt. Die Niederungen der Froschperspektive bleiben uns aber nicht ganz erspart. Da das Ganze alles andere als malen nach Zahlen ist sollten Sie sich darüber bewusst sein, dass es hier nach wie vor um native C++ Programmierung geht. Die grafische Arbeit sorgt lediglich dafür, dass wir eine andere Perspektive und gleichzeitig eine adäquate Dokumentation der Architektur des Systems haben. Das ganze müsste in einer klassischen IDE einfach vom Programmierer als Quelltext getippt werden. Das Quelltext tippen des Architekturrahmens übernimmt für uns der Codegenerator. Nicht mehr und nicht weniger. Über die konkrete Verarbeitungslogik entscheiden nach wie vor Sie in der Rolle des Programmierers. Hier eine einfache Lösung die rote LED blinken zu lassen.
onWork
roteLED.toggle(); waitMs(300);
Wenn wir die zwei Zeilen richtig eingegeben und das Modell korrekt erstellt haben können wir aus dem Klassendiagramm den Quellcode generieren, diesen übersetzen und auf den Controller übertragen. Das erfolgt über das Aktionsmenü in der Objektbibliothek. Wählen sie dort den Menüpunkt Erstellen, Brennen & Ausführen.
"Intelligenter" Lichtschalter, EVA Eingabe, Verarbeitung, Ausgabe
Als nächsten Schritt erweitern wir unsere Firmware um die Funktionalität eines Tasters. Die rote LED soll nur blinken, wenn der Taster gedrückt ist. Den Taster schließen wir an Port D Bit 2 an. Folgende Vorüberlegungen stellt der Systemdesiner an:
- das System hat einen Taster
- der Taster ist mit dem Controller über Port D Bit 2 verbunden
- der Taster benötigt einen PullUp
- wenn das System instanziiert (angelegt und hochgefahren) wird soll der Taster automatisch verfügbar sein
- der Taster ist über die gesamte Laufzeit des Systems verfügbar
Das kommt uns bekannt vor. Der Systemdesiner in uns entscheidet sich für die gleiche Vorgehensweise wie bei der roten LED. Als geeignete Templates wählt er PecPinInput, PinPullUp und pinD2. Diese bindet er an die Aggregierte Klasse Taster.
Den Quellcode der Operation onWork ergänzen wir wie folgt:
onWork
// Eingabe, Verarbeitung, Ausgabe if (taste.getState()==0) { roteLED.toggle(); waitMs(300); } else { roteLED.off(); }
haben wir das Modell und den Quellcode korrekt erstellt sollte das system nach dem Bilden und Übertragen wie gewünscht funktionieren.
Videozusammenfassung
Und hier diesen Abschnitt als kurze Videozusammenfassung.
Vertiefende Themen
- EVA mit Attributen (nur über eine SiSy-Lizenz verfügbar)
- EVA über Vererbung (nur über eine SiSy-Lizenz verfügbar)
- Blinky mit dem SysTick (nur über eine SiSy-Lizenz verfügbar)
Nächstes Thema
Wer mag kann sich jetzt ein wenig in den Bibliotheken umschauen
oder