Forum: Compiler & IDEs Timer0 : Nur ein Overflow?


von Joachim Jacobi (Gast)


Angehängte Dateien:

Lesenswert?

Hallo zusammen!
Ich versuche gerade mit dem Timer0 eine LED an PortB pro sec. einmal
blinken zu lassen.
Aber wenn ich dem MC Strom gebe, blinkt die LED nur einmal und das auch
länger als eine Sekunde.
Wahrscheinlich stimmt dann was mit dem Overflow und meiner Umrechnung
nicht.
Bei der Rechnung habe ich mir das so gedacht: 4 MHz / 8 Vorteiler =
500000 Hz. Timer0 mit 6 vorladen --> alle 2000 Hz ein Overflow. Also
wenn ich dann bis 2000 zähle wäre genau eine Sekunke vorbei, oder liege
ich da falsch?
Den Code im Anhang habe ich hier irgendwo im Bord gefunden und etwas
umgebaut, weil ich später ms zählen möchte und einen 4433 verwende.
Danke im vorraus!

Joachim

von Jörg Wunsch (Gast)


Lesenswert?

Es wäre nicht schlecht, wenn die Kommentare mit der Realität
übereinstimmen würden...  Die Kommentare sprechen von einem
10-ms-Interrupt, du machst aber was komplett anderes.  Das ist
ziemlich verwirrend.

Dein eigentliches Problem ist das Umschalten der LED:

  if(bit_is_set(PORTB,1))      //PIN gesetzt ???
    PORTB = 0x00;
  else
    PORTB = 0x01;

Die Bitnummerierung ist 0-basiert, du testest also das Bit mit dem
Muster 0x02, setzt/löschst aber das mit 0x01.  Das ist vermutlich
nicht ganz das, was du willst...

Sinnvoller schreibt man das sowieso aber mit C-Bitoperatoren als:

  PORTB ^= 0x01;

count2000 muss übrigens ausnahmsweise nicht volatile sein, da die
Variable nur in der Interruptroutine benutzt wird, nicht auch noch
aus dem main() heraus.  (Man könnte sie auch innerhalb der ISR als
`static' anlegen.)  Wenn du sie aus irgendwelchen Gründen volatile
lassen willst, weil der Inhalt später aus main() abgefragt werden
soll, empfiehlt sich ein lokaler Mirror:

...
 uint16_t count_2000_mir = count_2000;
...
 count_2000_mir++;

 if(count_2000_mir >= 2000)
 {
...
   count_2000_mir = 0;               //Zähler löschen
 }
 count_2000 = count_2000_mir;
}

Auf diese Weise gestattet man es dem Compiler, den Wert von count_2000
innerhalb der ISR in einem Register(paar) zu halten und nur einmal
vom/zum Speicher zu kopieren.  Andernfalls würde das volatile jeden
Zugriff über die entsprechende Speicherstelle erzwingen.

von Joachim Jacobi (Gast)


Angehängte Dateien:

Lesenswert?

Ahhh!!!
Jetzt funktioniert es. Das mit der Variable muss ich mir nochmal
genauer anschauen.
Die Kommentare sind noch Reste von dem Programm was ich wie gesagt hier
im Bord gefunden habe. Im Anhang ist jetzt das funktionierende Programm
mit den richtigen Kommentaren.
Danke für die ausführliche Hilfe!

Joachim

von Joachim Jacobi (Gast)


Angehängte Dateien:

Lesenswert?

Mist. Da sind immernoch falsche Kommentare drin. Jetzt aber hoffentlich
nicht mehr.

von Joachim Jacobi (Gast)


Lesenswert?

Hallo!
Das Programm funktioniert jetzt, ABER 1 sec. ist nicht 1 sec. Ich habe
jetzt mal 60 sec. gezählt und die Zahl binär auf Port B ausgegeben. Pro
Minute verliere ich ca. 1 sec. Da ich damit eigentlich später eine
Stopuhr basteln wollte ist das nicht so toll.
Ist meine Überlegung im Programm falsch? Habe ich irgendetwas vergessen
zu beachten?

MfG
Joachim

von Lutz Müller (Gast)


Lesenswert?

Hallo,
habe nach dem fetten Sonntagsbraten nix nachgerechnet (das Blut wird
woanders gebraucht), aber
- Ein 8-Bit-Zähler zählt von 0 bis 255 (=256 verschiedene Werte)
- //Port einstellen
  DDRB = 0x01;               //PortB.1 auf Ausgang
=> scheint zwar eine eigene Definition zu sein, aber man sollte lieber
die Bezeichnungen aus dem Datenblatt nehmen, dann kann man sich
seltener verheddern. Dann ist´s nämlich "//PORTB0 auf Ausgang".

Gruß
Lutz

von Joachim Jacobi (Gast)


Lesenswert?

Ja da sind immernoch ein paar Kommentare drin die nicht stimmen, weil
ich das alles aus mehreren Beispielen zusammengebastelt habe. Aber mein
gesamter PortB ist Ausgang, auch wenn im Kommentar was anderes steht.

Aber kann man den Timer nicht immer vorladen? Ich habe das in einem
anderen Beispielt gesehen. Und eigentlich lade ich den Timer immer mit
6 vor, so dass er nur 250 Schritte zählt.

MfG
Joachim

von Hubert (Gast)


Lesenswert?

Verwende doch den Timer1 mit Compare-Match und CTC. Für eine Stoppuhr
würde ich auch den Prescaler nicht verwenden, da du dann nicht mehr
fein genug skalieren kannst.
Die Voreinstellung von 6 gilt nur beim Start. Nach dem Überlauf beginnt
der Timer mit 0 daher auch dein Zeitfehler. Du müsstest nach jedem
Durchlauf stoppen neu voreinstellen und starten.

von mathias giacomuzzi (Gast)


Lesenswert?

Ach, da habe ich jetzt auch eine frage, heisst das jetz wenn man zum
beispiel, im main stehen hat:

code von einem attiny2313

int main(){
 ...
 ....
 TCCR0B = (1<<CS01); // count with cpu clock/8 , bei A90S2313 TCCR0
 TIMSK = 1<<TOIE0; // enable TCNT0 overflow
 TCNT0 = 0x9c; //100uSEc bei 8Mhz ==> vorladen
 ...
 ...
}
und dann mit timer owerflow 0 irgend was macht

SIGNAL(SIG_TIMER0_OVF){  // bei 90S2313 SIG_OVERFLOW0

   TCNT0 = 0x9c; //100uSEc bei 8MHz und vorteiler 8!!  ==> nachladen

   // code....

}

das er dann nicht wie im beispiel mit 100 us arbeitet ??? oder wie??
es steht doch irgendwo im wiki das man das so macht oder nicht??!!

danke im voraus

mfg mathias

von Joachim Jacobi (Gast)


Lesenswert?

Aha! Also geht das gar nicht so. Dann muss ich mich jetzt mal schlau
machen was "Compare-Match und CTC" ist :-)

MfG
Joachim

von mathias giacomuzzi (Gast)


Lesenswert?

ist hier niemand mehr ?? wäre super wenn der eine oder andere mal was
dazu schreiben könnte!!!

mfg mathias

von Hubert (Gast)


Lesenswert?

@Joachim
Bei Compare-Match gibst du einen Timer-Stand vor bei dem ein Interrupt
ausgelöst wird z.B TIMER1_COMPA. MIt aktivieren von CTC setzt du den
Timer bei compare-match wider auf Null zurück.

@mathias
Ich habe nicht nachgelesen was im Wiki steht. Aber der timer0 kann kein
compare-match. Für den gibt es nur einen Overflow Interrupt. Wenn du ihn
dann nicht stoppst beginnt er bei Null wieder zu zählen.

Ihr sollted beide mal genau im Datenblatt nachlesen und etwas damit
herumprobieren, dann wird sicher einiges klar.

von Werner B. (Gast)


Lesenswert?

@Hubert

Was TimerX kann hängt (in der Regel) vom jeweiligen Prozessor ab.

ATtiny12 != ATtiny26 != ... != ATmega8 != ATmega128

Da hilft nur Datenblatt lesen.

Wie es immer so schön heißt

"Wer lesen kann ist klar im Vorteil."

oder weniger kultiviert ausgedrückt

RTFM - und zwar das Richtige

von Hubert (Gast)


Lesenswert?

@ Werner
Da bin ich ganz deiner Meinung. Das Datenblatt sollte die erste
Hilfe-Lektüre sein. In diesem Fall war allerdings von einem 4433 die
Rede.

Hubert

von mathais giacomuzzi (Gast)


Lesenswert?

ja ab er dann stimmt ja das nicht mehr was auf dieser Seite steht unter
der Rubrik Timer !!?? oder wie

http://www.mc-project.de/


@ Hubert ja aber er wird ja wieder nachgeladen !!

und ich habe das jetzt nochmal ausprobiert und die 100us stimment mit
meinem alten OSZi nicht schlecht ==> ist das jetzt zufall??

mfg mathias

von Hubert (Gast)


Lesenswert?

@mathias
In deinem Fall wird der Timer wieder nachgeladen. Es kommt darauf an
wie genau du die 100µsec brauchst. Sonst musst du auch noch die
Taktzyklen bis zum Timerstart mit einrechnen und die Quarzabweichung
ausgleichen.
Das wäre auch eine alternative für Joachim. Ich finde allerdings den
Compare-Match besser zu handeln.
Sonst gilt: Alle möglichen Timer und Varianten ausprobieren, dann
findet man heraus welcher timer in welcher Form in welchem Fall am
günstigsten ist. Allgemeine Regeln gibt es da nicht.

von Joachim Jacobi (Gast)


Lesenswert?

Ich hatte eigentlich gedacht, dass der Timer in meinem Programm auch
wieder nachgeladen wird. Im Interrupt und beim starten des Timers wird
in TCNT0 immer die 6 geschrieben.
In dem Beispiel auf www.mc-project.de wird er auch nicht gestoppt oder
sehe ich das nur nicht?
Das Datenblatt hab ich mir auch schon angeguckt, aber das bringt mich
nicht wirklich nach vorne.
Danke schon mal für deine Bemühungen!

MfG
Joachim

von Hubert (Gast)


Lesenswert?

Du hast recht Joachim, der Timer wird nachgeladen, da habe ich drüber
geschaut. Aber es passt die Sekunde nicht genau. Hier musst du
varieren.
Messen welche Zeit dir fehlt, die Voreinstellung ändern oder beim
2000ensten Durchlauf die Voreinstellung ändern. Da kannst du dich aber
nur mit einer Langzeitmessung annähern. Je ganuer du es willst um so
länger musst du dich spielen.

von Joachim Jacobi (Gast)


Lesenswert?

Also stimmen meine Überlegungen was die Sekunde angeht nicht genau? Dann
werde ich mich doch mal genauer mit Timer1 beschäftigen.

MfG
Joachim

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
Noch kein Account? Hier anmelden.