Inhaltsverzeichnis

Einen LED auf dem MM32 light Board dimmen

Puls-Weiten-Modulation PWM ist eine wichtige Technik zum Erzeugen von Pseudo-Analogwerten. Es ist mit verhältnismäßig geringem Aufwand, zum Beispiel mit einem RC-Glied, auch möglich aus diesem Signal echte Analogwerte zu erzeugen. Meist ist das jedoch gar nicht notwendig, wie wir an diesem Beispiel im wahrsten Sinne der Wortes sehen werden. Eigentlich müsste man sagen nicht sehen werden. Unser Auge wird nicht die einzelnen Impulse wahrnehmen aus denen das PWM-Signal besteht. Anwendung findet PWM nicht nur beim Ansteuern von LEDs sondern auch bei einfache Gleichstrommotoren, Schrittmotoren, Servomotoren, Wechselrichtern, Elektroheizungen, Magnetventilen, usw.. Die Liste der möglichen Anwendungsfälle ist recht lang. Deshalb haben auch alle modernen Mikrocontroller die Möglichkeit PWM-Signale mit Hardwarebausteinen generieren zu lassen. Prädestiniert für diese Aufgabe sind Timer.

Die Aufgabe

Es ist eine Mikrocontrolleranwendung zu entwickeln, bei der eine LED für das menschliche Auge sanft auf und abblendet.

Anforderungen:

Vorbereitung

Führen Sie folgende Vorbereitungsarbeiten durch:

Lösungsansatz

Die Aufgabe besteht darin eine LED für das menschliche Auge sanft Auf- und Abzublenden. Dazu soll ein entsprechendes PWM-Signal generiert werden. PWM ist kein analoges sondern ein digitales Signal in Form einer schnelle Folge von Impulsen mit unterschiedlicher Breiten. Jeder Impuls entspricht immer der vollen verfügbare Spannung in unserem Fall 3,3V die Pausen zwischen den Impulsen sind entsprechend 0V. Das Verhältnis zwischen High und Low ergibt die gewünschte Effektivspannung.

In faktisch allen modernen Mikrocontrollern haben Timer die Fähigkeit ein oder mehrere PWM-Signale zu erzeugen. Dazu müssen die Entwickler der Hardware und Software sich über die möglichen Timer, PWM-Kanäle und Pinbelegungen im Datenblatt informieren. Hardware-PWM ist nicht an jedem beliebigen Pin möglich. Wir können dazu die myMM32 light Referenzkarte nutzen.

Für das Pin B0 ergibt sich die Möglichkeit TIMER 3 Channel 3 zu nutzen. Im PEC Framework steht uns der Bibliotheksbaustein PecPwmChannel zur Verfügung. Dieser Baustein hat alle nötigen Merkmale um unsere LED zu dimmen.

Damit ergibt sich folgender Grobentwurf.

Die konkrete Hardwareanbindung Timer3, Channel3, PinB0 muss in der Realisierung erfolgen.

MERKE: PWM = Timer + Channel + Pin

Realisierung

Die Realisierung sollte die im obigen Entwurf beschriebenen Elemente beinhalten. Zusätzlich muss die konkrete Hardwareanbindung für Timer3, Channel3 und PinB0 erfolgen. Dazu suchen wir die entsprechenden Elemente im Explorer, ziehen diese per Drag&Drop ins Diagramm und verbinden sie mit der Led-Klasse Pwm. Für das langsame also sanfte Auf- und Abblenden benötigen wir eine Variable als Zähler. Diese legen wir als Attribut mit dem namen duty der Klasse Controller an. Da der Bibliotheksbaustein das PWM-Signal von 0 bis 1000 ansteuert benötigen wir mindestens einen 16 Bit Wert. Orientieren Sie sich an der folgenden Darstellung bei der Realisierung ihres Entwurfes:

In diesem Beispiel muss der Timer mit der gewünschten PWM Frequenz initialisiert und gestartet werden. Die PWM Frequenz sollte für das Auge nicht unter 60 Hz liegen, für das Ohr nicht unter 200 Hz (brummen von Endstufen bei echten Anwendungen) sollte aber auch nicht zu schell sein. Zu hohe Frequenzen können je nach Leitungslänge und angesteuertem Baustein zu ungewollte Effekte führen. Wir sollten also vermeiden zu weit in den Kilohertzbereich zu gehen. Ergänzen Sie den folgenden Code in der Operation onStart() der Klasse Controller.

Controller::onStart():void
// boot sequence after start SysTick
// Initialisierung PWM Channel
// startet Timer mit gewünschter PWM Frequenz
pwm.configHz(1000);

Als erstes entwickeln wir eine einfache Lösung um das PWM Signal verhältnismäßig langsam ansteigen zu lassen. Dafür benutzen wir die Zählervariable duty. Die Operation setDuty(duty) des Bibnliotheksbausteins PecPwmChannel erwartet Werte von 0 = LED aus bis 1000 LED maximale Helligkleit. Damit darf der Zähler entsprechend von 0 bis 1000 laufen. Mit einer kleinen Pause sorgen wir dafür, dass der Vorgang des langsamen Aufblendens auch wirklich langsam genug ist für das Auge. Notieren Sie den folgenden Code in der Operation onWork() der Klasse Controller.

Controller::onWork():void
duty++;
if (duty>=1000)
{
    duty=0;
}
pwm.setDuty(duty);
waitMs(1);

Test

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

  1. Rote LED mit Pin B0 verbinden
  2. Anwendung erstellen (Kompilieren und Linken)
  3. Anwendung übertragen (Brennen)
  4. Anwendung testen

Lösungsvarianten

Die erste einfache Lösung hat folgenden Signalverlauf erzeugt:

Man kann mit diesem Signal schon recht gut das Aufblenden der LED erkennen aber wirklich schön ist es nicht. Die nächste Lösung soll auch das langsame Abblenden der LED verwirklichen. Dazu müssen wir den folgenden Signalverlauf erzeugen:

Der Zähler muss also so angewendet werden, dass nach dem steigenden auch der fallende Signalverlauf folgt.
Ändern Sie den Code der Operation onWork() der Klasse Controller wie folgt:

Controller::onWork():void
duty++;
if (duty<1000) {
    pwm.setDuty(duty);
}
else if (duty<2000) {
    pwm.setDuty(2000-duty);
}
else {
    duty=0;
}
waitMs(1);

Erstellen, übertragen und testen Sie diese Anwendungsvariante.
Man kann jetzt deutlich das Auf- und Abblenden der LED erkennen.

Aber auch dieser Signalverlauf erscheint unserem Auge noch nicht wirklich angenehm. Das liegt daran, dass wir die Helligkeit nicht linear wahrnehmen. Das Auge nimmt kleine Änderungen der Helligkeit im unteren Bereich recht gut wahr. Ab spätestens 50% können wir kaum noch die Änderung der Helligkeit erkennen. Eine Lösung ist es den Signalverlauf nicht linear sondern exponentiell zu gestalten. Das könnte zum Beispiel so aussehen:

Mit der Formel POTENZ(X,Y) kann man in Excel den gewünschten Signalverlauf in 1000 Schritten gut experimentell ermitteln. Man kommt in etwa zu dem Ergebnis POTENZ(1,00693;Step). Die entsprechende C/C++ Funktion ist pow(x,y) und findet sich in der #include „math.h“. Dazu muss ein entsprechender Eintrag in der Klasse Controller vorgenommen werden. Selektieren Sie die Klasse Controller und wählen im Kontextmenü (rechte Maustaste) den Menüpunkt Definieren…. Im Dialog Deklarationen/Implementation ergänzen sie bitte folgende Zeile:

Jetzt können wir die Funktion pow(x,y) aus der math.h anwenden.
Ändern Sie Code der Operation onWork() der Klasse Controller wie folgt:

Controller::onWork():void
//---------------------------------------------------------------
// atmende LED mit Exponentialfunktion pwm 0-1000 #include math.h
duty++;
if      (duty<1000) pwm.setDuty( pow(1.00693,duty) );
else if (duty<2000) pwm.setDuty( pow(1.00693,2000-duty) );
else                duty=0;
waitMs(1);

Erstellen, übertragen und testen Sie diese Anwendungsvariante.
Man kann jetzt deutlich das sanfte Auf- und Abblenden der LED erkennen. Die LED scheint regelrecht zu atmen.

Videozusammenfassung

Erlernte und gefestigte Arbeitsschritte:

  1. Klassendiagramm anlegen und öffnen
  2. Diagrammvorlage für PEC Applikation auswählen, laden und Treiberpaket für MM32L0 einfügen
  3. gewünschte Bausteine im Explorer/Navigator suchen und ins Diagramm ziehen
  4. Klassen aggregieren
  5. Attribute und Operationen einer Klasse anlegen
  6. Klassen und Templates zu Komponenten zusammenbauen
  7. den nötigen Quellcode in den Operationen erstellen
  8. Erstellen und Brennen einer ARM Applikation im Klassendiagramm
  9. das SiSy-ControlCenter konfigurieren und anwenden

Und hier diesen Abschnitt wiederum als Videozusammenfassung.

oder die schnelle Version ohne Sprachkommentare

Übung 7

Erweitern Sie zur Übung die Anwendung um eine UART-Verbindung mit 19200 BAUD zum SiSy-ControlCenter. Senden sie die PWM-Werte für die Ansteuerung der LED als 8 Bit Zahlen an das SiSy-ControlCenter. Verfolgen Sie den Signalverlauf in der Oszi-Ansicht des ControlCenters.

Weiter mit:

Suchbegriffe