Das einzeln Gelernte zusammen anwenden

In diesem Tutorialabschnitt sollen zum Abschluss noch einmal alle vorgestellten Bausteine in einem Beispiel zusammen angewendet werden. Das Beispiel umfasst somit folgende Elemente:

  • ein Anwendung mit dem PEC-Grundgerüst aufsetzen
  • Einfache Bibliotheksbausteine für digitale Ein- und Ausgaben anwenden
  • Leistungsfähige Bibliotheksbausteine für die Anwendunfsfälle mit Tasten und LEDs nutzen
  • Den UART Bibliotheksbaustein zur Kommunikation mit dem PC verwenden
  • Analogwerte einlesen mit eimen ADC Bibliotheksbaustein
  • Eine LED mit dem PWM Bibliotheksbaustein dimmen
  • Den SystemTick des Application-Frameworks anwenden
  • Für zyklische Aufgaben einen Timerbaustein konfigurieren und anwenden
  • Einen externen Interrupt mit dem entsprechenden Bibliotheksbaustein auswerten

Diese Funktionspunke ergeben bereits eine Anwendung mit mehr Komplexität als die vorangegangenen Beispiele. Das erlernte Programmierkonzept wird uns auch bei der gestiegenen Komplexität zum Erfolg führen.

Die Aufgabe

Das geforderte Anwendungssystem besitzt drei Betriebsmodi (ECO, NORMAL, SPEED) und soll über eine einfache Mensch-Maschine-Schnittstelle verfügen. Diese umfasst zwei Tasten (Funktionsauswahl und Notschalter), eine optische Statusanzeige, eine Systembeleuchtung in Abhängigkeit von der Umgebungshelligkeit, einen Lichtsensor, eine akustische Alarmeinrichtung, und einen USB-Anschluss für das Monitoring des Systems. Die Kommunikation mit dem PC-Terminal soll über eine LED für den Anwender optisch verifizierbar sein. Für die einzelnen Systembausteine lassen sich die Anforderungen wie folgt zusammenfassen:

  • Funktionstaste
    • einschalten, aus 3 Betriebsmodi auswählen, ausschalten
    • Klick, nächsten Betriebsmodus wählen (OFF→ECO→NORMAL→SPEED→ECO→NORMAL→SPEED→…)
    • Halten, System ausschalten (OFF)
  • StatusLED
    • aus (OFF), slow blink (ECO) , Blinkcode 3 (NORMAL), flicker (SPEED)
  • Notschalter und Speaker
    • bei Betätigung sofort Alarm auslösen (Interrupt fallende Flanke)
    • Speaker Signalton 1500 Hz (Timer)
    • nach 2 Sekunden Alarmton abschalten
  • Lichtsensor und BackLight
    • umso dunkler das Umgebungslicht desto dunkler die Systembeleuchtung (Blenden vermeiden)
  • UART Systemstatus zusammengefasst senden
    • im ECO-Mode nur 10 mal pro Sekunde
    • im NORMAL-Mode 20 mal pro Sekunde
    • im SPEED-Mode 50 mal pro Sekunde

Wenn Sie noch ein Klassendiagramm geöffnet haben wählen Sie im Kontextmenü (rechte Maustaste) des Diagramms den Menüpunkt „nach oben“. Falls das Projekt nicht mehr geöffnet ist, öffenen sie das SiSy UML-Projekt wieder. Führen Sie folgende Vorbereitungsarbeiten durch:

  • neues Klassendiagramm anlegen
  • Zielsprache ARM C++
  • Zielplattform STM32F042 mySTM32 Board light HAL
  • Diagrammvorlage Application Grundgerüst für PEC Anwendungen (XMC, STM32, AVR) laden
  • Treiberpaket für STM32F0 zuweisen
  • optional Template stm32F042_48Mhz zuweisem

Zunächst sind für unseren objektorientierten Programmieransatz die benötigten Systembausteine (Objekte) zu identifiziereen. Wie gehabt abstrahieren wir die Bausteine als Klassen. Die konkrete Instanzstruktur (Systemarchitektur) legen wir im Klassendiagramm graphisch fest.

Wir können alle benötigten Bausteine bereits anlegen und die Architektur der Anwendung entwerfen. Für die Realisierung gehen wir dann Schritt für Schritt vor. Wir realisieren in jedem Schritt immer nur einen teilaspekt des Systems und testen diesen. Mit etwas Erfahrung ist es dann auch möglich das System von Anfang an in einzeln zu realisierende Komponenten aufzuteilen.

Aus dem PEC-Framework nutzen wir die Bibliotheksbausteine: PecPinInput, PecPinOutput, PecPinInterrupt, PecLed, PecButton, PecAdcChannel, PecPwmChannel und PecUart. Als einfacher Entwurf könnte die Lösung mit folgender Architektur entwickelt werden.

MERKE: Komplexe Systeme = Schritt für Schritt realisieren = itterative Vorgehensweise

Die Realisierung sollte die im obigen Grobentwurf beschriebenen Elemente beinhalten. Da die zu realisierende Löaung etwas komplexer ist, soll der Entwurf in mehreren kleineren Schritten realisiert werden. Die folgende Darstellung zeigt das angestrebte Endergebnis.

Für die schrittweise Realisierung des angestrebten Klassenmodells strukturieren wir das Projekt in möglichst zusammenhängende Komponenten.

  1. Funktionstaste und StatusLED
  2. Notschalter und Speaker
  3. Lichtsensor und Systembeleuchtung
  4. UART Protokoll

Über die Funktionstaste soll das System ein- und ausgeschaltent sowie aus 3 Betriebsmodi ausgewählt werden. Dafür nutzen wir den Bibbliotheksbaustein PecButtonClickAndHold. Das Klickereignis schaltet das System ein und in den nächsten Betriebsmodus (OFF→ECO→NORMAL→SPEED→ECO→NORMAL→SPEED→…). Das Halten der Taste schaltet das System aus (OFF). Den aktuellen Systemzustand bilden wir in einem öffentlichen Attribut des Controllers ab. Ergänzen Sie das Grundgerüst zu folgendem Klassenmodell:

Das geforderte Systemverhalten realisieren wir in den Operatuionen onClick und onHoldStart der Klasse FunktionKey.

FunktionKey::onClick():void
// 0 = off 		- StatusLED off
// 1 = eco 		- StatusLED slow Blink
// 2 = normal 		- StausLED blink 3
// 3 = full speed	- statusLED flicker
app.mode++;
if (app.mode>3)	app.mode=1;
// StausLED aktualisieren
if (app.mode==1) app.statusLED.slowBlink();
if (app.mode==2) app.statusLED.blink(3);
if (app.mode==3) app.statusLED.flicker();

FunktionKey::onHoldStart():void
app.statusLED.flash();		// signal für user
app.mode=0;			// standBy

Jetzt erstellen und testen

Übersetzen Sie das Programm. Korrigieren Sie ggf. Schreibfehler. Übertragen Sie das lauffähige Programm in den Programmspeicher des Controllers.

  1. Erstellen (Kompilieren und Linken)
  2. Brennen
  3. verbinden Sie Pin B1 mit der gelbe LED und die Taste mit Pin A0
  4. testen Sie die geforderte Funktionalität.

Notschalter und Speaker bilden die nächste funktionelle Einheit des Systems. Bei Betätigung des Notschalters ist sofort Alarm auszulösen (Interrupt fallende Flanke). Der Speaker erzeugt für zwei Sekunden einen Signalton mit 3000 Hz (Timer). Spätestens nach 2 Sekunden ist der Alarmton abzuschalten. Wird während des Alarms ein weiterer ausgelöst verlängert sich die Alarmzeit um jeweis zwei Sekunden. Dafür benötigen wir einen Zähler als Attribut der Klasse Controller. Ergänzen Sie das Klassenmodell wie folgt:

Im Pin-Interrupt aktivieren wir den Tongenerator (Speaker/Timer) und starten den Alarm-Zeit-Zähler. Um einen 1500 Hz Ton durch Pin-Toggeln zu erzeugen müssen wir den Timer auf 3000 Zyklen pro Sekunde initialisieren.

AlarmButton::onPinInterrupt():void
if (app.mode>0)				// nur wenn das System aktiv ist
{
	app.alarmCounter+=2; 		// 2 Sekunden Alarm hinzufügen
	app.speaker.configHz(3000); 	// Speaker ON 2x1500=3000
}

Im Timer-Interrupt erzeugen wir den Ton durch Umschalten (toggeln) des Speaker-Pins.

Speaker::onTimer():void
// den Alarmton generieren
toggle();

Die App zählt den Alarm-Zeit-Zähler einmal pro Sekunde runter und schaltet nach Ablauf der Zeit den Alarmton aus.

Controller::onEvent1s():void
if (alarmCounter>0)		// wenn Alarm dann
{
	alarmCounter--;		// Alarmzeit runter zählen
	if (alarmCounter==0)	// wenn Alarmzeit vorbei
 	{
		speaker.stop();	// Alarm aus
	}
}

Jetzt erstellen und testen

Übersetzen Sie das Programm. Korrigieren Sie ggf. Schreibfehler. Übertragen Sie das lauffähige Programm in den Programmspeicher des Controllers.

  1. Erstellen (Kompilieren und Linken)
  2. Brennen
  3. verbinden Sie Pin B4 mit dem Speaker und die Taste 2 mit Pin A1
  4. testen Sie die geforderte Funktionalität

Lichtsensor und Systembeleuchtung (BackLight) bilden die nächste funktionelle Einheit. Sie sollen eine ausreichende Beleuchtung des Systems gewährleiten und gleichzeitig vermeiden, dass der Anwender geblendet wird wenn zum Beispiel das Umfeld des Systems sehr dunkel ist.

Die Initialisierung des PWM Signals können wir in der Startsequenz onStart der Applikationsklasse Controller durchführen.

Controller::onStart():void
// boot sequence after start SysTick
backlight.configHz(1000); // PWM Frequenz festlegen

Die Steuerung der Systembeleuchtung realisieren wir einfach als kontinuierliche Aufgabe in der Operation onWork der Applikationsklasse Controller (mainloop).

Controller::onWork():void
// Hintergrundbeleuchtung an Umgebungslicht anpassen
if (app.mode>0)
{
	valueAL=ambientLightSensor.getValue();
	if (valueAL>1000) 
		valueBL=0;
	else
		valueBL=1000-valueAL;
	backlight.setDuty(valueBL-1);
}
else
	backlight.setDuty(0);	// standBy

Jetzt erstellen und testen

Übersetzen Sie das Programm. Korrigieren Sie ggf. Schreibfehler. Übertragen Sie das lauffähige Programm in den Programmspeicher des Controllers.

  1. Erstellen (Kompilieren und Linken)
  2. Brennen
  3. verbinden Sie Pin A7 mit dem Lichtsensor oder dem Potentiometer und die grüne LED mit Pin B0
  4. testen Sie die geforderte Funktionalität

Im öletzten Realisierungsschritt soll der Systemstatus zusammengefasst per UART gesendet werden. Dabei sollen auch die verschiedenen Betriebsmodi angedeutet werden in dem die Update-Rate der Systemgeschwindigkeit folgt.

  • im ECO-Mode nur 10 mal pro Sekunde
  • im NORMAL-Mode 20 mal pro Sekunde
  • im SPEED-Mode 50 mal pro Sekunde

Für die Realisierung dieser unterschiedlichen Update-Raten benötigen wir ein Attribut nextCycle in der Applikationsklasse Controller. Ergänzen Sie das Klassenmodell wie folgt:

In der Operation onWork der Applikationsklasse Controller muss folgender Code hinzugefügt werden.

Controller::onWork():void
// ...
if (mode>0 && nextCycle==0)
{
	// jetzt Systemstatus als Text formatieren und senden
	String statusText="\nSystemstaus: ";
	statusText.formatAdd("mode=%d ",mode);
	statusText.formatAdd("alarm=%d ",alarmCounter);
	statusText.formatAdd("AL=%d ",valueAL);
	statusText.formatAdd("BL=%d ",valueBL);
	terminal.writeString(statusText);
	trafficLED.flash();
	// arbeitsgeschwindigkeit
	if (app.mode==1) nextCycle=100; // 1 = eco   - langsam
	if (app.mode==2) nextCycle=50;  // 2 = normal - mittel
	if (app.mode==3) nextCycle=20;  // 3 = speed - schnell
}

Der Zykluszähler wird im SysTick-Timer runtergezählt.

Controller::onTimer10ms():void
// Zykluszähler runterzählen
if (nextCycle>0) nextCycle--;

Jetzt erstellen und testen

Übersetzen Sie das Programm. Korrigieren Sie ggf. Schreibfehler. Übertragen Sie das lauffähige Programm in den Programmspeicher des Controllers.

  1. Erstellen (Kompilieren und Linken)
  2. Brennen
  3. verbinden Sie Pin B3 mit der roten LED
  4. testen Sie die geforderte Funktionalität

Videozusammenfassung

Erlernte und gefestigte Arbeitsschritte:

  1. Klassendiagramm anlegen und öffnen
  2. Diagrammvorlage für PEC Applikation auswählen, laden und Treiberpaket für STM32F0 einfügen
  3. im Explorer PEC-Bausteine aus der Bibliothek suchen
  4. gewünschte Bibliotheksbausteine und ins Diagramm ziehen
  5. Klassen verbinden (Aggregation, Realisierung)
  6. den nötigen Quellcode in den Operationen erstellen
  7. Erstellen und Brennen einer STM32 Applikation im Klassendiagramm

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

oder die schnelle Version ohne Sprachkommentare

Übung 13

Erweitern Sie zur Übung die Anwendung um die Funktionalität das System per UART fernsteuern zu können. Das Protokoll soll folgende Kommandos umfassen:

  • E, Betriebsmodus ECO
  • N, Betriebsmodus NORMAL
  • S, Betriebsmodus SPEED
  • O, System ausschalten OFF
  • A, Alarm

Weiter mit:

Suchbegriffe