70000 / 5 = 888

Gast #1317385
Lesenswert?

Hallo,

ich programmiere einen ATMega644 in C mit dem AVR-Studio. Dabei
fiel mir auf, dass eine Rechenoperation irgendwie nicht das tut, was sie
tun soll.
1
#include <avr/io.h>
2
#include <util/delay.h>
3
#include <avr\interrupt.h>
4
#include <math.h>
5
#include <stdlib.h>
6
#include <stdio.h>
7
#include <string.h>
8
#include <stdint.h>
9

10
int main(void)
11
{
12

13
long pulstimerwert = 0;
14

15
  while(1)
16
  {
17

18
OCR1A = pulstimerwert / 5;
19

20
  }
21
}

Wenn ich das Ganze nun genauer anschaue, stelle ich fest, dass sobald
pulstimerwert (pulstimerwert ist immer restlos durch 5 teilbar) über die
65535 (16 bit) kommt, die Division kein richtiges Ergebnis mehr
liefert – 70000 / 5 = 888.

Ich habe schon verschiedene andere Datentypen ausprobiert – int, uint,
long, uint16_t, uint32_t – und die Rechenoperation auf eine Zwischen-
variable gelegt … Jedoch irgendwie will dieses Problem nicht
verschwinden.

Suche und bing konnten mir bis jetzt keine Lösung liefern und jetzt in
Mein C-Programm mit Assembler rumzuflicken will ich nicht.
Ich würde das Ganze nun versuchen mit einer Fallunterscheidung
für pulstimerwert zu lösen, ich hoffe aber, dass jemand von euch weiß
was ich hier falsch mache und eine bessere Lösung hat /:
#1317388
Lesenswert?

Das einzige was ich an diesem Beispiel erkennen kann, ist dass 
pulstimerwert 0 ist, und das Problem folglich nicht auftritt.

Es bringt nichts, einen Code zu posten bei dem das Problem garantiert 
nicht auftreten kann. Der Code muss schon noch den Fehler enthalten, 
sonst wird das nichts.

Ansonsten: Welche Version vom WinAVR?
Gast #1317412
Lesenswert?

>.<

Im Laufe des Programms werden pulstimerwert Werte zwischen 400 und
300000 zugewiesen. Je nachdem was der User auswählen wird. Ich habe
"long pulstimerwert = 0;" nur angegeben, um zu zeigen wie die Variable
derzeit deklariert ist.

AVR-Studioversion: 4.16
#1317416
Lesenswert?

auf schrieb:
> Im Laufe des Programms werden pulstimerwert Werte zwischen 400 und
> 300000 zugewiesen.

Das ist aus dem von dir geposteten Codeteil nicht ersichtlich. Wenn du 
Hilfe willst, dann poste einen Code, der von jedem compilierbar ist, und 
der den Fehler zeigt. Nur so können andere das Problem nachvollziehen 
und den Fehler suchen.
#1317455
Lesenswert?

GB schrieb:
>
1
>   while(1)
2
>   {
3
> 
4
> OCR1A = (uint) (pulstimerwert / 5); // <- expliziter Cast, da OCR1A ein
5
>                                     //  16-Bit-Register ist
6
> 
7
>   }
8
>

das ist nicht der springende Punkt. Der springende Punkt ist: was steht 
eigentlich in pulstimer tatsächlich für ein Wert drinnen. Auch wenn der 
OP denkt, dass da 70000 drinnenstehen sollte, muss das ja nicht so sein.

(70000 - 65536) / 5 = 892

verdächtig nache an den angegebenen 888. Die Vermutung liegt also nahe, 
dass er bei irgendeiner Eingabe- oder Rechenaktion von den gewünschten 
32 Bit irgendwo die oberen 16 Bit verloren hat.
#1317911
Lesenswert?

Hallo,

über das Problem bin ich letzten auch schon gestolpert. Das Problem ist 
wahrscheinlich das er die 5 durch die du teilen möchtest als 16Bit nimmt 
und dein long auf 16bit castet. Schreibe mal einfach hinter der 5 ein 
kleines l.
1
OCR1A = pulstimerwert / 5l;

kann sein das du das Ergebnis aber noch casten musst.

CA Dirk
Gast #1317912
Lesenswert?

Pulstimerwert hat sich aus einer Summe von multiplizierten Int-Werten.
generiert. Das war der Fehler >.<
Zumindest funktioniert es nun wie es soll.

Danke fürs Schubsen in die richtige Richtung und das nächste Mal gebe
ich nicht nur den Teil an Informationen mit an wo ich denke, dass das
das alleinige Problem sein könnte >.<
#1317924
Lesenswert?

Dirk Broßwick schrieb:

> über das Problem bin ich letzten auch schon gestolpert. Das Problem ist
> wahrscheinlich das er die 5 durch die du teilen möchtest als 16Bit nimmt
> und dein long auf 16bit castet.

Wenn eine der beiden Seiten "long" ist wird in "long" gerechnet.
#1317959
Lesenswert?

@A. K.

sorry, habe es eben nochmal getestet ... und siehe da es stimmt, du hast 
recht. Und habe auch festgestellt das das Beispiel bei mir richtig 
rechnet.
AVR-GCC 4.2.4. Das Problem bei mir war wenn ich zwei Zahlen vergleichen 
wollte.

z.b.
1
if ( ByteCounter < ( 1024l*1024l ) )
2
   printf_P( PSTR(" %ld kBytes "), ByteCounter / 1024 );

und
1
if ( ByteCounter < ( 1024*1024 ) )
2
   printf_P( PSTR(" %ld kBytes "), ByteCounter / 1024 );

Das erste Beispiel geht, das zweite nicht. ByteCounter ist vom Typ long.

CA
#1317994
Lesenswert?

C hat viele gemeine Regeln, wann wie umgewandelt und gerechnet wird, vor 
allem was das Vorzeichen angeht. So Sachen wie unsigned*signed sind 
extrem gemein, und sollten daher so gut es geht vermieden werden, wenn 
man sich nicht besonders damit auskennt (ich bin da selbst schon 
merhmals drauf reingefallen).
#1318043
Lesenswert?

Benedikt K. schrieb:
> C hat viele gemeine Regeln, wann wie umgewandelt und gerechnet wird, vor
> allem was das Vorzeichen angeht. So Sachen wie unsigned*signed sind
> extrem gemein, und sollten daher so gut es geht vermieden werden, wenn
> man sich nicht besonders damit auskennt (ich bin da selbst schon
> merhmals drauf reingefallen).

Ja, signed / unsigned kann immer wieder zu Überraschungen führen. Das 
hat wohl jedem schon mal graue Haare eingebracht. (Ein ganzes Büschel 
links hinten geht auf dieses Konto)

Aber agesehen davon ist die simple Grundregel die:

In C ist es völlig irrelevant wie ein Ergebnis verwendet wird. Der 
Compiler berücksichtigt für eine Operation immer nur die Datentypen der 
an der Operation beteiligten Operanden, niemals den Datentyp der 
letztendlich das Ergebnis aufnehmen wird. Der kleinere der beiden 
Datentypen wird auf den größeren hoch gehoben. Ist einer der beiden ein 
Floating Point Typ, wird es der andere auch.
Was noch? Ach ja: Bei signed / unsigned gewinnt immer unsigned (wobei es 
immer spannend ist: Was geschieht mit einem ev. negativen Vorzeichen im 
signed)

Damit lassen sich die Mehrzahl aller Probleme analysieren und bei Bedarf 
bereinigen.
#1318067
Lesenswert?

Karl heinz Buchegger schrieb:
> Benedikt K. schrieb:
>> C hat viele gemeine Regeln, wann wie umgewandelt und gerechnet wird, vor
>> allem was das Vorzeichen angeht. So Sachen wie unsigned*signed sind
>> extrem gemein, und sollten daher so gut es geht vermieden werden, wenn
>> man sich nicht besonders damit auskennt (ich bin da selbst schon
>> merhmals drauf reingefallen).
>
> Ja, signed / unsigned kann immer wieder zu Überraschungen führen. Das
> hat wohl jedem schon mal graue Haare eingebracht. (Ein ganzes Büschel
> links hinten geht auf dieses Konto)

Ich habe zwar nicht so viele Haare, aber die grauen gehen definitiv auf 
das Konto von C.
Aber zurück zum Problem. Ich selber kann es nicht so wirklich 
nachvollziehen. Es wäre mit Sicherheit mal interessant wie der restliche 
Code aussieht.

CA Dirk

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