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
intmain(void)
11
{
12
…
13
longpulstimerwert=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?
>.<
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.
>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.
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?
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.
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
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
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
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.
@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
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