Hallo Leute,
ich hier ein kleines Verständnisproblem.
Ich habe hier einen Code im internet gefunden für einen Timer Compare.
Ich habe den Timer2 bei einen Atmega1280 mit 11,0592 Mhz so gesetzt das
er alle 2 ms einen Compare Interrupt auslöst.
Der Code sieht so aus:
SIGNAL(SIG_OUTPUT_COMPARE1A)
{
static unsigned char cnt=0;
cnt++;
if (cnt & 0x01) // 4ms
{
... tu was 4ms
}
if ((cnt & 0x3F) == 0x20) // 64ms
{
... tu was nach 64ms
}
}
Also als erstes weißt "static" eine feste Adresse zu, soweit klar. Also
nehme ich auch mal an das "cnt" bei jeden Einsprung in die Routine nicht
auf null gesetzt wird duch "static unsigned char cnt=0;" sondern der
Wert erhalten bleibt bis Überlauf ?
Wieso lösen die IF abfragen bei 4ms und bei 64ms aus.
Sehe ich das so richtig:
also wenn cnt=1 ist dann:
cnt 0000 0001
& 0000 0001
----------------
0000 0001 also Wahr
Also löst diese schleife beim ersten Durchlauf aus und dann bei jeden
2.ten wieder oder?
Aber bei der anderen blick ich garnet durch.
cnt 0010 0000
& 0x3F 0011 1111
----------------
0010 0000
=0x20 0010 0000
Also löst doch diese schleife nur einmal aus und dann nicht mehr. Aber
die realität sieht anders aus, die löst alle 64ms aus.
Aber wieso??? ;(((
Bitte erleuchtet mich mal.
Danke!
Gruß
Reini!
Reinhard Winkelmaier schrieb:> if ((cnt & 0x3F) == 0x20) // 64ms> {> ... tu was nach 64ms> }
Hier wird erst maskiert (auf die untersten 6 Bits) und anschließend das
6. Bit getestet. Das kann man auch einfacher schreiben:
if (cnt & 0x20) // 64ms
{
... tu was nach 64ms
}
Meines Erachtens ist die Maskierung hier unnötig.
Trotzdem ist mir schleierhaft, was das soll. Nach 64ms wird nämlich
jedesmal die Bedingung wahr, jedenfalls vom Zählerstand 0010 0000 bis
0011 1111. Erst beim Zählerstand 0100 0000 ist dann wieder Schluss mit
dem "tu was nach 64ms". Absicht?
> Also als erstes weißt "static" eine feste Adresse zu, soweit klar. Also> nehme ich auch mal an das "cnt" bei jeden Einsprung in die Routine nicht> auf null gesetzt wird duch "static unsigned char cnt=0;" sondern der> Wert erhalten bleibt bis Überlauf ?
Eine static-Variable bleibt die ganze Zeit am Leben. Sie wird hier mit 0
initialisiert und läuft hoch bis 255. Das nächste cnt++ bewirkt, dass
sie wieder auf 0 gesetzt wird. Dann geht das Spiel wieder von vorn los.
> Wieso lösen die IF abfragen bei 4ms und bei 64ms aus.
Siehe oben.
> Sehe ich das so richtig:>> also wenn cnt=1 ist dann:> cnt 0000 0001> & 0000 0001> ----------------> 0000 0001 also Wahr>> Also löst diese schleife beim ersten Durchlauf aus und dann bei jeden> 2.ten wieder oder?
Richtig.
> Aber bei der anderen blick ich garnet durch.>> cnt 0010 0000> & 0x3F 0011 1111> ----------------> 0010 0000> =0x20 0010 0000>> Also löst doch diese schleife nur einmal aus und dann nicht mehr. Aber> die realität sieht anders aus, die löst alle 64ms aus.> Aber wieso??? ;(((
Die löst nicht nur alle 64ms aus, sondern nach 64ms mehrfach alle 2ms,
bis dann 0100 0000 erreicht ist. Dann ist erstmal wieder Ruhe. Wenn dann
cnt durch den Überlauf 0 geworden ist, fängt das Spiel von vorne an.
Gruß,
Frank
Frank M. schrieb:> Hier wird erst maskiert (auf die untersten 6 Bits) und anschließend das> 6. Bit getestet. Das kann man auch einfacher schreiben:>> if (cnt & 0x20) // 64ms> {> ... tu was nach 64ms> }>> Meines Erachtens ist die Maskierung hier unnötig.
Das war Quatsch,
if ((cnt & 0x3F) == 0x20) // 64ms
ist natürlich nur wahr bei:
0010 0000
0110 0000
1010 0000
1110 0000
und damit nur bei jedem 32ten Aufruf, also alle 64ms.
Gruß,
Frank
Hallo Frank,
vielen Dank fuer die Antwort, aber
der 64ms Timer hat dann schon einen Aussetzer oder?
Maske 0010 0000
32 0010 0000 ist Wahr
64 0100 0000 ist nicht Wahr, also setzt hier aus
96 0110 0000 ist Wahr
128 1000 0000 wieder nicht Wahr
160 1010 0000 ist Wahr
192 1100 0000 nicht Wahr
224 1110 0000 ist Wahr
256(0) 0000 0000 nicht Wahr
Also taktet der Timer doch nur bei jeden 2.ten aml also 128ms oder?
ist eine solche Schreibweise nicht besser:
IF ( (cnt % 32) == 0 )
{
}
oder hat das Irgendwelche Nachteile?
Und nochwas, was bewirkt so eine EODER Bitmanipulation
REGISTER = 1<<BIT1 ^ 1<<BIT2
Was bewirkt das? Also ich nehme mal an beide Bits werden gesetzt, aber
wofuer das EODER (^) ?
Vielen Dank!
Reinhard Winkelmaier schrieb:> vielen Dank fuer die Antwort, aber> der 64ms Timer hat dann schon einen Aussetzer oder?>> Maske 0010 0000> 32 0010 0000 ist Wahr> 64 0100 0000 ist nicht Wahr, also setzt hier aus> 96 0110 0000 ist Wahr> 128 1000 0000 wieder nicht Wahr> 160 1010 0000 ist Wahr> 192 1100 0000 nicht Wahr> 224 1110 0000 ist Wahr> 256(0) 0000 0000 nicht Wahr
Doch: alle obigen Werte (bis auf die 256(0)) sind wahr. Wenn Du die
Werte mit der Maske 0x3F verbindest, kommt immer 0x20 raus.
> Also taktet der Timer doch nur bei jeden 2.ten aml also 128ms oder?
Nö.
> ist eine solche Schreibweise nicht besser:>> IF ( (cnt % 32) == 0 )> {> }>> oder hat das Irgendwelche Nachteile?
Kommt auf den Compiler und die Optimierungsstufe an.
> Und nochwas, was bewirkt so eine EODER Bitmanipulation>> REGISTER = 1<<BIT1 ^ 1<<BIT2>> Was bewirkt das? Also ich nehme mal an beide Bits werden gesetzt, aber> wofuer das EODER (^) ?
Das sieht nach Code von Peter Danegger aus, er benutzt da gern den
EXOR-Operator '^' statt dem bitweisen ODER-Operator '|'. Ich glaube, er
findet das lesbarer. Andere, die in der Verwendung vom EXOR-Operator
ungeübt sind, finden das aber eher kryptisch - was ich nachvollziehen
kann.
Gruß,
Frank
>> Vielen Dank!
Mal ganz anders, wieso nimmst du nicht einfach zwei Timer, die
unabhängig voneinander nen Interrupt auslösen - dann immer in der
gewünschten Zeit. Oder keine Ressourcen vorhanden?
> ist eine solche Schreibweise nicht besser:> IF ( (cnt % 32) == 0 )
Aus diesem Grund solltest du deine Bitmanipulation besser so machen:
if ((cnt & 0x1F) == 0) // 64ms
Das hat dann die selbe Funktion...
> Also ich nehme mal an beide Bits werden gesetzt,
Wie kommst du darauf?
> Also ich nehme mal an beide Bits werden gesetzt,
Nur, wenn der Wert von BIT1 != BIT2
EDIT:
> Mal ganz anders, wieso nimmst du nicht einfach zwei Timer
Ein böser Würgaraund... :-/
Wozu denn die Timer bei einer so simplen Aufgabe so vergeuden?
Frank M. schrieb:> Doch: alle obigen Werte (bis auf die 256(0)) sind wahr. Wenn Du die> Werte mit der Maske 0x3F verbindest, kommt immer 0x20 raus.
Schon wieder Unsinn, ich sollte besser erst einen Kaffee trinken, bevor
ich lese - und vor allen Dingen - schreibe.
Du hast recht: nur bei jedem zweiten Mal kommt 0x20 raus. Insgesamt also
nur 4 mal bei einem Durchlauf von 0 bis 255. Wenn die ISR tarsächlich
alle 2 ms aufgerufen wird, wären das dann 256 * 2 / 4 = 128ms.
Bist Du Dir sicher, dass die ISR tatsächlich alle 2ms und nicht jede ms
aufgerufen wird?
Gruß,
Frank
Hallo Frank,
immer noch nicht durchgeblick.
If (cnt & 0x3F) == 0x20)
das "cnt & 0x3F" ist doch eine Bitweise ver-undung ?
also, hat der Counter jetzt den Wert 64 dann:
cnt 0100 0000
0x3F 0011 1111
= 0100 0000 ???
ist doch dann nicht Wahr oder?
Ich glaub ich verstehe das Und falsch?
also kann man beim setzen von meheren bits statt:
Register = (1<<BIT1) | (1<BIT2) | (1<<BIT3)
auch
Register = (1<<BIT1) ^ (1<BIT2) ^ (1<<BIT3)
Korrekt?
Gruss Reini!
Ich hatte die Lösung schon geschrieben, nur wollt sie keiner lesen...
:-/
1
if((cnt&0x1F)==0)// 32*2ms
Und damit gilt:
Maske 0001 1111
32 0010 0000 ist Wahr
64 0100 0000 ist Wahr
96 0110 0000 ist Wahr
128 1000 0000 ist Wahr
160 1010 0000 ist Wahr
192 1100 0000 ist Wahr
224 1110 0000 ist Wahr
256(0) 0000 0000 ist Wahr
> also kann man beim setzen von meheren bits statt:> Register = (1<<BIT1) | (1<BIT2) | (1<<BIT3)> auch> Register = (1<<BIT1) ^ (1<BIT2) ^ (1<<BIT3)
Ja, und man spart sich 3x die Alt-GR Taste... ;-)
Das geht wie gesagt, wenn BIT1!=BIT2!=BIT3
dass der Vergleich nur dann wahr ergibt, wenn die untersten 6-Bits von
cnt exakt 0x20 ergeben. Die obersten 2 Bits von cnt können stehen wie
sie wollen, die sind uninteressant. Aber die restlichen müssen exakt
0x20 ergeben.
Wenn man also vom Zähler die obersten 2 Bits auf 0 setzt (weil sie ja
uninteressant sind), dann soll da nicht 0x21, 0x22, 0x23 .... im Zähler
sein, sondern genau 0x20 (oder dezimal 32)
Für die "Wahrheitshäufigkeit" ist der genaue Vergleichswert irrelevant
(solange in dem Wert die oberen 2 Bits 0 sind). Egal ob da nun 0x20 oder
0 oder auch 0x0a steht, es ist immer 4 mal pro 256 wahr (also alle 64
mal). Der Code ist also für einen 1ms-Interrupt geschrieben. Der
Vergleichswert legt nur die genaue Position dieser 4 innerhalb der 256
fest. Man kann so z.B. ein "Zusammenfallen" von Ereignissen bei mehreren
Intervallen vermeiden.
Hallo Leute,
jetzt wirds suspekt.
Also die Loesung von Lothar Miller, klingt mir absolut einleuchtend.
1
if((cnt&0x1F)==0)// 32*2ms
Aber das was karl Heinz Buchegger schreibt klingt auch logisch,
wuerde aber bedeuten der Timer loest nur einmal aus?
Bis zum naechsten Ueberlauf.
Das Was Stefan Ernst schreibt mit den 4 mal ausloesen klingt mir
garnicht
mehr plausibel. wenn der Compare wert doch 32 ist ?
das
1
if((cnt&0x3F)==0x20)
erzeugt die Maske fuer die ver-undung oder?
also 0011 1111
es werden quasi die oberen 2 Bits ausgeblendet und nur diese Bits
uebernommen bei denen 1 und 1 ist, richtig?
Aber dann ist doch die Bedingung == 32 nur einmal erfuellt oder?
Ich werd noch mischugge.
Danke!
Gruss Reini!
Reinhard Winkelmaier schrieb:> Hallo Leute,>> jetzt wirds suspekt.>> Also die Loesung von Lothar Miller, klingt mir absolut einleuchtend.>>
1
if((cnt&0x1F)==0)// 32*2ms
>> Aber das was karl Heinz Buchegger schreibt klingt auch logisch,> wuerde aber bedeuten der Timer loest nur einmal aus?
Nein.
Er löst 4 mal bei einem Umlauf des cnt von 0 bis 255 aus.
Dies deshalb, weil ja die obersten 2 Bits wegmaskiert werden und daher
keine Rolle spielen
0010 0000 hier ist der Vergleich true
0110 0000 und hier ist er true
1010 0000 hier noch einmal
1110 0000 und zu guter letzt hier nochmal
^^
|------ diese beiden Bits werden durch das & 0x3F wegmaskiert und
spielen daher keine Rolle
Aber
0010 0000 hier ist der Vergleich true
0010 0001 hier aber nicht mehr!
Die obigen 4 Binärzahlen, sind die einzigen, bei denen der Vergleich
true ergben wird. In allen anderen Fällen ist der Vergleich false.
(Alle Zahlen sind Binärzahl, wenn nicht anders durch die C-Schreibweise
angegeben)
Reinhard Winkelmaier schrieb:> Also die Loesung von Lothar Miller, klingt mir absolut einleuchtend.
Wenn du einen 2ms-Interrupt hast, dann ja. Aber es ging ja um die
Erklärung des vorhandenen Codes. Und der ist ganz offensichtlich für
einen 1ms-Interrupt gedacht.
> Das Was Stefan Ernst schreibt mit den 4 mal ausloesen klingt mir> garnicht mehr plausibel. wenn der Compare wert doch 32 ist ?
Ok, dann etwas ausführlicher. ;-)
1
(cnt&0x3F)==X
Bedeutet konkret: unteren 6 Bits von cnt sind genau X, oberen 2 Bits
sind egal (alles mal unter der Annahme cnt sei 8 Bit groß).
Aus dem "oberen 2 Bits egal" ergibt sich die Häufigkeit. Sie können 00,
01, 10 oder 11 sein, also 4 pro 256.
Aus dem "genau X" ergibt sich die genaue Position dieser 4 innerhalb der
256.
Hier einfach mal ein paar konkrete Beispiele:
> Er löst 4 mal bei einem Umlauf des cnt von 0 bis 255 aus.
Ich hatte das genau so aufgefasst, dass ausgehend vom zuerst geposteten
Code die eine Aktion alle 4 ms ausgeführt werden soll, und die andere
zyklisch alle 64 ms.
Wenn eine Aktion einmalig zum Zeitpunkt 64 ms ausgelöst werden soll,
dann wäre die Abfrage nach
1
if(cnt==64)...
und ein passendes Zurücksetzen der Variable cnt wohl am
sinnvollsten...
Lothar Miller schrieb:> Wenn eine Aktion einmalig zum Zeitpunkt 64 ms ausgelöst werden soll,> dann wäre die Abfrage nach>
1
>if(cnt==64)...
2
>
> und ein passendes Zurücksetzen der Variable cnt wohl am> sinnvollsten...
Seh ich auch so.
Aber wissen nicht, was in der ISR sonst noch so passiert und ob es einen
guten Grund gibt, warum cnt nicht einfach auf 0 zurückgesetzt wird.
Hallo Leute,
Vielen Dank nun ist es doch angekommen.
Also die weitere ISR existiert noch garnicht, es war eine reine
Verstaendnisfrage von mir.
Die Ihr mir aber hervorragend beantwortet habt.
Vielen Dank euch allen, bis zur naechsten Frage :)
Gruss Reini!