I need to store some float types in the EEPROM of a PIC in my C18 code.
(I searched on the PICList web site but nothing is leaping out at me.)
To store the other C types I used an example routine from Microchip that
reads and writes bytes.
(BTW it works just fine but I remember changing the addressing part because
it used an unsigned char for the address portion that way I could address
more than 256 bytes)
When I needed to store integers and unsigned integers I was able to do that
with out much trouble.
I just masked off bytes one at a time and did a shift then stored them using
the trusty write a byte routine.
I then read the bytes and using shift operations I was able to reconstruct
my integers and of course unsigned integers.
Strings were a no brainer too just read with respect to the order written
one byte at a time.
Can someone tell me how to get the 4 bytes that comprise a float(MPLAB C18
format) and then how to turn those bytes back into a float using C?
The only way I can think to do it is to get the address of the float var and
then use inline ASM to manipulate the individual bytes.
(Seems like I've done this/some one showed me a clever C trick before but it
was a long time ago in a different environment.
I'll be danged if I can remember just how I did it exactly. )
Thanks to the usual smart people in advance.
Phillip
Things should be as simple as possible but no simpler
Phillip
Things should be as simple as possible but no simpler
Phillip Coiner
CTO, GPS Source, Inc.
Your source for quality GNSS Networking Solutions and Design Services, Now!
{Original Message removed}
On 3/8/07, Phillip Coiner <spam_OUTpcoinerTakeThisOuTgpssource.com> wrote:
>
> Hi All
>
> I need to store some float types in the EEPROM of a PIC in my C18 code.
You can reference the individual bytes in a float by either using a union:
union float_bytes
{
float value;
unsigned char bytes[sizeof(float)];
} myvar;
myvar.value = 123.456;
for (i = 0; i < sizeof(float); i++)
{
write_eeprom_byte(ee_base+i,myvar.bytes[i]);
}
and read it by:
for (i = 0; i < sizeof(float); i++)
{
myvar.bytes[i] = read_eeprom_byte(ee-base+i);
}
Or you can use a pointer:
unsigned char *p;
float myval;
myval = 123.456;
p = (unsigned char *)&myval;
for (i = 0; i < sizeof(float); i++, p++)
write_eeprom_byte(ee_base+i,*p);
and read it by
p = (unsigned char *)&myval;
for (i = 0; i < sizeof(float); i++, p++)
*p = read_eeprom_byte(ee_base+i);
Bill
--
Psst... Hey, you... Buddy... Want a kitten? straycatblues.petfinder.org
Hi Marcel
Mucho thanks I'll try it as soon as my next meeting ends
I couldn't get it to compile in one fell swoop but this compiles.
unsigned char float_to_bytes[4] = {0}; // I'm told the complier zeros my
vars but old habits die hard
float_to_bytes[4]= *(unsigned char*) & my_float;
I have the same/similar issue with declaring vars after any code in my
functions.
For example if I try this
for(int i = 0; i < MAX_SATS; i++)
gives an error
So to get ride of the error I have to do this
(no code is allowed here only variable declarations)
int i = 0;
for(i = 0; i < MAX_SATS; i++)
if I try this
x char = 0;
x += 5; // if I do any thing before I finish my delcarations
then I get compile errors
int i = 0;
for(i = 0; i < MAX_SATS; i++)
I asked Microchip but their answer was that it should work.
When I read the bytes back from memory can I just do a straight cast back
the other direction like this?
my_float = (float) *float_to_bytes;
Phillip
Things should be as simple as possible but no simpler
Phillip Coiner
CTO, GPS Source, Inc.
Your source for quality GNSS Networking Solutions and Design Services, Now!
Hi Phillip, you're mixing some C++ (or maybe also C, but more recently :)
things with older ones,
specifically the for(int i=0 ...
and declarations after statements
Hi Phillip, you're mixing some C++ (or maybe also C, but more recently :)
things with older ones,
specifically the for(int i=0 ...
and declarations after statements
Hi Bill
I couldn't get Marcel's example to work....most likely because I wasn't
following the example correctly.
I was able to get the union example you suggested to work badda bing badda
boom.
I just wanted to say thanks again.
Phillip
Things should be as simple as possible but no simpler
Phillip Coiner
CTO, GPS Source, Inc.
Your source for quality GNSS Networking Solutions and Design Services, Now!
{Original Message removed}
On 3/9/07, Phillip Coiner <pcoinerspam_OUTgpssource.com> wrote:
> Hi Bill
> I couldn't get Marcel's example to work....most likely because I wasn't
> following the example correctly.
> I was able to get the union example you suggested to work badda bing badda
> boom.
> I just wanted to say thanks again.
You're welcome.
Bill
--
Psst... Hey, you... Buddy... Want a kitten? straycatblues.petfinder.org
>You can reference the individual bytes in a float by either using a union:
> union float_bytes
> {
> float value;
> unsigned char bytes[sizeof(float)];
> } myvar;
>
> myvar.value = 123.456;
> for (i = 0; i < sizeof(float); i++)
> {
> write_eeprom_byte(ee_base+i,myvar.bytes[i]);
> }
>Bill
I have long wanted something that could do this, but alas, my K&R tells me:
" Any of these types may be assigned to u and then used in expressions, so
long as the usage is consistent: the type retrieved must be the type most
recently stored. It is the programmer's responsibility to keep track of
which type is currently stored in a union; the results are
implementation-dependent if something is stored as one type and extracted
as another. "
I'd go as far as saying that C should have been provided with something
that did what you're trying above. As an ex-assembly language programmer,
I resent being told how I can access my data :-)
> I have long wanted something that could do this, but alas, my K&R tells me:
>
> " Any of these types may be assigned to u and then used in expressions, so
> long as the usage is consistent: the type retrieved must be the type most
> recently stored. It is the programmer's responsibility to keep track of
> which type is currently stored in a union; the results are
> implementation-dependent if something is stored as one type and extracted
> as another. "
>
> I'd go as far as saying that C should have been provided with something
> that did what you're trying above. As an ex-assembly language programmer,
> I resent being told how I can access my data :-)
You don't really NEED unions, you can just go with (unsigned
char*)&myFloat to read the value as bytes:
> You don't really NEED unions, you can just go with (unsigned
> char*)&myFloat to read the value as bytes:
>
> unsigned char* bytes = (unsigned char*)&myFloat;
> eeprom_write(bytes[0]);
In the spirit of the recent discussion about type checking, there can be
said a word or two about minimizing the number of casts. A union like
suggested tells the reader of the code that this variable is meant to be
read byte-wise, so he better not change the internal representation without
looking carefully at /all/ code that accesses it. A cast somewhere deep in
the code doesn't provide the same type of code-inherent documentation.
OTOH, it can become tedious having to carry along the .value or similar
qualifier of the union through all the code (even though a good editor
helps a bit with this). It all depends, as usually... :)
I have a Delphi 5 windows application that converts the floating point
text into Microchip float format and then writes it over the serial port
as two 16 bit HEX values to the target which saves it into EEROM.
When the Delphi app is launched it reads a HEX dump of EEROM and pulls
the data into floats that are then displayed in the text boxes. You
just have to make sure you keep track of BYTE ordering.
> I have long wanted something that could do this, but alas, my K&R tells me:
>
> " Any of these types may be assigned to u and then used in expressions, so
> long as the usage is consistent: the type retrieved must be the type most
> recently stored. It is the programmer's responsibility to keep track of
> which type is currently stored in a union; the results are
> implementation-dependent if something is stored as one type and extracted
> as another. "
That doesn't mean you can't do it; it just means that the behavior is
not defined by the standard and thus is not portable between different
compilers.
If you want to do it portably, convert the address of the float to an
unsigned char pointer, and use the pointer to walk through the bytes
of the float.
> At 04:47 PM 3/8/07 -0500, William Couture wrote:
>
>>You can reference the individual bytes in a float by either using a union:
>> union float_bytes
>> {
>> float value;
>> unsigned char bytes[sizeof(float)];
>> } myvar;
>>
>> myvar.value = 123.456;
>> for (i = 0; i < sizeof(float); i++)
>> {
>> write_eeprom_byte(ee_base+i,myvar.bytes[i]);
>> }
>>Bill
>
> I have long wanted something that could do this, but alas, my K&R tells
> me:
>
> " Any of these types may be assigned to u and then used in expressions,
> so long as the usage is consistent: the type retrieved must be the type
> most recently stored. It is the programmer's responsibility to keep
> track of which type is currently stored in a union; the results are
> implementation-dependent if something is stored as one type and
> extracted as another. "
This is kind of obvious, it seems to me. What's the problem? Isn't this the
exact purpose of storing two different variables in the same memory
location (independently of the language you're using for this): have the
memory being interpreted in different ways? Of course, if you store your
general string and read it as a double, you usually won't get a result that
makes a lot of sense. But doing with this feature something that makes
sense (like storing a float value byte by byte in an EEPROM) seems to make
sense to me :)
> I'd go as far as saying that C should have been provided with something
> that did what you're trying above.
It is provided with something that does. Bill is not trying, he's showing
how this is done in C (two of the more common ways, anyway).
> As an ex-assembly language programmer, I resent being told how I can
> access my data :-)
Whenever you use a language (even assembly), you're being told by the tool
and by the target what you can do and what you can't do. The difference
doesn't seem to be that you're being told, but what you're being told :)
One major advantage of unions (vs type casts) is that they inherently
document how the data is supposed to be accessed. In this sense, there's a
huge difference between a float and a union float_bytes (as above): A float
implies that it doesn't matter if I implement it as a double (potentially
more precision, different internal format, but every calculation that is
done as a float should also work if done as a double). A union float_bytes
implies that the content is meant to be accessed byte-wise, so you should
not assume that you can replace it with a double and everything works as
before. It's a matter of reading what the code tells you and making
appropriate use of this.
BTW, K&R are really good for helping with the understanding of the essence
of C. But their accent, so to speak, is quite ancient and few current
compilers work according to K&R C. For the details, you're probably better
off with a C89 or C99 manual.
John Temples <@spam@piclist2KILLspamxargs.com> wrote:
> On Tue, 27 Mar 2007, Barry Gershenfeld wrote:
> > I have long wanted something that could do this, but alas, my K&R
> > tells me:
> >
> > "Any of these types may be assigned to u and then used in expressions,
> > so long as the usage is consistent: the type retrieved must be the type
> > most recently stored. It is the programmer's responsibility to keep
> > track of which type is currently stored in a union; the results are
> > implementation-dependent if something is stored as one type and
> > extracted as another. "
>
> That doesn't mean you can't do it; it just means that the behavior is
> not defined by the standard and thus is not portable between different
> compilers.
>
> If you want to do it portably, convert the address of the float to an
> unsigned char pointer, and use the pointer to walk through the bytes
> of the float.
Even that approach depends on the endianess of your hardware. To do
it truly portably, you have to assign the float value to an integer
variable that's at least as large (e.g., long or long long), and then
do the explicit shifting and masking to get at the individual bytes.
In the network world, this is known as "serializing" or "marshalling"
the data.
> On 3/8/07, Phillip Coiner <RemoveMEpcoinerTakeThisOuTgpssource.com> wrote:
> >
> > Hi All
> >
> > I need to store some float types in the EEPROM of a PIC in my C18 code.
>
> You can reference the individual bytes in a float by either using a union:
> union float_bytes
> {
> float value;
> unsigned char bytes[sizeof(float)];
> } myvar;
>
> myvar.value = 123.456;
> for (i = 0; i < sizeof(float); i++)
> {
> write_eeprom_byte(ee_base+i,myvar.bytes[i]);
> }
>
> and read it by:
>
> for (i = 0; i < sizeof(float); i++)
> {
> myvar.bytes[i] = read_eeprom_byte(ee-base+i);
> }
>
> Or you can use a pointer:
>
> unsigned char *p;
> float myval;
> myval = 123.456;
> p = (unsigned char *)&myval;
> for (i = 0; i < sizeof(float); i++, p++)
> write_eeprom_byte(ee_base+i,*p);
>
> and read it by
>
> p = (unsigned char *)&myval;
> for (i = 0; i < sizeof(float); i++, p++)
> *p = read_eeprom_byte(ee_base+i);
>
I'd just use more general eeprom read/write functions which take a
count and pointer:
> John Temples <spamBeGonepiclist2spamBeGonexargs.com> wrote:
>> If you want to do it portably, convert the address of the float to an
>> unsigned char pointer, and use the pointer to walk through the bytes
>> of the float.
>
> Even that approach depends on the endianess of your hardware.
It's portable in the sense that you're guaranteed to get all of the
bytes of the float without relying on implementation-defined or
undefined behavior. Whether endianness is relevant to the application
is another matter. They're not if you reading and writing a local
EEPROM.
> To do
> it truly portably, you have to assign the float value to an integer
> variable that's at least as large (e.g., long or long long),
How would you assign a float containing 3.141 to an integer?
On Tue, 2007-03-27 at 15:32 -0700, John Temples wrote: {Quote hidden}
> On Tue, 27 Mar 2007, Dave Tweed wrote:
>
> > John Temples <TakeThisOuTpiclist2EraseMEspam_OUTxargs.com> wrote:
> >> If you want to do it portably, convert the address of the float to an
> >> unsigned char pointer, and use the pointer to walk through the bytes
> >> of the float.
> >
> > Even that approach depends on the endianess of your hardware.
>
> It's portable in the sense that you're guaranteed to get all of the
> bytes of the float without relying on implementation-defined or
> undefined behavior. Whether endianness is relevant to the application
> is another matter. They're not if you reading and writing a local
> EEPROM.
>
> > To do
> > it truly portably, you have to assign the float value to an integer
> > variable that's at least as large (e.g., long or long long),
>
> How would you assign a float containing 3.141 to an integer?
Depends of course what precision you want. You could just do a i = f,
which would result in 3.
Otherwise decide on a "number of decimal places" and use fixed point
math, i.e. i = f*1000 -> 3141, nothing that there are 3 decimal places.
Personally, I've found there have been VERY few cases where I NEEDED
floating point numbers. I have used them on the PC side since they are
easy to use, but rarely have I NEEDED floats and couldn't have gotten by
with fixed point math.
part 1 771 bytes content-type:text/plain; (unknown type 8bit not decoded)
> Even that approach depends on the endianess of your hardware. To do
> it truly portably, you have to assign the float value to an integer
> variable that's at least as large (e.g., long or long long), and then
> do the explicit shifting and masking to get at the individual bytes.
> In the network world, this is known as "serializing" or "marshalling"
> the data.
and even that is not nessacerally portable because the endian differences between your platforms may not be the same for integers as they are for floats.
--
No virus found in this outgoing message.
Checked by AVG Free Edition.
Version: 7.5.446 / Virus Database: 268.18.18/733 - Release Date: 25/03/2007 11:07
part 2 35 bytes content-type:text/plain; charset="us-ascii" (decoded 7bit)
> -----Original Message-----
> From: RemoveMEpiclist-bouncesTakeThisOuTmit.edu [piclist-bouncesEraseME.....mit.edu]On
> Behalf Of Barry Gershenfeld
> Sent: 27 March 2007 22:13
> To: Microcontroller discussion list - Public.; Microcontroller
> discussion list - Public.
> Subject: Re: [PIC] float to byte - byte to float in C
>
>
> At 04:47 PM 3/8/07 -0500, William Couture wrote:
>
> >You can reference the individual bytes in a float by either
> using a union:
> > union float_bytes
> > {
> > float value;
> > unsigned char bytes[sizeof(float)];
> > } myvar;
> >
> > myvar.value = 123.456;
> > for (i = 0; i < sizeof(float); i++)
> > {
> > write_eeprom_byte(ee_base+i,myvar.bytes[i]);
> > }
> >Bill
>
> I have long wanted something that could do this, but alas, my K&R
> tells me:
>
> " Any of these types may be assigned to u and then used in
> expressions, so
> long as the usage is consistent: the type retrieved must be the type most
> recently stored. It is the programmer's responsibility to keep track of
> which type is currently stored in a union; the results are
> implementation-dependent if something is stored as one type and extracted
> as another. "
of course they are implementation dependant because the internal formats of data types vary between systems.
nearly all non trivial C programs rely on inplementation defined behaviour, the important thing is to remember how stuff behaves on all the common implementations (and #ifdef if nessacery)
--
No virus found in this outgoing message.
Checked by AVG Free Edition.
Version: 7.5.446 / Virus Database: 268.18.18/733 - Release Date: 25/03/2007 11:07
part 2 35 bytes content-type:text/plain; charset="us-ascii" (decoded 7bit)
On 3/27/07, peter green <EraseMEplugwashp10link.net> wrote:
>
> > Even that approach depends on the endianess of your hardware. To do
> > it truly portably, you have to assign the float value to an integer
> > variable that's at least as large (e.g., long or long long), and then
> > do the explicit shifting and masking to get at the individual bytes.
> > In the network world, this is known as "serializing" or "marshalling"
> > the data.
> and even that is not nessacerally portable because the endian differences between your platforms may not be the same for integers as they are for floats.
The whole point of marshalling is to avoid such problems...
> -----Original Message-----
> From: RemoveMEpiclist-bouncesEraseMEEraseMEmit.edu [RemoveMEpiclist-bouncesspam_OUTKILLspammit.edu]On
> Behalf Of Orin Eman
> Sent: 28 March 2007 04:14
> To: Microcontroller discussion list - Public.
> Subject: Re: [PIC] float to byte - byte to float in C
>
>
> On 3/27/07, peter green <RemoveMEplugwashTakeThisOuTspamp10link.net> wrote:
> >
> > > Even that approach depends on the endianess of your hardware. To do
> > > it truly portably, you have to assign the float value to an integer
> > > variable that's at least as large (e.g., long or long long), and then
> > > do the explicit shifting and masking to get at the individual bytes.
> > > In the network world, this is known as "serializing" or "marshalling"
> > > the data.
> > and even that is not nessacerally portable because the endian
> differences between your platforms may not be the same for
> integers as they are for floats.
>
> The whole point of marshalling is to avoid such problems...
yes properly done marshalling should avoid the problems but what was described in the post i replied to (assigning the float value to an integer that is just as large and then reading the individual bytes of that integer using shift/mask operators) is not properly done marshalling and will not solve the problems.
--
No virus found in this outgoing message.
Checked by AVG Free Edition.
Version: 7.5.446 / Virus Database: 268.18.18/733 - Release Date: 25/03/2007 11:07
part 2 35 bytes content-type:text/plain; charset="us-ascii" (decoded 7bit)
>Even that approach depends on the endianess of your hardware.
That is probably why K&R worded their book they way they did, so there was
no assumption that the bytes would be read in the correct order, whatever
the endianness of the processor.