Pages: [1]   Go Down
Author Topic: Float I2c  (Read 2731 times)
0 Members and 1 Guest are viewing this topic.
WV
Offline Offline
Full Member
***
Karma: 0
Posts: 160
Arduino, Helps With the ADD
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Is there a nice simple way to Pass Float Value over I2C -to a second arduino-  (example 3.12 for Volts). All ive seen is elaborate unions and pointers ,, Seems WAY over complexe so i skipped reading further. Any thoughts/ideas /Examples/referances smiley ?
Logged

WV
Offline Offline
Full Member
***
Karma: 0
Posts: 160
Arduino, Helps With the ADD
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Wow thers a first, never had one with out some kind of responce smiley
Logged

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 474
Posts: 18696
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

You need a union. You said you don't want to use one. Not much left to say. They are not particularly elaborate BTW.
Logged

WV
Offline Offline
Full Member
***
Karma: 0
Posts: 160
Arduino, Helps With the ADD
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Nick Gammon , you sem to the goto for I2C ,, have your had the chance to run "unions" before ?
Logged

Global Moderator
Offline Offline
Brattain Member
*****
Karma: 474
Posts: 18696
Lua rocks!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

OK, here's how to do it. Based on the EEPROM_Anything idea I did this ...



I2C_Anything.h

Make a new tab in the IDE called "I2C_Anything.h". Put this in it:

Code:
// Written by Nick Gammon
// May 2012

#include <Arduino.h>
#include <Wire.h>

template <typename T> int I2C_writeAnything (const T& value)
  {
    const byte * p = (const byte*) &value;
    unsigned int i;
    for (i = 0; i < sizeof value; i++)
          Wire.write(*p++);
    return i;
  }  // end of I2C_writeAnything

template <typename T> int I2C_readAnything(T& value)
  {
    byte * p = (byte*) &value;
    unsigned int i;
    for (i = 0; i < sizeof value; i++)
          *p++ = Wire.read();
    return i;
  }  // end of I2C_readAnything

Now here is an example of sending a float and a long to a slave:



Master

Code:
// Written by Nick Gammon
// May 2012

#include <Wire.h>
#include "I2C_Anything.h"

const byte SLAVE_ADDRESS = 42;

void setup()
{
  Wire.begin ();
}  // end of setup

void loop()
{

 long foo = 42;
 
 for (float fnum = 1; fnum <= 10; fnum += 0.015)
    {  
    Wire.beginTransmission (SLAVE_ADDRESS);
    I2C_writeAnything (fnum);
    I2C_writeAnything (foo++);
    Wire.endTransmission ();
      
    delay (200);
    }  // end of for

}  // end of loop



And here is the slave:

Slave

Code:
// Written by Nick Gammon
// May 2012

#include <Wire.h>
#include "I2C_Anything.h"

const byte MY_ADDRESS = 42;

void setup()
{
  Wire.begin (MY_ADDRESS);
  Serial.begin (115200);
  Wire.onReceive (receiveEvent);
}  // end of setup

volatile boolean haveData = false;
volatile float fnum;
volatile long foo;

void loop()
{
  if (haveData)
    {
    Serial.print ("Received fnum = ");
    Serial.println (fnum);  
    Serial.print ("Received foo = ");
    Serial.println (foo);  
    haveData = false;  
    }  // end if haveData

}  // end of loop

// called by interrupt service routine when incoming data arrives
void receiveEvent (int howMany)
 {
 if (howMany >= (sizeof fnum) + (sizeof foo))
   {
   I2C_readAnything (fnum);  
   I2C_readAnything (foo);  
   haveData = true;    
   }  // end if have enough data
 
 }  // end of receiveEvent

The template in the .h file will convert any data type (eg. float, int, long) into a pointer to a series of bytes and send (or receive) those one at a time via I2C.

Example output:

Code:
Received fnum = 6.52
Received foo = 410
Received fnum = 6.53
Received foo = 411
Received fnum = 6.55
Received foo = 412
Received fnum = 6.56
Received foo = 413
Received fnum = 6.58
Received foo = 414
Received fnum = 6.59
Received foo = 415
Received fnum = 6.61
Received foo = 416
Received fnum = 6.62
Received foo = 417
Received fnum = 6.64
Received foo = 418
Received fnum = 6.65
Received foo = 419
Received fnum = 6.67
Received foo = 420
« Last Edit: May 07, 2012, 07:01:32 pm by Nick Gammon » Logged

WV
Offline Offline
Full Member
***
Karma: 0
Posts: 160
Arduino, Helps With the ADD
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Holy Crap, Ty for the info -I would have never expected a complete sketch  tyvm smiley . Now i have to break it down to get the idea of how its works, then to incorporate into my increasingly growing sketch. thank you again smiley
« Last Edit: May 07, 2012, 07:25:34 pm by woody_unreal » Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 4
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I'm having trouble using I2C_Anything with Wire.requestFrom, and any help would be greatly appreciated.

I'd like the master to request data from the slave, but all my floats arrive as nan .  I've tried sending individual bytes and it works.  I'm confident in my wiring because I can get I2C_Anything to work as written in this post.  There's something about how I'm using requestFrom which is breaking something!


Here are the files:

Master, an Uno which uses Wire.requestFrom to ask for the data
Code:
// Eric Rombokas
// Jan 3 2013
// Arduino is i2c master, arduIMU is i2c slave .  arduino dumps requested i2c data to serial
// Using gammon I2C_readAnything.h for translating I2C bytes to other data types

#include <math.h>
#include <Wire.h>
#include "I2C_writeAnything.h"

const int SLAVE_ADDRESS = 10;

volatile float volatileYaw;

void setup() {
  Serial.begin(115200);
  Wire.begin(); // begin with no address specified joins the bus as a master
}

void loop() {
  
  delay(1000);  
  
  if (Wire.requestFrom(SLAVE_ADDRESS, 4, true) == 4) {
    I2C_readAnything(volatileYaw);
    Serial.println(volatileYaw);
  }  
 
 
}


And slave, which uses I2C_writeAnything in its requestEvent()

Code:

// Eric Rombokas
// Jan 3 2013
// ArduIMU runs as an i2c slave, querying freeIMU for yaw, pitch, roll when asked to by the i2c master
// Adapted from Fabio Varesano's FreeIMU_Yaw_pitch_roll RIP
// i2c float/byte stuff adapted from "WanaGo" on arduino forum

#include <ADXL345.h>
#include <bma180.h>
#include <HMC58X3.h>
#include <ITG3200.h>
#include <MS561101BA.h>
#include <I2Cdev.h>
#include <MPU60X0.h>
#include <EEPROM.h>

//#define DEBUG
#include "DebugUtils.h"
#include "CommunicationUtils.h"
#include "FreeIMU.h"
#include "I2C_writeAnything.h"
#include <Wire.h>
#include <SPI.h>
#include <math.h>

volatile float volatileYaw = 42.42;

const int I2CSlaveAddress = 10;

void setup() {
 
  
  Wire.begin(I2CSlaveAddress);
  Wire.onRequest( requestEvent ) ; // declare function handle to be called when i2c master requests
  
}

void loop() {
  

}

// called by onRequest interrupt
void requestEvent() {

  I2C_writeAnything(volatileYaw);
    
}
 

Any ideas?

Thanks,
Eric R

(edited to remove superfluous stuff)
« Last Edit: January 03, 2013, 06:51:34 pm by rombokas » Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 4
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

An update.  Sending multiple bytes at all during a requestEvent results in error.

I'm running on two Uno R3 arduinos.  

Master uses requestFrom to ask for bytes.  If I ask for one, it works, but if I ever ask for more than 1, they come back corrupted.

Master code:

Code:
#include <Wire.h>

int numReceived = 0;

void setup()
{
Wire.begin();        // join i2c bus (address optional for master)
Serial.begin(115200);
}

void loop()
{
  numReceived = 0;
  Wire.requestFrom(2, 2);

  while(Wire.available())
  {
  byte c = Wire.read();
  Serial.print("Received: ");
  Serial.print(c);        
  Serial.println(" . ");
  numReceived++;
  }

  delay(500);
  Serial.print(" Received ");
  Serial.print(numReceived);
  Serial.println(" bytes.  ");
}

Slave code:

Code:
#include <Wire.h>

byte val1 = 0;
byte val2 = 1;

void setup()
{
Wire.begin(2);                // join i2c bus with address #2
Wire.onRequest(requestEvent); // register event
}

void loop()
{
delay(100);
}

void requestEvent()
{
  Wire.write(val1);
  Wire.write(val2);
}

Output is :

Received: 1 .
Received: 255 .
 Received 2 bytes. 


What is happening here?

-Eric
Logged

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 601
Posts: 48543
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Try this:
Code:
byte vals[2];

void requestEvent()
{
  vals[0] = 14;
  vals[1] = 172;

  Wire.write(vals, 2);
}
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 4
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks for the reply! 

It works correctly using the single call to Wire.write().  If I split it into two calls it fails:

eg
Code:
Wire.write(vals[0]);
Wire.write(vals[1]);

Produces

 Received 2 bytes. 
Received: 172 .
Received: 255 .

Is there something about the Wire library that means only a single write() should be used in an interrupt?  I2C_writeAnything() uses multiple Wire.write() calls in a for-loop, so that would mean it can't be used in an onRequest handler.

Perhaps I could modify it to fill a byte array, then send using a single write() call, like this:

Code:
float someFloat = 1.2;
byte vals[4];

byte * p = (const byte*) someFloat;
unsigned int i;
for (i = 0; i < sizeof someFloat; i++)
  vals[i] = *p++;

Wire.write(vals, 4);


Or something like that?

-Eric




Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 4
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

That worked. 

I added the following function to I2C_Anything.h

Code:

template <typename T> int I2C_singleWriteAnything (const T& value) {
  int size = sizeof value;
  byte vals[size];
  const byte* p = (const byte*) &value;
  unsigned int i;
  for (i = 0; i < sizeof value; i++) {
    vals[i] = *p++;
  }
 
  Wire.write(vals, size);
  return i;
}

And it works perfectly, even in the onRequest handler. 

Thanks 4.2 zillions!

Eric Rombokas
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 1
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thanks a lot! it works perfectly with the last addition. MasterWrite works great even with Due. But requestEvent is not working with Due smiley-sad it always prints only "0.00", it doesn't matter if you connect a slave to the master..help please! smiley-cry
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 5
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

thannks for respon,  smiley
Logged

Pages: [1]   Go Up
Jump to: