Hallo zusammen,
ich habe mit dem 8Bit Timer/Counter0 des AtMega16 ein PWM-Signal
erzeugt. Das funktioniert wunderbar. Ich habe den Timer initialisiert
und in auf Phase Correct PWM eingestellt. Er generiert nun am OC0-Pin
das richtige Signal und ein Voltmeter zeigt mir je nach Wert im
OCR-Register ca 0,2 bis 5V an. Eine LED leuchtet dann auch, je nach
Einstellung, unterschiedlich hell.
Ich betreibe den AVR mit 4Mhz, wenn ich den Prescaler auf 1024 einstelle
blinkt die LED schon sichtbar, bei "No Prescaling" leuchtet sie schön
dauerhaft, was ja auch logisch ist.
Ich würde diese LED aber gerne per Programmaufruf dimmen, also immer von
00 bis ff und umgekehrt den Wert im OCR ändern. Im Timing-Diagramm des
Datenblatts steht, dass man den OCR-Wert immer bei Zählerstand ff
updaten soll. Wie soll denn das gehen? Der Compare-Interrupt sorgt ja
für das umschalten des Pins, und der Overflow-Interrupt wird ja in
diesem Modus bei Bottom ausgelöst und eben nicht bei Top.
Ich hab mir gedacht: Egal, wertest halt mal den Overflow-Interrupt aus,
aber nicht mal das funktioniert. Im Simulator ruft er einfach die ISR
nicht auf und im Controller natürlich auch nicht.
Das Programm dazu
warum funktioniert das nicht?
Gibt es eine Möglichkeit, an diesen Top-Zustand ranzukommen, um eben OCR
upzudaten, wanns genau sein muss?
Es wäre auch nett, wenn ihr mir sagen könntet, mit welchen Werten ich
die Register laden muss, um einen sichtbaren Dimmvorgang erzeugen zu
können.
Frohe Kunde:
The OCR0 Register is double buffered when using any of the Pulse Width
Modulation(PWM) modes. For the normal and Clear Timer on Compare (CTC)
modes of operation,the double buffering is disabled. The double
buffering synchronizes the update of the OCR0 Compare Register to either
top or bottom of the counting sequence. The synchro-nization prevents
the occurrence of odd-length, non-symmetrical PWM pulses, thereby making
the output glitch-free.The OCR0 Register access may seem complex, but
this is not case. When the double buffering is enabled, the CPU has
access to the OCR0 Buffer Register, and if double buffering is disabled
the CPU will access the OCR0 directly.
Also einfach reinschreiben, Wert wird erst bei TOP übernommen!
Nee, sorry. keine Ahnung.
Sowohl "Timer/Counter0 Output Compare Match Interrupt" als auch
"Timer/Counter0 Overflow Interrupt" sollten eigentlich funktionieren...
Mit dem Overflow Interrupt funktioniert das zwar, aber nicht wirklich
zufriedenstellend.
Der updatet das dann halt bei bottom und eben nicht bei Top, würde der
andere Interrupt gehen, wäre das kein Problem.
Könnte jemand bitte meinen Quelltext mal im Simulator ausprobieren und
mir dann sagen, warum der Interrupt nicht ausgelöst wird?
> Könnte jemand bitte meinen Quelltext mal im Simulator ausprobieren und> mir dann sagen, warum der Interrupt nicht ausgelöst wird?
Der Simulator hat so seine Schwierigkeiten mit den Timern.
Besonders in den PWM Modi funktioniert da bei weitem nicht
alles so wie es sein soll.
Du brauchst aber auch keinen Interrupt um OCR neu zu beschreiben.
Je nach eingestelltem PWM und Pin Umschaltmodus macht sich
das die CPU selbst, so dass ein korrekter Update erfolgt.
> Der updatet das dann halt bei bottom und eben nicht bei Top,> würde der andere Interrupt gehen, wäre das kein Problem.
Selbst dann würde der Update erst bei Bottom erfolgen.
Das ist ja gerade der Sinn der Sache eines phase korrektem
PWM
Ja. Aber für einen Dimmvorgang muss ich nun mal das OCR Register von 0
nach 255 bzw andersherum erhöhen, bzw erniedrigen.
Theorethisch kann man das klar ohne Interrupt machen, geht halt
wahnsinnig Zeit drauf, in welcher der Controller außer für Interrupts
nicht empfänglich ist.
Der Compare Match Interrupt funktioniert sowohl in AVR Studio als auch
im Controller selbst. Der OV bei beiden nicht. Das mag ein Bug sein im
studio, jedoch funktioniert der auch im Controller nicht.
In der Simulation wird der Timer auch immer pro Schritt um 2 verändert,
sodass 00 übersprungen wird. Aber im Controller dürfte das doch nichzt
passieren, oder?
Florian Glaser wrote:
> Ja. Aber für einen Dimmvorgang muss ich nun mal das OCR Register von 0> nach 255 bzw andersherum erhöhen, bzw erniedrigen.
Und?
Was hindert dich daran das zu tun?
>> Theorethisch kann man das klar ohne Interrupt machen, geht halt> wahnsinnig Zeit drauf, in welcher der Controller außer für Interrupts> nicht empfänglich ist.
Quatsch.
Du weist dem OCR Register den Wert zu den du haben willst.
Fertig.
Mit welcher Frequenz willst du den die PWM von 0 bis 255
durchdimmen? Du wirst doch nicht bei jedem PWM Durchlauf
einen neuen OCR Wert setzen wollen, oder doch?
Okey, das versteh ich. Ich initialisiere also meinetwegegen mit 00 und
weiße dem dann einfach einen neuen Wert zu, um ihn zu dimmen.
Korrekt?
Ich sehe nur nix vom dimmen. Selbst wenn ich den Timer mit Prescaler
1024 (bei 4MHZ) betreibe und ihn dann auf zb 127 update, geht die LED
einfach sprunghaft auf den Wert und dimmt nicht.
Wenn ich den Wert bei jedem Output Compare Interrupt um eins erhöhe
sieht man selbst bei voller Taktfrequenz ein schnönes dimmen. Hat halt
den Nachteil, dass dann andauernd ein Interrupt ausgelöst wird.
Praktisch funktioniert das schon. Ich habe im Controller ein
I2C-Programm, dass nach dem Empfang mit statuskontrolle(ebenfalls
Interrupt) das empfanenge Zeichen auf einem LCD ausgibt. Das kommt alles
an, selbst während des Dimmvorgangs treten keinerlei sichtbaren
Verzögerungen auf.
Aber das ist mir irgendwie zu unsicher. Wer weiß, was passiert, wenn es
doch einmal dumm läuft.
Verstehst du mein Problem?
Florian Glaser wrote:
> Okey, das versteh ich. Ich initialisiere also meinetwegegen mit 00 und> weiße dem dann einfach einen neuen Wert zu, um ihn zu dimmen.>> Korrekt?>> Ich sehe nur nix vom dimmen. Selbst wenn ich den Timer mit Prescaler> 1024 (bei 4MHZ) betreibe und ihn dann auf zb 127 update, geht die LED> einfach sprunghaft auf den Wert und dimmt nicht.
Mal ganz langsam.
Unter dimmen einer LED versteht man wenn die LED nicht mit
voller Helligkeit brennt.
Was du noch zusätzlich willst, ist eine Rampe auf der die
LED zum gewünschten Wert ein-'fadet'. Das hat zunächst mal
nichts mit dimmen zu tun.
Da gibt es ganz banale Lösungen
* mittels delay in einer Schleife neue Werte setzen
for( i = 0; i < 127; i += 2 ) {
OCR = i;
_delay_ms( 10 );
}
alle 10 Millisekunden wird ein neuer OCR Wert gesetzt.
Macht bei einer Schrittweite von 2 127 / 2 = 63 * 10 = 630
Millisekunden, also etwas länger als eine halbe Sekunde.
Nun ist delay natürlich so eine Sache. Wenn der Prozessor
in der Zwischenzeit eigentlich etwas anderes tun sollte, dann
möchte man ihn natürlich nicht in einer Schleife hängen lassen.
Dann nimmt man einen weiteren Timer der einem eine 1 ms oder
5 ms oder 10 ms Zeitbasis erzeugt. Sowas braucht man sowieso
in den meisten Fällen in jedem Programm. Und in dessen
Interrupt Behandlung, die zb. alle 1 ms aufgerufen wird, wird
der OCR Wert wieder ein Stück näher an seinen Zielwert
gesetzt. Neben all den anderen Dingen, die alle 1 ms getan
werden müssen.
uint8_t FadeTo;
ISR( TIMER0_OVF_vect)
{
if( OCR < FadeTo )
OCR++;
if( OCR > FaceTo )
OCR--;
}
Du setzt FadeTo auf den Wert den die LED haben soll und
der regelmäßige Interrupt kümmert sich im Hintergrund darum,
dass der Dimmer/Timer schön langsam an diesen Wert herangeführt
wird. Wenn es dir zu langsam ist:
* Entweder den Timer öfter feuern lassen
* oder OCR nicht um 1 sondern um 2 oder 3 erhöhen/erniedrigen
> Wer weiß, was passiert, wenn es doch einmal dumm läuft.
Mach dir da mal keine grossen Sorgen. Der µC ist schnell
genug.
Wunderbar. Die Idee mitdem 2ten Timer ist wunderbar ;) Das muss ichn ur
noch in ASM portieren, aber das ist gar kein Problem. Auch wenn dann ein
Timer draufgeht.
Aber kannst du mir noch sagem, warum dieser sch*** Overflow Interrupt
nicht geht? Das wäre doch teilweise zuuuuuuu praktisch.
Florian Glaser wrote:
> Wunderbar. Die Idee mitdem 2ten Timer ist wunderbar ;) Das muss ichn ur> noch in ASM portieren, aber das ist gar kein Problem. Auch wenn dann ein> Timer draufgeht.>> Aber kannst du mir noch sagem, warum dieser sch*** Overflow Interrupt> nicht geht? Das wäre doch teilweise zuuuuuuu praktisch.
Vermutlich, weil Du mit ihm schimpfst (sch***). Sei lieb zu ihm, frag
das Datenblatt, was er gerne hätte, dann tut's er auch...
...
Hmpf. Naja, dann nehm ich mir in einer langweiligen Unterrichtsstunde
mal die Timereinheit genau vor. Vielleicht finde ich ja den Bug mit
Datenblatt. Wenn den sonst jemand hier findet, wärs super nett, wenn ers
sagen könnte ;)
Florian Glaser wrote:
> Hmpf. Naja, dann nehm ich mir in einer langweiligen Unterrichtsstunde> mal die Timereinheit genau vor. Vielleicht finde ich ja den Bug mit> Datenblatt. Wenn den sonst jemand hier findet, wärs super nett, wenn ers> sagen könnte ;)
Es wäre nett, wenn Du statt dieses Bit-Kauderwelsches
1
out SPL,akku
2
ldi akku,HIGH(RAMEND)
3
out SPH,akku
4
ldi akku,$ff ;Register ff
5
out DDRB,akku ;PortD als Ausgang
6
ldi r16,0b01110001 ;Timer initialiseiren
7
out TCCR0,r16 ;ohne Prescaling, FC-PWM
8
ldi r16,0x01 ;Overflow-Interrupt enablen
9
out TIMSK,r16 ;
10
ldi r16,0x50 ;Beliebigen Startwert laden
11
out OCR0,r16 ;außer 00 und ff
12
sei ;Interrupts an
die Bits mit den im Datenblatt genannten Namen ansprechen würdest. Dann
hättest Du vermutlich auch die Chance, dass jemand beim Drüberschaun
einen Fehler findet. Wenn man aber erst das Datenblatt öffnen muss und
sich die von Dir benutzten Bits dort zusammensuchen muss, dann ist die
Motivation zum Helfen schnell dahin.
Wie gesagt, es wäre nett... - Du musst das aber nicht tun. Genausowenig
muss ich aber um die Ecke recherchieren, was Du da initialisiert hast.
Denn die Timer in meinen Programmen machen schon das, was sie sollen.
Zwar nicht immer auf Anhieb, aber dann half das Datenblatt sehr schnell.
Nette Grüße,
Hannes
Hi
Wo kommt der Wert in r16 her, den du in der Interruptroutine
erhöhst? Dort fehlt 'in r16,OCR0'.
Ausserdem solltest du dir angewöhnen in Interruptroutinen das
SREG zu sichern. In deinem Programm stört das zwar im Moment
nicht. Aber wenn du in 'Loop' noch was anderes machen willst
bekommst du Probleme.
MfG Spess
Das fehlt natürlich, genauso wie das SREG. Aber in dem Programm macht
das nichts, da ändert niemand was an r16.
Das eigentliche Problem, dass der overflow interrupt nicht ausgelöst
wird, ist damit leider immer noch nicht gelöst :(
Florian Glaser wrote:
> jawohl meister, kommt sofort ;)> so besser l(e/ö)sbar?
wäre eigentlich ein Grund, sich rauszuhalten.
> irgendjemand das problem gesehen?
Ja sicher doch...
> Das eigentliche Problem, dass der overflow interrupt nicht ausgelöst> wird, ist damit leider immer noch nicht gelöst :(
Nagut, dann will ich mal nicht aso sein. Ich habe es zwar nicht
ausprobiert, aber es wäre eine logische Erklärung:
Bist Du sicher, dass Dein Timer jeweils überläuft?
Du hast mit WGM Phase-correct-PWM eingestellt, das heißt, Dein Timer
legt oben den Rückwärtsgang ein und rattert wieder runter. Das von Dir
erwartete Überlauf-Ereignis bleibt also aus.
Wie gesagt, ich habe es nicht ausprobiert. Ich käme auch nicht auf die
Idee, den Timer hoch und runter laufen zu lassen und dann einen Überlauf
zu erwarten.
...
Hi
Scheint ein Simulatorproblem zu sein.
Ich habe gerade mal das Programm mit einem ATMega16 und JTAG getestet.
Dort wird der Overflowinterrupt angesprungen.
MfG Spess
echt? merkwürdig, bei meinem nicht.
und @hannes: das waren 2 späßchen, meister und das andere war in
keinster weise irgendwie veräppelnd gemeint, verstehe mich da bitte
nicht falsch.
Ich versuch das heute abend gleich nochmal!