user276: I'm trying to save GPS coordinates to an EEPROM.
In this example I feed it the latitude of 56060066 as the argument float x
void writeFloat(unsigned int addr, float x)
{
  byte seriesOfBytes[3];
  *((float *)seriesOfBytes) = x;
  // Write all four bytes.
  for(int i = 0; i < 4; i++)
  {
    i2c_eeprom_write_byte(0x57, addr, myFloat.bytes[i]); // Write byte to EEPROM
    Serial.println(seriesOfBytes[i],BIN);  // Debug line
  }
}

I'm expecting to receive the following four bytes from the serial print:
00000011
01010111
01101000
10100010

Instead I'm getting these:
00101000
11011010
01010101
01001100

I've tried changing all sorts of parameters, but can't seem to find the problem. Can anyone spot the issue?

user4143: If you were to enable the display of warnings you would most likely see it complain about "dereferencing type-punned pointer will break strict-aliasing rules" which is what you are doing here.
Basically you are trying to cast an array of four 8-bit values which can have any alignment they like (byte alignment) to a 32-bit float value which needs 4-byte alignment.  And the two just don't mesh.
Instead you need to work the other way around - cast a type that has smaller alignment requirements over the type that has larger requirements.
So instead of getting 4 bytes and trying to fill them as a float you get a float and read it as 4 bytes:
byte *b = (byte *)&floatVal;

Then you can access b[0] to b[3] quite happily.
Another way to do it is with a union:
union {
    float fval;
    byte bval[4];
} floatAsBytes;

floatAsBytes.fval = floatVal;
EEPROM.write(0, floatAsBytes.bval[0]);
EEPROM.write(1, floatAsBytes.bval[1]);
EEPROM.write(2, floatAsBytes.bval[2]);
EEPROM.write(3, floatAsBytes.bval[3]);

Also, in your code, you only allocated enough room for 3 bytes, not 4...

user10794: This mucking around with casts and arrays is far too complex.
See: Reading and Writing Data Structures to EEPROM
The library EEPROMAnything.h will accomplish this. 

EEPROMAnything.h
The library just consists of this file. Save into your "libraries" folder under the folder name EEPROMAnything.
#include <Arduino.h>  // for type definitions
#include <EEPROM.h>

template <typename T> unsigned int EEPROM_writeAnything (int ee, const T& value)
{
    const byte* p = (const byte*)&value;
    unsigned int i;
    for (i = 0; i < sizeof(value); i++)
        EEPROM.write(ee++, *p++);
    return i;
}

template <typename T> unsigned int EEPROM_readAnything (int ee, T& value)
{
    byte* p = (byte*)&value;
    unsigned int i;
    for (i = 0; i < sizeof(value); i++)
        *p++ = EEPROM.read(ee++);
    return i;
}


Example code
#include <EEPROM.h>
#include <EEPROMAnything.h>

void setup ()
  {
  Serial.begin (115200);
  Serial.println ();
  float foo = 56060066;
  EEPROM_writeAnything (0, foo);

  float bar;
  EEPROM_readAnything (0, bar);

  Serial.println (bar);
  }  // end of setup

void loop ()
  {
  }  // end of loop


Output from above
56060064.00

Note you don't get exactly the same number back. This is because of the precision of 4-bytes floats.

After re-reading the question I see you are using I2C EEPROM. That changes the answer a bit, but you can see an adaptation of that library for I2C here. The general idea is the same though.


i2c_eeprom_write_byte(0x57, addr, myFloat.bytes[i]); // Write byte to EEPROM

Your code seems to be writing all of the bytes to the same address, I don't know how that could work.

user972: You are getting exactly what you said you want. 4 bytes representing the number in float format.
What you are expecting to get, is 4 bytes representing the number in big-endian integer format.
Using Majenkos solution for casting, you need to change the types and reverse the for loop for big-endinaness.
I also used int32_t because the size of the int is 16-bit (2-byte) on the Arduino Uno (and other ATMega based boards) and on the Arduino Due it's 32-bit (4-byte). Its better to define the exact int in this case.
union {
    int32_t ival;
    byte bval[4];
} int32AsBytes;

void writeInt32(unsigned int addr, int32_t x)
{
    int32AsBytes.ival = x;
    for(int i = 3; i >= 0; i--) // reverse for big-endian
    {
        i2c_eeprom_write_byte(0x57, addr, myFloat.bytes[i]); // Write byte to EEPROM
        Serial.println(int32AsBytes.bval[i], BIN);  // Debug line
    }
}


276: <p>I'm trying to save GPS coordinates to an EEPROM.</p>

<p>In this example I feed it the latitude of 56060066 as the argument float x</p>

<pre><code>void writeFloat(unsigned int addr, float x)
{
  byte seriesOfBytes[3];
  *((float *)seriesOfBytes) = x;
  // Write all four bytes.
  for(int i = 0; i &lt; 4; i++)
  {
    i2c_eeprom_write_byte(0x57, addr, myFloat.bytes[i]); // Write byte to EEPROM
    Serial.println(seriesOfBytes[i],BIN);  // Debug line
  }
}
</code></pre>

<p>I'm expecting to receive the following four bytes from the serial print:</p>

<pre><code>00000011
01010111
01101000
10100010
</code></pre>

<p>Instead I'm getting these:</p>

<pre><code>00101000
11011010
01010101
01001100
</code></pre>

<p>I've tried changing all sorts of parameters, but can't seem to find the problem. Can anyone spot the issue?</p>
 4143: <p>If you were to enable the display of warnings you would most likely see it complain about <em>"dereferencing type-punned pointer will break strict-aliasing rules"</em> which is what you are doing here.</p>

<p>Basically you are trying to cast an array of four 8-bit values which can have any alignment they like (byte alignment) to a 32-bit float value which needs 4-byte alignment.  And the two just don't mesh.</p>

<p>Instead you need to work the other way around - cast a type that has smaller alignment requirements over the type that has larger requirements.</p>

<p>So instead of getting 4 bytes and trying to fill them as a float you get a float and read it as 4 bytes:</p>

<pre><code>byte *b = (byte *)&amp;floatVal;
</code></pre>

<p>Then you can access b[0] to b[3] quite happily.</p>

<p>Another way to do it is with a union:</p>

<pre><code>union {
    float fval;
    byte bval[4];
} floatAsBytes;

floatAsBytes.fval = floatVal;
EEPROM.write(0, floatAsBytes.bval[0]);
EEPROM.write(1, floatAsBytes.bval[1]);
EEPROM.write(2, floatAsBytes.bval[2]);
EEPROM.write(3, floatAsBytes.bval[3]);
</code></pre>

<p>Also, in your code, you only allocated enough room for 3 bytes, not 4...</p>
 10794: 

<p>This mucking around with casts and arrays is far too complex.</p>

<p>See: <a href="http://playground.arduino.cc/Code/EEPROMWriteAnything" rel="nofollow">Reading and Writing Data Structures to EEPROM</a></p>

<p>The library EEPROMAnything.h will accomplish this. </p>

<hr>

<h2>EEPROMAnything.h</h2>

<p>The library just consists of this file. Save into your "libraries" folder under the folder name <code>EEPROMAnything</code>.</p>

<pre class="lang-C++ prettyprint-override"><code>#include &lt;Arduino.h&gt;  // for type definitions
#include &lt;EEPROM.h&gt;

template &lt;typename T&gt; unsigned int EEPROM_writeAnything (int ee, const T&amp; value)
{
    const byte* p = (const byte*)&amp;value;
    unsigned int i;
    for (i = 0; i &lt; sizeof(value); i++)
        EEPROM.write(ee++, *p++);
    return i;
}

template &lt;typename T&gt; unsigned int EEPROM_readAnything (int ee, T&amp; value)
{
    byte* p = (byte*)&amp;value;
    unsigned int i;
    for (i = 0; i &lt; sizeof(value); i++)
        *p++ = EEPROM.read(ee++);
    return i;
}
</code></pre>

<hr>

<h3>Example code</h3>

<pre class="lang-C++ prettyprint-override"><code>#include &lt;EEPROM.h&gt;
#include &lt;EEPROMAnything.h&gt;

void setup ()
  {
  Serial.begin (115200);
  Serial.println ();
  float foo = 56060066;
  EEPROM_writeAnything (0, foo);

  float bar;
  EEPROM_readAnything (0, bar);

  Serial.println (bar);
  }  // end of setup

void loop ()
  {
  }  // end of loop
</code></pre>

<hr>

<h3>Output from above</h3>



<pre class="lang-none prettyprint-override"><code>56060064.00
</code></pre>

<p>Note you don't get exactly the same number back. This is because of the precision of 4-bytes floats.</p>

<hr>

<p>After re-reading the question I see you are using I2C EEPROM. That changes the answer a bit, but you can see an adaptation of that library for I2C <a href="http://www.gammon.com.au/forum/?id=10896&amp;reply=8#reply8" rel="nofollow">here</a>. The general idea is the same though.</p>

<hr>

<blockquote>
  <p><code>i2c_eeprom_write_byte(0x57, addr, myFloat.bytes[i]); // Write byte to EEPROM</code></p>
</blockquote>

<p>Your code seems to be writing all of the bytes to the same address, I don't know how that could work.</p>
 972: <p>You are getting exactly what you said you want. 4 bytes representing the number in float format.</p>

<p>What you are expecting to get, is 4 bytes representing the number in big-endian integer format.</p>

<p>Using Majenkos solution for casting, you need to change the types and reverse the <code>for</code> loop for big-endinaness.<br>
I also used <code>int32_t</code> because the size of the <a href="https://www.arduino.cc/en/Reference/Int" rel="nofollow"><code>int</code></a> is 16-bit (2-byte) on the Arduino Uno (and other ATMega based boards) and on the Arduino Due it's 32-bit (4-byte). Its better to define the exact <code>int</code> in this case.</p>

<pre class="lang-c++ prettyprint-override"><code>union {
    int32_t ival;
    byte bval[4];
} int32AsBytes;

void writeInt32(unsigned int addr, int32_t x)
{
    int32AsBytes.ival = x;
    for(int i = 3; i &gt;= 0; i--) // reverse for big-endian
    {
        i2c_eeprom_write_byte(0x57, addr, myFloat.bytes[i]); // Write byte to EEPROM
        Serial.println(int32AsBytes.bval[i], BIN);  // Debug line
    }
}
</code></pre>
