Unterschiede

Hier werden die Unterschiede zwischen zwei Versionen angezeigt.

Link zu dieser Vergleichsansicht

Beide Seiten der vorigen Revision Vorhergehende Überarbeitung
Nächste Überarbeitung
Vorhergehende Überarbeitung
light_all_in_one [2020/01/14 13:46]
huwi [Weiter mit:]
light_all_in_one [2020/07/07 14:18] (aktuell)
huwi [Übung]
Zeile 1: Zeile 1:
 +====== Das einzeln Gelernte zusammen anwenden ======
 +{{tag>UART USART ADC ANALOG INT INTERRUPT BUTTON TASTE LED PWM SYSTICK}}
 +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
  
-{{:stm32light:stm32bl7.png?direct&600|}}+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.
  
 +{{ :stm32light:allinone.png?nolink&600|}}
 +====== 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
 +
 +===== Vorbereitung =====
 +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
 +
 +{{:neueskldhallo.jpg?direct&290|}}{{:pecapplication.jpg?direct&250|}}{{:stm32light:stml001.png?direct&450|}} 
 +
 +===== Lösungsansatz =====
 +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.
 +
 +{{:uml:taste.jpg?nolink&70|}} {{:uml:taste.jpg?nolink&70|}} {{:uml:sensor.png?nolink&150|}}  {{:uml:smd32pin.jpg?nolink&100|}} {{:LEDgruen.jpg?nolink&110|}} {{:LEDgelb.jpg?nolink&110|}}{{:LEDrot.jpg?nolink&110|}} {{::smdspeaker.jpg?nolink&100|}} {{::laptopuart.png?nolink&150|}}
 + 
 +{{:uml:classfunktionkey.png?nolink&120|}} {{:uml:classalarmbutton.png?nolink&105|}} {{:uml:classambilight.png?nolink&145|}} {{:uml:klassecontroller.jpg?nolink&110|}}  {{:uml:classstatusled.png?nolink&100|}} {{:uml:classbacklight.png?nolink&110|}}
 +{{:uml:classtrafficled.png?nolink&110|}} {{:uml:classspk.png?nolink&110|}} 
 +{{:uml:classterminal.png?nolink&110|}}
 +
 +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.
 +
 +{{:stm32light:grobkdallinone.png?direct&1100|}}
 +
 +**__MERKE:__ Komplexe Systeme = Schritt für Schritt realisieren = itterative Vorgehensweise**
 +
 +===== Realisierung =====
 +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.
 +
 +{{:stm32light:feinkdallinone.png?direct&1100|}}
 +
 +Für die schrittweise Realisierung des angestrebten Klassenmodells strukturieren wir das Projekt in möglichst zusammenhängende Komponenten.
 +  - Funktionstaste und StatusLED
 +  - Notschalter und Speaker
 +  - Lichtsensor und Systembeleuchtung
 +  - UART Protokoll
 +
 +==== Erster Realisierungsschritt ====
 +
 +Ü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:
 +
 +{{:stm32light:aio_step1.png?direct&1000|}}
 +
 +Das geforderte Systemverhalten realisieren wir in den Operatuionen **onClick** und **onHoldStart** der Klasse **FunktionKey**.
 +{{ :stm32light:aio_sd11.png?direct&350|}}
 +>FunktionKey::onClick():void<code c>
 +// 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();
 +</code>
 +{{ :stm32light:aio_sd12.png?direct&350|}}
 +>FunktionKey::onHoldStart():void<code c>
 +app.statusLED.flash(); // signal für user
 +app.mode=0; // standBy
 +</code>
 +
 +=== Jetzt erstellen und testen ===
 +Übersetzen Sie das Programm. Korrigieren Sie ggf. Schreibfehler. Übertragen Sie das lauffähige Programm in den Programmspeicher des Controllers.
 +  - Erstellen (Kompilieren und Linken)
 +  - Brennen
 +  - verbinden Sie Pin B1 mit der gelbe LED und die Taste mit Pin A0
 +  - testen Sie die geforderte Funktionalität.
 +
 +{{:erstellenbrennen.png?350|}}{{:stm32light:flashlight.png?direct&300|}}{{:stm32light:stm32bl7.png?direct&300|}}
 +
 +
 +==== Zweiter Realisierungsschritt ====
 +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:
 +
 +{{:stm32light:aio_step2.png?direct&1000|}}
 +
 +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.
 +
 +{{ :stm32light:aio_sd21.png?direct&350|}}
 +>AlarmButton::onPinInterrupt():void<code c>
 +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
 +}
 +</code>
 +
 +Im Timer-Interrupt erzeugen wir den Ton durch Umschalten (toggeln) des Speaker-Pins.
 +
 +{{ :stm32light:aio_sd22.png?direct&120|}}{{ ::space.png?nolink|}}{{ ::space.png?nolink|}}{{ ::space.png?nolink|}}
 +>Speaker::onTimer():void<code c>
 +// den Alarmton generieren
 +toggle();
 +</code>
 +
 +Die App zählt den Alarm-Zeit-Zähler einmal pro Sekunde runter und schaltet nach Ablauf der Zeit den Alarmton aus.
 +
 +{{ ::stm32light:aio_sd23.png?direct&260|}}{{ ::space.png?nolink|}}
 +>Controller::onEvent1s():void<code c>
 +if (alarmCounter>0) // wenn Alarm dann
 +{
 + alarmCounter--; // Alarmzeit runter zählen
 + if (alarmCounter==0) // wenn Alarmzeit vorbei
 +  {
 + speaker.stop(); // Alarm aus
 + }
 +}
 +</code>
 +
 +=== Jetzt erstellen und testen ===
 +Übersetzen Sie das Programm. Korrigieren Sie ggf. Schreibfehler. Übertragen Sie das lauffähige Programm in den Programmspeicher des Controllers.
 +  - Erstellen (Kompilieren und Linken)
 +  - Brennen
 +  - verbinden Sie Pin B4 mit dem Speaker und die Taste 2 mit Pin A1
 +  - testen Sie die geforderte Funktionalität
 +
 +{{:erstellenbrennen.png?350|}}{{:stm32light:flashlight.png?direct&300|}}{{:stm32light:stm32bl7.png?direct&300|}}
 +
 +
 +==== Dritter Realisierungsschritt ====
 +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. 
 +
 +{{:stm32light:aio_step3.png?direct&1100|}}
 +
 +Die Initialisierung des PWM Signals können wir in der Startsequenz **onStart** der Applikationsklasse **Controller** durchführen.
 +
 +{{ :stm32light:aio_sd30.png?direct&250|}}{{ ::space.png?nolink|}}{{ ::space.png?nolink|}}{{ ::space.png?nolink|}}
 +>Controller::onStart():void<code c>
 +// boot sequence after start SysTick
 +backlight.configHz(1000); // PWM Frequenz festlegen
 +</code>
 +
 +Die Steuerung der Systembeleuchtung realisieren wir einfach als kontinuierliche Aufgabe in der Operation **onWork** der Applikationsklasse Controller (mainloop).
 +
 +>Controller::onWork():void{{ :stm32light:aio_sd31.png?direct&400|}}<code c>
 +// Hintergrundbeleuchtung an Umgebungslicht anpassen
 +if (app.mode>0)
 +{
 + valueAL=ambientLightSensor.getValue();
 + if (valueAL>1000) valueBL=0;
 + else   valueBL=1000-valueAL;
 + setDuty(valueBL);
 +}
 +else
 + setDuty(0); // standBy
 +</code>
 +
 +=== Jetzt erstellen und testen ===
 +Übersetzen Sie das Programm. Korrigieren Sie ggf. Schreibfehler. Übertragen Sie das lauffähige Programm in den Programmspeicher des Controllers.
 +  - Erstellen (Kompilieren und Linken)
 +  - Brennen
 +  - verbinden Sie Pin A7 mit dem Lichtsensor oder dem Potentiometer und die grüne LED mit Pin B0
 +  - testen Sie die geforderte Funktionalität
 +
 +{{:erstellenbrennen.png?350|}}{{:stm32light:flashlight.png?direct&300|}}{{:stm32light:stm32bl7.png?direct&300|}}
 +
 +
 +==== Vierter Realisierungsschritt ====
 +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:
 +
 +{{:stm32light:aio_step4.png?direct&1100|}}
 +
 +
 +In der Operation **onWork** der Applikationsklasse **Controller** muss folgender Code hinzugefügt werden.
 +
 +{{ :stm32light:aio_sd41.png?direct&400|}}
 +>Controller::onWork():void<code c>
 +// ...
 +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
 +}
 +</code>
 +{{ :stm32light:aio_sd42.png?direct&150|}}{{ ::space.png?nolink|}}{{ ::space.png?nolink|}}{{ ::space.png?nolink|}}{{ ::space.png?nolink|}}
 +Der Zykluszähler wird im SysTick-Timer runtergezählt. 
 +
 +>Controller::onTimer10ms():void<code c>
 +// Zykluszähler runterzählen
 +if (nextCycle>0) nextCycle--;
 +</code>
 +
 +
 +=== Jetzt erstellen und testen ===
 +Übersetzen Sie das Programm. Korrigieren Sie ggf. Schreibfehler. Übertragen Sie das lauffähige Programm in den Programmspeicher des Controllers.
 +  - Erstellen (Kompilieren und Linken)
 +  - Brennen
 +  - verbinden Sie Pin B3 mit der roten LED 
 +  - testen Sie die geforderte Funktionalität
 +
 +{{:erstellenbrennen.png?350|}}{{:stm32light:flashlight.png?direct&300|}}{{:stm32light:stm32bl7.png?direct&300|}}
 +
 +
 +====== Videozusammenfassung ======
 +{{tag>Video}}
 +Erlernte und gefestigte Arbeitsschritte:
 +  - //Klassendiagramm// anlegen und öffnen
 +  - Diagrammvorlage für //PEC Applikation// auswählen, laden und Treiberpaket für STM32F0 einfügen
 +  - im Explorer //PEC-Bausteine// aus der Bibliothek suchen
 +  - gewünschte Bibliotheksbausteine und ins Diagramm ziehen
 +  - Klassen verbinden (Aggregation, Realisierung)
 +  - den nötigen //Quellcode// in den Operationen erstellen
 +  - //Erstellen und Brennen// einer STM32 Applikation im Klassendiagramm
 + 
 +Und weil es so schön war hier das Ganze noch mal als Video.
 +
 +<html><iframe width="1028" height="580" src="https://www.youtube.com/embed/5ycM45-3mus" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe></html>
 +
 +[[https://youtu.be/dWX6T9_8TV4|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: ====== ====== Weiter mit: ======
   * [[ein kleines Projekt mit dem mySTM32 light]] <sub>(erfordert eine SiSy Lizenz ab Version 3.7x)</sub>   * [[ein kleines Projekt mit dem mySTM32 light]] <sub>(erfordert eine SiSy Lizenz ab Version 3.7x)</sub>
   * [[mystm32_board_light_tutorial|zurück zur Übersicht]]   * [[mystm32_board_light_tutorial|zurück zur Übersicht]]
 +
 +====== Suchbegriffe ======