Die Templates für Button und LED anwenden

Bei unserer ersten PEC-Übung bauten wir die Blinky-Beispiele mit den Templates PecPinOutput welches wir für die Realisierung der LED nutzen und PecPinInput für die Realisierung des Tasters. Das reichte für die gestellte Anforderung auch völlig aus. Erweitern wir die Anforderungen werden die Möglichkeiten dieser beiden Templates schnell erreicht. Die scheinbar einfache Anforderung, dass der Taster zum Beispiel einen kurzen Click von längerem Halten unterscheiden können soll, verlässt den Bereich der trivialen Programmierung. Wenn jetzt noch die Anforderung besteht, dass die Mainloop (onWork) möglichst unbelastet bleiben soll damit dort weitere Verarbeitungsaufgaben ausgeführt werden können wird es selbst für manche erfahrene Programmierer diffizil.

Bevor wir beginnen benötigen wir ein neues Klassendiagramm. Dazu müssen Sie zurück in die oberste Ebene gehen (rechte Maustaste / nach oben oder einfach Taste ESC). Dort legen Sie ein neues Klassendiagramm an. Zur Erinnerung:

Zunächst realisieren wir das Blinky-Beispiel mit einem höher entwickeltem Template, der PecLed. Diese umfasst bereits typische Anwendungsfälle einer LED über das simple on und off hinaus. Wir rekapitulieren die bereits getroffenen Annahmen:

  • 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
  • die LED soll blinken

Statt des Low-Level-Templates PecPinOutput schauen wir uns ein etwas höher entwickeltes Template an: Das Template PecLed. Im Folgenden ein Ausschnitt aus dem Klassenmodell des PEC-Framework:

Dieses Template verfügt offenbar über spannende Eigenschaften. Zum einen ist es eine Ableitung von dem bereits kurz besprochenen PecAppModul. Das bedeutet, dass diese Klasse aktiv ist, sozusagen ein eigener Thread. Neben den öffentlichen Operationen on, off und toggle finden wir unter anderem die Operationen flash, blink und nextBlinkCode. Offensichtlich kann diese LED von sich aus schon mal aufblitzen und blinken ohne dass der Entwickler mit Wartezyklen hantieren oder sich eine anderweitige eigene Timingstrategie ausdenken muss. Es ist bereits an der Signatur des Templates zu erkennen, dass hier der System-Timer (10 Millisekunden SysTick) genutzt wird. Also verwenden wir doch diesmal dieses komfortable LED-Template ;-)

Die Vorgehensweise entspricht dem bisher besprochenen:

  1. eine eigene Klasse RoteLED anlegen
  2. die Klasse RoteLED in der Klasse Controller aggregieren
  3. das Template pecLed an die Klasse RoteLED binden
  4. das Template pinB0 an die Klasse RoteLED binden

Die so vorbereitete Systemstruktur muss jetzt nur noch mit dem gewünschten Verhalten ergänzt werden. Es ist denkbar einfach. Wir senden der roten LED einfach die Nachricht, dass sie doch bitte blinken möge.

Controller::onStart
  roteLED.blink();

Wenn wir die Zeile richtig eingegeben und das Modell korrekt erstellt haben können wir aus dem Klassendiagramm wie gehabt 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. Verbinden Sie die rote LED mit Pin B.0, nutzen Sie Patchkabel. Nach erfolgtem Brennvorgang blinkt die rote LED.

Das Beispiel um die Taste erweitern

Die neue LED ist offensichtlich doch recht sexy. Schauen wir uns für die Taste ebenfalls ein etwas höher entwickeltes Template an. Den PecButtonClickAndHold. Die folgende Darstellung zeigt wiederum einen Ausschnitt aus dem Klassenmodell des PEC-Framework. Es ist ein vereinfachter Ausschnitt und eine Zusammenfassung.

Wie schon beim Template PecLED fällt die Ableitung vom PecAppModul auf. Desweiteren hat das neue Template offensichtlich alle Eigenschaften des von uns bereits benutzen PecPinInput. Es ist also voll kompatibel mit der bisherigen Lösung unseres Tastenbeispiels. Gehen Sie wie bereits erlernt vor:

  1. eine Klasse Taste anlegen
  2. die Klasse Taste in der Klasse Controller agreggieren
  3. die Templates PecButtonClickAndHold, pinD2 und pinPullUp an die Klasse Taste binden

Die spannensten Aspekte dieses Templates sind die Event Handler onClick und onHoldxx. Doch diese sollen erst im nächsten Erweiterungsschritt besprochen werden. Zunächst bemühen wir uns um eine Lösung die in etwa der bisherigen entspricht. Ich schlage mal folgenden Code vor:

Controller::onWork
  if (taste.isPressed())
  {
     // nur wenn die LED noch nicht blink Nachricht senden
     if (roteLED.getBlinkCode()==0)
         roteLED.blink();
  }
  else
  {
     roteLED.off();
  }
 

Beachten Sie, dass es zielführend ist den bisherigen Code in onStart zu deaktivieren. Kommentieren Sie den Code einfach aus.

Controller::onStart
//  roteLED.blink();

Vergleichen wir diesen Lösungsvorschlag mit dem der einfachen IN/OUT Variante fällt zunächst auf, dass hier das waitMs fehlt. Dafür ist eine Bedingung mehr enthalten. Es lässt sich jetzt bestimmt streiten was mehr Schreibaufwand für den Entwickler bedeutet. Aber eines lässt sich nicht leugnen. Es wird nicht sinnlos Prozessorzeit in Form einer Warteschleife verbraten. Eine 100 Millisekunden Warteschleife bedeuten bei schlappen 3,6864 MHz in Worten Dreihundertachtundsechzigtausend Takte sinnlose NOPs. Testen Sie diese Lösung.

Haben Sie das Modell und den Quellcode korrekt erstellt sollte das System nach dem Bilden und Übertragen wie gewünscht funktionieren. Verbinden Sie die rote LED mit PIN B.0 und die Taste mit Pin D.2. Die LED blinkt nur auf, wenn die Taste gedrückt ist.

Die Möglichkeiten des Templates PecButtonClickAndHold nutzen

Im nächsten Schritt wollen wir schauen wie viel Arbeit uns eine hoch entwickelte Klasse bzw. ein hochentwickeltes Template abnehmen kann. Wir stellen uns folgende Aufgabe:

  • wenn der Taster nur kurz gedrückt also geklickt wurde, soll der Blink-Code der roten LED um eins erhöht werden
  • wenn der Taster jedoch lange gedrückt also gehalten wird, soll die Zweitbelegung der Tastenfunktion die LED komplett ausschalten

Das ist eigentlich eine recht knifflig zu programmierende Benutzerinteraktion. Schauen wir uns an wie das mit dem PEC-Template zu realisieren ist.

  • ziehen Sie ein Operation aus der Objektbibliothek auf die Klasse Taste

Im Folgenden wird Ihnen das UML-Tool SiSy einen Folge von Dialogen anbieten bei der Sie aufgefordert werden Operationen der Basisklassen zu überschreiben. Das ist genau der Punkt an dem Sie sich in das Ereignissystem des Framworks „reinhängen“. Indem Sie eine geeignete Operation überschreiben weisen Sie das System an, dass beim Eintreten des entsprechenden Ereignisses Ihr spezifischer, individueller Code ausgeführt wird. Überschreiben Sie die Operationen onClick und onHoldStart der Klasse Taste.

Wenn Sie die entsprechenden Operationen überschrieben haben sollte Ihr Klassenmodell wie folgt aussehen. Beachten Sie die Signatur der Klasse Taste.

Die bisherige Lösung muss jetzt erst mal weg. Markieren Sie den Inhalt der Operation onWork und kommentieren Sie diesen aus. Benutzen Sie dazu die Tastenkombination Strg+K.

Controller::onWork
//  if (taste.isPressed())
//  {
//     // nur wenn die LED noch nicht blink Nachricht senden
//     if (roteLED.getBlinkCode()==0)
//         roteLED.blink();
//  }
//  else
//  {
//     roteLED.off();
//  }
//  

Ergänzen Sie den Code der überschriebenen Event Handler wie folgt:

Taster::onClick
   app.roteLED.nextBlinkCode();
Taster::onHoldStart
   app.roteLED.off();

Testen Sie diese Lösung.

Nur für das Protokoll. Die jetzt vorliegende Funktionalität wurde zu 99% vom Systemdesigner in Ihnen grafisch, mit der UML, über die Systemarchitektur gelöst. Der Programmierer in Ihnen musste 2, in Worten zwei Zeilen programmieren. Wer bis hier immer noch der Meinung ist, Mikrocontrollerprogrammierung macht nur Spaß wenn man hunderte oder besser tausende Zeilen in einen Zeileneditor hackt, sollte wohl jetzt besser die Reißleine ziehen.

Videozusammenfassung

Und hier diesen Abschnitt als kurze Videozusammenfassung.

Nächstes Thema

button_und_led.txt · Zuletzt geändert: 2017/03/17 11:53 von huwaldt