Forum: Mikrocontroller und Digitale Elektronik 70000 / 5 = 888


von auf (Gast)


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 /:

von (prx) A. K. (prx)


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?

von auf (Gast)


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

von Benedikt K. (benedikt)


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.

von Gast (Gast)


Lesenswert?

Glaskugel an

Der vom Benutzer gewählte Wert wird irgendwo auf 16 Bit (implizit) 
gecasted und noch ein wenig "abgerundet".

Glaskugel aus

von GB (Gast)


Lesenswert?

1
  while(1)
2
  {
3

4
OCR1A = (uint) (pulstimerwert / 5); // <- expliziter Cast, da OCR1A ein 
5
                                    //  16-Bit-Register ist
6

7
  }

von (prx) A. K. (prx)


Lesenswert?

Die Frage ist eher, wo der Wert zugewiesen wird.
Und die Version!!!!!

von Karl H. (kbuchegg)


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.

von horst (Gast)


Lesenswert?

Unter Linux mit gcc reicht es nicht, math.h zu inkludieren, um die 
mathematische Bibliothek einzubinden. Da braucht der linker noch ein 
-lm.

Ist das beim AVR-Studio vielleicht ähnlich?

von Karl H. (kbuchegg)


Lesenswert?

horst schrieb:

> Ist das beim AVR-Studio vielleicht ähnlich?

ist ähnlich. Aber er braucht ja nichts aus der math Library. Das ist 
eine popelige long Division.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

libm.a wird hier nicht benötigt, da es nicht um Floatingpoint-Arithmetik 
geht.

Das ist reine Integer-Arithmetik, die braucht keine Libraries. Und auch 
kein math.h

von Dirk B. (sharandac)


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

von auf (Gast)


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 >.<

von (prx) A. K. (prx)


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.

von Dirk B. (sharandac)


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

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

1
if ( ByteCounter < ( 1024*1024 ) )
Standardmäßig werden Konstanten als int (bei gcc = 16bit) gerechnet.
Erst am schluß wird die Konstante dann auf long erweitert und daher geht 
dir vorher schon was verloren bevor der Compiler das auf long erweitern 
kann.

von Dirk B. (sharandac)


Lesenswert?

@Läubi,

ja, das habe ich dann nach dem intensiven lesen meiner C Lektüre auch 
gelesen. Zum damaligen Zeitpunkt als ich angefangen habe C zu lernen war 
mir das nur völlig unklar.

CA

von Benedikt K. (benedikt)


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).

von Karl H. (kbuchegg)


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.

von Dirk B. (sharandac)


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

von (prx) A. K. (prx)


Lesenswert?

Dirk Broßwick schrieb:

> Aber zurück zum Problem. Ich selber kann es nicht so wirklich
> nachvollziehen.

Das ist längst gelöst (15:25).

von Dirk B. (sharandac)


Lesenswert?

Äh ... mal wieder verpeilt ... lang genau nach meinem und vor deinem 
Beitrag :-)

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.