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