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.
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)
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
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)
> 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.
>> 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.
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