Sie sind vermutlich noch nicht im Forum angemeldet - Klicken Sie hier um sich kostenlos anzumelden Impressum 
Sie können sich hier anmelden
Dieses Thema hat 7 Antworten
und wurde 15.841 mal aufgerufen
 Bascom - Unser Einsteigerkurs
diezel Offline



Beiträge: 709

08.04.2013 23:17
[BEK09] PWM per Timer und Software Zitat · Antworten

Hallo,

heute möchte ich Euch zeigen, wie man Pulsweitenmodulation (PWM) erzeugt.
PWM? Das ist ein Rechtecksignal mit fester Frequenz, bei dem die Ein- und Auszeiten variert werden können. Damit kann man dann z.B. eine LED in der Helligkeit steuern. Wird die Ein-Zeit länger gemacht, bekommt die LED länger Strom und leuchtet länger. Da die Frequenz aber so schnell ist, kommt unser Auge da gar nicht mit und erkennt nur eine LED, die eben in der Helligkeit variiert.

Wer will, kann sich hier die ersten 2 Kapitel ansehen:
http://www.mikrocontroller.net/articles/Pulsweitenmodulation

Wir haben 2 Möglichkeiten diese PWM zu erzeugen. Als erstes machen wir dies, in dem wir die Hardware-PWM unseres Atmega nutzen. Wir können die Timer auch so konfigurieren, daß sie an vorgegebenen Pins ein PWM-Signal ausgeben. Der Atmega8 hat 3 Ausgänge für Hardware PWM: Timer1 gibt sie auf den Pins PB1 und PB2 aus, Timer2 belegt PB3. Seht euch doch bitte im Datenblatt die "Pin configurations" auf Seite 2 an. Dort sind diese Pins so bezeichnet: OC1A, OC1B und OC2. Also Timer1 hat 2 PWM-Kanäle, Timer2 hat einen und Timer0 kann gar keine Hardware-PWM.

Hier eine Beispiel-Konfiguration des Timers:

1
2
3
4
 
Config Timer1 = Pwm , Pwm = 10 , Compare A Pwm = Clear Down , Compare B Pwm = Clear Down, Prescale = 64
Pwm1a = 0
Pwm1b = 0
 
 


Config Timer1 = PWM: hier sagen wir dem Timer1 daß er im PWM-Modus arbeiten soll
PWM = 10: hier wird bestiimt, wie fein abgestuft die PWM sein soll. Hier können 8-Bit, also 256 Stufen, 9-Bit = 512 Stufen und 10 Bit = 1024 Stufen konfiguriert werden.
Compare A Pwm = Clear Down: ääähhhh ja. Seht euch mal schnell auf Seite 111 des Datenblattes die Grafik an.
Der Timer ist ja ein Zähler. Er zählt bei unserer 10-Bit-PWM von 0 bis 1023 und von 1023 wieder zurück auf 0. Also diese Zickzack-Linie "TCNTn" im Bild. Der jeweilige Zählerstand wird fortlaufend mit einem Vergleichswert, den wir vorgeben, verglichen. In der Grafik ist der Vergleichswert bei den ersten 2 Zacken auf maximal, also Wert 1023, danach in der Mitte und zum Schluß bei ca.80%.
Wir sehen uns die mittleren beiden Punkte an und erkennen, daß wenn der Timer runterzählt und mit dem Vergleichswert gleich ist, wird der Ausgang auf High gesetzt.
Beim nächsten Treffer ist der Zähler beim raufzählen und der Ausgang wird Low. Dieser Modus nennt sich in Bascom "Compare A Pwm = Clear Up". Eine invertierte PWM erhält man bei "Clear Down", und genau brauchen wir wegen der invertierten Logic der LED (0=Ein, 1=Aus)
Achtung: seit Bascom Version 2.0.7.1 ist diese Einstellung wie beschrieben, bei älteren Versionen war Clear Up/Down getauscht.

Prescale = 64: wie schon bei der normalen Timer-Konfiguration, können wir auch hier einen Prescaler benutzen. Ich rechne wieder: 8 MHz Systemtakt, 256 Prescale und 1024 PWM Auflösung. Das Ergebnis hiervon müssen wir nochmals halbieren: wer die Grafik aufmerksam anschaut, bemerkt daß der Timer von 0 - 1023 und wieder zurück zählen muß, damit ein PWM-Signal entsteht:
8000000 / (64 * 1024 * 2) = 61Hz

genug der Worte, hier ein Beispiel:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
 
$regfile = "m8adef.dat"                                     'Mikrocontroller ist Atmega 8
$crystal = 8000000 'Arbeitsfrequenz 8 MHz
$hwstack = 40 'Hardware-Stack
$swstack = 32 'Software-Stack
$framesize = 60 'Frame
$baud = 19200 'serielle Übertragungsgeschwindigkeit
 
'*** Ein/Ausgänge deklarieren **************************************************
'brauchen wir hier nicht
 
'*** Variablen definieren ******************************************************
Dim Zaehler As Word 'Word weil Werte zwischen 0 und 1023 möglich
 
'*** Timer konfigurieren *******************************************************
Config Timer1 = Pwm , Pwm = 10 , Compare A Pwm = Clear Down , Compare B Pwm = Clear Down , Prescale = 64
 
'erstmal noch beide Ausgänge AUS
Pwm1a = 0 'PWM-Kanal A des Timer1 Vergleiswert zuweisen
Pwm1b = 0 'PWM-Kanal B des Timer1 Vergleiswert zuweisen
 

'*** Hauptschleife *************************************************************
 
Wait 2
 

Do 'Beginn Hauptschleife
For Zaehler = 0 To 1023 'in ca. 1sec aufdimmen
Pwm1a = Zaehler
Waitms 1
Next Zaehler
 
Wait 1 '1sec halten
 
For Zaehler = 1023 To 0 Step -1 'in ca. 1sec abdimmen
Pwm1a = Zaehler
Waitms 1
Next Zaehler
 
Wait 1 '1sec halten
 

Loop 'Ende Hauptschleife
 
End
 



Der große Nachteil an der Hardware-PWM ist, daß für 2 PWM-Kanäle ein Timer belegt ist. Da Timer aber eh meist zu wenige sind und wir gar keine so hohe Auflösung für ne LED brauchen, zeig ich euch morgen, wie man das "von Hand" machen kann, ähhm, die PWM mein ich.


Gruß
Gerhard

-------------------------------------------------------------------------------------------
hier mein aktueller TinyKatalog


diezel Offline



Beiträge: 709

09.04.2013 20:42
#2 RE: [BEK09] PWM per Timer und Software Zitat · Antworten

Hallo,

heute zeig ich euch, wie man eine (oder mehrere) LEDs per PWM in Software auf und abdimmt. Dieses Grundschema kann auch auf andere Situationen angepaßt werden, z.B. wenn ein Motor angesteuert werden soll.

Paar Gedanken im Vorfeld:
wir wollen ja „nur“ eine LED dimmen. Da unser Auge aber so träge ist, brauchen wir gar nicht die Auflösung, wie wir sie gestern programmiert haben. 50 unterschiedliche Helligkeitsstufen sollten reichen, mehr kann das Auge eh nicht erkennen. Genauso steht´s mit der „Bildwiederholrate“, hier reichen auch 50Hz.

Im Programm müssen wir das Verhalten der Hardware-PWM nachbilden. Also eine Variable wird fortlaufend hochgezählt und mit einem Helligkeitswert verglichen. Um dies gleichmäßig zu machen, wird dieser Programmteil in einer Interruptroutine eines Timers abgearbeitet.

Jetzt geht´s darum, herauszufinden, wie oft diese Interruptroutine angesprungen werden muß. Dazu multiplizieren wir die Bildwiederholrate mir den Helligkeitsstufen:
50 x 50 = 2500Hz
Wir müssen also den Timer so konfigurieren, daß er 2500 mal die Sekunde überläuft, oder anders gesprochen er muß jeweils 3200 Takte zählen (8000000 / 2500 = 3200). Dazu verwenden wir beispielhaft den Timer0, der 8-Bit zählen kann, also bis 255.
Wir rechnen wieder, um den nötigen Prescale rauszufinden:
3200 / 256 = 12,5
Wir müssen also den nächstgrößeren Prescale auswählen, Prescale = 64 ist die nächste Möglichkeit.
Jetzt müssen wir noch ausrechnen, wieviel der Timer vorgeladen werden muß, um auf die genaue Frequenz zu kommen.
3200 / 64 = 50
Der Timer muß also genau 50 Zählschritte machen, wir müssen ihn also mit 205 vorladen.


Und was muß alles in die Interruptroutine?
Als erstes muß der Timer 0 vorgeladen werden. Dies muß immer als allererstes gemacht werden, da sonst Takte verloren gehen.
Danach Inkrementieren wir die Variable, mit der wir die Helligkeitsstufe der LED vergleichen, ich hab sie Timerzähler genannt.
Da wir nur 50 Helligkeitsstufen wollen, begrenzen wir die Variable auch auf 50.
Danach vergleichen wir den Timerzähler mit dem gewünschten Helligkeitswert, für den ich die Variable Led1 verwendet habe.
Ist der Timerzähler noch kleiner als Led1, muß die LED eingeschaltet werden. Wegen unserer invertierten Ansteuerung also den Ausgang auf 0 setzen. Den hab ich am Anfang mit Alias auf Led1_pin getauft.

In der Main-Loop können wir dann wieder spielen und die LED auf- und abdimmen, oder sonst was…


Gruß
Gerhard

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
 
$regfile = "m8def.dat"                                      'Mikrocontroller ist Atmega 8
$crystal = 8000000 'Arbeitsfrequenz 8 MHz
$hwstack = 40 'Hardware-Stack
$swstack = 32 'Software-Stack
$framesize = 60 'Frame
$baud = 19200 'serielle Übertragungsgeschwindigkeit
 
'*** Ein/Ausgänge deklarieren **************************************************
Config Portb.0 = Output 'PortB als Ausgang
Led1_pin Alias Portb.0 'Ausgang PortB.0 heitßt ab jetzt "Led1"
 
'*** Variablen definieren ******************************************************
Dim Zaehler As Byte
Dim Led1 As Byte 'Auflösung 0 - 49
Dim Timerzaehler As Byte 'Maximalwerte wie LED1
 
'*** Timer konfigurieren *******************************************************
Config Timer0 = Timer , Prescale = 64 'Timer konfigurieren
On Timer0 Timerroutine 'Timerinterrupt Subroutine zuweisen
Enable Timer0 'Timer aktivieren
Start Timer0 'Timer starten
Timer0 = 205 'Timer vorladen
 
Enable Interrupts 'Interrupt erlauben
 

'*** Hauptschleife *************************************************************
 

Do 'Beginn Hauptschleife
For Zaehler = 0 To 49 'in ca. 1sec aufdimmen
Led1 = Zaehler 'hier wird der Schleifenwert der LED zugewiesen
Waitms 20
Next Zaehler
 
Wait 1 '1sec halten
 
For Zaehler = 49 To 0 Step -1 'in ca. 1sec abdimmen
Led1 = Zaehler
Waitms 20
Next Zaehler
 
Wait 1
Loop 'Ende Hauptschleife
 
End
 

'*** Subs **********************************************************************
Timerroutine: 'Beginn Subroutine
Timer0 = 205
Incr Timerzaehler
If Timerzaehler = 50 Then Timerzaehler = 0 'Timerzaehler auf LED-Auflösung begrenzen
If Timerzaehler < Led1 Then Led1_pin = 0 Else Led1_pin = 1 'Vergleich Timerzähler mit LED-Wert -> LED Ein- od. Ausschalten
Return 'Ende Subroutine
 

-------------------------------------------------------------------------------------------
hier mein aktueller TinyKatalog

Dateianlage:
Aufgrund eingeschränkter Benutzerrechte werden nur die Namen der Dateianhänge angezeigt Jetzt anmelden!
bek09-2.bas.txt

diezel Offline



Beiträge: 709

09.04.2013 21:17
#3 RE: [BEK09] PWM per Timer und Software Zitat · Antworten

Hallo,

gebt mir bitte Feedback, ob die Timergeschichte - zumindest für´s Erste - ausreichend erklärt ist.
Ich würd das hier gerne bald abschließen, um zur ersten richtigen Anwendung zu kommen. Sonst wird´s noch zu trocken.
Und ob es jetzt wirklich sinnvoll ist, alle Möglichkeiten der Timer durchzukauen, glaub ich eh nicht.


Gruß
Gerhard

-------------------------------------------------------------------------------------------
hier mein aktueller TinyKatalog


diezel Offline



Beiträge: 709

10.04.2013 00:00
#4 RE: [BEK09] PWM per Timer und Software Zitat · Antworten

und hier noch ein Beispiel, wie mehrere LEDs gedimmt werden.
Ist so ein Knight-Rider-Lauflicht mit Nachlaufeffekt incl. Lookup-Funktion.
Viel Spaß beim grübeln wie es funktioniert


Gruß
Gerhard

-------------------------------------------------------------------------------------------
hier mein aktueller TinyKatalog

Dateianlage:
Aufgrund eingeschränkter Benutzerrechte werden nur die Namen der Dateianhänge angezeigt Jetzt anmelden!
bek09-3.bas.txt

Tüftler_Senior Offline




Beiträge: 79

10.04.2013 21:53
#5 RE: [BEK09] PWM per Timer und Software Zitat · Antworten

Hallo Gerhard

Erst noch mal Danke für deine Erklärungen und deine Mühe!

Ich für mich mich muss sagen, das ich zur Zeit noch etwas zu kämpfen habe mit der Materie,
werde aber schon mitkommen!
Zur Not hilft mir mein Sohn mit dem Erklären wenn ich mal was nicht Verstehe!

Also Danke nochmal!

Ich bleibe am Ball!

Gruß Michael


Scotch Offline




Beiträge: 415

10.04.2013 23:43
#6 RE: [BEK09] PWM per Timer und Software Zitat · Antworten

Hallo Gerhard,

Mit dem Timer bin ich soweit noch mit gekommen.
Das mit der PWM Geschichte muss ich mir noch mal auf der Zunge zergehen lassen.
Ist wohl schon etwas spät für die graue Masse ;-)
Leider habe ich gerade auch kein Bascom installiert, somit fällt das Testen auch aus. :-(
Am Wochenende sollte ich mehr Zeit haben.
Aber alles in allem, wieder sehr Gut erklärt von Dir.
Vielen Dank für Deine Arbeit.

Gruß Ingo

------------------------------------------

Meine Webseite


diezel Offline



Beiträge: 709

11.04.2013 00:11
#7 RE: [BEK09] PWM per Timer und Software Zitat · Antworten

Hallo Ingo,

Bascom sollte schon verfügbar sein, sonst bringt´s eh nix.
Am Besten erst mal alles durchkauen, dann selbst eine Aufgabe setzen und schaun wie man es umsetzt. Nur so steigt man auch voll durch.

Wer dann mal ne Frage hat, der macht doch bitte nen eigenen Thread auf, postet seine Aufgabenstellung und das Programm. Dann schaun wir uns das Gemeinsam an. Davon haben dann alle was.
Und auch wer es alleine Geschafft hat, kann sein Programm posten. Weitere Beispiele können nie schaden.
Macht die Threads dann auch ruhig in diesem Forenbereich auf. Die Kursbeiträge hab ich ja durch die eckigen Klammern gekennzeichnet, die bleiben auch automatisch in der Übersicht oben stehen.


Gruß
Gerhard

-------------------------------------------------------------------------------------------
hier mein aktueller TinyKatalog


Scotch Offline




Beiträge: 415

11.04.2013 22:30
#8 RE: [BEK09] PWM per Timer und Software Zitat · Antworten

Hallo Gerhard,
Bascom ist ja schon vorhanden, nur ich habe mein Win XP auf Win 7 aktualisiert und
bis Heute noch kein Bascom installiert.
Arbeite normalerweise auf eine Apfel und habe nur Win für solche Sachen.
Leider Gibt es kein Bascom für Mac OS :-(
Werde jetzt mal schauen ob alles läuft und der DX ISP Prog richtig installiert ist.
Der Treiber hatte etwas herumgezigt
Gruß Ingo

------------------------------------------

Meine Webseite


 Sprung  

disconnected Mikromodell-Chat Mitglieder Online 4
Xobor Xobor Community Software
Datenschutz