Hi
ich wollte gerne die OCR Werte automatisch berechnen lassen, weil ich in
der Entwicklungsphase mehrere Zeiten ausprobieren möchte. (Und in
Zukunft generell die Zeiten mit der Formel berechnen)
Kann ich das einfach so machen, oder gibt es bei zu großen Werten einen
Überlauf bzw. bei vielen "Teil"-aufgaben, abgeschnittene Werte?
Habe mir das so vorgestellt:
1
#define F_CPU 4000000UL
2
#define Prescaler 256
3
4
#define time 50 //(in ms)
5
6
//mit Taschenrechner gerechnet: 50ms bei 4MHz OCR1A = 781
7
8
OCR1A=(F_CPU*50)/Prescaler/1000;
9
//bzw.
10
OCR1A=(F_CPU/Prescaler/1000)*50;
Geht das so?
weil
1.: 4.000.000 * 50 = 200.000.000 (Überlauf?)
2.: 4.000.000 256 1000 = 15,625 (15 oder 16?)
Wäre cool wenn ihr die Antwort allgemein haltet, vielleicht brauche ich
irgendwann mal andere Werte. z.B. F_CPU 1MHz, Prescaler 1024, etc.
Schönen Gruß
fortgeschrittener Anfänger
Mitleser schrieb:> 1.: 4.000.000 * 50 = 200.000.000 (Überlauf?)
Warum Überlauf? F_CPU mit 4.000.000 läuft ja auch nicht über. Wenn du
rausfindest, warum nicht, dann weisst du auch, warum das 50-fache davon
auch nicht überläuft.
> 2.: 4.000.000 256 1000 = 15,625 (15 oder 16?)
15.
Mit der 2. Formel bekommst du OCR1-Werte in 50-er Schritten. Ist nicht,
was du willst.
Oliver
Mitleser schrieb:> 1.: 4.000.000 * 50 = 200.000.000 (Überlauf?)
Das UL als Postfix bei den 4Mio
#define F_CPU 4000000UL
kennzeichnet die Zahl als unsigned long.
Damit steht da in den Datentypen betrachtet
unsigned long * int
und diese Berechnung wird im höchsten Datentyp durchgeführt, also
unsigned long. Das Ergebnis davon ist dann ebenfalls ein unsigned long.
Die Preisfrage lautet daher: wie groß kann eigentlich ein unsigned long
maximal werden, ehe er überläuft.
Glücklicherweise weißt du aber, dass ein unsigned long auf deinem System
aus 32 Bits besteht. D.h. du musst dir nur ausrechnen, welches die
größte Zahl ist, die man unsigned mit 32 Bits darstellen kann.
8 Bit: (2 hoch 8) - 1) -> 255
16 Bit: (2 hoch 16) - 1) -> 65535
32 Bits: (2 hoch 32) - 1) -> ????????
Und wenn deine Berechnung mit den für dich relevanten Zahlen darunter
bleibt (Achtung: bei einer komplexeren Formel musst du jede Operation
für sich betrachten!), dann hast du auch keinen Überlauf.
Karl Heinz Buchegger schrieb:> Das UL als Postfix bei den 4Mio> #define F_CPU 4000000UL> kennzeichnet die Zahl als unsigned long.>[...]> und diese Berechnung wird im höchsten Datentyp durchgeführt, also> unsigned long. Das Ergebnis davon ist dann ebenfalls ein unsigned long.
Das war der Hintergrund!
Danke Karl Heinz!
Das Ergebnis wird in ein Register geschrieben, welches ja nur 16 Bit
aufnehmen kann, das die Berechnung sich an dem höchstem Datentyp in der
Formel richtet, war mir nicht bewusst.
Daher danke für die Erklärung!
Oliver schrieb:> 15.> Mit der 2. Formel bekommst du OCR1-Werte in 50-er Schritten.
Auch dafür danke, Oliver.
Es richtet sich also auch nach dem Rechenweg bzw. der Reihenfolge
innerhalb der Formel.
Fazit:
Wieder etwas dazugelernt!!
Einen schönen Tag noch
Mitleser schrieb:> Das Ergebnis wird in ein Register geschrieben, welches ja nur 16 Bit> aufnehmen kann, das die Berechnung sich an dem höchstem Datentyp in der> Formel richtet, war mir nicht bewusst.
Nein. Nicht in der Formel.
In der Operation!
F_CPU * ( 1000 * 1000 )
Die Berechnungsreihenfolge ist
1000 * 1000
und erst dann wird mit F_CPU multipliziert!
1000 * 1000, das sind aber beides int. Daher wird diese Berechnung als
int Multiplikation ausgeführt und liefert ein int Ergebnis. Und erst
dieses int-Ergebnis wird dann mit einem unsigned long multiplizert und
daher wird der entstandene int zuerst zu einem unsigned long
hochgehoben, multipliziert und das Ergebnis ist ein unsigned long.
Aber: die int*int Multiplikation 1000*1000 wird auf einem 16-Bit int
überlaufen. Und daher ist das komplette Ergebnis unbrauchbar, weil es
zwischendurch einen Overflow gab, obwohl das Endergebnis ein unsigned
long ist.
Falk Brunner schrieb:> Festkommaarithmetik
Übrigens beherrscht avr-gcc Festkommaarithmetik und Typen wie accum oder
short fract etc. Wäre bestimmt ein Update von "Festkommaarithmetik"
wert!
@ Johann L. (gjlayde) Benutzerseite
>Übrigens beherrscht avr-gcc Festkommaarithmetik und Typen wie accum oder>short fract etc.
Was bedeutet das praktisch? Welche Vorteile hat das?
> Wäre bestimmt ein Update von "Festkommaarithmetik" wert!
Na dann mal los!
@ Mitleser (Gast)
>Wenn ich das alles richtig verstanden habe, sollte folgende Berechnung>richtig sein:>#define F_CPU 4000000UL>#define ZEIT_IN_MS 50>#define PRESCALER 256>OCR1A = (uint16_t)( (F_CPU*ZEIT_IN_MS)/(uint32_t)(PRESCALER*1000) )
Für diesen Fall ist das OK, allgemein würde ich liber überall UL hinter
die Konstanten schreiben, damit ist es sicher und man muss nicht über
cast nachdenken.
>#define F_CPU 4000000UL>#define ZEIT_IN_MS 50UL>#define PRESCALER 256UL>OCR1A = (uint16_t)( (F_CPU*ZEIT_IN_MS)/(PRESCALER*1000) )
Mitleser schrieb:> Wenn ich das alles richtig verstanden habe
anscheinend aber nicht
> #define F_CPU 4000000UL> #define ZEIT_IN_MS 50> #define PRESCALER 256>> OCR1A = (uint16_t)( (F_CPU*ZEIT_IN_MS)/(uint32_t)(PRESCALER*1000) )
PRESCALER wird durch 256 ersetzt. Die 1000 stehen schon da.
Also steht da nach der Textersetzung (256*1000)
256 ist ein int (16 Bit)
1000 ist ein int (16 Bit)
Also wird dies Multiplikation als int Multiplikation durchgeführt. Und
patsch: das abseits vom µC gefundene Ergebnis 256000 ist zu groß um als
int-Ergebnis noch korrekt zu sein.
Und nein. Der Cast nach uint32_t hilft dir nichts. Denn hier wird zuerst
multipliziert und dann gecastet.
Mitleser schrieb:> OCR1A = (uint16_t)( (F_CPU*ZEIT_IN_MS)/(uint32_t)(PRESCALER*1000) )
Löse einfach mal die Klammern auf und sortiere die Variablen und
Konstanten so, dass du sicher im Wertebereich von 32Bit bleibst und
die Genauigkeit nicht darunter leidet. Dann klappt's auch ohne
Kommazahlen!
Falk Brunner schrieb:> @ Johann L. (gjlayde) Benutzerseite>>> Wäre bestimmt ein Update von "Festkommaarithmetik" wert!>> Na dann mal los!
Selbst hab ich anwendungsseitig nicht viel mit Festkommaarithmetik zu
tun; ich hab lediglich die Arithmetik von Sean in den Compiler eingebaut
und ein paar Optimierungen vorgenommen.
Seans Arithmetik war bereits in einigen Atmel-AVR-Toolchains enthalten,
IIRC in der 4.6.2. Der Support in 4.8+ unterscheidet sich allerdings in
der Darstellung und der Position des Dezimalpunkts bei den Fixed-Werten
mit Ganzzahl-Anteil.
Für die Ergänzung im Wiki wär's m.E. sinnvoll, wenn das jemand machen
würde der Festkommaarithmetik tatsächlich in freier Wildbahn einsetzt.
Eine eigene Frage?
Dieser Thread ist über 13 Jahre alt.
Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.