Forum: Compiler & IDEs Array aus Floatwerten in EEPROM schreiben - falsche Werte..
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?
@ 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.
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?
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.
@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!
@ 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.
> 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.
*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.
|