1.7 🚧 PWM (PulsWeitenModulation) Ausgabe
Synopsis: [de.wikipedia.org/wiki/Pulsdauermodulation 🔗] [www.arduino.cc/reference/en/language/functions/analog-io/analogwrite/ 🔗]
Wieder so ein „explosives“ 🧨 Thema! Sobald man sich näher damit beschäftigt kann es spannend aber auch kompliziert werden…
- Verwendung
- Leistung steuern
- Töne ausgeben
- Servos ansteuern
- Per Timer-Hardware an bestimmten Pins möglich
- Arduino: analogWrite(…)…
- analogWrite(…)
- analogWriteResolution(…)
- analogWriteFrequency(…)
- einfach aber sehr eingeschränkt und ggfs. mit Nebenwirkungen.
- STM32-API Befehle
- setPWM(…)
- setMode(…)
- setOverflow(…)
- setCaptureCompare(…)
- µC-Register wissend selber einstellen
- AVR
- STM32
- Arduino: analogWrite(…)…
- Per Software an allen Pins möglich
- Arduino: Servo [www.arduino.cc/reference/en/libraries/servo/ 🔗]
- Arduino: tone() [www.arduino.cc/reference/de/language/functions/advanced-io/tone/ 🔗]
- Selbst gebaute Software 🤠
Arduino: analogWrite()
[docs.arduino.cc/learn/microcontrollers/analog-output/ 🔗]
Die Helligkeit der LED an PC7 soll durch den low-aktiven prellfreien UserButton an PC13 in den Stufen
0% -> 25% -> 50% -> 75% -> 100% -> 0% usw.
mit einer ISR isr_UserB() verändert werden.
Mit analogWrite(LED,analogWert) wird der Wert von analogWert zwischen 0..255 die Helligkeit von 0%..100% als PWM-Signal auf LED ausgegeben.
Vorgabe-Code:
#define USER_B PC13 // User-Button prellfrei low aktiv
#define LED PC7 // AusgabePin
volatile unsigned int helligkeit=0; // Globale Variable für Helligkeitswert in Prozent
void isr_UserB(){ // ISR für Helligkeit verändern
int analogWert; // Ausgabewert PWM
...
analogWert = helligkeit * 2; // erster Ansatz zur Umrechnung
analogWrite(LED,analogWert); // Arduino-Funktion für PWM Ausgabe an bestimmten Port-Pins
Serial.printf("Helligkeit %d%% Analogwert %d \n",helligkeit,analogWert);
}
void setup(){
Serial.begin (9600); // Serielle kommunikation starten
...
}
void loop(){}
Vervollständigen Sie das Programm.
Lösungsvorschlag
#define USER_B PC13 // User-Button prellfrei low aktiv
#define LED PC7 // AusgabePin
volatile unsigned int helligkeit=0; // Globale Variable für Helligkeitswert in Prozent
void isr_UserB(){ // ISR für Helligkeit verändern
int analogWert; // Ausgabewert PWM
if(helligkeit>=100){
helligkeit=0;
}
else{
helligkeit+=25;
}
analogWert = helligkeit * 2; // erster Ansatz zur Umrechnung
analogWrite(LED,analogWert); // Arduino-Funktion für PWM Ausgabe an bestimmten Port-Pins
Serial.printf("Helligkeit %d%% Analogwert %d \n",helligkeit,analogWert);
}
void setup(){
Serial.begin (9600); // Serielle kommunikation starten
pinMode(USER_B, INPUT);
attachInterrupt (digitalPinToInterrupt (USER_B), isr_UserB, FALLING); // fallende Flanke
pinMode(LED,OUTPUT);
}
void loop(){}
Umrechnung Prozentwert in Analogwert
Wie Sie sicher erkennen wird bei der Vorgabe der 100%-Wert nicht in analogWert=255 umgerechnet sondern in analogWert=200.
Problem: Erstelle eine Gleichung analogWert = … helligkeit … für die richtige Umrechnung.
Die typische Lösung: analogWert = helligkeit / 100 * 255 ist mathematisch korrekt, funktioniert aber nicht, weil mit ganzen Zahlen gerechnet wird und da gilt: 50 / 100 ist 0!
Dieser Ausdruck funktioniert wie gewünscht: analogWert = helligkeit*255/100; // es lebe die Numerik!
Gegen Kopfschmerzen map(…) Funktion?
Oft müssen Wertebereiche in andere Bereiche umgerechnet werden, es gibt bei Arduino eine Funktion dafür [www.arduino.cc/reference/en/language/functions/math/map/ 🔗] damit wäre die Lösung einfach:
analogWert = map(helligkeit,0,100,0,255); // Arduino-Umrechnungsfunktion
Falls diese Funktion in der Formelsammlung auftaucht, dürfen Sie sie auch problemlos verwenden…
Messen des Ausgabe-Signals mit Oszilloskop
Welches Signal geben wir aus, um die Helligkeit, bzw. die Leistung der LED zu steuern? Messen wir es mit einem Oszilloskop!
Die Frequenz ist 1 kHz, die Genauigkeit ist bedingt durch nur 256 Stufen von 0%..100% nicht besonders hoch.
PWM noch besser?
Es gibt zwei Einstellmöglichkeiten für die PWM-Ausgabe mit analogWrite(..):
analogWriteResolution(n); // n=8..16
Gibt die Bit-Auflösung des AnalogWertes an. Bei 8 Bit ist der Maximalwert 255, bei 16 Bit 65535 für 100%.
Bei 16 Bit Auflösung ist die Genauigkeit höher.
Testcode
#define USER_B PC13 // User-Button prellfrei low aktiv
#define LED PC7 // AusgabePin
volatile unsigned int helligkeit=0; // Globale Variable für Helligkeitswert in Prozent
void isr_UserB(){ // ISR für Helligkeit verändern
int analogWert; // Ausgabewert PWM
if(helligkeit>=100){
helligkeit=0;
}
else{
helligkeit+=25;
}
//analogWert = helligkeit*255/100;
analogWert = helligkeit*65535/100;
//analogWert = map(helligkeit,0,100,0,255);
analogWrite(LED,analogWert); // Arduino-Funktion für PWM Ausgabe an bestimmten Port-Pins
Serial.printf("Helligkeit %d%% Analogwert %d \n",helligkeit,analogWert);
}
void setup(){
Serial.begin (9600); // Serielle kommunikation starten
pinMode(USER_B, INPUT);
attachInterrupt (digitalPinToInterrupt (USER_B), isr_UserB, FALLING); // fallende Flanke
pinMode(LED,OUTPUT);
analogWriteResolution(16);
//analogWriteFrequency(10000);
}
void loop(){}
analogWriteFrequency(10000);
Die Ausgabefrequenz kann damit angepasst werden. Wie ist der Bereich?
Nachteilig ist, dass die Anpassungen immer für alle analogWrite(..) gelten.
Welche Ausgänge können PWM?
Nicht mit allen Ausgängen kann per Hardware PWM betrieben werden. Hier ein Überblick welche Ausgänge geeignet sind: mezmedia.de/etc/hardware/stm32-nucleo-l152re/