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!
![Oszillogramm für 25%](https://mezmedia.de/wp-content/uploads/TI4-Ard-1701-Oszi-8Bit-1kHz-25.png)
![Oszillogramm für 50%](https://mezmedia.de/wp-content/uploads/TI4-Ard-1702-Oszi-8Bit-1kHz-50.png)
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.
![Oszillogramm für 25% mit 16Bit](https://mezmedia.de/wp-content/uploads/TI4-Ard-1703-Oszi-16Bit-1kHz-25.png)
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/