Forum: Compiler & IDEs Array aus Floatwerten in EEPROM schreiben - falsche Werte..


von Kaan A. (deranfaenger)


Angehängte Dateien:

Lesenswert?

Hi Leute,

folgendes Problem:  (es handelt sich um einen ATMega 88PA)

um in meiner PWM effizient arbeiten zu können, möchte ich Divisionen 
vermeiden, indem ich Werte als Konstanten vordefiniere und in einem 
Array abspeichere. Dieses Array soll im EEPROM gespeichert werden.
Es werden die Werte i/255  mit i = 0 - 255 gespeichert.
1
float const adcAccuracy[256] EEMEM={
2
  0.0,
3
  0.00392156862745098,
4
  0.00784313725490196,
5
...........................
6
  0.9921568627450981,
7
  0.996078431372549,
8
  1.0
9
};
Allerdings wenn ich mir die Werte dann beim Debuggen anschaue, finde ich 
komische Zahlen(siehe Anhang). Kann mir jemand sagen, warum das so ist? 
Sind das Rundungsfehler?
Hab ne Weile gegooglet aber ich finde keine Lösung. Ich selbst bin 
C-Anfänger.
Oder gibt es einen besseren Weg, vorzugehen?
Wenn ich 128 Werte (i=0-127) im SRAM speichere habe ich keine Probleme. 
Allerdings wären 256 Werte erwünscht, da dies ein ganzes Byte ist. 
Leider hat mein SRAM nur eine Kapazität von 1KB.

Meine nächste Frage, wenn diese denn geklärt wird, wäre folgende:
Mir wurde gesagt ich solle bei jedem µC start mit Hashing überprüfen, ob 
die Werte im EEPROM den korrekt sind, falls nicht diese neu 
einschreiben.
Kann mir jemand sagen wie ich da vorgehen muss, bzw ob das denn wirklich 
notwendig ist?

von Falk B. (falk)


Lesenswert?

@ Kaan Ayhan (deranfaenger)

>um in meiner PWM effizient arbeiten zu können, möchte ich Divisionen
>vermeiden, indem ich Werte als Konstanten vordefiniere und in einem
>Array abspeichere. Dieses Array soll im EEPROM gespeichert werden.
>Es werden die Werte i/255  mit i = 0 - 255 gespeichert.

Dafür kann man float nehmen, osft ist Feskommaarithmetik aber 
günstiger und ausreichend.

>Allerdings wenn ich mir die Werte dann beim Debuggen anschaue, finde ich
>komische Zahlen(siehe Anhang). Kann mir jemand sagen, warum das so ist?

Sieht nach einem Darstzellungsfehler aus. Denn 9,1e-41 gibt es bei float 
nicht.

>Wenn ich 128 Werte (i=0-127) im SRAM speichere habe ich keine Probleme.
>Allerdings wären 256 Werte erwünscht, da dies ein ganzes Byte ist.
>Leider hat mein SRAM nur eine Kapazität von 1KB.

Wenn deine Werte konstant sind, sind sie noch besser im FLASH 
aufgehoben, davon hast du mehr und der LEsezugriff ist auch etwas 
schneller.

>Mir wurde gesagt ich solle bei jedem µC start mit Hashing überprüfen, ob
>die Werte im EEPROM den korrekt sind, falls nicht diese neu
>einschreiben.

Kann man machen, ist aber nicht zwingend.

>Kann mir jemand sagen wie ich da vorgehen muss,

Mit einem geeigneten Algorithmus berechnet man eine Prüfsumme und 
vergleicht sie mit der gespeicherten Prüfsumme. Gibt es einen 
Unterschied, ist beim letzten Schreibzugriff was schief gelaufen.

> bzw ob das denn wirklich notwendig ist?

Nein.

von Kaan A. (deranfaenger)


Angehängte Dateien:

Lesenswert?

Danke für die schnelle Antwort.

> Dafür kann man float nehmen, osft ist Feskommaarithmetik aber
> günstiger und ausreichend.
Ich nehme ja Floatwerte. Festkomma wäre ja garnicht möglich denn ich 
habe nur Werte zwischen 0 und 1 oder nicht?

> Sieht nach einem Darstzellungsfehler aus. Denn 9,1e-41 gibt es bei float
> nicht.
Wenn du sagst es sind Darstellungsfehler, wie kann ich dann überprüfen 
ob die korrekten Werte übernommen wurden? Muss ich jetzt einfach davon 
ausgehen?

Falk Brunner schrieb:
> Wenn deine Werte konstant sind, sind sie noch besser im FLASH
> aufgehoben, davon hast du mehr und der LEsezugriff ist auch etwas
> schneller.
Danke für den Tipp, das werde ich jetzt wohl auch so machen. allerdings 
bekomme ich hier auch ähnliche Fehler (siehe Anhang):
1
static const __flash float adcAccuracy[] = { ... };
Ist das so denn richtig deklariert?

von Karl H. (kbuchegg)


Lesenswert?

Kaan Ayhan schrieb:
> Danke für die schnelle Antwort.
>
>> Dafür kann man float nehmen, osft ist Feskommaarithmetik aber
>> günstiger und ausreichend.
> Ich nehme ja Floatwerte. Festkomma wäre ja garnicht möglich denn ich
> habe nur Werte zwischen 0 und 1 oder nicht?

Wenn du nur Werte zwischen 0 und 1 hast, dann hindert dich niemand 
daran, das zb 255 fache des jeweiligen Wertes im EEPROM abzulegen. Oder 
das 1000-fache. Oder das 10000-fache.

Floating Point bringt dir nur dann was, wenn du Werte aus krass 
unterschiedlichen Zahlenbereichen hast. Hast du aber nicht. Du musst in 
deinem Programm dann halt einfach nur berücksichtigen, dass ezb ein Wert 
von 255 die Zahl 1.0 darstellt. Oder 127 wären dann eben 0.498

Vorteil: du kannst den Zahlenbereich von 0.0 bis 1.0 in zb 256 
verschiedene Werte aufteilen und brauchst dafür nur ein einziges Byte im 
Speicher. Nimmst du 2 Bytes (einen uint16_t), dann kannst du den 
Wertebereich von 0 bis 1.0 in bereits 65536 Abstufungen darstellen. Das 
sollte eigentlich ausreichen, allerdings muss man dann bei der Rechnerei 
auf mögliche Überläufe aufpassen. Aber gut: Floating Point ist auch 
nicht so problemlos, wie immer alle denken.


> bekomme ich hier auch ähnliche Fehler (siehe Anhang):
>
1
> static const __flash float adcAccuracy[] = { ... };
2
>
> Ist das so denn richtig deklariert?

prinzipiell ja.

Hast du denn an deinem µC keine Möglichkeit, dir irgendwo Zahlen 
auszugeben? UART, LCD oder irgendwas, wo du vom laufenden Programm aus 
Ausgaben machen kannst?
Nein?
Na dann weiter viel Spass. Keine derartige Möglichkeit zu haben ist 
meiner Meinung nach der Kardinalfehler aller Anfänger.

von Falk B. (falk)


Lesenswert?

@Kaan Ayhan (deranfaenger)

>Ich nehme ja Floatwerte. Festkomma wäre ja garnicht möglich denn ich
>habe nur Werte zwischen 0 und 1 oder nicht?

Oder nicht. Lies den Artikel Festkommaarithmetik.

>Wenn du sagst es sind Darstellungsfehler, wie kann ich dann überprüfen
>ob die korrekten Werte übernommen wurden?

Man kann versuchen, die Darstellung im Debugger umzuschalten. Oder 
mittles Trick einen Pointer auf die Daten setzen und sich diese 
byteweise anzuschauen.

uint8_t *p;

p= (uint8_t*)&adcAccuracy;

Dann p im Denugger anschauen.

> Muss ich jetzt einfach davon ausgehen?

NEIN! Das ist eines der großen Grundübel der Leute. Sie GLAUBEN, anstatt 
zu WISSEN!

von Falk B. (falk)


Lesenswert?

@ Karl Heinz (kbuchegg) (Moderator)

>Hast du denn an deinem µC keine Möglichkeit, dir irgendwo Zahlen
>auszugeben? UART, LCD oder irgendwas, wo du vom laufenden Programm aus
>Ausgaben machen kannst?

Ein ICE Debugger kann das. Wenn der aber wie hier einen Bug hat, ist das 
doof.

>Nein?
>Na dann weiter viel Spass. Keine derartige Möglichkeit zu haben ist
>meiner Meinung nach der Kardinalfehler aller Anfänger.

Nö, denn ein ICE Debugger ist eigentlich schon optimal, nur UART und LCD 
sind Workarounds.

von Kaan A. (deranfaenger)


Lesenswert?

> Floating Point bringt dir nur dann was, wenn du Werte aus krass
> unterschiedlichen Zahlenbereichen hast. Hast du aber nicht. Du musst in
> deinem Programm dann halt einfach nur berücksichtigen, dass ezb ein Wert
> von 255 die Zahl 1.0 darstellt. Oder 127 wären dann eben 0.498
Ah ok verstehe..  ob sich das denn für mich lohnt, denn dann müsste ich 
ja alle anderen Werte auch mit bspw. 255 multiplizieren, damit die 
Proportionen stimmen. Somit müsste aber auch mein Timer in der 255fachen 
Frequenz Interrupts schmeißen. Vom rein rechnerischen her vereinfacht 
das die Sache, doch von der zeitkritischen Seite her könnte das Probleme 
bereiten. Ich werde das mal nachrechnen.
Aber danke auch für den Tipp. Ich merke, wie das Fragen in Foren auch 
die Lernkurve verbessert. Jeder Tipp, jede Methode, die zusätzlich 
erläutert wird, ist willkommenes Wissen :)

> Hast du denn an deinem µC keine Möglichkeit, dir irgendwo Zahlen
> auszugeben? UART, LCD oder irgendwas, wo du vom laufenden Programm aus
> Ausgaben machen kannst?
Den µC habe ich ja noch garnicht... das Board dazu ist erst noch in 
Entwicklung. Im Moment läuft das Ganze noch im Simulator.
Ich habe das jetzt so gemacht dass ich am Anfang des Programms ein paar 
Beispielwerte aus dem Array herausgezogen habe. Im Watch-Fenster des 
AtmelStudio sind die Werte korrekt. Nur im Quickwatch-Fenster taucht der 
Darstellungsfehler auf. Also kann ich davon ausgehen, dass die Werte 
korrekt sind.

von Kaan A. (deranfaenger)


Lesenswert?

*Nachtrag:

Bzw. muss ich den Timerinterrupt nicht 255fach schmeißen, sondern 
einfach die Variable mit 255 statt 1 inkrementieren. dann wäre das 
Problem auch gelöst. Ich werde das morgen mal testen. Wenn es den 
Zeitaufwand minimiert ist das perfekt. thumbs up

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.