70000 / 5 = 888

Gast #1317385
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 /:
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
>.<

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
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.
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.
Gast
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?
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
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 >.<
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.
@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
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).
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.
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

Eine eigene Frage? Dieser Thread ist über 17 Jahre alt. Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.

Neuen Thread starten

Eine Lösung, Ergänzung oder Rückmeldung zu diesem Thread? Dann antworte hier.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.