Forum: Mikrocontroller und Digitale Elektronik AVR Pointer verhält sich anders als Computer


von ZeigerGehenAufDenZeiger (Gast)


Lesenswert?

Hallo Forum.

Manchmal zweifle ich an meinen Fähigkeiten.
Ich will den Vergleich Wert für einen 16 bit Timer während der Laufzeit 
ausrechnen und da muss man ja ein High Register setzen und ein Low 
Register.

Wenn ich mache:
1
OCR1AH = 0xF4;
2
OCR1AL = 0x24;

Kommt genau 1 Sekunde raus für den Timer (Prescaler 256 und 16MHz) und 
das klappt auch.

Jetzt zur gesagten Berechnung:
1
void setCompRegister(int ms) {
2
    uint16_t compareVal = 16000 * ms / 256;
3
    uint8_t *ptr = (uint8_t *) &compareVal;
4
    OCR1AH = ptr[1];
5
    OCR1AL = ptr[0];
6
}
mit dem Aufruf:
setCompRegister(1000);

Da müsste wieder genau
1
OCR1AH = 0xF4;
2
OCR1AL = 0x24;
rauskommen.

Ich habe leider keinen AVR Debugger, aber wenn ich den Code auf dem 
Rechner laufen lasse funktioniert er!
Nur auf dem ATmega328p kommt was anderes raus (viel kleiner, also höhere 
Frequenz)

Was mach ich nur falsch.

von Einer K. (Gast)


Lesenswert?

ZeigerGehenAufDenZeiger schrieb:
> Wenn ich mache:
> OCR1AH = 0xF4;
> OCR1AL = 0x24;

OCR1A = 0xF424;
Kann dein Kompiler nicht?

von leo (Gast)


Lesenswert?

ZeigerGehenAufDenZeiger schrieb:
> uint16_t compareVal = 16000 * ms / 256;

Hier hast du einen Overflow.

leo

von ZeigerGehenAufDenZeiger (Gast)


Lesenswert?

leo schrieb:
> ZeigerGehenAufDenZeiger schrieb:
>> uint16_t compareVal = 16000 * ms / 256;
>
> Hier hast du einen Overflow.
>
> leo

Tatsache. Danke!

Arduino Fanboy D. schrieb:
> OCR1A = 0xF424;
> Kann dein Kompiler nicht?

Ich wusste nicht, dass das so geht. Ich werde es Mal testen.

von Axel S. (a-za-z0-9)


Lesenswert?

ZeigerGehenAufDenZeiger schrieb:
> Arduino Fanboy D. schrieb:
>> OCR1A = 0xF424;
>> Kann dein Kompiler nicht?
>
> Ich wusste nicht, dass das so geht.

Nicht nur, daß das so (auch) geht - es ist sogar die empfohlene 
Variante. Denn beim Zugriff auf 16-Bit IO-Register muß man eine 
bestimmte Reihenfolge einhalten. Der Compiler weiß das und macht es 
richtig. Wenn du auf L- und H-Teil separat zugreifst und nicht darauf 
achtest, machst du es in 50% der Fälle falsch herum.

Außerdem ist dein ganzes Pointer-Gedöhns unsinnig. Wenn du einen 16-Bit 
Wert in H- und L-Teil zerlegen willst, dann kannst du das kurz und 
schmerzlos auf dem arithmetischen Weg machen:
1
uint16_t x= 0x1234;
2
// ...
3
uint8_t xl= x & 0xFF;
4
uint8_t xh= x / 0x100;

Und keine Sorge, der Compiler rechnet da nichts. Er greift direkt auf 
den L- bzw H-Teil der langen Variable zu. Wir leben im 21. Jahrhundert 
und nicht mehr in der Computersteinzeit.

von ZeigerGehenAufDenZeiger (Gast)


Lesenswert?

Danke für die ausführliche Antwort! Man lernt ja nie aus...

Axel S. schrieb:
> uint8_t xl= x & 0xFF;
> uint8_t xh= x / 0x100;

Jetzt hast du aber die Reihenfolge falsch :)

von mech (Gast)


Lesenswert?

ZeigerGehenAufDenZeiger schrieb:
> Jetzt hast du aber die Reihenfolge falsch :)

Naja berechnen kannst du die ja in der Reihenfolge die dir am besten 
gefällt. Erst beim Schreiben in Register wird's interessant

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.