Go Down

Topic: Función para partir y unir un float (Read 1 time) previous topic - next topic

Jose Francisco

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

Code: [Select]
#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.

chiva

#1
Jun 17, 2012, 02:30 am Last Edit: Jun 17, 2012, 02:34 am by chiva Reason: 1
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.

Code: [Select]

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;
}
Mercadillo electrónico. Kit iniciación a Arduino, shield LCD a color y más cosas!

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


chiva


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
Mercadillo electrónico. Kit iniciación a Arduino, shield LCD a color y más cosas!

Jose Francisco

Ostras, union hace la fuerza
Voy a probarlo

Jose Francisco

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:


Code: [Select]


//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?

curro92

#6
Jun 18, 2012, 05:42 am Last Edit: Jun 18, 2012, 05:54 am by curro92 Reason: 1
Hola,

Prueba con este ejemplo, el Serial.print a mí me da 3.141593
Code: [Select]


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);
}





Jose Francisco

Pues a mi me da...

Code: [Select]

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.

matiasdelellis

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.

Jose Francisco

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:

Code: [Select]

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.

Jose Francisco

Efectivamente.

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

Muchas gracias compañeros.

Go Up