29. Lektion: Puls Weiten Modulation (PWM): Unterschied zwischen den Versionen

Aus Attraktor Wiki

Wechseln zu: Navigation, Suche
(Beschränkungen der PWM)
(Praktische Anwendung)
 
Zeile 175: Zeile 175:
 
pwm = PWM(Pin(22), freq=100000, duty_ns=9999)
 
pwm = PWM(Pin(22), freq=100000, duty_ns=9999)
  
for i in range(256):
+
for i in range(257):
 
     pwm.duty_u16(i*i)
 
     pwm.duty_u16(i*i)
 
     print(i, pwm.duty_u16())
 
     print(i, pwm.duty_u16())
 
     sleep_ms(20)
 
     sleep_ms(20)
 
</pre>
 
</pre>
 
 
  
 
== Links:==
 
== Links:==

Aktuelle Version vom 30. Januar 2024, 18:19 Uhr

PulsWeitenModulation (PWM) was ist das?

PWM bedeutet, dass in regelmässigen Abständen ein Impuls definierter Länge ausgegeben wird. Diese Konzept wird z.B. zur Steuerung von Servos, aber auch zur Erzeugung analoger Spannungen eingesetzt.
PWM Anwendungen


PWM im Pico

Es gibt 8 unabhängige PWM-Generatoren, so genannte Slices, die jeweils zwei Kanäle haben, so dass insgesamt 16 PWM-Kanäle zur Verfügung stehen, die von 8 Hz bis 62,5 MHz bei einer machine.freq() von 125 MHz getaktet werden können.
Die beiden Kanäle eines Slice laufen mit der gleichen Frequenz, können aber ein unterschiedliches Tastverhältnis haben.
Die beiden Kanäle werden normalerweise benachbarten GPIO-Pin-Paaren mit geraden/ungeraden Nummern zugewiesen. So befinden sich GPIO0 und GPIO1 auf Slice 0, GPIO2 und GPIO3 auf Slice 1, und so weiter.
Ein bestimmter Kanal kann verschiedenen GPIO-Pins zugewiesen werden (siehe Pinout). Zum Beispiel kann Slice 0, Kanal A sowohl GPIO0 als auch GPIO16 zugewiesen werden.

Beschränkungen der PWM

Aufgrund der diskreten Natur der Computerhardware können nicht alle Frequenzen mit absoluter Genauigkeit erzeugt werden. In der Regel wird die PWM-Frequenz durch Teilung einer ganzzahligen Basisfrequenz durch einen ganzzahligen Teiler ermittelt. Wenn die Basisfrequenz beispielsweise 80 MHz beträgt und die gewünschte PWM-Frequenz 300 kHz ist, muss der Teiler eine nicht ganzzahlige Zahl sein 80000000 / 300000 = 266,67. Nach dem Runden wird der Teiler auf 267 gesetzt und die PWM-Frequenz ist 80000000 / 267 = 299625,5 Hz, nicht 300kHz. Wenn der Teiler auf 266 gesetzt wird, dann ist die PWM-Frequenz 80000000 / 266 = 300751,9 Hz, aber wieder nicht 300kHz.
Einige Ports wie der RP2040 verwenden einen fraktionalen Teiler, der eine feinere Granularität der Frequenz bei höheren Frequenzen ermöglicht, indem er die PWM-Pulsdauer zwischen zwei benachbarten Werten umschaltet, so dass die resultierende Durchschnittsfrequenz näher an der beabsichtigten Frequenz liegt, allerdings auf Kosten der spektralen Reinheit.
Das Tastverhältnis hat den gleichen diskreten Charakter und seine absolute Genauigkeit ist nicht zu erreichen. Auf den meisten Hardware-Plattformen wird das Tastverhältnis bei der nächsten Frequenzperiode angewendet. Daher sollten Sie mehr als "1/Frequenz" warten, bevor Sie das Tastverhältnis messen.
Die Frequenz und die Auflösung des Tastverhältnisses sind in der Regel voneinander abhängig. Je höher die PWM-Frequenz ist, desto geringer ist die verfügbare Auflösung des Tastverhältnisses und andersherum. Bei einer PWM-Frequenz von 300 kHz kann die Auflösung des Tastverhältnisses beispielsweise 8 Bit betragen, nicht 16 Bit, wie man vielleicht erwarten würde. In diesem Fall sind die untersten 8 Bits von duty_u16 unbedeutend. Also:

# beide der folgenden Codezeilen ergeben das selbe 50% duty cycle.

pwm=PWM(Pin(13), freq=300_000, duty_u16=2**16//2)

pwm=PWM(Pin(13), freq=300_000, duty_u16=2**16//2 + 255)

Die höchste Frequenz für die vollen 16-Bit Duty-Cycle beträgt 953,6743 Hz:

>>> 125e6/2/2**16
953.6743 

Eine Instanz von PWM erzeugen

machine.PWM(dest, *, freq, duty_u16, duty_ns, invert)

dest
ist die Entität, auf der die PWM ausgegeben wird, in der Regel ein machine.Pin-Objekt, aber ein Port kann auch andere Werte zulassen, z. B. Ganzzahlen.
freq
sollte eine ganze Zahl sein, die die Frequenz in Hz für den PWM-Zyklus festlegt.
duty_u16
legt das Tastverhältnis als Verhältnis duty_u16 / 65535 fest.
duty_ns
legt die Pulsbreite in Nanosekunden fest.
invert
invertiert den jeweiligen Ausgang, wenn der Wert True ist. Kann nur bei der Initialisierung eingestellt werden!
from machine import Pin, PWM

# create PWM object from a pin and set the frequency of slice 0
# and duty cycle for channel A
>>> pwm0 = PWM(Pin(0), freq=2000, duty_u16=32768)

>>> print(pwm0)
<PWM slice=0 channel=0 invert=0>

Die Parameter ändern

pwm0.freq()             # get the current frequency of slice 0
pwm0.freq(1000)         # set/change the frequency of slice 0
pwm0.duty_u16()         # get the current duty cycle of channel A, range 0-65535
pwm0.duty_u16(200)      # set the duty cycle of channel A, range 0-65535
pwm0.duty_u16(0)        # stop the output at channel A
print(pwm0)             # show the properties of the PWM object.
pwm0.deinit()           # turn off PWM of slice 0, stopping channels A and B

Slices & Channels

Was sind Slices und Channels? Die Doku von Micropython.org hat bei mir noch einigen Nebel hinterlassen. Deshalb habe ein wenig herumgespielt:

>>> from machine import Pin, PWM

>>> pwm0 = PWM(Pin(0), freq=2000, duty_u16=32768)
>>> print(pwm0)
<PWM slice=0 channel=0 invert=0>

>>> pwm1 = PWM(Pin(1), freq=2000, duty_u16=32768)
>>> print(pwm1)
<PWM slice=0 channel=1 invert=0>

>>> pwm2 = PWM(Pin(2), freq=2000, duty_u16=32768)
>>> print(pwm2)
<PWM slice=1 channel=0 invert=0>

>>> pwm4 = PWM(Pin(4), freq=2000, duty_u16=32768)
>>> print(pwm4)
<PWM slice=2 channel=0 invert=0>

>>> pwm10 = PWM(Pin(10), freq=2000, duty_u16=32768)
>>> print(pwm10)
<PWM slice=5 channel=0 invert=0>

# Wenn's nervt:
>>> pwm10.deinit()
# Dann ist Ruhe.

# Die Frequenz ist in einem Slice immer gleich:
>>> pwm0.freq(1000)
>>> pwm0.freq()
1000
>>> pwm1.freq()
1000

>>> pwm1.freq(5000)
>>> pwm0.freq()
5000
>>> pwm1.freq()
5000

# Hinterm Horizont geht's weiter

>>> pwmy = PWM(Pin(16), freq=2000, duty_u16=32768)
>>> print(pwmy)
<PWM slice=0 channel=0 invert=0>

>>> pwmx = PWM(Pin(22), freq=2000, duty_u16=32768)
>>> print(pwmx)
<PWM slice=3 channel=0 invert=0>

# Siehe da
>>> pwm1.freq()
2000

Praktische Anwendung

Wir wollen die LED auf dem Demoboard dimmen:

# pwm_test_01.py

from machine import Pin, PWM
from time import sleep_ms

pwm = PWM(Pin(22), freq=100000, duty_ns=9999)

for i in range(0,10000):
    pwm.duty_ns(i)
    print(pwm.duty_ns())
    sleep_ms(10)

# Ausgabe:
3928
3928
3936
3936
3936
3936
3936
3936
3936
3936
3944
3944
3944
3944
3944
3944
3944
3944
3952
3952

Und jetzt noch mal quadratisch:

from machine import Pin, PWM
from time import sleep_ms

pwm = PWM(Pin(22), freq=100000, duty_ns=9999)

for i in range(257):
    pwm.duty_u16(i*i)
    print(i, pwm.duty_u16())
    sleep_ms(20)

Links:

Navigation

Zurück zur "Micropython Kurs 2023 Teil 2" Startseite
Zurück zur "Micropython Kurs 2023" Startseite
Zurück zur Programmieren Startseite
Zurück zur Wiki Startseite

Diese Seite wurde zuletzt am 30. Januar 2024 um 18:19 Uhr geändert. Diese Seite wurde bisher 886 mal abgerufen.