Besten Dank, sternst.
Wieder was gelernt.
Ciao,
Simon
Besten Dank, sternst.
Wieder was gelernt.
Ciao,
Simon
Hallo Stefan,
Hallo Simon,
ich habe euren Thread hier interessiert verfolgt.
Den ocr_Wert über eine Funktion zu bestimmen ist für meinem Fall zu aufwendig. Ich brauche keine so weite Bandbreite an möglichen Frequenzen. Bei mir wechselt nur die Taktfrequenz vom ATMega. Ich wollte also den ocr_Wert mit einer Präprozessor #define berechnen. Und habe folgenden Code verwendet:
Der aber fehlerhaft sein muss. Ich erhalte als Frequenz ca. 14hz, was bei einem Quarz mit 7,3728Mhz auf einen ocs_Wert von 255 schließen läßt.Code:.... // CTC-Modus TIMSK |= (1 << OCIE0); // ocr_Wert setzen #define ocr_Wert ((F_CPU/(2 * 1024 * 50))-1) // #define ocr_Wert 71 #if ((Vergleichswert > 256) || (Vergleichswert < 0)) #error "Fehler bei der Initialisierung Timer0!" #endif OCR0 = ocr_Wert; ....![]()
Der übrigen Code ist aber richtig und funktionsfähig. Wenn ich #define ocs_Wert 71 schreibe (wie auskommendiert) erhalte ich exakt die gewünschten 50hz an einem Ausgangspin.
Das Problem hat vermutlich was mit der Berechnung zu tun: Weil der GCC warning: integer overflow in expression für die Zuweisung OCR0 = ocr_Wert; auswirft.
Präpozessor #defines sind reine Textersetzungen und keine eigenen Berechnungen. So weit klar. Aber der Ausdruck wird/sollte doch vom Compiler als Konstante gesehen werden und auch so gehändelt werden. Wird aber offensichtlich nicht. Des im Ausdruck mit uint16_t gerechnet wird, ist ebenfalls klar. Aber das Ergebniss ist doch eine uint8_t und müsste zu OCR0 passen. Habe ich mir jedenfalls so gedacht, was aber wie gesagt offensichtlich falsch ist. Auch alle Versuche den Ausdrucken Typen zu zu weisen, haben nichts gebracht.
Was mache ich dann da noch falsch? Hätte jemand eine Idee?
@Stefan:
Die Wirkung von 2UL * habe ich zwar verstanden, die Hintergründe aber nicht wirklich. Wo kann man sich da mal schlau lesen? Hättest Du einen Tip für mich.
Auf alle Fälle schon mal vielen Dank.
mfg
Uwe
Legasteniker on Board!
gefundene Rechtschreibfehler dienen der Belustigung des Lesers und dürfen von diesem behalten werden.
Doch, wird er, aber auch diese Konstante muss ja erst vom Compiler berechnet werden. Und diese Berechnung geschieht natürlich nach den C-Regeln, damit das gleiche dabei rauskommt, wie wenn die Berechnung erst zur Laufzeit passieren würde. Im Gegensatz zur Berechnung zur Laufzeit kann der Compiler hier aber direkt sehen, dass es zu einem Überlauf kommt, und dich warnen.Aber der Ausdruck wird/sollte doch vom Compiler als Konstante gesehen werden und auch so gehändelt werden. Wird aber offensichtlich nicht.
Ne, ist nicht klar, und auch falsch. Der Teil in der Klammer wird in int gerechnet (und da passiert auch gleich der Überlauf). Das (bereits falsche) Zwischenergebnis wird dann nach long promotet, und der Rest in long weiter gerechnet (außer natürlich dein F_CPU ist ungewöhnlich klein).Des im Ausdruck mit uint16_t gerechnet wird, ist ebenfalls klar.
Und auch in deinem Fall hier würde ein UL (oder auch nur L) hinter einer der Zahlen in der Klammer weiterhelfen. Dadurch, dass du einen der Operanden in einen größeren Typ zwingst, erzwingst du, dass die Rechnung in der Klammer insgesamt in einem größeren Typ stattfindet.Die Wirkung von 2UL * habe ich zwar verstanden, die Hintergründe aber nicht wirklich.
MfG
Stefan
Hallo Stefan,
ich habe mich jetzt versucht mal schlau zu machen. Habe aber noch nicht alles verstanden.
Nach Deinen Hinweis ist die Sache zumindest einigermaßen klar, habe einen Fehler in den Berechnungen per Taschenrechner gemacht. (2 * 1024 * 5) wird vom Compiler als uint_16 berechnet, da die längste Zahl in diesem Ausdruck uint_16 ist. Das Ergebniss dieser Multiplikation sprengt aber uint_16. Anstelle des richtigen Ergebniss 102.400 wird mit 36.864 weitergerechnet. Die dann folgende Division F_CPU / 36.864 ist dann natürlich auch fehlerhaft. In meinem Fall ergibt sich dann 7372800 / 36.864, also 200. -1 dann, also 199. Stelle ich mir das so richtig vor? Bin mir nicht sicher, weil ich mit meiner nicht funktionieren Formel ca. 14hz gemessen habe, bei 199 müsste sich aber 18hz messen lassen. Kann aber auch an meinem Messgerät liegen. Im unteren Frequenzberich sind die Abweichungen manchmal größer.
Okay. L zwingt man einer Zahl einen Datentyp auf. Mit L eine uint_32, mit UL eine uint_64? Richtig so? Weil ich leider nicht viel darüber gefunden habe. Ist das so wie eine CAST-Operator zu verstehen? Welche anderen Typkennzeichen gibt es denn noch? Oder hättest Du einen Tip, wo ich mich da schlau machen könnte?
Was aber am wichtigsten ist, der Code funktioniert jetzt!Code:#define ocr_Wert ((F_CPU / (1024 * 2 * 50L)) - 1)
Vielen Dank für Deine Tips.
mfg
Uwe
Legasteniker on Board!
gefundene Rechtschreibfehler dienen der Belustigung des Lesers und dürfen von diesem behalten werden.
Nein, als int (int16_t).(2 * 1024 * 5) wird vom Compiler als uint_16 berechnet
Nein, mit -28672.Anstelle des richtigen Ergebniss 102.400 wird mit 36.864 weitergerechnet.
Für die weitere Rechnung wird das nach uint32_t promotet, was 4294938624 ist. Das Ergebnis der Division ist damit 0. Und 0 - 1 in uint32_t ist 4294967295. Das wird dann nach uint8_t gecastet, und wir landen schlussendlich bei 255.
Nein, L steht für long (int32_t), und UL für unsigned long (uint32_t).Mit L eine uint_32, mit UL eine uint_64? Richtig so?
Ja.Ist das so wie eine CAST-Operator zu verstehen?
In jedem halbwegs brauchbaren C-Buch.Oder hättest Du einen Tip, wo ich mich da schlau machen könnte?
MfG
Stefan
Lesezeichen