PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Rechenoperationen nur bis 16bit



aircode
13.12.2009, 15:49
Hallo,

kann das sein, dass das Rechnen (+,-,*,/) nur bis 16Bit möglich ist?

Das Terminal spuckt mir bei unten stehende Code kein brauchabres Ergebnis aus (bzw. eigentlich gibt es mir den Wert aus "Ergebnis - 65535 -1"!? Und das obwohl meine Variablen mit 32Bit deklariert worden sind!?

THX for Help...

mfg
Aircode


#include "RP6RobotBaseLib.h"

// -------------------------------------------------------------------------------------
// -------------------------------------------------------------------------------------
// -------------------------------------------------------------------------------------

int main(void)
{

initRobotBase();
powerON();

while(true)
{

uint32_t wert1 = 89200;

uint32_t wert2 = wert1 + 32800;

writeInteger(wert1, DEC);writeString("\n");
writeInteger(wert2, DEC);writeString("\n");

mSleep(5000);

}
return 0;
}

KingTobi
13.12.2009, 16:02
Nur weil du uint32_t schreibst heisst das nicht das der Compiler da auch ne 32Bit Variable draus macht.

radbruch
13.12.2009, 16:10
writeInteger() erwartet eine 16bit-Variable.

aircode
13.12.2009, 16:39
ok, anders:

der code funzt ohne probleme:


#include "RP6RobotBaseLib.h"

// -------------------------------------------------------------------------------------
// -------------------------------------------------------------------------------------
// -------------------------------------------------------------------------------------

int main(void)
{

initRobotBase();
powerON();

while(true)
{

uint32_t wert1 = 700 / 100 * 100;

writeInteger(wert1, DEC);writeString("\n");

mSleep(5000);

}
return 0;
}

der code gibt einen anderen wert aus, und das obwohl zu dem zeitpunkt, wo "wert1" ausgegeben werden soll, "wert1" nur 16Bit groß ist!?


#include "RP6RobotBaseLib.h"

// -------------------------------------------------------------------------------------
// -------------------------------------------------------------------------------------
// -------------------------------------------------------------------------------------

int main(void)
{

initRobotBase();
powerON();

while(true)
{

uint32_t wert1 = 700 * 100 / 100;

writeInteger(wert1, DEC);writeString("\n");

mSleep(5000);

}
return 0;
}

THX
aircode

KingTobi
13.12.2009, 16:41
Ähm, wo ist der Unterschied in den Codes?!

aircode
13.12.2009, 16:49
code 1: uint32_t wert1 = 700 / 100 * 100;
code 2: uint32_t wert1 = 700 * 100 / 100;

im code 1 wird erst dividert, dann multipliziert und umgekehrt...

KingTobi
13.12.2009, 16:53
Glatt übersehen.

Code1: 700 / 100 = 7(geht) * 100 = 700 (geht)
Code2: 700 * 100 = 70000 (geht nicht!) / 100 = 700 (ginge auch)

Punkt vor Strichrechnung scheint ihn da nicht zu interessieren.

aircode
13.12.2009, 17:12
Code2: 700 * 100 = 70000 (geht nicht!) / 100 = 700 (ginge auch)

warum geht nicht? wert1 = 32Bit und 32Bit geht ja bis 4294967295!

KingTobi
13.12.2009, 17:17
Nur weil du uint32_t schreibst heisst das nicht das der Compiler da auch ne 32Bit Variable draus macht.
Mach das mal:


int main(void)
{

initRobotBase();
powerON();

while(true)
{

uint32_t wert1 = 700 * 100 / 100;

writeInteger(sizeof(wert1), DEC);writeString("\n");

mSleep(5000);

}
return 0;
}


Dann siehst du wieviel Speicher (Bytes) für wert1 reservieret wurde.

aircode
13.12.2009, 17:24
1. beim compilieren kommt ein fehler "owerflow"

2. sizeof(wert1) = 4 ... laut terminal

KingTobi
13.12.2009, 17:28
Ja ist ja auch einer, wenn der Controller kein 32Bit Register hat.

aircode
13.12.2009, 17:40
:-)

nagut, wie dem auch sei... ich würde gerne den Wert adcBat korrgieren (um Faktor 0.968) ... wollte dafür eigentlich adcBat erst mit 1000 multiplizieren und dann durch 1033 divideren...

OK, geht leider nicht :-(

Wie kann ich adcBat dann mit den zu Verfügung stehenden Mitteln anpassen?

THX

dennisstrehl
13.12.2009, 17:41
uint32_t wert1 = 700 / 100 * 100;

Ich vermute mal, dass das Standard-Datenformat deines Controllers 16bit ("int") ist. Die Konstanten (700, 100, 100) werden als int behandelt. Erst beim Schreiben in "wert1" (das kommt als letztes) wird der Wert in 32 bit umgewandelt.
Lösung:

uint32_t wert1 = (uint32_t)700 / 100 * 100;
oder vielleicht auch so:
uint32_t wert1 = 700UL / 100 * 100;

Teste das bitte mal.

Besserwessi
13.12.2009, 17:43
Die Variable hat so schon 32 Bit, nur kurz vor der Ausgabe, wenn die Daten an WriteInteger übergeben werden, bleiben nur die unteren 16 über.

Bei den Rechnungen muß man noch angeben das die konstanten auch 32 bit sein sollen. Die Berechnung wird GCC (zumindest mit Optimierung) ohnehin schon beim compilieren ausführen. Ohne Zusatz sind in C konstanten erstmal Integer also 16 Bit. Man muß also statt 700 einfach 700L schreiben, und bei den andern Zahlen analog.

Das hat nichts damit zu tun ob der Conroller 32 bit Register hat - hier passiert das abschneiden ja sogar schon am PC.

KingTobi
13.12.2009, 17:43
Die Variable hat so schon 32 Bit, nur kurz vor der Ausgabe, wenn die Daten an WriteInteger übergeben werden, bleiben nur die unteren 16 über.
...
Ohne Zusatz sind in C konstanten erstmal Integer also 16 Bit. Man muß also statt 700 einfach 700L schreiben, und bei den andern Zahlen analog.

Auch ne Möglichkeit, hab ich nicht dran gedacht.




nagut, wie dem auch sei... ich würde gerne den Wert adcBat korrgieren (um Faktor 0.968) ... wollte dafür eigentlich adcBat erst mit 1000 multiplizieren und dann durch 1033 divideren...

Ja dann benutz doch einfach den Faktor 0,968, dafür gibt es ja Fliesskomma zahlen!

aircode
13.12.2009, 18:01
Lösung -> uint32_t wert1 = 700L * 106L / 100L;

Die Zeile gibt nun den gewünschten Wert aus!

@KingTobi
Fliesskommazahlen wollte ich nicht verwenden, da ich beim Durchstöbern des Forums immer wieder gelesen habe, dass man das vermeiden sollte...

THX an Alle

SlyD
14.12.2009, 10:50
Die writeInteger Funktion kannst Du übrigens auch auf 32 Bit erweitern bei Bedarf.

Einfach aus der Lib rauskopieren. Anstatt itoa müsstest Du ltoa verwenden
http://www.nongnu.org/avr-libc/user-manual/group__avr__stdlib.html


MfG,
SlyD

yaro
14.12.2009, 21:51
Fließkommazahlen sind nicht schlimm, solange du keine übertriebens zeitintensiven Programme hast.

Gruß, Yaro

aircode
14.12.2009, 22:10
Im Moment ist das Programm nicht groß, aber ich bin hart am arbeiten...

Der RP6, ausgestattet mit einem LCD & sonstigem Zeug was noch hinzukommt, soll dann über eine Menüführung welche über Taster und gleichzeitig über RC5 Codes gesteuert werden kann, unterschiedlichste Dinge erledigen.

Ich möchte alles in ein Programm reinpacken was geht... einfach mal um nicht immer nur kurze 08/15 Programme zu schreiben.

Dehalb die Lösung mit" uint32_t wert1 = 700L * 106L / 100L;" .... die gefällt mir eigentlich ganz gut, ist übersichtlich und ich erspare mir die Fließkommazahlen^^

mfg
Aircode

KingTobi
15.12.2009, 14:47
@aircode
Du könntest die Berechnung auch direkt in writeInteger packen, dürfte Speicher sparen, wären immerhin 4 Byte.

aircode
16.12.2009, 06:40
@aircode
Du könntest die Berechnung auch direkt in writeInteger packen, dürfte Speicher sparen, wären immerhin 4 Byte.

Hi Tobi, danke für den Tip...

Das mit writeInteger-Beispiel (von oben) hab ich nur hier im Forum als kleines Beispielprogramm angegeben...

Jetzt sieht der Code ja so aus: (adcBat wird korregiert und gleichzeitig aufgeteilt und dann über die Funktion "send_param();" an den Master übergeben.



uint16_t ubat_aktuell = 0;

void batteriestat (void)
{
if (((ubat_aktuell - 10) > adcBat) || ((ubat_aktuell + 10) < adcBat))
{
param_slave_master[0] = cmd_batteriestatus;
param_slave_master[1] = (adcBat * 1033L / 1000L) / 100;
param_slave_master[2] = adcBat - (param_slave_master[1] * 100);

ubat_aktuell = adcBat;

send_param();
}
}

mfg
Aircode