4 bytes a float (solucionado)

Buenos dias, tengo una pequeña duda que he visto ya comentada por el foro pero no acabo de aclararme.
Principalmente tengo un codigo en matlab que envia datos a arduino.

En la primera parte recibo 4 byte,
el primero es independiente, los dos siguientes son el cuarto descompuesto, es decir en lugar de 22000 lo descompongo el dos byte que son 240 y 85, (typecast(int16(22000),'uint8')--Codigo matlab)

Estos los junto en arduino y lo uso como el valor 22000 otra vez.

mi problema reside en la segunda parte del codigo( esta vez desde matlab envio un floar descompuesto en 4 byte)

Con matlab typecast(single(3.4), 'uint8') == 154 153 89 64
typecast(uint8([154 153 89 64]), 'single') == 3.4000

Mi pregunta es la siguiente.

¿Con los valores de 154, 153, 89 64 como los recostruyo en arduino para formar el 3.4?

Os pongo el codigo que tengo de arduino que me verifica que he recibido esos codigos, ya que los envio de regreso a matlab para ver que son eso.

// definir variables
int t_motor;
byte comando, bytelow, bytehigh;
byte dato1[4];
//float dato1float;

void setup() {
              pinMode(13,OUTPUT);
              Serial.begin(9600);
             
             }   

void loop() {

//Serial.flush();
delay(50);
if (Serial.available()>0){
   delay(500);
   comando=Serial.read();
   if (comando==99){
                    digitalWrite(13,HIGH);
                    bytelow=Serial.read();
                    bytehigh=Serial.read();
                    t_motor=bytehigh+bytelow*256;
                    Serial.println(comando);
                    Serial.println(bytelow);
                    Serial.println(bytehigh);
                    Serial.println(t_motor);
                    delay(t_motor);
                    Serial.flush();
                   }
     else if(comando==50){
                    digitalWrite(13,HIGH);
                    dato1[1]=Serial.read();
                    dato1[2]=Serial.read();
                    dato1[3]=Serial.read();
                    dato1[4]=Serial.read();
                    Serial.println(comando);
                    Serial.println(dato1[1]);
                    Serial.println(dato1[2]);
                    Serial.println(dato1[3]);
                    Serial.println(dato1[4]);               
                    delay(500);
                    Serial.flush();
                   }
                   
     
   } 
 
   digitalWrite(13,LOW);
   
}

Se me ha ido el enunciado y no se como cambiar. Tambien seria bueno modificar el titulo.....

Está claro que lo tuyo no son ni los butes ni los floar ... :grin:

¿Podrías ser un poco más didáctico con qué operaciones haces con los bytes y qué relación tienen con los resultados?

Saludos

buenas tardes, vamos a ver si ahora me explico mejor sin liarla..... jajaja

en matlab convierto 3.4 a cuatro bytes y los envio por el puerto serie.

Leo esos valores en arduino pero como estan sueltos son: 154 153 89 64

¿como los transformo para tener el 3.4 en arduino dentro de una variable?

Hola,
¿Podrían ir por aquí los tiros?
float
Saludos

creo que no, ya que como decia yo tengo descompuesto el valor 3.4 en 4 bytes y lo que quiero es volver a componerlo pero dendro de arduino.

Josko85:
creo que no, ya que como decia yo tengo descompuesto el valor 3.4 en 4 bytes y lo que quiero es volver a componerlo pero dendro de arduino.

El sistema de almacenamiento que emplea el C (arduino) ocupa 4 bytes para un float: si no me equivoco en la forma "mantisa - exponente" o algo así.
¿No puedes mirar en la documentación del mathlab cómo lo hace? (Muy probablemente es lo mismo, pero hay que estar seguros)
Saludos

Josko85:
ya que como decia yo tengo descompuesto el valor 3.4 en 4 bytes y lo que quiero es volver a componerlo pero dendro de arduino.

float f = 0.0;
byte* fp = (byte*)&f;

for (byte i = 0; i < sizeof(float); i++) fp[i] = vector[i];

De nada…

vffgaston efectivametne se descompones asi pero al hacerlo con una funcion interna de matlab no ecuento el codigo de como lo hace.

Lucario448 mas o menos entiendo tu codigo y creo que van los tiros por eso.

Pero me faltaria adaptarlo a mis datos.

Por ejemplo la entrada yo la tengo en dato1, que es un vector de cuatro componente.

tambien en el codigo que has puesto fp no esta declarada entiendo que seria un vector por lo que veo abajo.

Josko85:
Lucario448 mas o menos entiendo tu codigo y creo que van los tiros por eso.

Lo propuse sin explicación justamente para probar tu interés en comprender el porqué de la solución.

Josko85:
Por ejemplo la entrada yo la tengo en dato1, que es un vector de cuatro componente.

Si por "componentes" te refieres a bytes y no otra cosa, ya tienes lo necesario. Aquí vector se refiere ese conjunto de bytes los cuales (dices tú) componen el valor punto flotante.

Josko85:
tambien en el codigo que has puesto fp no esta declarada entiendo que seria un vector por lo que veo abajo.

Aquí es donde la explicación se me pone cuesta arriba.

Si sabes lo que es un "puntero de memoria", fácilmente comprenderías lo que voy a decir a continuación.

Al obtener el puntero de una variable, este se puede reinterpretar al tipo que mas convenga (byte en este caso).
Este truco es útil para obtener o modificar el valor de una variable de cualquier tipo de otra manera, usualmente como un vector de otro tipo más pequeño que el original; sin tener que recurrir a operaciones de bits que incluso tardan más en ejecutarse

Así, un float puede trabajarse como un vector de 2 int o de 4 bytes. ¿Lo ves? Es justo lo que buscabas, ¿o no?
¿Por qué un puntero como vector? Pues en C y C++ (lenguaje en el que se basan los sketches de Arduino), un puntero y un vector vienen siendo la misma cosa (ya que al final este último es simplemente un espacio contiguo en memoria RAM). Es válido operar con en una variable declarada como puntero.

Incluso se puede hacer lo opuesto: reinterpretar directamente un conjunto de valores como una variable de un tipo más grande, hasta con menos líneas de código saldría.

float* fp = (float*)vector; // No usamos '&' porque no queremos el puntero de un puntero
float resultado = *fp;

Se puede condensar a una sola línea, solo que no lo puse de primer ejemplo porque se vería más difícil de entender.

float resultado = *((float*)vector); // No usamos '&' porque no queremos el puntero de un puntero

Mira que aquí el asterisco (*) es importante, ya que este proceso es únicamente posible con punteros.

Muchas gracias por la explicacion, el tema es que yo vengo de automatizacion de automatas entonces aunque muchas cosas son parecidad es la forma de escribir algunas cosas lo que cambia. el tema de punteros y direccionamiento indirecto y directo en automatas si lo he usado, en esto pues estoy empezando.

Lo dicho muchas gracias por el tiempo dedicado.

@Lucario448

¿Es el mismo formato en Mathlab y en C?. ¿Es un formato "normalizado"?.
Saludos

Buenas nuevamente, he mirado lo de los punteros y leido sobre ellos, en prometec los explica para poder comprenderlos pero siento decir que el condigo continua sin funcionarme bien.

Pongo el codigo completo que estoy usando ahora mismo, he añadido un lcd para poder ver los valores reales que tengo en las variables.

//libreria para la pantalla
#include  <Wire.h>
#include  <LiquidCrystal_I2C.h>

// Aqui se configuran los pines asignados a la pantalla del PCF8574
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE); 

// definir variables
int v_motor, ledPin = 12 ;
byte comando, bytelow, bytehigh;
byte dato1[4];
float f = 3.4;
float dato1float=0;
//

void setup() {
              pinMode(13,OUTPUT);
              Serial.begin(9600);
                    // Indicar a la libreria que tenemos conectada una pantalla de 16x2
                    lcd.begin(16, 2);
                    // Mover el cursor a la primera posición de la pantalla (0, 0)
                    lcd.home (); //lcd.setCursor(0,0);
                    // Imprimir "Hola Mundo" en la primera linea
                        }   

void loop() {
//Serial.flush();
delay(50);
if (Serial.available()>0){
   delay(500);
   comando=Serial.read();
   if (comando==99){//leo dos variables mas la de entrada, respondo 4 variables byte
                 //   digitalWrite(13,HIGH);
                    bytelow=Serial.read();
                    bytehigh=Serial.read();
                    v_motor=bytehigh+bytelow*256;
                    Serial.println(comando);
                    Serial.println(bytelow);
                    Serial.println(bytehigh);
                    Serial.println(v_motor);
                    delay(v_motor);
                    Serial.flush();
                //    digitalWrite(13,LOW);
                   }
     else if(comando==50){
                  //  digitalWrite(13,HIGH);
                    dato1[1]=Serial.read();
                    dato1[2]=Serial.read();
                    dato1[3]=Serial.read();
                    dato1[4]=Serial.read();
                    Serial.println(comando);
                    Serial.println(dato1[1]);
                    Serial.println(dato1[2]);
                    Serial.println(dato1[3]);
                    Serial.println(dato1[4]);               
                    delay(500);
                    Serial.flush();
                    
                    float* fp = (float*)dato1; // No usamos '&' porque no queremos el puntero de un puntero
                    float dato1float = *fp;
                    
                    //float dato1float = *((float*)dato1); // No usamos '&' porque no queremos el puntero de un puntero
                   }
              
        }   

   
//pantalla
lcd.setCursor(0,0);
lcd.print("comando");  // 

lcd.setCursor(8,0);
lcd.print("dato1float");  // 

lcd.setCursor(0,1);
lcd.print(comando);  // sin las comillas se usa para llammar a la variable

lcd.setCursor(8,1);
lcd.print(dato1float);  // sin las comillas se usa para llammar a la variable
//

Tal y como se ve en la foto que adjunto al principio esta todo en 0 y 0.0 pero cuando le envio a comando 50 si lo toma pero no hace la conversion apra tener en dato1float el 3.4 que le envio

(realmente envio 154 153 89 64 )

que respondiendo a la pregunta son los valores de 4 bytes descompuestos por matlab para formar el 3.4

Codigo en matlab

typecast(single(3.4), 'uint8')

Usa Estándar IEEE 754 al igual que creo que hace matlab


A ver si esto te sirve Link : Send numerical values from Matlab to arduino

EDITO: Aunque lo anterior es una solución posible esta tmb puede serlo porque apunta mas específicamente a como lo planteas tu pero te comento que usa la sugerencia de @Lucario

Convert float to 4 Bytes and then back again

Solo que no esta hecho para Arduino pero la conversión es inmediata.

vffgaston:
¿Es el mismo formato en Mathlab y en C?. ¿Es un formato "normalizado"?

Si estamos hablando de la codificación IEEE 754, debería. Obviamente si la codificación es distinta, el valor reconstruido sería incorrecto; también puede haber problemas si hasta difieren en la precisión (tomar arbitrariamente 32 bits de un punto flotante de 64 bits).

Josko85:
pero siento decir que el condigo continua sin funcionarme bien.

Es por esto:

dato1[1]=Serial.read();
dato1[2]=Serial.read();
dato1[3]=Serial.read();
dato1[4]=Serial.read();

Recuerda que los índices de un vector inician en 0, no en 1.

Mi propuesta reinterpreta el conjunto a partir de la posición cero, por lo tanto el último byte iba a faltar y además los que tomaba estaban en la posición incorrecta.

Gracias :-[ siempre me pasa lo mismo, es como la 's' de la tercera persona del singular.... que siempre se pierde por el camino, pues con el 0 me pasa igual.

Muchas gracias por todo.

Con esto la duda queda resuelta.

Josko85:
siempre me pasa lo mismo, es como la ‘s’ de la tercera persona del singular… que siempre se pierde por el camino

Supongo que te refieres al idioma inglés; porque hasta donde yo recuerde, en clases de español nunca se ha dicho que todo verbo conjugado en tercera persona singular debe terminar en ‘s’; pero en inglés sí.

@Lucario448

Gracias mil.