Hallo allerseits, ich bin ein Neuling im Bereich Mikrocontroller und habe eine Frage zum Timer. Der Timer0 vom Atmega 128 funktioniert ja indem er in dem Register TCNT0 Register hoch zaehlt bis maximal 255. Die Frequenz mit der hoch gezaehlt wird kann mit einem Prescaler reduziert werden. Nun kann man den Wert von TCNT0 mit einem Vergleichsregister OCR0 vergleichen. In dieses OCR0 Register kann ich einen beliebigen Wert von 0-255 eintragen. Bis zu diesem Wert wird gezaehlt!. Der Timer kann im Interruptbetrieb durch zwei Unterschiedliche Interrupts unterbrochen werden: • Bit 1 – OCIE0: Timer/Counter0 Output Compare Match Interrupt Enable When the OCIE0 bit is written to one, and the I-bit in the Status Register is set (one), the Timer/Counter0 Compare Match interrupt is enabled. The corresponding interrupt is executed if a compare match in Timer/Counter0 occurs, i.e., when the OCF0 bit is set in the Timer/Counter Interrupt Flag Register – TIFR. • Bit 0 – TOIE0: Timer/Counter0 Overflow Interrupt Enable When the TOIE0 bit is written to one, and the I-bit in the Status Register is set (one), the Timer/Counter0 Overflow interrupt is enabled. The corresponding interrupt is executed if an overflow in Timer/Counter0 occurs, i.e., when the TOV0 bit is set in the Timer/Counter Interrupt Flag Register – TIFR. OCIE0 wartet also bis OCF0 gesetzt ist (der Timerwert identisch ist mit dem vorgegebenen Wert, OCR0=TCNT0) TOIE0 wartet also bis TOV0 gesetzt ist (der Timerwert TCNT0 einen hoeheren Wert als 255 hat und das Register "ueberlaeuft" ?) OCIE0 verstehe ich. Macht Sinn einen Interrupt zu haben der ausloest wenn ein "Match" stattfindet. Was aber hat es mit diesem TOIE0 auf sich? Und wann kommt er zum Einsatz ? Danke schonmal im Voraus. VG Luke.
@ Luke (Gast) >vergleichen. In dieses OCR0 Register kann ich einen beliebigen Wert von >0-255 eintragen. Bis zu diesem Wert wird gezaehlt!. Wenn man den CTC-Modus oder einen ähnlichen Modus eingestellt hat. Im Normalmodus zählt der immer bis 255. >Der Timer kann im Interruptbetrieb durch zwei Unterschiedliche >Interrupts unterbrochen werden: Nicht der Timer wird unterbrochen sondern es wird ein Interrupt ausgelöst. Der Timer läuft normal weiter. Wenn die Interupts freigeschaltet sind, wird der Programmablauf der CPU unterbrochen, siehe Interrupt. >• Bit 1 – OCIE0: Timer/Counter0 Output Compare Match Interrupt Enable TCNT0 == OCRA0 >• Bit 0 – TOIE0: Timer/Counter0 Overflow Interrupt Enable When the TOIE0 TCNT0 geht von 255 auf 0 >OCIE0 wartet also bis OCF0 gesetzt ist (der Timerwert identisch ist mit >dem vorgegebenen Wert, OCR0=TCNT0) Ja. >TOIE0 wartet also bis TOV0 gesetzt ist (der Timerwert TCNT0 einen >hoeheren Wert als 255 hat Hat er nie. > und das Register "ueberlaeuft" ?) Das schon eher. >OCIE0 verstehe ich. Macht Sinn einen Interrupt zu haben der ausloest >wenn ein "Match" stattfindet. Kommt auf die Anwendung an. > Was aber hat es mit diesem TOIE0 auf sich? >Und wann kommt er zum Einsatz ? Viel öfter. Nämlich dann, wenn man einen periodischen Interrupt haben möchte, mit dem periodisch in gleichbleibenden Abständen Dinge erledigt werden sollen. Interne Uhr, Tasten abfragen, Signale generieren, State Machines abarbeiten etc.
Falk Brunner Gebt diesem user einen award. Danke vielmals. Sehr kompakt und verständlich erklärt. LG Luke.
Eine Frage hat sich im Nachhinein doch noch ergeben. So wie du er erklärt hast ist TOIE0 ein Sepzialfall von OCIE0 ! Bei OCIE0 wird ein Interrupt ausglöst sobald der von mir eingestellte Wert erreicht wurde (Vergleich mit Compare-register). Bei TOIE0 wird er immer bei 255 ausgelöst. Denn ein Überlauf findet ja nur statt wenn er auf 255 noch 1 dazuzählt. Wenn ich also im Compare-register 255 (max) stehen habe ist das Verhalten dieser beiden Interrupts identisch ??? Danke im Voraus. LG Luke
Ja, einmal bekommst du einen Interrupt, wenn der Zählerstand TCNT0 gerade gleich OCR0 ist: COMPARE-MATCH-INTERRUPT, oder wenn der Zähler "überläuft": OVERFLOW-INTERRUPT. Im Normal-Mode erscheinen beide Interrupts (wenn auch verschoben) im selben Zeitabstand: Meist nicht sehr interessant... Interessant wird es doch eher, wenn du den Timer im CTC-Mode nicht bis 255 zählen lässt, sondern nur bis zu einer gewüschten Zahl in OCR0 - dann gibt es aber keinen Überlauf-Interrupt: Die 255 wird nie erreicht. Bei passender Wahl für den Wert von OCR0 kannst du aber die gewünschte Wiederholfrequenz recht genau einstellen! Und mit Hilfe des OCR0-Interrupts z.B eine Stoppuhr mit 1/100 s Auflösung verwirklichen...
Hi Jakob, danke für deinen Input. Eine Frage noch zu deinem letzen Abschnitt. Wird das OCR0 nach einem "match" geleert ? Oder bleibt der Wert erhalten und triggert das Compare-Interrupt zyklisch immer wieder auf den voreingestellten Wert ? Falls dem so ist, verstehe ich ehrlich gesagt den Sinn des Overflow Interupts nicht. Er erscheint sinnlos. Noch eine super dumme Frage für die ich auf keinen Fall ein neues Topic eröffnen kann: Die folgenden Statements machen alle dasselbe in C oder ? unsigned char byte = 0x00; byte = 0x03; byte = 3; byte |= (1<<1)|(1<<2); byte = 0b00000011 Vielen Dank schonmal! LG Luke
@ Luke (Gast) >Wird das OCR0 nach einem "match" geleert ? Nein! >Oder bleibt der Wert erhalten und triggert das Compare-Interrupt >zyklisch immer wieder auf den voreingestellten Wert ? JA! >Falls dem so ist, verstehe ich ehrlich gesagt den Sinn des Overflow >Interupts nicht. Er erscheint sinnlos. Nein, er hat schon seine Funktion. Mach dir mal nicht zuviele Gedanken. >Die folgenden Statements machen alle dasselbe in C oder ? Sicher, es sind nur andere Zahlensysteme und Bitmanipulation.
Hi Luke schrieb: > unsigned char byte = 0x00; Ne, setzt byte auf Null Luke schrieb: > byte |= (1<<1)|(1<<2); Je nachdem, was vorher in byte stand, kann Da dann auch mehr als 3 drin sein. MfG EDIT Zweifler schrieb: > Bist Du hier sicher? Oha, da steht ja <<1 und <<2 ... neee, das gibt auf jeden Fall eine schöne 6 (eine 1 ist 1<<0, also 1 um 0 Bit verschoben)
:
Bearbeitet durch User
Patrick J. schrieb: > Je nachdem, was vorher in byte stand, kann Da dann auch mehr als 3 drin > sein. Patrick J. schrieb: > Oha, da steht ja <<1 und <<2 ... neee, das gibt auf jeden Fall eine > schöne 6 (eine 1 ist 1<<0, also 1 um 0 Bit verschoben) Ja, ich empfehle: https://www.mikrocontroller.net/articles/Bitmanipulation
Ahaaa. Also steht bei dem Ausdruck (1<<x) bei x nicht um wie viel stellen es rein geschoben wird sondern an welche stelle es geschoben wird!!!! Richtig wäre also: byte |= (1<<0)|(1<<1); damit eine dezimale 3 rauskommt. Ich bin mir bewusst darüber das die anderen Bits unverändert bleiben, weshalb ich das ganze Byte anfangs auf 0 gesetzt hab. Und ja, diese Info hätte ich auch schnell "ergooglen" können :) Aber ich hab es einfach mal hier gefragt da ich ja eh schon am "Hilfe erbeten" war. Danke an alle für eure zahlreichen Kommentare. @Zweifler, du machst deinem Namen alle Ehre, haha. Viel Grüße und einen sonnigen Sonntag wünsche ich. Luke
Luke schrieb: > Also steht bei dem Ausdruck (1<<x) bei x nicht um wie viel stellen es > rein geschoben wird sondern an welche stelle es geschoben wird!!!! Bist Du Dir da sicher?
Hi Du kannst auch komplexere Bitgebilde (aka Zahlen) shiften. Dabei gibt die hintere Zahl an, um wie viele Stellen die Zahl verschoben wird, also ein <<0 verschiebt um keine Stelle - man könnte sich Das theoretisch auch sparen, da die Zahl sie selber bleibt - in der Praxis ist die hintere Zahl aber eine Konstante der Innereien eines µC. Und wenn ich die Taktrate des Timer 0 'komfortabel' im Listing einstellen können will, schreibe ich ldi r16,(0<<CS13)|(1<<CS12)|(0<<CS11)|(0<<CS10) Um das Bitmuster 0100 an die entsprechenden Stellen zu schieben. Dabei ist CS10 wohl in so ziemlich jedem AVR eine Null, wenn aber nicht, funktioniert die Zeile immer noch - kostet nur Rechenzeit beim Compiler/Assembler, lässt sich leicht lesen und funktioniert bestens. Du kannst damit auch Zahlen verdoppeln (auch mehrfach), so macht ein Shiften um 2 das Gleiche, wie die Multiplikation mit 4 (2x2). Nur aufpassen, daß 'links' Nichts raus fällt ;) MfG
Jap absolut. Steht hier auf der Seite unter Bitmanipulation: Beispiel: ldi temp, (1<<3) | (1<<1) | (1<<2) | (1<<0) entspricht: ldi temp, 8 | 2 | 4 | 1 Es wird jeweils eine logische 1 an die Stelle 0,1,2 und 3 geschrieben. Patrick, danke für die Info! LG Luke
Luke schrieb: > Jap absolut. > > Steht hier auf der Seite unter Bitmanipulation: > Es wird jeweils eine logische 1 an die Stelle 0,1,2 und 3 geschrieben. Im Ergebnis, ja. Aber: 1<<0 bedeutet, die 1 wird null mal geschoben. Zitat aus meinem Link: << = Links schieben (Bsp: a<<b ist das gleiche wie a * 2^b; bzw. bei 1<<3 wird die 1 um drei Stellen nach links geschoben) (Ok, das ist Krümelk....)
ouhhhh, jetzt verstehe ich es. also genau gesehen wird nur im Bezug aufs Ergebniss der Wert an die Stelle x geschrieben. Ansonsten heißt dieses x : schiebe 00000001 um x stellen nach links !!!!!! Danke das du so lange, tapfer gezweifelt hast Zweifler ! ^^ LG Luqman
Luke schrieb: > Danke das du so lange, tapfer gezweifelt hast Zweifler ! ^^ Jetzt nicht frech werden ... ;-) Viel Erfolg weiterhin!
Patrick J. schrieb: > Hi > > Du kannst auch komplexere Bitgebilde (aka Zahlen) shiften. > Dabei gibt die hintere Zahl an, um wie viele Stellen die Zahl verschoben > wird, also ein <<0 verschiebt um keine Stelle - man könnte sich Das > theoretisch auch sparen, da die Zahl sie selber bleibt - in der Praxis > ist die hintere Zahl aber eine Konstante der Innereien eines µC. > Und wenn ich die Taktrate des Timer 0 'komfortabel' im Listing > einstellen können will, schreibe ich > ldi r16,(0<<CS13)|(1<<CS12)|(0<<CS11)|(0<<CS10) > Um das Bitmuster 0100 an die entsprechenden Stellen zu schieben. Lesbarer finde ich:
1 | ldi r16,(0b0100<<CS10) |
denn dann steht genau die CD-Konstante aus dem Datenblatt da. (wenn ich das auch sonst immer in C* schreibe)
:
Bearbeitet durch User
Carl D. schrieb: > Lesbarer finde ich: >
1 | ldi r16,(0b0100<<CS10) |
> denn dann steht genau die CD-Konstante aus dem Datenblatt da.
Das funktioniert aber nur dann, wenn die CSnx-Bits wohlgeordnet sind.
Zwar ist das wohl bei allen AVR8 der Fall, aber zwingend ist es nicht,
zumindest theoretisch könnten die Bits auch völlig irregulär angeordnet
im Register liegen, Atmel hat sich diese Option dadurch offen gehalten,
dass eben jedes einzelne Bit seinen eigenen symbolischen Namen hat.
Und die lange Variante würde eben auch diesen Fall problemlos abdecken,
deine hingegen würde dann Mist bauen.
c-hater schrieb: > Carl D. schrieb: > >> Lesbarer finde ich: >>
1 | ldi r16,(0b0100<<CS10) |
>> denn dann steht genau die CD-Konstante aus dem Datenblatt da. > > Das funktioniert aber nur dann, wenn die CSnx-Bits wohlgeordnet sind. > Zwar ist das wohl bei allen AVR8 der Fall, aber zwingend ist es nicht, > zumindest theoretisch könnten die Bits auch völlig irregulär angeordnet > im Register liegen, Atmel hat sich diese Option dadurch offen gehalten, > dass eben jedes einzelne Bit seinen eigenen symbolischen Namen hat. > > Und die lange Variante würde eben auch diesen Fall problemlos abdecken, > deine hingegen würde dann Mist bauen. Ja, das ist mir bekannt. Dafür verwende ich dann die mehrfach gehatete Sprache, die es erlaubt WGM0..3 auch auf 2 verschieden HW-Register verteilt am Stück anzusprechen und sogar nur erlaubte Werte aus einem enum zuweisen zu lassen. Böse Abstraktion, die am Ende genau die beiden Register füllt, je ein ldi und ein std. Sogar wenn auch die anderen Bits dieser Register angesprochen werden. BTW, bitweise muß man natürlich auch wissen, in welchem Register die jeweils liegen.
:
Bearbeitet durch User
Hi, >verstehe ich ehrlich gesagt den Sinn des Overflow >Interupts nicht. Er erscheint sinnlos. Lasse den Timer normal laufen und du hast 2 Int. zb. für Tasten (FF>00) und OC0 in der Hälfte für... LCDtakt oder eben 2x LCD und 1x Tasten. viel Erfolg, Uwe
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.