TIMSK|=(1<<TOIE0);// Interrupt beim Overflos auslösen
10
TCCR0B|=(1<<CS01);// prescale = 8
11
sei();// Interrupts freigeben
12
13
while(1){
14
}
15
16
}
17
18
ISR(TIM0_OVF_vect){
19
zaehler++;
20
if(zaehler==1953)zaehler=0;// eine Sekunde ist vorbei (1953*0.512=0,99s)
21
if(zaehler<1)PORTB|=(1<<PB0);//Lasse LED kurz aufblinken
22
elsePORTB&=~(1<<PB0);
23
24
}
Ich habe gedacht, dass ich alle 0,512ms einen Interrupt auslöse.
Und zunächst jede Sekunde die LED kurz aufblinken lassen. Dies
funktioniert auch, allerdings wesentlich schneller.
Was habe ich falsch gemacht? Oder wie berechne ich sonst die Zeit eines
Interrupts?
Bis jetzt habe ich es so gerechnet
t=(2^(Bit des Timers)*Vorteiler)/(Systemtakt in Hz)=(2^8*8)/4000000
Eigentlich hätte ich gesagt, dass der mit 4MHz läuft, da ich dass ja
ganz oben so definiert habe. Aber jetzt bin ich mir da nicht mehr so
sicher, bzw. würde dann fast sagen, dass der das nicht macht. Dann
müsste der ja (wenn meine Berechnung ansonsten richtig ist) schneller
laufen.
Tim schrieb:> Eigentlich hätte ich gesagt, dass der mit 4MHz läuft, da ich dass ja> ganz oben so definiert habe
das ist nur eine Info. Damit ändert sich nichts Takt.
Hast du ein Quarz dran? Wie sind die Fuse gesetzt?
In Normalfall müsste er mit 1Mhz laufen
(habe jetzt nicht im Datenblatt nachgelesen)
kopfkratz
Also ersteinmal Kardinalsfehler bei globalen Variablen und IRQs VOLATILE
vergessen (hat hier vorerst keine Auswirkungen da Du auch eine lokale
Variable nehmen könntest) !
Dann wird der Takt nicht im Programm definiert, sondern durch die Fuses
auf dem Käfer, die mal mit z.B. avrdude auslesen.
Die Formeln für die einzelnen Modi des jeweiligen Timers findest Du im
Datenblatt.
Daher Datenblatt lesen, den passenden Timer-Modus auswählen und
programmieren und dann nach der Formel berechnen wie oft der Timer
durchgelaufen ist bis z.B. eine Sekunde erreicht wird.
Einen Quarz habe ich nicht dran.
Bei Fuses bin ich mir nicht ganz sicher, da ich auch nicht wirklich
weiss was das ist.
AVRDUDE gibt mir aber folgendes
hfuse 0b11100010
lfuse 0b11011111
leider sagt mir das noch gar nichts. Habe aber jetzt die (hoffentlich)
passende Seite http://www.mikrocontroller.net/articles/AVR_Fuses dazu
gefunden
Habe mir die Seite und das Datenblatt angesehen, aber das mit den Fuses
noch nicht so wirklich verstanden.
Allerdings steht im Datenblatt, dass der Auslieferungszustand mit 8MHz
ist.
Dann habe ich allerdings noch ein Problem
mit Prescale = 1, bekomme ich einen Interrupt alle
(2^8*1)/8000000Hz=0,032ms
das mach genau 31250 Interrupts für eine Sekunde (ohne komma irgendwas).
1
ISR(TIM0_OVF_vect){
2
zaehler++;
3
if(zaehler==31250)zaehler=0;// -> 1 Sekunde
4
if(zaehler<15625)PORTB|=(1<<PB0);
5
elsePORTB&=~(1<<PB0);
6
7
}
Mein erstes Problem ist, dass es trotzdem noch etwas schneller als eine
Sekunde ist. Noch ist es realtiv egal, da ich es erst einmal mit den
Interrupts ausprobieren wollte. Wenn ich aber später meine Uhr machen
möchte, sollte es doch schon etwas genauer sein.
Das zweite Problem ist eher ein verständnisproblem. Das heisst ja, dass
ich bei einem höheren bit-timer (16bit) wesentlich ungenauer arbeiten
kann, da
(2^16*1)/8000000Hz=8,192ms
ist das richtig?
Meiner Meinung nach müsste ich wesentlich genauer arbeiten können.
Die dritte Frage ist, was ist ein Kardinalsfehler und IRQs VOLATILE?
Hi
>Allerdings steht im Datenblatt, dass der Auslieferungszustand mit 8MHz>ist.
Ja, aber mit gesetzter CKDIV8-Fuse. Das macht dann wieder 1 MHz.
MfG Spess
Ein "Kardinalsfehler" ist ein Fehler den ein "Kardinal" (eine Person im
Kirchenrange eines Kardinals) macht, gemacht hat oder machen wird.
Vermutlich ist ein "Kardinalfehler" (ohne s) gemeint. Ein Haupt-,
Basis-, Grund- oder auch grundsätzlicher Fehler.
Tim schrieb:> Mein erstes Problem ist, dass es trotzdem noch etwas schneller als eine> Sekunde ist. Noch ist es realtiv egal, da ich es erst einmal mit den> Interrupts ausprobieren wollte. Wenn ich aber später meine Uhr machen> möchte, sollte es doch schon etwas genauer sein.>
Was steht denn im Datenblatt über Prescaler & Co. ?
Welchen Timer-Modus nimmst Du und warum ?
> Das zweite Problem ist eher ein verständnisproblem. Das heisst ja, dass> ich bei einem höheren bit-timer (16bit) wesentlich ungenauer arbeiten> kann, da> (2^16*1)/8000000Hz=8,192ms> ist das richtig?> Meiner Meinung nach müsste ich wesentlich genauer arbeiten können.>
Welche Formel zur Berechnung steht denn im Datenblatt ?
Wie kommst Du auf Deine Formel ?
> Die dritte Frage ist, was ist ein Kardinalsfehler und IRQs VOLATILE?
Lies mal das Tutorial komplett durch:
http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#Datenaustausch_mit_Interrupt-Routinen
So, habe noch einmal sehr viel gelesen, aber wenn ich ehrlich bin nicht
allso viel verstanden.
Was steht im Datenblatt über Prescalar?
Der Prescalar dient doch einfach nur als vorteiler oder?
Welchen Timer Modus benutze ich?
Ehrlich gesagt, keine Ahnung. Ich denke aber mal Modus 0
also bei TCCR0A
WGM00=0, WGM01=0, WGM02=0.
Dies ist das sinnvollste, was ich im datenblatt dazu finden konnte.
Da ich es aber nicht im Code hingeschrieben habe, müssten die gleich
null sein oder?
Zur berechnung habe ich die Formel von
http://www.mikrocontroller.net/articles/AVR-Tutorial:_Timer
(Abschnitt 'Der Vorteiler') verwendet.
Das Tutorial habe ich mir auch angeguckt.
Ich habe jetzt anstelle von
Nicht vom Information-Overflow irre machen lassen. Du bist schon auf dem
richtigen (und sehr steinigen) Weg.
Dein Tiny scheint ja auf 8Mhz internem Takt zu laufen (auch wenn die
Fuses, die du veröffentlicht hast etwas anderes sagen), also nimm das
erst einmal als gegeben hin.
Nun möchtest du also mit diesen 8Mhz und dem Weg über einen
überlaufenden Timer möglichst genau Sekunden zählen. Dabei stößt du auf
drei Probleme:
1. Je nach Vorteiler ist die Sekunde nicht genau beim Überlauf, sondern
irgendwann dazwischen erreicht
2. Dein Tiny läuft sicher nicht mit exakt 8Mhz (Datenblatt 21.4.1
Calibrated Internal RC Oscillator Accuracy), sondern hat eine
systematische Abweichung
3. Besonders konstant ist dieser Takt auch nicht.
Probleme 1 und 2 kannst du in den Griff bekommen.
Ein 16-Bit-Timer (wenn der Tiny einen hätte) könnte zwar nützlich sein,
aber es geht auch ohne.
Grundgedanke (ein möglicher Weg von vielen):
- Alle soundsoviel Timerüberläufe ist ungefähr eine Sekunde vorbei, also
wird ein Sekundenzähler hochgezählt. Allerdings hast du dir
währenddessen auch einen systematischen Fehler eingefangen. Also zählst
du auch einen "Fehlerzähler" hoch. Wenn hier ein kritischer Wert
erreicht ist (ausprobieren und rechnen) spendierst du deinem Timer einen
zusätzlichen Überlauf (oder eine Überlauf weniger), bevor die nächste
Sekunde als beendet erklärt wird.
Die Fallstricke, die hier noch lauern (z.B. Variablentypen - signed,
unsigned, wie groß...) garantieren viel Lernspaß.
Schönes WE
Flohzirkus