Hallo, ich möchte 2 Leds über PWM dimmen. Eine LED ist rot und die andere ist blau. Nun soll von blau über lila nach rot übergeblendet werden. Da mein µC (Atmel At90S2313) nur einen PWM Pin hat, möchte ich das über software steuern. Kann mir jemand sagen, wie man das in Basic programmiert oder zumindes prinziepjell? Ich habe leider nicht´s finden können! Überall steht, wie man die PWM Pinns ansteuert, aber nirgend wo steht wie man beliebige Pinns mit PWM ansteuert. vielen Dank, Tobias
Du kannst ja mal nach Pulsweitenmodulation suchen. Oder dir den Abschnitt im Datenblatt zu den PWM funktionen durchlesen, dann solltest du auch verstehen, wie eine PWM funktioniert.
Hallo Mike, genau das habe ich gemacht und überall steht wie man die fest definierten PWM Pinns ansteuert! Aber ich möchte dafür beliebige Pinns benutzen und das habe ich nirgens gefunden! Also wenn jemand eine Seite weiß wo NICHT die PWM Ausgänge benuzt werden dann bitt zu mir. -Sonic Wie meinst du das per Interrupt? Pin bei jedem Interrupt togglen?! Dann hätte ich ja immer 50%... Tobias
Lass im Timer-Interrupt einen Zähler (Variable) laufen und vergleiche dessen Zählerstand mit den Sollwerten der einzelnen PWM-Kanäle. Ist der Sollwert überschritten, machst Du die LED aus, ist er unterschritten, machst Du sie an. ...
Oder mit 2 Interrupts: Im Compare-Interrupt-Handler wird die eine LED jeweils ein- und die andere ausgeschaltet, im Overflow-Interrupt-Handler umgekehrt. Wenn man den Compare-Wert jetzt kontinuierlich ändert, bekommt die eine LED mehr und die andere weniger Saft ab.
Hier mal ein Beispiel für ein PWM für drei Ausgänge (PORTD, Pin 5-7) /*Hauptdatei*/ volatile unsigned char pwm0; // PortD - Pin 5 volatile unsigned char pwm1; // PortD - Pin 6 volatile unsigned char pwm2; // PortD - Pin 7 /* Jetzt kannst du jeden Kanal mit pwm0 = 100; oder so steuern, wobei 0=0 und 255=max ist. */ /*Interruptdatei, kannst du auch in eine machen*/ volatile unsigned char tm0; extern volatile unsigned char pwm0; extern volatile unsigned char pwm1; extern volatile unsigned char pwm2; ISR(TIMER0_OVF_vect) { ++tm0; if(tm0 == 255) { tm0 = 0; PORTD &= ~((1<<5)|(1<<6)|(1<<7)); } else { if(tm0 == 0xFF-pwm0) PORTD |= (1<<5); if(tm0 == 0xFF-pwm1) PORTD |= (1<<6); if(tm0 == 0xFF-pwm2) PORTD |= (1<<7); } }
@Nico: Ich glaube, wenn er in Basic programmieren will, wird ihn Dein Code nicht wirklich weiterbringen...
Danke HanneS, das ist doch mal eine Auskunft! Und damit die Led automatisch langsam abgedimmt wird nehme ich wohl einen 2.timer oder? Dann ist nur noch die Frage, wie ich es schaffe, das z.b. die blaue Led 100% leuchtet und so lange wartet bis die Rote auch mit 100% leuchtet und erst dann runter dimmt wärend die Rote wartet (hab das Bild noch mal drangehängt). Die Version von johnny.m hab ich noch nicht verstanden... dann macht die eine Led immer das Gegenteil von der ersten? Dann habe ich aber nicht, das eine auf 100% ist wären die ander hoch dimmt... Tobias
> Und damit die Led automatisch langsam abgedimmt wird nehme ich wohl > einen 2.timer oder? Nööö... Du hast doch schon einen Timer-Interrupt, darin hannst Du doch weitere Variablen hoch- oder runterzählen, die Du dann im Hauptprogramm nutzen kannst, z.B. für abweisende Schleifen. ...
Bei meiner Version hättest Du eine LED voll an, die dann schwächer wird, während die andere entsprechend heller wird. Am Ende ist die LED, die am Anfang eingeschaltet war, aus und die andere leuchtet mit 100%. Und genau das ist dann doch genau der Farbverlauf, den Du brauchst, um von 100% blau über lila (z.B. 50% rot und 50% blau) nach 100% rot zu dimmen... Oder hab ich Dein Vorhaben falsch verstanden?
jain... wenn es nicht viel aufwändiger ist würde ich gerne Lila bei 100% rot und 100% blau wegen der Helligkeit (2x100% ist heller als 2x50%). 1.Zeile Rot 2. Blau 3. beide zusammen 0% rot --dimmt hoch-100%rot/// bleibt so-100%rot ///bleibt so-100%r 100% blau--beibt so---100blau///dimmt runter-0%blau///dimmt ho100 BLAU-------------------LILA ///LILA-----------ROT ///
50% PWM ist nicht 50% Helligkeit... ;-) Daher kommt Johnnys Vorschlag Deinem Wunsch schon etwas entgegen. Aber mit einzeln ansteuerbarer mehrfach-PWM bist Du natürlich bedeutend flexibler. Ob das in BASCOM schnell genug realisierbar ist, ist natürlich eine andere Frage. Wir hatten hier kürzlich erst das Thema 8-Kanal-Software-PWM und Anbindung eines LCD, aber das wurde in Assembler realisiert. ...
Ich dachte ich hätte PWM verstanden ?! wieso ist 50% PWM nicht auch 50% helligkeit? Bei 50% ist die LED doch genauso lange an wie aus oder? und dann müsste die doch auch bei hälfte an hälfte aus halbe helligkeit haben...? Aber wenn nicht ist doch 2x 100% heller als 2x 50% oder auch nicht?
> wieso ist 50% PWM nicht auch 50% helligkeit?
Objektiv ja, subjektiv aber nicht weil Dein Auge da anderer Meinung
ist.
...
Ohr und Auge des Menschen folgen einer eher logarithmischen Kennlinie. Beim Auge kommt noch Trägheit hinzu.
Ich meinte z.B. Timer Overflow 31250 Hz (Teiler x1 bei 8MHz Taktfrequenz), dann eine Variable auf 256 hochzählen und bei einem bestimmten Wert den Pin auf '1', anschließend Pin auf '0'. Das gibt einen PWM mit ca. 122 Hz.
Hallo, ich dachte ein Film hat 25 Bilter pro sekunde und darum hab ich versucht meine Variable 25 mal pro sekunde um 1 zu erhöhen. Aber da ist irgendwo der wurm drin... 'PWM über Zähler '----------------------------------------------------------------------- -------- 'Konfiguration µC: $regfile = "2313def.dat" 'AT90S2313-Deklarationen $crystal = 3686400 'Quarz: 3.6864 MHz '----------------------------------------------------------------------- -------- '----------------------------------------------------------------------- -------- 'Variablen '----------------------------------------------------------------------- -------- Dim Sollwert As Byte Dim Zähler0 As Byte '----------------------------------------------------------------------- -------- ' Ein- und Ausgänge '----------------------------------------------------------------------- -------- 'Pin Eingang/Ausgang 1 Portd. 0 = 1 'Ausgang LED1 Portd. 1 = 1 'Ausgang LED2 '----------------------------------------------------------------------- -------- Config Timer0 = Timer , Prescale = 64 '3686400/64/100=576Hz Enable Timer0 Timer0 = 155 'Starte bei 155 Enable Interrupts 'erlaube Interrupts On Timer0 Ontimer0overflow 'Timer0-Interruptroutine deklarieren '----------------------------------------------------------------------- -------- 'Hauptprogramm '----------------------------------------------------------------------- -------- If Sollwert < Zähler0 Then Portd.0 = 1 Else Portd.0 = 0 End If '----------------------------------------------------------------------- -------- 'Sprungmarken '----------------------------------------------------------------------- -------- Ontimer0overflow: 'Timer0-Interruptroutine Incr Zähler0 Return
hab noch etwas vergessen als Sollwerte wollte ich 100 nehmen. 100 = 100% Einschaltdauer ;-) Tobias
Also das Programm im Anhang macht eine 8-Kanal-PWM auf dem Mega8515 mit 8MHz intern mit einer PWM-Frequenz von etwa 860Hz und gibt die PWM-Sollwerte der 8 Kanäle auf einem LCD 2x16 in % aus. Es ist in ASM geschrieben. Es ist allerdings noch nicht aufgeräumt, es wurde aus anderen Programmen zusammenkopiert. Es ist auch nicht für ein ernsthaftes Projekt gemacht worden, sondern nur als Demonstration, wie man es machen könnte. Vielleicht hilft ja die Analyse beim Verständnis der Dinge. ...
Also die led blinkt langsam ... das hat aber noch nichts mit dimmen zu tun... hat da jemand eine idee??? ich habe zum testen mal ein lcd angeschlossen 'PWM über Zähler '----------------------------------------------------------------------- -------- 'Konfiguration µC: $regfile = "2313def.dat" 'AT90S2313-Deklarationen $crystal = 3686400 'Quarz: 3.6864 MHz '----------------------------------------------------------------------- -------- '----------------------------------------------------------------------- -------- 'Variablen '----------------------------------------------------------------------- -------- Dim Zähler1 As Byte Dim Zähler11 As Byte Dim Zähler2 As Byte Dim Zähler1merker As Bit Dim Zähler11merker As Byte Dim Zähler2merker As Bit '----------------------------------------------------------------------- -------- ' Ein- und Ausgänge '----------------------------------------------------------------------- -------- 'Pin Eingang/Ausgang 1 'Ddrd = &B0000011 'Ausgang LED1&2 Ddrd = &B1011011 Portd. 0 = 1 Portd. 3 = 1 Portd. 4 = 1 '----------------------------------------------------------------------- -------- Config Timer0 = Timer , Prescale = 1 '3686400/1024/101 = 35,644Hz Enable Timer0 Timer0 = 155 'Starte bei 155 Enable Interrupts 'erlaube Interrupts On Timer0 Ontimer0overflow 'Timer0-Interruptroutine deklarieren '======================================================================= ======== ' LCD Parametrieren '======================================================================= ======== Dim Sresult As String * 40 At &H64 Overlay Config Lcd = 40 * 2 Config Lcdpin = Pin , Db4 = Portb.4 , Db5 = Portb.3 , Db6 = Portb.2 , Db7 = Portb.1 , E = Portd.6 , Rs = Portb.0 Cls 'Cursor Off Noblink '----------------------------------------------------------------------- -------- 'Hauptprogramm '----------------------------------------------------------------------- -------- Do cls Lcd "Z 1: " Lcd Zähler1 Lcd " Z 11: " Lcd Zähler11 If Zähler1 < Zähler11 Then 'richtig Portd.0 = 1 Else Portd.0 = 0 End If Loop '----------------------------------------------------------------------- -------- 'Sprungmarken '----------------------------------------------------------------------- -------- Ontimer0overflow: 'Timer0-Interruptroutine If Zähler1 > 50 Then Zähler1merker = 1 End If If Zähler1 < 1 Then Zähler1merker = 0 End If If Zähler1merker = 0 Then Incr Zähler1 'um 1 hochzählen Else Decr Zähler1 'um 1 runterzählen End If '-- If Zähler11 > 100 Then Zähler11merker = 1 End If If Zähler11 < 1 Then Zähler11merker = 0 End If If Zähler11merker = 0 And Zähler1 = 25then Incr Zähler11 'um 1 hochzählen Else Decr Zähler11 'um 1 runterzählen End If Return
also es läuft ABER viel zu langsam led blinkt und wird nicht gedimmt obwohl der Timer mit Quarztakt läuft!!! 'PWM über Zähler '----------------------------------------------------------------------- -------- 'Konfiguration µC: $regfile = "2313def.dat" 'AT90S2313-Deklarationen $crystal = 3686400 'Quarz: 3.6864 MHz '----------------------------------------------------------------------- -------- '----------------------------------------------------------------------- -------- 'Variablen '----------------------------------------------------------------------- -------- Dim Zähler1 As Byte Dim Zähler11 As Long Dim Zähler2 As Byte Dim Zähler11merker As Byte '----------------------------------------------------------------------- -------- ' Ein- und Ausgänge '----------------------------------------------------------------------- -------- 'Pin Eingang/Ausgang 1024 'Ddrd = &B0000011 'Ausgang LED1&2 Ddrd = &B1011011 Portd. 0 = 1 Portd. 3 = 1 Portd. 4 = 1 '----------------------------------------------------------------------- -------- Config Timer1 = Timer , Prescale = 1 '3686400/1024/101 = 35,644Hz Enable Timer1 Timer1 = 65534 'Starte bei 155 Enable Interrupts 'erlaube Interrupts On Timer1 Ontimer1overflow 'Timer1-Interruptroutine deklarieren '======================================================================= ======== ' LCD Parametrieren '======================================================================= ======== Dim Sresult As String * 40 At &H64 Overlay Config Lcd = 40 * 2 Config Lcdpin = Pin , Db4 = Portb.4 , Db5 = Portb.3 , Db6 = Portb.2 , Db7 = Portb.1 , E = Portd.6 , Rs = Portb.0 Cls 'Cursor Off Noblink '----------------------------------------------------------------------- -------- 'Hauptprogramm '----------------------------------------------------------------------- -------- Do cls Lcd "Z 1: " Lcd Zähler1 Lcd " Z 11: " Lcd Zähler11 If Zähler1 < Zähler11 Then Portd.0 = 1 Else Portd.0 = 0 End If Loop '----------------------------------------------------------------------- -------- 'Sprungmarken '----------------------------------------------------------------------- -------- Ontimer1overflow: 'Timer0-Interruptroutine 'Zähler 1 von 0 - 100 SCHNELL!!! Incr Zähler1 'um 1 hochzählen If Zähler1 = 20 Then Zähler1 = 0 End If 'Zähler 11 von 0 - 100 langsam If Zähler11 = 20 Then Zähler11merker = 1 End If If Zähler11 = 1 Then Zähler11merker = 0 End If If Zähler11merker = 0 And Zähler1 = 0 Then Incr Zähler11 'um 1 hochzählen End If If Zähler11merker = 1 And Zähler1 = 0 Then Decr Zähler11 'um 1 runterzählen End If Return
Du hast in Deiner Timer-ISR kein Timer-Reload. Der Timer braucht daher (außer beim ersten mal) immer 65536 Takte bis zum Überlauf. :-( Bei Verwendung des 16-Bit-Timers bietet sich der Compare-Interrupt mit CTC-Mode an, da wird der Timer beim Erreichen des Compare-Register-Wertes auf 0 gesetzt und der Interrupt ausgelöst. Wenn es unbedingt der Überlauf-Interrupt sein soll, dann nimm doch den 8-Bit-Timer, da geht Reload schneller weil nur 8 Bit erforderlich ist. ...
timer reload? also in der unterroutine einfach "Timer0 = xxx" gleicher wert wie in der configuration? >Wenn es unbedingt der Überlauf-Interrupt sein soll, dann nimm doch >den 8-Bit-Timer, da geht Reload schneller weil nur 8 Bit >erforderlich ist. Welchen Interrups würdes du empfehlen? gibt es einen der schneller/öfter kommt als der Überlauf-Interrupt? Tobias P.S. die LED blinkt immer noch...:-( 'PWM über Zähler '----------------------------------------------------------------------- -------- 'Konfiguration µC: $regfile = "2313def.dat" 'AT90S2313-Deklarationen $crystal = 3686400 'Quarz: 3.6864 MHz '----------------------------------------------------------------------- -------- '----------------------------------------------------------------------- -------- 'Variablen '----------------------------------------------------------------------- -------- Dim Zähler1 As Byte Dim Zähler11 As Byte Dim Zähler2 As Byte Dim Zähler11merker As Byte '----------------------------------------------------------------------- -------- ' Ein- und Ausgänge '----------------------------------------------------------------------- -------- 'Pin Eingang/Ausgang 1024 'Ddrd = &B0000011 'Ausgang LED1&2 Ddrd = &B1011011 Portd. 0 = 1 Portd. 3 = 1 Portd. 4 = 1 '----------------------------------------------------------------------- -------- Config Timer0 = Timer , Prescale = 8 '3686400/1024/101 = 35,644Hz Enable Timer0 Timer0 = 219 'Starte bei 155 Enable Interrupts 'erlaube Interrupts On Timer0 Ontimer0overflow 'Timer0-Interruptroutine deklarieren '======================================================================= ======== ' LCD Parametrieren '======================================================================= ======== Dim Sresult As String * 40 At &H64 Overlay Config Lcd = 40 * 2 Config Lcdpin = Pin , Db4 = Portb.4 , Db5 = Portb.3 , Db6 = Portb.2 , Db7 = Portb.1 , E = Portd.6 , Rs = Portb.0 Cls 'Cursor Off Noblink '----------------------------------------------------------------------- -------- 'Hauptprogramm '----------------------------------------------------------------------- -------- Do Cls Lcd "Z 1: " Lcd Zähler1 Lcd " Z 11: " Lcd Zähler11 If Zähler1 < Zähler11 Then 'richtig Portd.0 = 1 Else Portd.0 = 0 End If Loop '----------------------------------------------------------------------- -------- 'Sprungmarken '----------------------------------------------------------------------- -------- Ontimer0overflow: 'Timer0-Interruptroutine Timer0 = 219 'Zähler 1 von 0 - 100 SCHNELL!!! Incr Zähler1 'um 1 hochzählen If Zähler1 = 99 Then Zähler1 = 0 End If 'Zähler 11 Von 0 - 100 Langsam!!! If Zähler11 = 99 Then Zähler11merker = 1 End If If Zähler11 = 1 Then Zähler11merker = 0 End If If Zähler11merker = 0 And Zähler1 = 0 Then Incr Zähler11 'um 1 hochzählen End If If Zähler11merker = 1 And Zähler1 = 0 Then Decr Zähler11 'um 1 runterzählen End If Return
> Welchen Interrups würdes du empfehlen? gibt es einen der > schneller/öfter kommt als der Überlauf-Interrupt? Wie schnell/oft ein Timer-Interrupt "kommt", bestimmt einzig und allein der Programmierer. Dabei muss er natürlich die vorhandenen Ressourcen im Auge behalten. Er kann einen Interrupt, der 300 Takte dauert, nicht alle 100 Takte aufrufen wollen, denn da ist der Interrupt ja noch nicht fertig. Also ist das erste Gebot: Interrupt-Service-Routinen so kurz wie möglich halten. Dann kannst Du ermitteln, wie lange (wieviele Takte) die ISR dauert. Daraus kannst Du dann ableiten, wie oft Du den Timer maximal einen Interrupt auslösen lassen darfst. Nun meinst Du sicherlich, dass es Dir schwerfällt das in BASCOM zu ermitteln. Da hast Du recht, deshalb verschmähe ich ja auch BASCOM und programmiere in ASM, da ist der Umgang mit der Hardware nämlich völlig durchschaubar. Da Eiert man nicht rum, sondern sieht, was man macht. Bei einer Software-PWM, deren Frequenz möglichst hoch sein soll, ist es unabdingbar, die ISR extrem kurz zu halten. Denn sie soll ja möglichst oft aufgerufen werden. Wie oft das geht, hängt von der Effizienz der Programmierung ab. Kann ich es mir leisten, in der ISR mit Exklusivregistern zu arbeiten, so erspare ich mir das Sichern und Wiederherstellen der Inhalte der benutzten Register. Das ist in ASM kein Problem, in BASCOM geht der Eiertanz aber los, den BASCOM sichert gleich mal ungefragt in der ISR alle Register, was schonmal 128 Takte kostet und 32 Bytes Stack. Die Timer-ISR in meinem ASM-Beispiel dauert weniger als 60 Takte (geschätzt, jetzt wegen Faulheit nicht nachgezählt), da würden die 128 Takte Registersicherung sich schon arg auswirken. In diesen 60 Takten ist dann neben der Sicherung des SREG, Timer-Reload, PWM-Erzeugung für 8 Kanäle auch noch die Entprellung von 8 Tastern mit drin. Welchen Interrupt ich empfehlen würde, hängt davon ab, was der AVR für Interrupts hat und was er sonst noch tun muss. Beim AT90S2313 gibt es Timer0 mit Überlauf und Timer 1 mit Überlauf, CompA, CompB und ICP. Jetzt kommt es auch noch darauf an, inwieweit man das Datenblatt verstanden hat und mit den vorhandenen Features umgehen kann. Meine ersten Programme nutzten daher erstmal nur den Überlauf-Interrupt des Timer0. Dieser ist nämlich sehr einfach, gut zu verstehen, und hat keine zusätzlichen Features, die man falsch interpretieren könnte. Man setzt (auch in der ISR!) der Timer auf einen Startwert (Reload) und lässt ihn bis zum Überlauf klappern. Da Timer0 nur 8 Bit breit ist, genügt zum Reload ein einziger OUT-Befehl, wenn man den Reload-Wert in einem Exklusivregister vorhält. Beim 16-Bit Timer sind das schon 2 Out-Befehle und 2 blockierte Register. Das würde ich nur opfern, wenn ich die 16 Bit des Timer1 wirklich brauche. Wenn ich aber weiß, dass ich keines der weiteren Features des Timer1 brauchen werde, dann kann ich den Compare-Interrupt des Timer1 verwenden. Der lässt sich nämlich mit dem CTC-Bit bei jedem Interrupt automatisch löschen, was das Timer-Reload (Zeit in der ISR) spart. Natürlich geht dabei die Möglichkeit verloren, gleichzeitig die anderen Features des Timer1 zu nutzen, die man aber auch nicht immer braucht. Mit dem Compare-Interrupt im CTC-Mode sparst Du also das Timer-Reload. - Das ist in ASM ein großer Gewinn, zwei Takte eingespart, zwei Takte schnellere ISR, bei 50 Takten 4% Performance-Gewinn... In BASCOM ist das in Anbetracht der 120 Takte Registersicherung ein lächerlicher Gewinn, den man unterm Strich nicht sieht... Du hast nun die Möglichkeit, weiter mit dem Baukasten BASCOM vorgefertigte Routinen zu Programmen zusammenzustellen und Dich über den schnellen Erfolg freuen. Oder Du beschäftigst Dich mit dem Datenblatt und dem ASM-Befehlssatz und lernst, effiziente Programme zu schreiben. Der BASCOM-Weg ist der leichtere, führt aber in die Sackgasse. Hardwarenahe effiziente Programme sind damit nicht (oder nur mit extrem viel Hintergrundwissen in BASIC und Assembler) möglich. ...
Vielen Dank für den ausfürlichen Beitrag! Also als erstes werde ich den Quarz von 4 auf 8 MHz erhöhen ;-)) und dann versuche ich die ISR zu kürzen...denn der µC soll noch etwas anderes machen auser die 2 LED´s dimmen! und zum schluss noch der Befehl "NOSAVE"? Tobias
Also ich komme nicht weiter. Hat jemand einen Vorschlag wie ich die LED schneller bekomme? Das einfach viel zu langsam! Wenn ich die Version von johnny.m nehme habe ich dann auch das Problem das die "PWM" zulansam ist?: johnny.m: Oder mit 2 Interrupts: Im Compare-Interrupt-Handler wird die eine LED jeweils ein- und die andere ausgeschaltet, im Overflow-Interrupt-Handler umgekehrt. Wenn man den Compare-Wert jetzt kontinuierlich ändert, bekommt die eine LED mehr und die andere weniger Saft ab.
Hallo, dein Interrupt muss doch nur alle 39µs kommen bei 8Bit Aufloesung des PWM, somit ergibt sich eine PWM Grundfreq. von 100Hz. ISR If Zähler = 0 Then PORTB = 0 End If If Zähler = PWMWERT0 and Zähler > 0 Then PORTB.0 = 1 End If If Zähler = PWMWERT1 and Zähler > 0 Then PORTB.1 = 1 End If END ISR. Oder hab ich irgendetwas verpasst. Gruß, Dirk
Du hast zwei Compare-Interrupts. In Verbindung mit dem Overflow-Interrupt kannst Du den Zählumfang begrenzen. Du müsstest dazu - im Overflow-Interrupt den Timer auf einen Wert 65536 minus Anzahl der gewünschten Takte voreinstellen und beide Ausgänge einschalten. (Der Timer klappert also immer nur die letzten Takte bis zum Überlauf) - im CompareA-Interrupt den Ausgang 1 ausschalten und den (evtl. neuen) PWM-Wert aus einer Variable in des CompareA-Register schreiben. - im CompareB-Interrupt den Ausgang 2 ausschalten und den PWM-Wert in das CompareB-Register schreiben. - in der Mainloop die PWM-Werte in Deinen Variablen ggf verändern. Somit kann Dein Timer1 langsamer laufen, denn er löst nur dann einen Interrupt aus, wenn eine Schalthandlung vorzunehmen ist, also nur drei Interrupts pro PWM-Periode (aber drei verschiedene). Du möchtest bei 4MHz Quarz einen PWM-Zählumfang von 100 (100%) realisieren. Also muss der Zählumfang des Timers auf die letzten 100 Takte begrenzt werden. Dir stehen dazu Vorteiler von 1, 8, 64, 256 und 1024 zur Verfügung. Damit könntest Du folgende PWM-Frequenzen erreichen: - VT 1: 4000000/100/1 = 40kHz (zu schnell, nicht genug Zeit für 3 ISRs) - VT 8: 4000000/100/8 = 5kHz (knapp, 800 Takte für 3 ISRs) - VT 64: 4000000/100/64 = 625Hz (besser, 6400 Takte für 3 ISRs) - VT 256: 4000000/100/256 = 156Hz (noch ok, 25600 Takte für 3 ISRs) - VT 1024: 4000000/100/1024 = 39Hz (zu langsam) Ich würde es zuerst mit Vorteiler 64 versuchen und bei Timing-Problemen auf 256 umstellen. Gehen wir erstmal von 64 aus: Alle 6400 Takte löst der Overflow-Interrupt aus. Dort wird: - Timer1 auf 65536-100 gesetzt, - Ausgang 1 und 2 eingeschaltet, falls deren PWM-Wert nicht 0 ist. Bei Timerstand 65436 + n wird ein Compare-Interrupt ausgelöst. n steht hierbei für den Tastgrad (0..99) der PWM (PWM-Wert der LED). Dies geschieht im Raster von 64 Takten, aber nur zweimal (einmal pro Kanal) innerhalb 6400 Takten. Die dabei auftretenden Verzögerungen der anderen ISR-Abarbeitungen relativieren sich, Du willst ja schließlich kein TV-Synchronsignal generieren, sondern nur zwei LEDs dimmen. In der jeweiligen Compare-ISR (Compare1A und Compare1B) wird: - die betreffende LED ausgeschaltet, - auf den Timer-Startwert von 65436 der Tastgrad-Wert (0..99) aufaddiert und ins entsprechende Compare-Register geschrieben. Ein "nosave" sollte nicht nötig sein, wenn doch, dann musst Du das SREG und die in der ISR verwendeten Register von Hand sichern. Damit kannst Du auch schnelleen Code realisieren, brauchst aber etwas ASM-Wissen. Ich denke, Dein Projekt mit nur zwei LEDs ist auch in BASCOM gut realisierbar, bei drei LEDs wird es aber mangels dritter Compare-Einheit verdammt eng... ...
> Hallo, dein Interrupt muss doch nur alle 39µs kommen bei 8Bit > Aufloesung des PWM, somit ergibt sich eine PWM Grundfreq. von 100Hz. > ... > Oder hab ich irgendetwas verpasst. Er will ja keine 8-Bit-PWM, sondern nur 100 Schritte, damit der Tastgrad-Wert in Prozent angegeben werden kann. 100Hz für LEDs empfinden viele Leute schon als flackernd. ...
Hallo, sorry das ich diese Frage stelle, aber ich hab gestern abend das Forum nach dem Thread durchsucht und leider nicht gefunden. Ich glaube die Antwort die ich suche war von Dir ...Hannes... und zwar ging es um asynchrone PWM. Du hattest auch ein Windows Programm gepostet. Weisst du noch wie der Thread hieß? oder kann man deine Aussagen woanders nach lesen? Gruß, Dirk
> ging es um asynchrone PWM. Das war mit Sicherheit nicht von mir. Denn als ich mich zum ersten mal mit PWM beschäftigte, wusste ich noch nicht, wie asynchrone PWM arbeitet und wie sie funktioniert. Es war mir damals auc sehr wichtig, dass die PWM synchron war, denn mein erstes PWM-Projekt war ein Modellbahn-Fahrtregler, bei dem die PWMs synchronisiert sein mussten, um beim Übergang von einem Fahrstromabschnitt auf den anderen keine Sprünge zu haben (60% und 50% bei gleicher Phasenlage bleiben 60%, bei unterschiedlicher Phasenlage können daraus schon mal unerwünschte 100% werden). Die Asynchrone PWM erfolgt durch Addieren der PWM-Sollwerte zu den PWM-Zählern (jeder Kanal hat seinen eigenen Zähler) und Auswerten des Carry-Flags. Dabei wird nach jeder Addition das Carry mittels ROR oder ROL in ein Register geschoben, welches nach den 8 Additonen (und Rotierungen) an den Port ausgegeben wird. Dies geht zwar in einer Schleife, ist aber ohne Schleife bedeutend schneller (keine bedingten Sprungbefehle). Der Vorteil der asynchronen PWM liegt in der Verteilung der Strom-Belastung, es schalten also nicht alle LEDs zum gleichen Zeitpunkt ein. Um den Thread zu finden, könntest Du nach Einsammeln und Carry suchen, das habe ich (glaube) dazu geschrieben... ;-) Hier könntest Du also fündig werden: http://www.mikrocontroller.net/forum/forum.php?query=%2Bcarry*+%2Beinsammeln&forums%5B%5D=1&number=20&action=sendsearch ...
Hallo, ich hab nun noch ein Programm gefunden. Die 3 LED´s haben aber feste werte! Nun habe ich versucht mit timer1 über die variable "LED" die LED B hochlaufen zu lassen und bei 255 auf 0 zu setzen. Muss ich dafür einen 2. Timer benutzen oder wie würdet ihr das machen? ' PULS WEITEN MODULATION (PWM) ' Sprache: Bascom AVR-Basic (Demoversion 1.11.6.2) ' Getestet mit 8 MHz auf 90S2333.Ausgabewert wird dann ca. 121 mal pro Sekunde ' erneuert. ' 3 Kanäle an Port B0, B1, B2 ' Bewust einfaches Programm zur Erklärung wie eine Software PWM funktionieren kann. ' Timerinterupt, der in gleichmäßigen Abständen ' das Hauptprogramm unterbricht und ein Unterprogramm (Interupthandler) aufruft ' das die Ausgänge ein oder ausschaltet. Im Mittel ergibt sich dann der gewünschte ' Ausgabewert (Normale Multimeter sind langsam genug d.h. der Ausgabewert kann ' für Testzwecke direkt am Pin gemessen werden) ' Sept. 2002 Bernhard T. 'Konfiguration µC: $regfile = "2313def.dat" 'AT90S2313-Deklarationen $crystal = 8000000 'Quarz: 8 MHz 'Timer konfigurieren, Vorteiler auf 1 ist gut fürs Simulieren (evtl. anpassen, dann aber ausgang mit R-C Tiefpass) Config Timer0 = Timer , Prescale = 1 Config Timer1 = Timer , Prescale = 8 Enable Timer1 On Timer1 Prog 'Definiere den Interrupthandler On Ovf0 Tim0_isr 'Wichtig: Config Pinb.0 = Output 'Port B = Ausgang Config Pinb.1 = Output Config Pinb.2 = Output Enable Timer0 'timer einschalten Enable Interrupts 'interrupts einschalten Dim R As Byte ' In diese Variablen muss man Dim G As Byte ' im Hauptprogram die gewünschten Dim B As Byte ' Ausgabewerte laden Dim Z As Word 'Byte ' Zähler Dim Ri As Byte ' Hilfsregister Dim Gi As Byte Dim Bi As Byte Dim Led As Byte Z = 0 Do 'your program goes here 'Bsp.: R = 51 ' bei Ub= 5V ca. 1Volt G = 102 ' ca. 2V B = 1 + Led ' 5V/256 = 0.01953125 V Soll 'R = 255 'G = 255 'B = 255 'Schleife: 'Goto Schleife Loop 'Interupthandler, wird bei jedem Timerüberlauf(bei 8 MHz und Vorteiler=1 alle 32 µSec.) 'aufgerufen: Tim0_isr: If Z = 0 Then 'Gewünschte Ausgabewerte an Ri = R 'Hilfsregister übergeben Gi = G Bi = B Z = 255 End If Z = Z - 1 If Ri > 0 Then 'R > Port B.0 Portb.0 = 1 'bei R = 51 wird hier Else 'Port B.0 51 mal auf 1 Portb.0 = 0 'und 205 mal auf 0 geschaltet End If 'das ergibt bei 5V Ub im Mittel Ri = Ri - 1 ' ca. 1 V If Ri = 255 Then Ri = 0 If Gi > 0 Then 'G > Port B.1 Portb.1 = 1 Else Portb.1 = 0 End If Gi = Gi - 1 If Gi = 255 Then Gi = 0 If Bi > 0 Then Portb.2 = 1 'B > Port B.2 Else Portb.2 = 0 End If Bi = Bi - 1 If Bi = 255 Then Bi = 0 ' Hier könnten eigentlich noch weitere Kanäle eingefügt werden Return Prog: Timer1 = 25536 Incr Led If Led > 255 Then Led = 0 End If Return
so nun dimmen die LED´s beide - gut. nur wenn die LED 100% erreicht hat geht sie kurz aus und wieder an und dimmt erst dann wieder runten? Kann mir jemand sagen warum die LED kurz aus geht?! ________________________ ' PULS WEITEN MODULATION (PWM) ' Sprache: Bascom AVR-Basic (Demoversion 1.11.6.2) ' Getestet mit 8 MHz auf 90S2333.Ausgabewert wird dann ca. 121 mal pro Sekunde ' erneuert. ' 3 Kanäle an Port B0, B1, B2 ' Bewust einfaches Programm zur Erklärung wie eine Software PWM funktionieren kann. ' Timerinterupt, der in gleichmäßigen Abständen ' das Hauptprogramm unterbricht und ein Unterprogramm (Interupthandler) aufruft ' das die Ausgänge ein oder ausschaltet. Im Mittel ergibt sich dann der gewünschte ' Ausgabewert (Normale Multimeter sind langsam genug d.h. der Ausgabewert kann ' für Testzwecke direkt am Pin gemessen werden) ' Sept. 2002 Bernhard T. 'Konfiguration µC: $regfile = "2313def.dat" 'AT90S2313-Deklarationen $crystal = 8000000 'Quarz: 8 MHz 'Timer konfigurieren, Vorteiler auf 1 ist gut fürs Simulieren (evtl. anpassen, dann aber ausgang mit R-C Tiefpass) Config Timer0 = Timer , Prescale = 1 Config Timer1 = Timer , Prescale = 8 Enable Timer1 On Timer1 Prog 'Definiere den Interrupthandler On Ovf0 Tim0_isr 'Wichtig: Config Pinb.0 = Output 'Port B = Ausgang Config Pinb.1 = Output Config Pinb.2 = Output Enable Timer0 'timer einschalten Enable Interrupts 'interrupts einschalten Dim R As Byte ' In diese Variablen muss man Dim G As Byte ' im Hauptprogram die gewünschten Dim B As Byte ' Ausgabewerte laden Dim Z As Word 'Byte ' Zähler Dim Ri As Byte ' Hilfsregister Dim Gi As Byte Dim Bi As Byte Dim Led1 As Byte Dim Led1m As Byte Dim Led2 As Byte Dim Led2m As Byte Z = 0 Led1 = 255 Do 'your program goes here 'Bsp.: R = 1 + Led2 ' bei Ub= 5V ca. 1Volt G = 102 ' ca. 2V B = 1 + Led1 ' 5V/256 = 0.01953125 V Soll 'R = 255 'G = 255 'B = 255 'Schleife: 'Goto Schleife Loop 'Interupthandler, wird bei jedem Timerüberlauf(bei 8 MHz und Vorteiler=1 alle 32 µSec.) 'aufgerufen: Tim0_isr: If Z = 0 Then 'Gewünschte Ausgabewerte an Ri = R 'Hilfsregister übergeben Gi = G Bi = B Z = 255 End If Z = Z - 1 If Ri > 0 Then 'R > Port B.0 Portb.0 = 1 'bei R = 51 wird hier Else 'Port B.0 51 mal auf 1 Portb.0 = 0 'und 205 mal auf 0 geschaltet End If 'das ergibt bei 5V Ub im Mittel Ri = Ri - 1 ' ca. 1 V If Ri = 255 Then Ri = 0 If Gi > 0 Then 'G > Port B.1 Portb.1 = 1 Else Portb.1 = 0 End If Gi = Gi - 1 If Gi = 255 Then Gi = 0 If Bi > 0 Then Portb.2 = 1 'B > Port B.2 Else Portb.2 = 0 End If Bi = Bi - 1 If Bi = 255 Then Bi = 0 ' Hier könnten eigentlich noch weitere Kanäle eingefügt werden Return Prog: Timer1 = 25536 If Led1 = 255 Then Led1m = 0 End If If Led1 = 0 Then Led1m = 1 End If 'Zähler1 hoch/runter If Led1m = 1 Then Incr Led1 'um 1 hochzählen End If If Led1m = 0 Then Decr Led1 'um 1 runterzählen End If '------- If Led2 = 255 Then Led2m = 0 End If If Led2 = 0 Then Led2m = 1 End If 'Zähler1 hoch/runter If Led2m = 1 Then Incr Led2 'um 1 hochzählen End If If Led2m = 0 Then Decr Led2 'um 1 runterzählen End If Return
> vielen dank für eure intensive Mithilfe!!!
Sorry, ich war nicht da. Manchmal habe ich auch Anderes zu tun und bin
dann nicht online.
...
??? das war ernst gemeint und nicht ironisch! Außerdem hast doch gerade du am meisten geschrieben / geholfen! Tobias
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.