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
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.
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
Mist. Da sind immernoch falsche Kommentare drin. Jetzt aber hoffentlich nicht mehr.
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
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
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
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.
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
Aha! Also geht das gar nicht so. Dann muss ich mich jetzt mal schlau machen was "Compare-Match und CTC" ist :-) MfG Joachim
ist hier niemand mehr ?? wäre super wenn der eine oder andere mal was dazu schreiben könnte!!! mfg mathias
@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.
@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
@ 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
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
@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.
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
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.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.