Ich möchte rechnen im unsigned int-Bereich von 1 bis etwa 400.000, also
verwende ich uint32_t. Das Ergebnis einer Rechenoperation ist ebenfalls
nur im Bereich der ganzen Zahlen für mich interessant, der Dezimalbruch
kann einfach wegfallen.
(mit #include "type.h" )
1
unit32_tFreq=3000;
2
3
uint32_tErgeb=(10000000/Freq);
Ergebnis ist 3333.333333...,
Ergeb ist 3333, also ausreichend.
1
unit32_tFreq=65000;
Ergebnis ist 153,846153846,
Ergeb ist 153, nicht weiter überraschend.
1
unit32_tFreq=66000;
Ergebnis ist 151,515151515,
Ergeb sollte sein 151, ist aber 13888.
Ab 65536 kippt der Wert, dabei dachte ich mit unint32_t sollte mich das
nicht mehr kratzen müssen.
Casten hilft nicht, zumindest nicht so wie ich es versucht habe:
1
uint32_tErgeb=(uint32_t)(10000000/Freq);
bzw.
1
uint32_tErgeb=(unsignedlongint)(10000000/Freq);
Plattform ist LPCXpresso 1769, also Arm Cortex M3.
Compiler ist GCC, LPCXpresso v6.0.2.
1.Frage: Wieso habe ich hier Probleme mit Werten grösser 16Bit?
2.Frage: Was kann ich dagegen tun?
Danke im Voraus.
cLangErr schrieb:> Casten hilft nicht, zumindest nicht so wie ich es versucht habe:uint32_t> Ergeb = (uint32_t) ( 10000000 / Freq );
ja weil es dort schon zu spät ist
Ergeb = 10000000ul / Freq;
cLangErr schrieb:> Casten hilft nicht, zumindest nicht so wie ich es versucht habe:>
1
>uint32_tErgeb=(uint32_t)(10000000/Freq);
2
>
> bzw.>
1
>uint32_tErgeb=(unsignedlongint)(10000000/Freq);
2
>
Ist das dein echter Code?
Denn:
du musst unterscheiden zwischen der eigentlichen Berechnung und dem was
mit dem Ergebnis passiert. Hier
>
1
uint32_tErgeb=(uint32_t)(10000000/Freq);
wird 10000000 durch Freq dividiert. Diese Division findet als 16 Bit
oder 32 Bit Division statt, je nach den Datentypen der beteiligten
Operanden. D.h. der Datentyp von 10000000 bzw. der Datentyp von Freq
entscheiden, wie die Division durchgeführt wird!
Aus der Division kommt ein Ergebnis und erst dieses Ergebnis forsierst
du dann zu einem uint32_t, das letzten Endes dann an Ergeb zugewiesen
wird.
Wie eine Operation durchgeführt wird, hängt einzig und alleine von den
Datentypen der beteiligten Operanden ab, aber niemals davon, was mit dem
Ergebnis dann weiter passiert (an welchen Variablentyp es zugewiesen
wird, oder ob damit weitergerechnet wird, oder ....)
@ Karl Heinz (kbuchegg) (Moderator)
>wird 10000000 durch Freq dividiert. Diese Division findet als 16 Bit>oder 32 Bit Division statt, je nach den Datentypen der beteiligten>Operanden.
Nöö. 10000000 (10e6) passt nur in 32 Bit.
Ja, das war der echte Code, soweit runter gebrochen, dass der Fehler
noch auftritt.
Freq ist doch aber uint32 und 10mio ist doch (offensichtlich) mehr als
16 Bit. Dann müsste das Ergebnis doch ebenfalls 32 Bit breit bleiben.
Ich habe mal 10000000 mit uL ergänzt, so grosse konstante Zahlenwerte
habe ich auch noch nie in Berechnungen gehabt. Das Ergebnis ist das
selbe.
Jetzt habe ich nochmal die 10 mio als const uint32_t heraus gezogen, das
Ergebnis ist aber trotzdem noch nicht besser.
Würden die 10000000 aber als 16 Bit-Wert aufgefasst, dann müssten die ja
schon vorher vom Compiler klein gemacht werden, dann könnten ja die
Rechenoperation für Freq-Werte kleiner 65535 nicht stimmen.
Falk Brunner schrieb:> @ Karl Heinz (kbuchegg) (Moderator)>>>wird 10000000 durch Freq dividiert. Diese Division findet als 16 Bit>>oder 32 Bit Division statt, je nach den Datentypen der beteiligten>>Operanden.>> Nöö. 10000000 (10e6) passt nur in 32 Bit.
Schon klar.
Darum hab ich auch gefragt, ob das der richtige Code ist.
Denn nur mit dem geposteten ist das Ergebnis nicht zu erklären.
cLangErr schrieb:> Ja, das war der echte Code, soweit runter gebrochen, dass der Fehler> noch auftritt.
OK.
Dann stellt sich die Frage, wie du feststellst, dass dein Ergebnis nicht
korrekt ist.
Du wärst nicht der Erste, der einem Fehler in der Berechnung nachläuft
und dann draufkommt, das er bei der Anzeige des Wertes eine implizite
Verkürzung auf 16 Bit hat.
Daher: kompletter Code! Oftmals sitzt der Fehler nicht dort, wo du ihn
vermutest.
cLangErr schrieb:> Würden die 10000000 aber als 16 Bit-Wert aufgefasst, dann müssten die ja> schon vorher vom Compiler klein gemacht werden, dann könnten ja die> Rechenoperation für Freq-Werte kleiner 65535 nicht stimmen.
Statt lauter "hätte", "wäre", "könnte", "müsste" und "würde" täte ich
einfach mal den erzeugten Assemblercode ansehen. Da sieht man recht
schnell, was der Compiler aus der C Zeile macht...
Lothar Miller schrieb:> Statt lauter "hätte", "wäre", "könnte", "müsste" und "würde" täte ich> einfach mal den erzeugten Assemblercode ansehen. Da sieht man recht> schnell, was der Compiler aus der C Zeile macht...
Der echte C Codeausschnitt wäre auch nicht schlecht. Irgendein grob
nachempfundener Code mit offensichtlichem Syntaxfehler ist keine grosse
Hilfe.
Ebenso ist "kippt der Wert" keine wahrhaft präzise Problemangabe.
Ja, ich habe das aus dem Code kopiert, habe aber die Zeilen mehrfach im
Browser-Editor bearbeitet, und da mache ich als freudsche Verschreiber
oft unit statt uint.
Cut&Paste läuft nicht immer ganz so problemlos, die IDE ist in einer
virtuellen Maschine.
Das ganze Programm hat ein paar tausend Zeilen Code, unter anderem kommt
der Wert von Freq übers TCP/IP rein. Das Ergebnis der Berechnung wird
wieder zurückgesendet, aber vor allem wandert es als Pulsperiode in die
PWM-Unit, welche zufällig mit 10MHz läuft.
Also sehe ich nicht nur den Zahlenwert als Antwort sondern auch den
Effekt im Oszilloskop.
Die Zeile sieht also so aus:
1
constuint32_tpwm_takt=10000000uL;
2
3
LPC_PWM1->MR0=Ergeb=(uint32_t)(pwm_takt/Freq);
4
LPC_PWM1->MR1=10;
5
LPC_PWM1->LER=(1<<0)|(1<<1);
Ich werde mal alles raus schmeissen und wirklich nur das minimalste
Programm posten.
Ich meine, mich erinnern zu können, dass der Cortex-M generell dazu
neigt, Rechenoperationen in 16Bit durchzuführen, wenn man keinen
Typecast am Operanden durchführt.
Probiere es mal mit
Das Ergebnis zu casten bringt dir nämlich nichts, zu dem Zeitpunkt ist
die Messe schon gelesen. Das führt dann nur noch dazu, dass die
Zuweisung als 32-Bit-Operation durchgeführt wird.
Frank Bär schrieb:> Ich meine, mich erinnern zu können, dass der Cortex-M generell dazu> neigt, Rechenoperationen in 16Bit durchzuführen, wenn man keinen> Typecast am Operanden durchführt.
Das wäre höchst seltsam. Zumal die Hardware das überhaupt nicht kann.
Die hat nämlich einen Divisionbefehl, aber nur für 32 Bits.
Aus dem präsentierten Code geht leider nicht eindeutig hervor, wer
hier dividiert. Wenn beide Seiten dem Compiler bekannt sind, dann
dividiert der Compiler, andernfalls der Prozessor.
Die Debug-Ausgabe ist jetzt (für mich überreaschend):
Rechentest
Freq = 65000 , Ergeb = 153
Freq = 66000 , Ergeb = 151
Ich habe den PWM-Teil absichtlich drin gelassen, damit ich weiter den
PWM-Ausgang messen kann.
Tja, scheint ja nun zu gehen :/
cLangErr schrieb:> Tja, scheint ja nun zu gehen :/
Womit wir wieder am Punkt angelangt wären:
dein Problem im richtigen Programm sitzt ganz wo anders. Was du dort
siehst, sind Symptome aber nicht Ursachen.
Darum, und das ist jetzt durchaus nicht bösartig gemeint, ist es so
wichtig, ein Problem in seinem vollen Umfeld zu zeigen. Sprich:
kompletter Code. Ist das zu gross, dann eben ein abgespecktes
vollständiges Programm, bei dem man aber vorher testen sollte, ob es das
gleiche Problem zeigt. Denn oft genug ist das dann nämlich nicht der
Fall.