Función para partir y unir un float

Buenas.

Por necesidades varias necesito coger un float y guardarlo como dos int (para transmitirlo por modbus); luego tengo que coger esos dos ints y volver a componer el float.

Dicho de otra manera.
-Crear un float
-Meter los dos primero bytes en un int
-Meter los dos segundos bytes en otro int
-transmitirlos por modbus (eso ya lo tengo en marcha)
-volver a componer el float en base a los dos ints

He echado un vistazo a las operaciones

#include <WProgram.h>
template <class T> int EEPROM_writeAnything(int ee, const T& value)
{
    const byte* p = (const byte*)(const void*)&value;
    int i;
    for (i = 0; i < sizeof(value); i++)
	  EEPROM.write(ee++, *p++);
    return i;
}

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

y se que aqui tengo la respuesta, pero no lo saco.

¿Alguna manita?

Gracias.

Si no funciona lo que te comento puedes utilizar la forma que se ha comentado alguna vez en el foro: http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1207242838
Debería estar en español por aquí, pero no lo encuentro mirando por encima.

Prueba con esto, a ver que tal funciona.

int send(const float& value)
{
    const int* p = (const int*)(const void*)&value;
    for (int i = 0; i < sizeof(value)/sizeof(int); i++)
	  MODBUS.SEND(*p++);
    return i;
}

int read(float& value)
{
    int* p = (int*)(void*)&value;
    for (int i = 0; i < sizeof(value)/sizeof(int); i++)
	  *p++ = MODBUS.READ();
    return i;
}

Hola,
También podrías declarar una union, que es una estructura de C que puede contener varias cosas distintas. Una vez comenté esa posibidad en el foro: http://arduino.cc/forum/index.php/topic,69929.0.html

curro92:
Hola,
También podrías declarar una union, que es una estructura de C que puede contener varias cosas distintas. Una vez comenté esa posibidad en el foro: http://arduino.cc/forum/index.php/topic,69929.0.html

Mira el primer enlace que he puesto XD

Ostras, union hace la fuerza
Voy a probarlo

Ya estoy de vuelta.

Con un servidor modbus en mi pc le puedo mandar el float partido en dos ints.
Esto lo hace bien y luego puedo recuperarlo de igual manera con el PC.

El problema viene cuando quiero volver a montar esos dos ints en un float y escribirlo en puerto serie.

El codigo que tengo es más o menos:

//fuera de setup y loop

unsigned int regs1[21];

union {
unsigned int ints[2];
float toFloat;
} foo;

void loop {

  foo.ints[0]=regs1[15];
  foo.ints[1]=regs1[16];

}


void contestar{

      Serial.println(foo.ints[0]);
      Serial.println(foo.ints[1]);
      Serial.println(foo.toFloat);
}

Eso está resumido.
Cuando llamo a "contestar" me aparece:
4059
16457
0.00

El float que debería aparecer es 3.141592654 (aprox)

Creo que el problema está en la implementación del float. Es decir: el pc ha mandado 2 ints que luego él sabe componer, pero arduino no.
¿Puede ser?
¿opiniones, ideas?

1 Like

Hola,

Prueba con este ejemplo, el Serial.print a mí me da 3.141593

union 
{
  unsigned int ints[2];
  float toFloat;
} foo;


void setup()
{
   Serial.begin(9600);
}   
   

   
void loop()
{
  // 3.141593
  foo.ints[0]=4059;
  foo.ints[1]=16457;

  Serial.println(foo.toFloat, 6); // con 6 decimales
  Serial.println(foo.ints[0]);
  Serial.println(foo.ints[1]);
  Serial.println("");
  delay(500);
}
1 Like

Pues a mi me da...

0.000000
4059
16457

0.000000
4059
16457

Y ahora es cuando yo digo... es que no estoy usando Arduino, estoy usando una chipkit max32.
Pero... ¿No debería dar igual?

Un saludo.

Sin mirar muhco tu codigo..
Y si enviás como dos intetegers directamente?? La parte entera como tal, y la real la "convertis" a un entero.. Algo parecido se usa para imprimir floats en LCDs..

mm. Ejemplo..

float = 2.25

entero = int(2.25); // entero = 2
enviar(entero);

real = (float - entero) * 100; // real = 25
enviar(real);

Despues tenes que hacer algo parecido para recuperar el dato.

Buenos dias.

  1. No puedo usar el método de partir entero y decimal por que no puedo elegír la manera. Ya me viene el float en 4 bytes

  2. Creo que ya se el motivo de que no funcione el union. Chipkit utiliza enteros de 4 bytes, con lo cual no sirve para la carambola. Intentaré hacer algo como:

union 
{
  unsigned short shorts[2];   //o uint16_t
  float toFloat;
} foo;


void setup()
{
   Serial.begin(9600);
}   
   

   
void loop()
{
  // 3.141593
  foo.ints[0]=4059;
  foo.ints[1]=16457;

  Serial.println(foo.toFloat, 6); // con 6 decimales
  Serial.println(foo.ints[0]);
  Serial.println(foo.ints[1]);
  Serial.println("");
  delay(500);
}

Cuando pueda lo probaré.

Un saludo, y muchas gracias.

Efectivamente.

int en Chipkit usa 4 bytes. Cuando he usado dos short para montar un float ha salido bien.

Muchas gracias compañeros.