Raspberry PWM-Ausgaben            

Elektronik-Labor  Projekte  Mikrocontroller  Raspberry     




Der PWM-Ausgang wird mit einem Schieberegler zwischen 0% und 100% eingestellt, was als 0 mV bis 3300 mV angezeigt wird. Eine zusätzliche Rampenfunktion ermöglicht eine kontinuierlich ansteigende oder abfallende Spannung mit einer Änderungsrate von 10 mV/s. Damit kann man die Helligkeit einer LED langsam auf- oder abblenden und verschiedene Experimente automatisch steuern. Ein Klick auf Stop friert die aktuelle Ausgabe ein.
Zusätzlich kann die PWM-Frequenz gewählt werden. Mit 0.2 Hz oder 1 Hz hat man einen langsamen Blinker mit einstellbarerer Impulsdauer, der sich als Signalquelle für die unterschiedlichsten Experimente eignet. Die Frequenzen 50 Hz bis 5000 Hz sind besser geeignet, wenn man das Ausgangssignal zu einer Gleichspannung glätten will. Dabei erreicht man mit 50 Hz die höhere Präzision, während bei den höheren Frequenzen bereits  gewisse Schwankungen beobachtet werden. 

Die PWM-Ausgabe wird in der Schieberegler-(Scale)-Funktion pwm_aus (sc) gesteuert. Die globale Variable d trägt den aktuellen Wert des Schiebereglers im Bereich 0 bis 3300. In der Variablen du steht die Änderungsrate für den Zeitraum 500 ms. Die Position des Schiebereglers wird entsprechend verändert und dann auf den Bereich 0 bis 100 umgerechnet, um sie an den PWM-Ausgang zu übergeben. Nach jeweils 500 ms ruft die Funktion sich selbst wieder auf.



Ein PWM-Signal ist eigentlich ein digitales Signal, denn die Spannung am Port ist immer ganz an oder immer ganz aus. Nur im Mittelwert ergibt sich daraus eine Spannung zwischen 0 V und 3,3 V. Mit einem einfachen Filter kann man aber eine echte Gleichspannung erzeugen. Ein Widerstand von 10 kΩ lädt einen Elektrolyt-Kondensator von 100 µF auf die mittlere eingestellte Spannung. 
  


Tatsächlich wird in jeder AN-Phase der Kondensator etwas aufgeladen und in jeder AUS-Phase etwas entladen. Die Restwelligkeit beträgt rund 16 mV bei 50 Hz und entsprechend nur noch etwa 1,6 mV bei 500 Hz. Einen Eindruck von Spannungsglättung mit einem RC-Glied vermittelt ein Messergebnis mit dem Raspberry-Oszilloskop, das später noch vorgestellt wird. Gemessen wurde die Spannung am Ladekondensator bei einem PWM-Signal von 0,2 Hz, 1 Hz und schließlich bei 50 Hz.


#Tk_GPIO10PWM.py Port 10 PWM-Ausgabe mit Schieberegler
from Tkinter import *
import RPi.GPIO as GPIO
GPIO.setwarnings(False)
GPIO.setmode(GPIO.BCM) # Broadcom
GPIO.setup(10, GPIO.OUT) # Port 10 Ausgang
p = GPIO.PWM(10, 500) # Port 10 PWM 500 Hz
p.start(0) # 0%

global d
d=0
global du
du=0

def anzeige(lb):
global d
lb.config(text="U = " + str(d) + " mV")
lb.after(100, anzeige, lb)

def pwm_aus(sc):
global d
global du
pwm=0.0
d = sc.get()
d=d+du
if d>3300:
d=3300
if d<0:
d=0
sc.set(d)
pwm = d
pwm=pwm/33.0
p.ChangeDutyCycle(pwm)
sc.after(500, pwm_aus, sc)

def hoch():
global du
du=5
def runter():
global du
du=-5
def stop():
global du
du=0

def f02():
global p
p.stop
p = GPIO.PWM(10, 0.2) # Port 10 PWM 0,2 Hz
p.start(0) # 0%
def f1():
global p
p.stop
p = GPIO.PWM(10, 1) # Port 10 PWM 1 Hz
p.start(0) # 0%
def f50():
global p
p.stop
p = GPIO.PWM(10, 50) # Port 10 PWM 50 Hz
p.start(0) # 0%
def f500():
global p
p.stop
p = GPIO.PWM(10, 500) # Port 10 PWM 500 Hz
p.start(0) # 0%
def f5000():
global p
p.stop
p = GPIO.PWM(10, 5000) # Port 10 PWM 5000 Hz
p.start(0) # 0%

def fstop():
global p
p.stop()

def on_closing():
GPIO.cleanup()
root.destroy()


root = Tk()
root.title("PWM GPIO 10")
root.font=('Helvetica', 30, 'normal')
Label(root, text="------------------", font = root.font).pack()
lb = Label(root, font = root.font)
lb.pack()
Label(root, text="------------------", font = root.font).pack()
sc = Scale(root, from_=0, to=3300, length=500,tickinterval=500, orient=HORIZONTAL)
sc.set(0)
sc.pack()
Button(root, text="+10 mV/s", width=20,command=hoch).pack()
Button(root, text='-10 mV/s',width=20, command=runter).pack()
Button(root, text='Stop',width=20, command=stop).pack()
Button(root, text='0.2 Hz',width=7, command=f02).pack(side=LEFT)
Button(root, text='1 Hz',width=7, command=f1).pack(side=LEFT)
Button(root, text='50 Hz',width=7, command=f50).pack(side=LEFT)
Button(root, text='500 Hz',width=7, command=f500).pack(side=LEFT)
Button(root, text='5 kHz',width=7, command=f5000).pack(side=LEFT)
Button(root, text='PWM Stop',width=7, command=fstop).pack()

anzeige(lb)
pwm_aus(sc)
root.protocol("WM_DELETE_WINDOW", on_closing)
root.mainloop()


Verbesserung: PWM ohne globale Viariablen

Auch in Bascom-Projekten habe ich viel mit globalen Variablen gearbeitet und kenne bereits die Nachteile. Bei sehr großen Projekten kann man den Überblick verlieren. Welche Prozedur ändert wann und welchen Bedingungen diese Variable, das ist oft nicht mehr leicht zu überblicken. Und manche Stunde mühsamer Fehlersuche war genau darauf zurückzuführen. Anderseits muss man auch bei der Verwendung lokaler Variablen und bei der Übergabe von Variablen an Funktionen und Prozeduren genau wissen was man tut, sonst gibt es auch nur Chaos. Das ist dann wieder ein Grund für den einfachen und nicht so schönen Weg, eben doch globale Variablen einzusetzen. Da sieht man gleich, dass ich kein richtiger Programmierer bin. Software ist für mich immer nur ein Mittel zum Zweck, und wenn es nur funktioniert, bin ich schon zufrieden. Denn danach geht die eigentliche Arbeit erst los, wobei dann der Schwerpunkt wieder in der Elektronik liegt.

Umso dankbarer bin ich für Verbesserungsvorschläge zur Software. Frank Behlich schrieb mir: "Habe am Code "rumgebastelt" und die "global" heraus geholt. "Global" gibt es zwar, ist aber unter "Höchststrafe" verboten. Habe es nicht auf dem Raspberry testen können - nur mit "print" durchgespielt. Hier das veränderte Script."


#Tk_GPIO10PWM.py Port 10 PWM-Ausgabe mit Schieberegler
from Tkinter import *
from functools import partial
#import RPi.GPIO as GPIO
#GPIO.setwarnings(False)
#GPIO.setmode(GPIO.BCM) # Broadcom

port = 10

#GPIO.setup(port, GPIO.OUT) # Port 10 Ausgang
#p = GPIO.PWM(port, 500) # Port 10 PWM 500 Hz
#p.start(0) # 0%

du_buttons = ((1, "+10 mV/s"), (-1, "-10 mV/s"), (0, "PWM STOP"))
hz_buttons = ((0.2, "hz"), (1, "hz"), (50, "hz"), (500, "hz"),
(5, "khz"), ("", "STOP"))

def pwm_aus(sc, lb):
if sc.get() < 3300 or sc.get() > 0:
#p.ChangeDutyCycle(sc.get() / 33.0)
lb.config(text="U = {0} mV".format(str(sc.get())))
sc.after(500, pwm_aus, sc, lb)

def set_du(mul, sc):
sc.set(sc.get() + 5 * mul)

def set_port(port, hz):
#port.stop
if isinstance(hz, float) or isinstance(hz, int):
#port = GPIO.PWM(port, hz)
#port.start(0)
print "GPIO.PWM({0}, {1})".format(port, hz)

def fstop(port):
#port.stop()
print port

def on_closing():
#GPIO.cleanup()
print "cleanup"
root.destroy()

root = Tk()
root.title("PWM GPIO 10")
lb = Label(root, width=22, bg="lightgreen", fg="gray", font=("Helvetica",
30, "normal"))
lb.pack()
sc = Scale(root, from_=0, to=3300, length=500,tickinterval=500,
orient=HORIZONTAL)
sc.set(0)
sc.pack()
for mul, text in du_buttons:
Button(root, text=text, width=20, command=partial(set_du, mul, sc)).pack()
for hz, text in hz_buttons:
Button(root, text="{0} {1}".format(hz, text), width=7,
command=partial(set_port, port, hz)).pack(side=LEFT)
pwm_aus(sc, lb)
root.protocol("WM_DELETE_WINDOW", on_closing)
root.mainloop()


Hysterese am GPIO-Input



Wo liegt die Schaltschwelle eines digitalen Eingangs am Raspberry? Diese Frage lässt sich mit dem PWM-Ausgang leicht untersuchen. Dazu müssen zwei Programme gleichzeitig verwendet werden, das PWM-Ausgabeprogramm und das Programm zum Lesen des Eingangs, wobei der Eingang hochohmig (High Z) sein soll.
 
Außerdem muss eine Verbindung zum Eingangsport GPIO 27 hergestellt werden. Durch langsame Änderung der PWM-Einstellung lässt sich nun feststellen, ab welcher Spannung der Zustand des Ports als high gelesen wird. Man muss sich viel Zeit lassen, weil die große Zeitkonstante des Tiefpassfilters von einer Sekunde dazu führt, dass die echte Gleichspannung dem eingestellten Wert etwas nachhinkt. Gefunden wurde eine Schwelle von 1210 mV, wobei allerdings gewisse Toleranzen möglich sind.




Beim Verringern der Spannung fällt sofort auf, dass der Port erst verzögert wieder den Low-Zustand erreicht, und zwar bei etwa 1160 mV. Es gibt also zwei Umschaltpunkte, den tieferen, bei dem ausgeschaltet wird und den höheren, bei dem eingeschaltet wird. Zwischen beiden liegt eine Hysterese von etwa 50 mV. Spannend wären noch weitere Messwerte zum Vergleich, um die Toleranzbreite abzuschätzen. Wenn jemand die Messungen wiederholen möchte würde ich mich über eine Rückmeldung freuen.


Elektronik-Labor  Projekte  Mikrocontroller  Raspberry