Hallo Leute,
ich stehe vor einem Berechnungsproblem.
Und zwar möchte ich aus zwei 8Byte Variable eine 16Byte Variable und
muss diese mit einem bestimmten Faktor Multiplizieren und das Ergebnis
als Kommazahl ausgeben.
Ich habe schon im Forum gesucht nach Möglichkeiten aber die Vorschläge
funktionieren bei mir nicht.
Hier mein Code den ich bis jetzt habe
Da es sich um einen ganzzahligen Ausdruck ((byte01*7)/4095)) handelt -
kommt immer Null heraus. Nimm eine 'float' Variable, die du mit 7
multiplizierst und dann durch 4095 dividierst.
Martin schrieb:> Da es sich um einen ganzzahligen Ausdruck ((byte01*7)/4095)) handelt -> kommt immer Null heraus. Nimm eine 'float' Variable, die du mit 7> multiplizierst und dann durch 4095 dividierst.
Falsch. (byte01 * 7 / 4095) ist in [0, 112].
Micha schrieb:> Hallo Leute,>> ich stehe vor einem Berechnungsproblem.> Und zwar möchte ich aus zwei 8Byte Variable eine 16Byte Variable und> muss diese mit einem bestimmten Faktor Multiplizieren
welches ist dein Faktor?
Wollte sagen zwischen 0 und 112 (falsche klammern)
Martin schrieb:>>> (byte01 * 7 / 4095) ist in [0, 112]>> Es gibt nur 2 Lösungen - 0 und 12. Glaube ich nich
Wollte sagen zwischen 0 und 112 (falsche klammern)
Hallo,
danke erstmal für die vielen Antworten aber irgendwie hilft mir das
alles nicht weiter.
Ich habe jetzt mal meine 16bit int Variable verODERt aber die Berechnung
stimmt immer noch nicht.
@Karlheinz: Mein Faktor ist eigentlich 7.2/4095, wollte es jetzt aber
erstmal mit 7/4095 zum laufen bekommen.
Also so sieht der aktuelle Stand aus aber das Erg. ist immer falsch,
egal ob ich es wie unten abgebildet mache oder mit %10
Restwertberechnung :-(
Micha schrieb:>> @Karlheinz: Mein Faktor ist eigentlich 7.2/4095, wollte es jetzt aber> erstmal mit 7/4095 zum laufen bekommen.
machs doch gleich richtig mit 7.2
Aufpassen musst du nur, dass dir byte01 * 72 keinen Overflow beschert.
Schlimmstenfalls müsste man auf long ausweichen oder aber man kürzte
72/4095 durch, so dass die Zahlen kleiner werden aber im Ergebnis noch
nichts verloren wird.
BTW: die 4095 stimmen? Oder sollten das nicht doch eher 4096 sein?
Karl heinz Buchegger schrieb:> uint16_t byte01 = buffer[0];> byte01 |= buffer[1] << 8;>> uint16_t transformed = byte01 * 72 / 4095;>> sprintf(disp_msg, "Test: %d.%01d", transformed/10, transformed%10 );
Äh Karl Heinz, dir ist aber klar, daß in der Variable "transformed"
jetzt ein 10 mal zu großer Wert steht (für den Fall das man
weiterrechnen möchte).
Wenn ihr einen Faktor 7.2/4095 benutzt könnt ihr euch den Wert in
Buffer[0] sparen, der wird durch das Teilen durch eine Zahl größer 256
sowiso komplett verschwinden.
U.R.Schmitt schrieb:> Wenn ihr einen Faktor 7.2/4095 benutzt könnt ihr euch den Wert in> Buffer[0] sparen, der wird durch das Teilen durch eine Zahl größer 256> sowiso komplett verschwinden.
Sorry ich hatte das Ursprungsposting nicht gut genug gelesen. Der TE
will nicht weiterrechnen, sondern nur als Kommazahl ausgeben. Ich habe
also Blödsinn geschrieben.
Hallo Karlheinz,
das mit der 4095 stimmt schon aber bei der Modulo Berechnung müsste es
doch dann (transformed/10)%10 heißen, da aus der eigentlichen 7.2 eine
72 gemacht wurde oder täusche ich mich ?
Gruß Micha
Micha schrieb:> das mit der 4095 stimmt schon
ganz sicher? Woher kommt der Wert?
Divisionen durch 1023, 2047, 4095 usw sind fast immer ein sicheres
Anzeichen dafür, dass der Programmierer nicht verstanden hat wie ein ADC
funktioniert.
Oder ohne nachzudenken irgendwo falschen Quelltext abgetippt hat.
Wenn dein Wert natürlich nicht von einem ADC kommt, könnte es eventuell
natürlich schon sein, dass dieser so seltsam skaliert ist...
Micha schrieb:> das mit der 4095 stimmt schon aber bei der Modulo Berechnung müsste es> doch dann (transformed/10)%10 heißen, da aus der eigentlichen 7.2 eine> 72 gemacht wurde oder täusche ich mich ?
Genau darum stimmt es ja. Durch das multiplizieren mit 72 ist der Wert
in der Variable transformed 10 mal zu groß.
transformed/10 teilt durch 10 und schneidet ab. Das ist der Wert vor dem
Dezimalpunkt. transformed%10 liefert den rest bei Division durch 10 also
für den korrekten Wert den Betrag nach dem Dezimalpunkt.
Und mit "Test: %d.%01d" gibst Du beide Werte, getrennt mit einem Punkt
aus.
Woher kommen die 4095?
Εrnst B✶ schrieb:> Divisionen durch 1023, 2047, 4095 usw sind fast immer ein sicheres> Anzeichen dafür, dass der Programmierer nicht verstanden hat wie ein ADC> funktioniert.
ACK. Allerdings ohne das "fast immer"... ;-)
Micha schrieb:> Ich habe ein Lastenheft vor mir liegen, indem die Berechnung mit dieser> Formel gemacht wird...
Das würde mir zu denken geben... :-o
U.R.Schmitt schrieb:> Karl heinz Buchegger schrieb:>> uint16_t byte01 = buffer[0];>> byte01 |= buffer[1] << 8;>>>> uint16_t transformed = byte01 * 72 / 4095;>>>> sprintf(disp_msg, "Test: %d.%01d", transformed/10, transformed%10 );>> Äh Karl Heinz, dir ist aber klar, daß in der Variable "transformed"> jetzt ein 10 mal zu großer Wert steht (für den Fall das man> weiterrechnen möchte).
Natürlich ist das klar.
Das ist ja der Sinn der Sache, damit du 1 "Kommastelle" hast.
Genau so funktioniert Fixkomma Arithmetik.
Wenn du anstelle von in Euro eine Berechnung in Cent machst, dann sind
alle Centwerte 100 mal so groß wie die zugehörigen Eurowerte.
Hallo,
nur zum Verstaendnis.
Die Eingangswerte liegen im Bereich 0..63716?
Denn 112.0*4095/7.2 = 63715,5....
Natuerlich kann man durch 4096 teilen/schieben, die Abweichung ist
erheblich kleiner als die Aufloesung von 1/(112 * 10)
// 1/n = 1/(n+1)+ 1/(n+1)^2+1/(n+1)^3 ...
// x/n = x* 1/n = x*1/(n+1) + (x* 1/(n+1)^2 ~ 0.27 bei maximalem x =
63716*72 = 4,587552 Mio.
Dann ist der Faktor nicht mehr 72/4095 sondern 72/4096 = 9/512
trotzdem kommt es zu einem Ueberlauf bei uint16_t
Man koennte dann ohne Ueberlauf mehrstufig rechnen
1
uint16_t transformed = byte01 >>2; // /4
2
transformed *= 3; // *3/4
3
transformed >= 2; // *3/16
4
transformed *= 3; // *9/16
5
transformed >= 5; // *9/512
6
7
//Alternativ in einem Schritt
8
uint32_t transformed = (byte01 *72) >>12;
9
10
//Um modulo zu sparen, falls byte01 jetzt frei ist
Horst Hahn schrieb:> Hallo,>> nur zum Verstaendnis.> Die Eingangswerte liegen im Bereich 0..63716?> Denn 112.0*4095/7.2 = 63715,5....
Die 112 stammen nicht vom TO
Persönlich glaube ich, dass die Eingangswerte nicht über 4095 liegen
werden. So nach dem Muster
Wir haben einen 12 Bit ADC und einer Referenzspannung von 7.2V
Wie rechne ich den ADC Wert auf die Spannung zurücke, wenn ich eine
Nachkommastelle haben will.
Das alles ist jetzt von mir allerdings nur geraten und nur der TO weiß,
ob das so stimmen kann oder nicht.
Bei diesem kurzen Schnipsel geht es ohne volatile nicht, der Kompiler
weiß nichts von den inneren Zuweisung in sprintf.
Natürlich braucht das enorm viel Programmspeicher, die Variante mit %2d
braucht etwa die Hälfte.
Horst Hahn schrieb:> Bei diesem kurzen Schnipsel geht es ohne volatile nicht,
Das wage ich zu bezweifeln. volatile hat (zumindest in deinem Schnipsel)
nichts damit zu tun.
> der Kompiler> weiß nichts von den inneren Zuweisung in sprintf.
Was willst du uns damit sagen?
Fakt ist, dass es 2 Varianten der Standard-Library gibt. In der einen
ist eine abgespeckte Version von sprintf drinnen, die zwar keine
float/double Unterstützung bietet dafür aber kleiner ist. Die andere ist
die voll aufgeblasene Version, die zwar alles kann, dafür aber auch mehr
Speicher benötigt, eben weil dann auch die komplette Floating Point
Arithmetik notwendig ist und mit eingebunden werden muss.
http://www.mikrocontroller.net/articles/FAQ#Aktivieren_der_Floating_Point_Version_von_sprintf_beim_WinAVR_mit_AVR-Studio
Hallo,
Jetzt nach dem Neustart, tut es der simulator es auch ohne volatile,
etwas suspekt das.
Keine Sorge, die volatile habe erst davor gesetzt als im simulator keine
Aenderung in der Varaibel puffer im Watch-Fenster war.