Hallo,
ich verzweifel gerade daran meinen Tiny13 zu konfigurieren. Eigentlich
kann das nichts großes sein, aber es funkt irgendwie nicht.
Und zwar möchtet ich mit dem Timer ein PWM-Signal erzeugen (Signal liegt
auf PB0 bzw. OC0A). Gleichzeitig soll aber auch das Timing der main()
gesteuert werden - das müsste ja dann über OC0B gehen.
Kann mir jemand helfen?
Vielen Dank!!!
1
#include<avr/io.h>
2
#include<avr/interrupt.h>
3
4
volatileuint8_tevent;
5
6
ISR(TIM0_COMPB_vect){
7
event++;
8
}
9
10
11
12
voidinit(){
13
DDRB=0xff;
14
DDRB&=~(1<<PB3);// PB3 wieder als Eingang
15
16
/** PWM definieren **/
17
OCR0A=200;// Ändert sich zwischen 0 und 255 !!!
18
TCCR0A|=(1<<COM0A1)|(1<<WGM01)|(1<<WGM00);
19
TCCR0B|=(1<<CS01);// Prescaler = 8
20
21
/** Taktzeit definieren **/
22
TIMSK0|=(1<<OCIE0B);
23
OCR0B=100;
24
25
sei();
26
}
27
28
29
30
intmain(void){
31
staticuint8_ttest=0;
32
init();
33
34
35
for(;;){
36
37
if(event==200){// Programm alle X-Sekunden durchlaufen
pal ... schrieb:> Hallo,>> ich verzweifel gerade daran meinen Tiny13 zu konfigurieren. Eigentlich> kann das nichts großes sein, aber es funkt irgendwie nicht.
'funkt irgendwie nicht'
ist die schlechteste Fehlerbeschreibung, die du geben kannst. Denn
darunter kann sich auf dieser Seite des Bildschirms keiner was
vorstellen.
> auf PB0 bzw. OC0A). Gleichzeitig soll aber auch das Timing der main()> gesteuert werden - das müsste ja dann über OC0B gehen.
Was meinst du mit 'Timing steuern'?
Wird der Compare Match Interrupt nicht aufgerufen?
Abgesehen davon. Nein, du kannst du nicht viel steuern (im Sinne von
einstellen). Denn der Compare Match Interrupt wird nach wie vor
regelmässig während eines Timer-Durchlaufs aufgerufen.
Eine Analogie: Auf deiner Armbanduhr mit Sekundenzeiger machst du etwas,
jedes mal wenn der Sekundenzeiger auf einer bestimmten Zahl steht. Aber:
Egal welche Sekunde du dir aussuchst, es ändert nichts daran, dass der
Zeiger jedesmal einen kompletten Durchlauf rund ums Zifferblatt braucht,
bis er wieder bei dieser Sekunde angelangt ist. Du kannst zwar durch
Wahl einer anderen Sekunde den Zeitpunkt verschieben, aber die 1 Minute
die der Zeiger einmal rundum braucht, die ändert sich dadurch nicht
(Jetzt mal von der einen Ausnahme abgesehen, wenn du die Zahl umsetzt).
Also: Was erwartest du? Was passiert statt dessen. Mit 'funkt nicht' hat
hier keiner eine Ahnung was du dir eigentlich vorstellst was passieren
sollte (und ich hab im vorhergehenden Absatz auch nur ins Blaue geraten,
weil diese 'Problemstellung' häufig vorkommt).
Karl Heinz Buchegger schrieb:> 'funkt irgendwie nicht'> ist die schlechteste Fehlerbeschreibung, die du geben kannst. Denn> darunter kann sich auf dieser Seite des Bildschirms keiner was> vorstellen.
Stimmt! Sorry, war wieder zu voreilig.
Also das PWM-Signal tut was es soll.
Jetzt will ich, dass mein Programm jede Millisekunde durchlaufen wird.
1
if(event==200){// Programm alle X-Sekunden durchlaufen
Zum testen steht dort zunächst eine 200
Der Compare Match Interrupt wird durchlaufen, aber eine Änderung an
OCR0B zeigt keine Änderung an meiner Programmablaufzeit.
Rein rechnerisch müsste ich eine Zeit von 33,67mSek [CLK /((OCR0B+1) *
Prescaler) --> 4800000 / ((100+1)*8) = 0,16833mSek --> 0,16833mSek * 200
= 33,67mSek]. Tatsächlich habe ich aber eine Zeit von 86mSek.
pal ... schrieb:> Der Compare Match Interrupt wird durchlaufen, aber eine Änderung an> OCR0B zeigt keine Änderung an meiner Programmablaufzeit.>> Rein rechnerisch müsste ich eine Zeit von 33,67mSek [CLK /((OCR0B+1) *> Prescaler) --> 4800000 / ((100+1)*8) = 0,16833mSek --> 0,16833mSek * 200> = 33,67mSek].
Nein!
Hast du den Post von Karl-Heinz überhaupt gelesen? Anschaulicher kann
man das doch kaum erklären.
Anderer Ansatz: versuch mal in Worten zu erklären, wie du dir den Ablauf
in Bezug auf den Timer vorstellst. Also er fängt bei 0 an zu zählen.
Irgendwann erreicht er die 100. Was passiert jetzt? Was danach? Wie geht
es weiter?
Hi
>Der Compare Match Interrupt wird durchlaufen, aber eine Änderung an>OCR0B zeigt keine Änderung an meiner Programmablaufzeit.
Wie sollte er auch? Damit änderst du nur den Zeitpunkt des Interrupts
aber nicht den Abstand zwischen zwei Interrupts. Genau so gut könntest
du den Overflow-Interrupt benutzen.
MfG Spess
> Hast du den Post von Karl-Heinz überhaupt gelesen?
Eigentlich schon
> Irgendwann erreicht er die 100. Was passiert jetzt? Was danach? Wie geht> es weiter?
Der Interrupt wird ausgelöst - event++ - Interrupt beginnt bei 0
Wie kann ich das "Timing" denn anders realisieren? Ich müsste den
Interrupt eigentlich zurücksetzen. Aber wie?
Schon einmal vielen Dank!!!
pal ... schrieb:>> Irgendwann erreicht er die 100. Was passiert jetzt? Was danach? Wie geht>> es weiter?> Der Interrupt wird ausgelöst - event++ - Interrupt beginnt bei 0
Was bitte soll denn "Interrupt beginnt bei 0" bedeuten?
Ich will wissen, wie es mit dem Zähler weitergeht.
Also:
Hi
>Wie kann ich das "Timing" denn anders realisieren?
Über deine event-Variable.
>Ich müsste den Interrupt eigentlich zurücksetzen. Aber wie?
Einen Interrupt kann man nicht zurücksetzen. Nur das zugehörige Flag.
MfG Spess
Stefan Ernst schrieb:> Ich will wissen, wie es mit dem Zähler weitergeht.> Also:
Birher war ich der Meinung, dass der Interrupt wieder auf 0 gesetzt
wird. Karl-Heinz hat mich aber mit diesem echt guten Beispiel eines
besseren belehrt.
Er zählt weiter... 101, 102, 103, ... 255
> Über deine event-Variable.
Habe ich auch schon versucht. Dadurch schaffe ich aber nur eine Zeit von
3ms und ich würde gerne auf 1ms kommen.
> Nur das zugehörige Flag.
mmmhhh.....aber das sagt mir doch auch nur, dass der Interrupt
stattgefunden hat.
pal ... schrieb:> Meinen Denkfehler habe ich nun verstanden :-)>>
1
ISR(TIM0_COMPB_vect){
2
>OCR0B+=100;
3
>event++;
4
>}
>> Aber dieses brachte auch keine Änderung.
Dann hast du bei der Programmerstellung oder beim Brennen in den µC
irgendwas verhaut. Denn genau so funktioniert das.
In der Uhrenanalogie ist das nichts anderes, als dass du bei deiner
festgelegten Sekunde, zb 23, vereinbarts, dass dein nächster
Stichzeitpunkt die Sekunde 43 sein soll, also 20 Sekunden später. Und zu
diesem Zeitpunkt vereinbarst du wiederrum, dass dein nächster
Vergleichszeitpunkt die Sekunde 3 (also wieder 20 Sekunden später) sein
soll. Fazit: der 'Auslöser' wird alle 20 Sekunden betätigt. Warum ist
das so? Na ganz einfach, weil du selbst genau den nächsten
Auslösezeitpunkt 20 Sekunden in die Zukunft gelegt hast.
-> Genauso, mit Berechnen des nächsten OCR0B Wertes in der ISR wird das
gemacht.
pal ... schrieb:> ansehe, erkenne ich keinen Unterschied.
Autsch. Das haben wir alle übersehen
1
Table 11-8. Waveform Generation Mode Bit Description
2
Mode WGM2 WGM1 WGM0 Mode of Operation TOP Update of OCRx
3
4
0 0 0 0 Normal 0xFF Immediate MAX
5
1 0 0 1 PWM(Phase Correct) 0xFF TOP BOTTOM
6
2 0 1 0 CTC OCRA Immediate MAX
7
3 0 1 1 Fast PWM 0xFF TOP MAX
Beachte die Spalte 'Update of OCRx'.
Der Timer unterscheidet da nicht. Sobald er im Fast PWM Modus ist,
werden die OCRx Register erst bei Erreichen des Top Wertes upgedatet.
D.h. du kannst OCR0B nicht zuverlässig in der ISR weiterrechnen, weil
der Wert erst beim Timerüberlauf ins echte OCR0B Register überführt
wird.
PWMmi schrieb:> Hast Du in der Zeile>> if(event == 200) { // Alle 1ms Programm durchlaufen>> die 200 mal verringert?>> Damit teilst Du Deine PWM ja herunter.
Die PWM hat damit nichts zu tun. Die wird sowieso vom Timer
hardwaremässig bedient.
Er möchte sich zusätzlich noch zur PWM einen 1ms Systemtakt erzeugen.
> Habe ich auch schon versucht. Dadurch schaffe ich aber nur eine Zeit von 3ms und
ich würde gerne auf 1ms kommen.
Ich fürchte, du wirst die Krot schlucken müssen.
Oder den Timer mit einem Prescaler von 1 laufen lassen und dann damit
weiterarbeiten.
Dann braucht er nur den PWM modus auf Normal zu schalten. Und wenn die
PWM Frequenz gleichbleiben soll dann noch den Prescaler auf 4 (falls
verfügbar).
Ween ich das richtig sehe hast Du
4,8Mhz Systemtakt und /8 für den Timer-Prescaler eingesetllt, der im
FastPWM-Mode läuft.
Dann ergibt sich eine PWM-Frewuqnz von
fclkio/(8*256) = 2343,75 Hz
Das ist gleich der Interruptfrequenz wenn Du OCR0B konstant läßt.
Wenn Du Deine Hauptprogrammschleife jede 1ms durchlaufen willst, also
mit 1000Hz, mußt Du 2 INT-Events warten.
Wenn Du also
if(event == 2) {
einsetzt, sollte das doch machbar sein!?
Oder habe mich irgendwo verrechnet?
Uwe schrieb:> Dann braucht er nur den PWM modus auf Normal zu schalten
Sobald ich auf Mode0 schalte bekomme ich kein PWM-Signal mehr raus.
Prescaler = 4 ist nicht möglich.
PWMmi schrieb:> sollte das doch machbar sein!?
mmmhhhh.... Stimmt!!! So sollte es funktionieren
Hab mich vielleicht einfach zu sehr auf die Register fixiert.
VIELEN DANK noch mal an alle für die guten Vorschläge.
Jetzt gehts los :-)
> Sobald ich auf Mode0 schalte bekomme ich kein PWM-Signal mehr raus.
Stimmt ist ja nicht "Normal PWM" gemeint, sondern "Normal operation",
also
als counter. hab mir jetz halt nicht extra das Datenblatt angeguckt.
Sorry