AVR: OCRx1 Werte automatisch berechnen

Gast #3200903
Lesenswert?

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
Gast #3200909
Lesenswert?

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
#3200922
Lesenswert?

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.
Gast #3200936
Lesenswert?

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
#3200955
Lesenswert?

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.
#3201075
Lesenswert?

@ 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!
Gast #3202294
Lesenswert?

Wenn ich das alles richtig verstanden habe, sollte folgende Berechnung 
richtig sein:
1
#define F_CPU       4000000UL
2
#define ZEIT_IN_MS  50
3
#define PRESCALER   256
4

5
OCR1A = (uint16_t)( (F_CPU*ZEIT_IN_MS)/(uint32_t)(PRESCALER*1000) )
#3202309
Lesenswert?

@ 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) )
#3202366
Lesenswert?

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.
Persönliche Seite #3204391
Lesenswert?

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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren