IO-deluxe, die Klassen Button und Led
Einer der wichtigsten Aspekte objektorientierter Programmierung ist die Nutzung vorhandener Klassen. Eine gewisse Auseinandersetzung mit dem sogenannten Framework, also der Gesamtheit der zur Verfügung stehenden Klassen und deren Zusammenwirken, ist dafür nötig. Aber das kann durchaus Schritt für Schritt geschehen. Wenden wir uns zuerst Klassen zu, welche die zuvor beschriebenen Ein- und Ausgabefunktionalität abbilden. In einem der vorausgegangenen Abschnitte wurde die einfache Arbeit mit dem Eingabegerät Taster und dem Ausgabegerät LED besprochen. Die Möglichkeiten der vorgestellten Strukturen waren recht gering und die sprachliche Umsetzung noch alles andere als selbsterklärend. Und wir können davon ausgehen, dass solche Problemstellungen wie Taster ist gedrückt und auch entprellt bereits gelöst sind und wir uns bei der Nutzung der Klassenbibliothek auf das Abbilden der fachlichen Anforderungen konzentrieren können.
Erste Schritte mit den Klassen
Vergegenwärtigen wir uns die Aufgabenstellung. Es ist eine Mikrocontrolleranwendung zu erstellen, bei der an den Controller eine Taste und eine LED angeschlossen sind. Wenn die Taste gedrückt ist soll die LED angeschaltet werden, ansonsten soll die LED aus sein.
Das myAVR C++ Framework stellt uns für die Abbildung einer Taste die Klasse Button zur Verfügung. Um eine einfache LED zu nutzen bietet sich, ja was sonst, die Klasse Led an. Die folgende Darstellung zeigt einen Ausschnitt aus dem UML Klassendiagramm des Framework mit genau diesen Klassen.
Beim ersten Darüberschauen ist schon zu sehen, dass diese Klassen uns Funktionen anbieten, die man in Mikrocontrolleranwendungen gut gebrauchen kann. Als Erstes beschränken wir uns auf die Anwendung der Möglichkeit den Taster zu fragen, ob er gedrückt ist und die LED ein bzw. auszuschalten.
Hier das Board mit der gewünschten Schaltung. Der Taster 1 ist an Port D Bit 2 angeschlossen und die rote LED an Port B Bit 0.
Zuerst notieren wir unsere konzeptuellen Gedanken als Kommentare an die richtigen Stellen in der geladenen Programmvorlage.
////////////////////////////////////////////////////////// // Lichtschalter 2 ENTWURF ////////////////////////////////////////////////////////// class Application : public Controller { // Attribut für den Taster 1 // Attribut für die rote LED public: void onStart() { // Taster 1 auf PortD Bit2 konfigurieren // die rote LED auf Port B Bit 0 konfigurieren } public: void onWork() { // wenn Taste 1 gedrückt ist // dann die rote LED anschalten // sonst // die rote LED ausschalten } } app; //////////////////////////////////////////////////////////
Nochmal ein kleines Review über das Konzept und dann kann es mit der Realisierung los gehen.
////////////////////////////////////////////////////////// // Lichtschalter 2 ////////////////////////////////////////////////////////// class Application : public Controller { protected: Button button1; protected: Led ledRed; public: void onStart() { button1.config(portD,bit2); ledRed.config(portB,bit0); } public: void onWork() { if (button1.isPressed()) { ledRed.on(); } else { ledRed.off(); } } } app; //////////////////////////////////////////////////////////
Die ursprünglichen Kommentare wurden in der Realisierung diesmal entfernt. Der Grund dafür ist, dass dieser Code absolut selbsterklärend ist und die Kommentare somit redundant sind.
Kompilieren, linken, brennen und testen Sie das Programm.
Möglichkeiten der Klassen nutzen
Als Nächstes soll angedeutet werden, welche Möglichkeiten hoch entwickelte Klassen dem Anwendungsentwickler bieten. Die Aufgabe besteht darin, eine Mikrocontrolleranwendung zu entwickeln, bei der über nur einen Taster verschiedene Funktionen angewählt werden können. Die durch kurzes Klicken des Tasters ausgewählte Funktion wird als Blinkcode mit einer LED dem Anwender visualisiert. Um den Ausgangszustand wieder herzustellen, soll der Anwender den Taster lange drücken können. Die LED wird in diesem Fall ausgeschaltet.
Für diese Funktionalität wird ein weiteres Merkmal des Framwork benötigt. Es bietet für bestimmte aktive Klassen die Möglichkeit, Ereignisse an die Applikation zu melden. Dafür muss die Applikation einen sogenannten EventHandler bereitstellen. Das ist eine Operation, die von einem Objekt welches ein Ereignis melden möchte aufgerufen werden kann. dabei muss das Objekt sich als Absender der Ereignisnachricht identifizieren und kann zusätzlich Daten über das Ereignis senden. Der Name und die Parameter der Operation für das Melden eines Ereignisses ist festgelegt, damit jeder potenzielle Absender einer Ereignismeldung diese auch erreichen kann. Das nennt man eine Schnittstelle (Interface). Legen Sie ein neues kleines Programm an und laden sie eine Programmvorlage. Ergänzen Sie die folgende Operation:
// EreignisHandler Absender Ereignisdaten public: void onEvent(const Object& sender, uint8 data) { ... }
Zuerst wieder das Konzept als Kommentare notieren.
////////////////////////////////////////////////////////// // Benutzerschnittstelle 1 ENTWURF ////////////////////////////////////////////////////////// class Application : public Controller { // Button1 anlegen // rote LED anlegen public: void onStart() { // Button auf Port D Bit 2 konfigurieren // LED auf Port B Bit 0 konfigurieren } public: void onWork() { // kann weg, ist eh leer } public: void onEvent(const Object& sender, uint8 data) { // wenn der Absender der Button war // dann schau ob das Ereignis ein Klick war, wenn ja // dann nächsten Blinkcode mit der LED anzeigen // wenn aber das Ereignis das Festhalten des Buttens war // dann schalte die LED aus } } app; //////////////////////////////////////////////////////////
Dann erfolgt die Realisierung.
////////////////////////////////////////////////////////// // Benutzerschnittstelle 1 ////////////////////////////////////////////////////////// class Application : public Controller { protected: Button button1; protected: Led ledRed; public: void onStart() { button1.config(portD,bit2); ledRed.config(portB,bit0); } public: void onEvent(const Object& sender, uint8 data) { if (sender == button1) { if (data == Button::Click) { ledRed.nextBlinkCode(); } if (data == Button::HoldStart) { ledRed.off(); } } } } app; //////////////////////////////////////////////////////////
Kompilieren, linken, brennen und testen Sie die Anwendung.
Beim Klicken der Taste 1 wird der Blinkcode der LED als Anzeige einer gewählten Funktion jeweils um eins weiter gestellt. Beim Halten der Taste 1 wird das Zurücksetzen der Funktion durch das Ausschalten der LED visualisiert. Vergleichen Sie die tatsächliche Funktionalität der Anwendung mit dem Quellcode des Programms. Versuchen Sie sich vorzustellen, welchen Aufwand eine Lösung ohne Klassenbibliothek erfordert hätte.