mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik MEGA32 ALU-Problem?


Autor: M. Gerlach (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Leute,

mein mega32 rechnet falsch!?
Ich lade 4 Byte aus dem EEPROM in eine globale Struktur und will dort
aus dem 32bit integer einen float-Wert machen. Der int-Wert landet
korrekt in einer Hilfsvariable auf dem RAM. Dann muss ich den int-Wert
durch 10^6 teilen und in der Struktur ablegen. Dabei kommt manchmal das
richtige und manchmal das falsch Ergebnis raus.
War kann helfen?

Autor: crazy horse (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
da der AVR selber nicht viel mehr als addieren und schieben kann (das
macht er übrigens ziemlich fehlerfrei), bleiben als Lösung für dein
Problem:
-dein eigenes Programm
-ein Compilerfehler
-Nichtbeachten der prinzipiellen float-Ungenauigkeiten

deine Angaben sind also etwas dürftig.

Autor: Μαtthias W. (matthias) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi

was ist richtig und was ist falsch? Mit welchem Compiler arbeitest du?
Oder hast du die FP-Routinen in ASM kodiert?

Meine Kristallkugel hat leider keinen TÜV mehr bekommen und die neue
ist noch nicht lieferbar.

Matthias

Autor: Daniel Braun (khani)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo M.Gerlach,

was fehlt, sind folgende Informationen :
 - verwendete Programmiersprache/Compiler
 - dein Quelltext (bitte nur den betreffenden Ausschnitt und den
kompletten Quelltext in den Anhang, wenn er Bestandteil des Problems
ist)
 - ein kommentiertes Beispiel

Liefere diese Informationen und Dir wird geholfen - Vorteil : Du
brauchst Dir kein Kristallkugelgewaffel anhören.

Ich hoffe, ich konnte Dir beim Stellen einer sinnvollen und
beantwortbaren Frage helfen.

MfG, Daniel.

Autor: Peter Dannegger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Warum legst Du nicht gleich den Wert als float ab, das sind auch 4
Byte.

float (23 Bit Mantisse) hat eine geringere Genauigkeit als long (32
Bit).


Peter

Autor: M. Gerlach (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Also,

ich benutze C, pn2 mit avrgcc3.3 und studio4.11. Weiterhin habe ich ein
JTAG-ice.

Zunächst zum Ablegen als float:
ich sende die Daten vom PC über USB zum Controller. Dazu muss ich den
ürsprünglichen float-Wert durch Multiplikation in int wandeln, da meine
Senderoutine auf dem PC nur int-weise sendet.

Richtig oder falsch bedeutet tatsächlich keine Ungenauigkeit im
Kommestellenbereich sondern völliger blödsinn oder exakt.

Hier noch ein kleiner Auszug:

        double temp2_m;
  long temp_m,cali_temp;
  unsigned int adr_i,adr_j;    // Adressvariablen
for(adr_i=0;adr_i<10;adr_i++)
    {
  temp_m=0;   // löschen damit ODER-Operation möglich
  adr_j=0;   // Adresszeiger
  cali_temp=0;
  cali_temp=memo_read(6*adr_i+adr_j);
  temp_m=cali_temp<<24;    // erstes byte --> high-byte

  adr_j++;
  cali_temp=0;
  cali_temp=memo_read(6*adr_i+adr_j);
  temp_m=temp_m|cali_temp<<16;

  adr_j++;
  cali_temp=0;
  cali_temp=memo_read(6*adr_i+adr_j);
  temp_m=temp_m|cali_temp<<8;

  adr_j++;
  cali_temp=0;
  cali_temp=memo_read(6*adr_i+adr_j);
  temp_m=temp_m|cali_temp;  // viertes byte --> low-byte

        temp2_m=(double)(temp_m);

  temp2_m=temp2_m/1000000;
  dat.1=temp2

Autor: M. Gerlach (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ach eins noch,

dass ich zwei Adressvariablen benutze hängt mit der Feldstruktur auf
dem EEPROM zusammen.

Autor: M. Gerlach (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Oh ich wurde gerade abgelengt.
Tschuldigung.

Autor: Bri (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich glaub du gehst die Sache komplett falsch an. Wenn ich es richtig
verstanden habe, versuchst du die Flaotzahl erstmal umzurechnen, damit
du sie dann senden kannst. Du solltest die Daten gleich binär schicken.
Falls dein Programm auf dem PC auch in C/C++ geschrieben ist, dann
solltest du es mit einer unit machen. zum Beispiel so:

typedef unit
{
  float f;
  char binary[4];
} Converter;

Das Senden sollte in etwa so aussehen:

Converter c;

c.f = 3.14;
RS232_Send(c.binary,4);

Das Empfangen auf dem Controller:

RS232_Receive(c.binary);
var = c.f

Autor: M. Gerlach (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das wird schwierig. An dem Programm auf dem PC kann ich nicht so einfach
etwas ändern. Und wieso RS232_...? Ich sende via USB.

Autor: M. Gerlach (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Weiterhin ist das Problem nicht auf das Laden der EEPROM-Daten
beschränkt. Das war jetzt nur eine Stelle an der das Auftritt. Generell
sieht es so aus, dass offensichtlich unter bestimmten Umständen
umfangreiche Rechenoperationen nicht nur falsch ausgeführt werden
sondern soger der Stack (Peter müsste wissen worums geht) beschädigt
wird. Das aussert sich durch Sprung ins Nirgendwo.
Kann es nicht sein, dass der compiler in den XYZ-Registern rumfuhrwerkt
weil nicht genügend Register zur Verfügung stehen?

Autor: Peter Dannegger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Du solltest erstmal feststellen, wobei der Fehler auftritt:

- stimmen die Bytes im EEPROM ?
- stimmt der long Wert
- stimmt der float Wert


Und dann braucht man natürlich mindestens je einen Beispielwert, wo es
stimmt und wo nicht, z.B. so:

1,2345 stimmt
1,2346 -> 1,6432 stimmt nicht


Peter

Autor: M. Gerlach (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Deie Daten im EEPROM und im long-Wert sind generell OK.

Gerade ist es z.B. so, dass folgende Zeile in der Laderoutine nicht
ausgeführt wird
      temp2_m=temp2_m/1000000;
sondern mein Debug-Pfeil einfach wieder zurückgesetzt wird!

Autor: M. Gerlach (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Um die Einzelrechenoperationen zu entschärfen, habe ich auch schon
versucht die Division auf zwei aufzuteilen.

Dabei kam der controller auf das merkwürdige Ergebnis

999878/1000=499.939

was genau die Hälfte des richtigen Ergebnisses ist!

Witzig, was!

Autor: M. Gerlach (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Keine Meinungen mehr?

Autor: edvdoctor (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das Problem ist nicht klar beschrieben. Wo soll jetzt ein Fehler
passieren? Wenn Du den Int-Wert durch 10^6 teilst? Dann steht da einmal
was von Umwandlung von int in float, dann wieder von float in int...

Wenn es nur an der Umwandlung scheitert, dann würde ich mal einen
einfachen Cast austesten.

int i = 23;
float f;

f = (float)i;

Autor: M. Gerlach (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Genau so läufts auch. Ich caste den int-Wert auf float und dividiere ihn
durch 10^6, wobei der int-Wert aus dem EEPROM stammt. Diese Operation
funktioniert mal und mal nicht obwohl der int-Wert immer richtig ist!

  temp2_m=(double)(temp_m);
  temp2_m=temp2_m/1000000;
  dat.1=temp2;

Autor: edvdoctor (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Die 1000000 sind eigentlich falsch, muss eigentlich 1000000.0 sein, weil
float bzw. double verarbeitet wird. Sollte aber der Compiler merken und
wohl nicht das Problem sein.

Ich würde auch nach dem Schieben noch maskieren, so:

temp_m = (cali_temp << 24) & 0xF000;    // erstes byte --> high-byte

temp_m= temp_m | (cali_temp << 16) & 0xF00;

usw.

Wieso nimmst Du double, das sind doch 64 Bit (müsste ich bei WinAVR
aber noch prüfen) ?

Autor: edvdoctor (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Achso,

ich hoffe das im Quelltext nicht wirklich:

temp2_m=temp2_m/1000000;
dat.1=temp2;

steht, sondern:

temp2_m=temp2_m/1000000;
dat.1=temp2_m;

Autor: edvdoctor (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Habe nochmal nachgeschaut:
float und double haben jeweils 32 Bit, war also voll ok.

Autor: M. Gerlach (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@edvdoctor

ja das warn schreibfehler. Bezüglich ausmaskieren: das kann ich noch
probiereb, aber das Problem sieht ja so aus , dass der int-Wert immer
korrekt zurechtgeschoben wird und der Operation cast/Division immer
richtig zur Verfügung steht.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.