hur sparas floats i AVR uC?
hur sparas floats i AVR uC?
jag har ett litet program som tar emot en float via UART'en på en AVR (dvs 4bytes som totalt skall ge en float, MSBytes skickas först)
frågan är nu
1 hur gör jag lämpligast om bytes'en -> en korrekt float (sitter och härjar med GCC...)
Mvh
Oscar Isoz
frågan är nu
1 hur gör jag lämpligast om bytes'en -> en korrekt float (sitter och härjar med GCC...)
Mvh
Oscar Isoz
Vet inte, men tror att om GCC inte går ifrån C-standarden när den gör AVR-program ska de ju sparas på samma sätt som i PC. Då borde du t.ex. kunna skicka och ta emot med hjälp av pekare.
Såg nu att du skrivit att MSB skickas först, isf borde det bara att vända på loopen i AVR-koden.
Kod: Markera allt
//PC:
float f;
char *fP;
fP=&f;
for (int i=0;i<sizeof(f);i++)
putchar(fP[i]);
//AVR;
float f;
char *fP;
fP=&f;
for (int i=0;i<sizeof(f);i++)
fP[i]=getchar();
Tack för hjälpen!
men... jag fick det inte att funka direkt där jag skulle använda det så jag satte mig och började ifrån "början"....
Nu ser koden ut så här (det den gör är att den kopierar en float till en annan genom att flytta byte för byte).
ch2_ptr = &f2;
c_ptr = &f;
f = M_PI;
for(int i= 0;i <= sizeof(f);i++){
ch2_ptr = c_ptr;
}
får ut nästan rätt på displayen
f = 3.141560316085
f2 =3.141540527343
Men det jag inte begriper är hur sjutton kan dom vara olika om det är samma bitmönster (viket det är...eller??....)??
/Isoz
men... jag fick det inte att funka direkt där jag skulle använda det så jag satte mig och började ifrån "början"....
Nu ser koden ut så här (det den gör är att den kopierar en float till en annan genom att flytta byte för byte).
ch2_ptr = &f2;
c_ptr = &f;
f = M_PI;
for(int i= 0;i <= sizeof(f);i++){
ch2_ptr = c_ptr;
}
får ut nästan rätt på displayen
f = 3.141560316085
f2 =3.141540527343
Men det jag inte begriper är hur sjutton kan dom vara olika om det är samma bitmönster (viket det är...eller??....)??
/Isoz
Jag vet inte om det här är felet, men jag är rätt säker på att raden:
for(int i= 0;i <= sizeof(f);i++)
inte ska innehålla "<=" utan "<". Då kommer den loopa rätt antal gånger.
Sen behövs det inte en "int" som index (som jag skrev) utan en "char" borde räcka, och dessutom göra progammet snabbare.
(Tror jag, beror på om indirekt adressering använder 8- eller 16-bitars variabler på AVR.)
Alltså, testa:
for(char i=0;i < sizeof(f);i++)
for(int i= 0;i <= sizeof(f);i++)
inte ska innehålla "<=" utan "<". Då kommer den loopa rätt antal gånger.
Sen behövs det inte en "int" som index (som jag skrev) utan en "char" borde räcka, och dessutom göra progammet snabbare.
(Tror jag, beror på om indirekt adressering använder 8- eller 16-bitars variabler på AVR.)
Alltså, testa:
for(char i=0;i < sizeof(f);i++)
Sodjan: jag använder dtostrf för att konvertera mellan float ->char
bearing: '<' istället för '<=' ökar felet....
hmm detta var intressant har skrivit in följande kod:
char *ch_ptr;
char *ch2_ptr;
char *c_ptr;
char *c1_ptr;
char c_arr2[14];
char c_arr[14];
float f;
float f2;
float f3;
ch2_ptr = &f2;
ch_ptr = &f;
f = M_PI; //spara den fördefinerade PI i f (finns i math.h)
for(int i= 0;i <= (sizeof(f));i++){
ch2_ptr = ch_ptr;
}
xmitByte(0x90,INSTR); //byter till rad 2 på displayen
xmitString("f"); //Skriver ut 'f' på displayen
c1_ptr= dtostrf(f,11,12,c_arr); //Skriver ut floaten med 11 decimaler
xmitString(c1_ptr); //
f2 = M_PI; //Sparar M_PI i f2 (dvs exakt samma som görs i början av kodexemplet
xmitByte(0xA0,INSTR); // byter rad
xmitString("Pi"); //Skriver ut 'f' på displayen
c1_ptr= dtostrf(f2,11,12,c_arr); //Skriver ut f2 på displayen
xmitString(c1_ptr);
f3 = f-f2; //Differansen medllan f och f2
xmitByte(0x80,INSTR); //Skriv ut den överst på displayen
c1_ptr= dtostrf(f3,11,12,c_arr);
xmitString(c1_ptr);
Man kan tro att denna kod skulle generera följande på displayen
0.0000000000
f3.141592653589 (dom första 14 tecknen i definitionen på pi i math.h
Pi3.141592653589
men icke
utan istället får jag
0.000024318695
f3.141564846038
Pi3.141592741012
hmm kompilatorn verkar ändra min float på något mystiskt sätt....
hittade dock http://babbage.cs.qc.edu/IEEE-754/Decimal.html där man kan omvandla mellan decimal och float -> (antar att GCC följer IEEE standarden...) om man avrundar defintionen på Pi så får man dom första 7 decimalerna som skrivs ut efter "Pi"
Frågan är dock vad tusan händer med floaten 'f' under det att 'for' satsen körs....Kan det vara något med optimeringen i kompilatorn?
Mvh
en konfunderad Isoz
bearing: '<' istället för '<=' ökar felet....
hmm detta var intressant har skrivit in följande kod:
char *ch_ptr;
char *ch2_ptr;
char *c_ptr;
char *c1_ptr;
char c_arr2[14];
char c_arr[14];
float f;
float f2;
float f3;
ch2_ptr = &f2;
ch_ptr = &f;
f = M_PI; //spara den fördefinerade PI i f (finns i math.h)
for(int i= 0;i <= (sizeof(f));i++){
ch2_ptr = ch_ptr;
}
xmitByte(0x90,INSTR); //byter till rad 2 på displayen
xmitString("f"); //Skriver ut 'f' på displayen
c1_ptr= dtostrf(f,11,12,c_arr); //Skriver ut floaten med 11 decimaler
xmitString(c1_ptr); //
f2 = M_PI; //Sparar M_PI i f2 (dvs exakt samma som görs i början av kodexemplet
xmitByte(0xA0,INSTR); // byter rad
xmitString("Pi"); //Skriver ut 'f' på displayen
c1_ptr= dtostrf(f2,11,12,c_arr); //Skriver ut f2 på displayen
xmitString(c1_ptr);
f3 = f-f2; //Differansen medllan f och f2
xmitByte(0x80,INSTR); //Skriv ut den överst på displayen
c1_ptr= dtostrf(f3,11,12,c_arr);
xmitString(c1_ptr);
Man kan tro att denna kod skulle generera följande på displayen
0.0000000000
f3.141592653589 (dom första 14 tecknen i definitionen på pi i math.h
Pi3.141592653589
men icke

0.000024318695
f3.141564846038
Pi3.141592741012
hmm kompilatorn verkar ändra min float på något mystiskt sätt....
hittade dock http://babbage.cs.qc.edu/IEEE-754/Decimal.html där man kan omvandla mellan decimal och float -> (antar att GCC följer IEEE standarden...) om man avrundar defintionen på Pi så får man dom första 7 decimalerna som skrivs ut efter "Pi"
Frågan är dock vad tusan händer med floaten 'f' under det att 'for' satsen körs....Kan det vara något med optimeringen i kompilatorn?
Mvh
en konfunderad Isoz
Hej.
Som tidigare sagts är i <= (sizeof(f) fel, det ska vara < bara. Tänk att storleken på f är 1. När du går in i for-satsen sätts i till 0, testas 0<1, loopen körs ett varv, i ökas till 1, testas igen 1<1 är fel varvid for-satsen avslutats. Du har alltså genomlöpt loopen 1 gång och det var väl det du ville. Med <= hade det blivit två gånger.
Sen förstår jag inte varför du kör loopen alls eftersom du skriver över värdet av f2 senare.
Nu känner jag inte till dtostrf, men vad jag hittade på nätet så definieras den som char* dtostrf(double __val, char __width, char __prec, char * __s ). Det går alltså inte med float. Dessutom kommer sedan width och därefter antalet decimaler. Du vill alltså ha 12 decimaler i ett 11-teckensfält.
Huvudskälet till felet är antagligen att du använder float i st f double.
Som tidigare sagts är i <= (sizeof(f) fel, det ska vara < bara. Tänk att storleken på f är 1. När du går in i for-satsen sätts i till 0, testas 0<1, loopen körs ett varv, i ökas till 1, testas igen 1<1 är fel varvid for-satsen avslutats. Du har alltså genomlöpt loopen 1 gång och det var väl det du ville. Med <= hade det blivit två gånger.
Sen förstår jag inte varför du kör loopen alls eftersom du skriver över värdet av f2 senare.
Nu känner jag inte till dtostrf, men vad jag hittade på nätet så definieras den som char* dtostrf(double __val, char __width, char __prec, char * __s ). Det går alltså inte med float. Dessutom kommer sedan width och därefter antalet decimaler. Du vill alltså ha 12 decimaler i ett 11-teckensfält.
Huvudskälet till felet är antagligen att du använder float i st f double.
Ja du Isoz, vad du krånglar till det. Du borde frågat mig eller PaGGe nere på XP-el. Det är precis som ie säger, M_PI är en 64b double som du läser in till ett 32b float. En 64b double består ju av 52b mantissa och 11b exponent, medans en 32b float består av 23b mantissa och 8b exponent. Hur denna typkonvertering trunkeras vet jag inte, men det är givet att det är detta fenomen som ger dina avvikelser på PIs decimaler. För att återgå till ditt egentliga problem föreslår jag att du skippar alla försök med pekare och använder dig av union istället. Jag ska försöka illustrera hur:
#include <stdio.h>
typedef union {
float f;
unsigned char auc[4];
} CHAR2FLOAT;
void main() {
CHAR2FLOAT longitud, latitud;
for(unsigned char ucI=0;ucI<4;ucI++)
longitud.auc[ucI] = läs in RX_UART;
longitud.f är nu en float som har värdet som din GPS-modul just överfört
}
#include <stdio.h>
typedef union {
float f;
unsigned char auc[4];
} CHAR2FLOAT;
void main() {
CHAR2FLOAT longitud, latitud;
for(unsigned char ucI=0;ucI<4;ucI++)
longitud.auc[ucI] = läs in RX_UART;
longitud.f är nu en float som har värdet som din GPS-modul just överfört
}