Erikblade
Posts: 13
Joined: Wed Jul 22, 2020 10:58 pm

variables float con i2c [SOLUCIONADO]

Mon May 17, 2021 6:24 pm

muy buenas a tod@s:

Estoy empezando con Python y la verdad estoy teniendo unos problemillas a la hora de realizar la comunicación i2C entre la RPI4 y arduino.

El tema es que tengo que enviar diversos datos (de momento son 4 variables tipo float y dos tipo int) entre ambos.
El lado del arduino lo tengo mas o menos hecho con el siguiente codigo: (solo pongo 2 de cada que si no se hace muy extenso)

Code: Select all

//Declaro las variables donde almacenar los datos de campo
float TEMP1;
float TEMP2;
int alarma1;
int alarma2;

//Declaro los arrays de datos
byte Datos_recibir[12];
byte Datos_enviar[12];

//Declaro las variables volatiles
volatile byte* TEMP1FloatPtr;
volatile byte* TEMP2FloatPtr;
volatile byte* alarma1IntPtr;
volatile byte* alarma2IntPtr;

void requestEvent(){ //Cuando el maestro solicite datos llamo a esta funcion
//Descompongo dichas variables
  TEMP1FloatPtr=(byte*)&TEMP1;
  TEMP2FloatPtr=(byte*)&TEMP2;
  alarma1IntPtr=(byte*)&alarma1;
  alarma2IntPtr=(byte*)&alarma2;
  
  //cargo el array de datos
  Datos_enviar[0]=TEMP1FloatPtr[0];
  Datos_enviar[1]=TEMP1FloatPtr[1];
  Datos_enviar[2]=TEMP1FloatPtr[2];
  Datos_enviar[3]=TEMP1FloatPtr[3];
  
  Datos_enviar[4]=TEMP2FloatPtr[0];
  Datos_enviar[5]=TEMP2FloatPtr[1];
  Datos_enviar[6]=TEMP2FloatPtr[2];
  Datos_enviar[7]=TEMP2FloatPtr[3];
  
  Datos_enviar[8]=alarma1IntPtr[0];
  Datos_enviar[9]=alarma1IntPtr[1];
  
  Datos_enviar[10]=alarma2IntPtr[0];
  Datos_enviar[11]=alarma2IntPtr[1];
  
  //envio el array de datos
  Wire.write(Datos_enviar,12);
  }
  
  void receiveEvent(int datos_recibir){//cuando el maestro envie datos se llama a esta funcion
  
  //Iniciamos la recepción de los datos
  
  int i=0;
  while(Wire.available()){
    Datos_recibir[i]=Wire.read();
    i=i+1;
    }
    //recompongo los datos recibidos
    union TEMP1_tag{
      byte TEMP1_b[4];
      float TEMP1_fval;
    }
    TEMP1_Union;
    TEMP1_Union.TEMP1_b[0]=Datos_recibir[0];
    TEMP1_Union.TEMP1_b[1]=Datos_recibir[1];
    TEMP1_Union.TEMP1_b[2]=Datos_recibir[2];
    TEMP1_Union.TEMP1_b[3]=Datos_recibir[3];
    TEMP1=TEMP1_Union.TEMP1_fval;

    union TEMP2_tag{
      byte TEMP2_b[4];
      float TEMP2_fval;
    }
    TEMP2_Union;
    TEMP2_Union.TEMP2_b[0]=Datos_recibir[4];
    TEMP2_Union.TEMP2_b[1]=Datos_recibir[5];
    TEMP2_Union.TEMP2_b[2]=Datos_recibir[6];
    TEMP2_Union.TEMP2_b[3]=Datos_recibir[7];
    TEMP2=TEMP2_Union.TEMP2_fval;
    
    alarma1_tag{
      byte alarma1_b[2];
      int alarma1_fval;
    }
    alarma1_Union;
    alarma1_Union.alarma1_b[0]=Datos_recibir[8];
    alarma1_Union.alarma1_b[1]=Datos_recibir[9];
    alarma1=alarma1_Union.alarma1_fval;

    alarma2_tag{
      byte alarma2_b[2];
      int alarma2_fval;
    }
    alarma2_Union;
    alarma2_Union.alarma2_b[0]=Datos_recibir[10];
    alarma2_Union.alarma2_b[1]=Datos_recibir[11];
    alarma2=alarma2_Union.alarma2_fval;
este codigo me funciona perfectamente cuando la comunicacion la hago entre dos arduinos, el tema es que al intentar meter la RPI4 no tengo ni idea de como poder hacer lo mismo en python (lo de descomponer las variables en bytes para cargar un array y luego recomponerlas de nuevo). he estado mirando el modulo struct pero el problema es que me crea variables del tipo tupla. y ya me pierdo.
comentar que soy algo nuevo con el Python, pero no soy novato en esto de la programación solo necesito un poco de orientación.

muchas gracias por su tiempo. si necesitan cualquier aclaracion o informacion ampliada no lo duden, comentenme
Last edited by Erikblade on Mon May 31, 2021 9:19 am, edited 1 time in total.

MicroControlador
Posts: 28
Joined: Mon Nov 11, 2019 8:53 pm

Re: variables float con i2c

Mon May 17, 2021 7:21 pm

El canal de transmisión solo funciona con bytes, si la variable es de dos bytes es decir 16 bits, solo tiene que calcularlo como byte LO y HI y enviarlos por separado.

Si el tipo de varible tiene 3 bytes es decir 24 bits, pues lo mismo, lo calcula en tres por separado y los envía.

Y si el tipo de variable tiene 4 bytes es decir 32 bits, pues lo mismo, lo calcula en cuatro separados y los envía.

Ejemplo:
Valor= V
Variable de dos2 bytes, 16 bits, Max Valor 65535. sin signo, la mitad con signo, ya que se utiliza un bit para ello.

HI=V/256 LO=V-HI



Ojo con los signos si es que los utiliza.

Saludos
Last edited by MicroControlador on Mon May 17, 2021 7:36 pm, edited 1 time in total.

Erikblade
Posts: 13
Joined: Wed Jul 22, 2020 10:58 pm

Re: variables float con i2c

Mon May 17, 2021 7:30 pm

muchas gracias pero creo que me he perdido más;

que el canal solo funciona por bytes ya sabia por eso lo de descomponer las variables, lo que no he entendido es lo de mandar LO o HI.

las variables TEMP contienen datos tipo:

TEMP1 = -25.24
TEMP2 = 65.21
etc;
y las variables alarma del tipo

alarma1 = 12
alarma2 = -30

no he comprendido lo de los HI y LO que me ha comentado

MicroControlador
Posts: 28
Joined: Mon Nov 11, 2019 8:53 pm

Re: variables float con i2c

Mon May 17, 2021 7:43 pm

Si solo puede enviar un byte, pues tendra que descomponer las variables en bytes.

Imaginemos una variable de 16 bits, 2 bytes, si la quiere sin signo el valor maximo sera 65535, si quiere enviar signo, pues la mitad creo recordar que el bit de mayor peso de HI es el signo.

Y como solo puede enviar un byte, pues tendrá que calcular el byte HI, el alto, y el LO el bajo y enviarlos seguidos pero por separado.
Ya le he puesto la formula.
HI= V/256 el byte de mas peso
LO=V-HI el byte de menos peso

Tiene que estudiar el formato de la variable y decodificarla en consecuencia en bytes para poder enviarla.

Saludos

Erikblade
Posts: 13
Joined: Wed Jul 22, 2020 10:58 pm

Re: variables float con i2c

Mon May 17, 2021 7:51 pm

Si el que tengo que "trocearla" lo entiendo.

Si se fija en el código que he pegado antes (es el método que hago con Arduino) es el proceso que hago

1 - descompongo los float en bytes
2 - cargo un array con esos bytes
3- envío el array de bytes
(En el receptor)
4- recibo el array de bytes
5 - recompongo los float

Lo que usted me comenta creo que es algo como esto?

Byte1 = alarma1/256
Byte2 = alarma1-256
Datos_enviar[Byte1,Byte2]

Me equivoco???

MicroControlador
Posts: 28
Joined: Mon Nov 11, 2019 8:53 pm

Re: variables float con i2c

Mon May 17, 2021 7:57 pm

Se equivoca.

ByteHI = Valor/256
ByteLO= Valor-ByteHI

Y los envia por separado, y a la hora de decodificarlos HI lo tendra que multiplicar por 256 y sumarle LO.

Valor=(ByteHI*256) + ByteLO

Ojo con el signo.

Saludos

Erikblade
Posts: 13
Joined: Wed Jul 22, 2020 10:58 pm

Re: variables float con i2c

Mon May 17, 2021 8:12 pm

Ok gracias, lo probaré mañana a ver qué tal.

MicroControlador
Posts: 28
Joined: Mon Nov 11, 2019 8:53 pm

Re: variables float con i2c

Mon May 17, 2021 8:14 pm

Suerte

Saludos

Erikblade
Posts: 13
Joined: Wed Jul 22, 2020 10:58 pm

Re: variables float con i2c

Tue May 18, 2021 12:53 pm

Pues lo he probado y la verdad funciona correctamente, muchas gracias por su tiempo.

Sin embargo el proceso lo he notado algo lento y tedioso, quizas para pocas variables si que sea una solución aceptable pero si el numero de variables a "trocear" se eleva resulta engorroso.

si se fija en el código que puse en el primer post (si es de arduino pero al final lo que llega a la RPI es lo mismo)

la trama que envío es un array de datos de 1 byte.

Datos[0], Datos[1], Datos[2], Datos[3] corresponden a la variable (float) TEMP1
Datos[4], Datos[5], Datos[6], Datos[7], corresponden a la variable (float TEMP2
y asi sucesivamente

si tengo que hacer la operación de suma y multiplicación para cada variable al final es tedioso.

por eso me preguntaba si no existiría algo en python similar a los punteros de arduino asi podría cargar el array de datos con expresiones del tipo
Datos[0]=(byte*)TEMP1Ptr[0]
Datos[1]=(byte*)TEMP1Ptr[1]
Datos[2]=(byte*)TEMP1Ptr[2]
Datos[3]=(byte*)TEMP1Ptr[3]
esto sería para descomponer el float en un array de 4 Bytes

y este otro para componerlo
union TEMP1_tag{
byte TEMP1_b[4];
float TEMP1_fval;
}
TEMP1_Union;
TEMP1_Union.TEMP1_b[0]=Datos_recibir[0];
TEMP1_Union.TEMP1_b[1]=Datos_recibir[1];
TEMP1_Union.TEMP1_b[2]=Datos_recibir[2];
TEMP1_Union.TEMP1_b[3]=Datos_recibir[3];
TEMP1=TEMP1_Union.TEMP1_fval;


Erikblade
Posts: 13
Joined: Wed Jul 22, 2020 10:58 pm

Re: variables float con i2c

Tue May 18, 2021 4:00 pm

muchas gracias;

le echo un vistazo

MicroControlador
Posts: 28
Joined: Mon Nov 11, 2019 8:53 pm

Re: variables float con i2c

Wed May 19, 2021 6:01 am

Erikblade wrote:
Tue May 18, 2021 12:53 pm
Pues lo he probado y la verdad funciona correctamente, muchas gracias por su tiempo.

Sin embargo el proceso lo he notado algo lento y tedioso, quizas para pocas variables si que sea una solución aceptable pero si el numero de variables a "trocear" se eleva resulta engorroso.

si se fija en el código que puse en el primer post (si es de arduino pero al final lo que llega a la RPI es lo mismo)

la trama que envío es un array de datos de 1 byte.

Datos[0], Datos[1], Datos[2], Datos[3] corresponden a la variable (float) TEMP1
Datos[4], Datos[5], Datos[6], Datos[7], corresponden a la variable (float TEMP2
y asi sucesivamente

si tengo que hacer la operación de suma y multiplicación para cada variable al final es tedioso.

por eso me preguntaba si no existiría algo en python similar a los punteros de arduino asi podría cargar el array de datos con expresiones del tipo
Datos[0]=(byte*)TEMP1Ptr[0]
Datos[1]=(byte*)TEMP1Ptr[1]
Datos[2]=(byte*)TEMP1Ptr[2]
Datos[3]=(byte*)TEMP1Ptr[3]
esto sería para descomponer el float en un array de 4 Bytes

y este otro para componerlo
union TEMP1_tag{
byte TEMP1_b[4];
float TEMP1_fval;
}
TEMP1_Union;
TEMP1_Union.TEMP1_b[0]=Datos_recibir[0];
TEMP1_Union.TEMP1_b[1]=Datos_recibir[1];
TEMP1_Union.TEMP1_b[2]=Datos_recibir[2];
TEMP1_Union.TEMP1_b[3]=Datos_recibir[3];
TEMP1=TEMP1_Union.TEMP1_fval;
Me alegro que le haya funcionado, no hay otra manera de hacerlo, a no ser que el lenguaje de programacion que utiliza tenga alguna función al respecto que haga eso precisamente.

Haga usted mismo una función de decodificacion para extraer al valor HI y LO de cualquier variable y llamela cuando sea necesario, asi solo la tendra que escribir una sola vez. Y haga otra de codificacion para extraer el valor a partir de HI y LO.

Si la variables es de cuatro bytes, 32 bits, el tercer byte lo tiene que divididir por 512 y el cuarto por 1024, y a la hora de multiplicar para extraer el valor lo mismo.
Valor = (ByteHIHI*1024) + (ByteHILO*512) + (ByteLOHI*256) + ByteLOLO


Al final lo que determina el tiempo de respuesta es la velocidad de transmisión, cuanto mas rápida mejor, no creo que una multiplicación y una suma le haga perder mucho tiempo de proceso. Si le funciona bien no se lo piense. AL final por lo que parece son temperaturas y alarmas, vamos que no suelen ser cosas muy rápidas.
Yo creo que pierde mucho mas tiempo con tantos arrays de datos. Calcula un dato y lo envía directamente, no los calcula todos y despues los envia y a la hora de recibir pues lo mismo, recibe uno y lo calcula y así con todos.

Saludos

Erikblade
Posts: 13
Joined: Wed Jul 22, 2020 10:58 pm

Re: variables float con i2c

Mon May 31, 2021 8:56 am

muy buenas;

Gracias por sus aportes. Les comunico que he conseguido solucionar el tema de una forma bastante elegante gracias al modulo smbus2 y al modulo struct en python3.

la estructura del codigo de arduino sigue igual; es decir :

Code: Select all

Datos[0]=(byte*)TEMP1Ptr[0]
Datos[1]=(byte*)TEMP1Ptr[1]
Datos[2]=(byte*)TEMP1Ptr[2]
Datos[3]=(byte*)TEMP1Ptr[3]

Datos[4]=(byte*)TEMP2Ptr[0]
Datos[5]=(byte*)TEMP2Ptr[1]
Datos[6]=(byte*)TEMP2Ptr[2]
Datos[7]=(byte*)TEMP2Ptr[3]
etc tantas como haga falta

luego en la RPI usando lo siguiente

Code: Select all

with SMBus(canal) as bus:
    msg = i2c_msg.read(esclavo, cantidad)
    bus.i2c_rdwr(msg)
   Datos_recibidos = list(msg)

#canal es el canal empleado para la comunicación, generalmente el 1
#esclavo es la direccion del esclavo del que leo
#cantidad es la cantidad de bytes que leo
lo he probado con hasta 124 bytes y ha funcionado correcto (tened en cuenta que las libreria wire.h de arduino por defecto solo permite 64 bytes, paa ampliarlo hay que modificar tanto la libreria wire.h como twi.h

luego para reconstruirlos

Code: Select all

[TEMP1_recibida] = struct.unpack('f',Datos_recibidos[0:4])
[TEMP2_recibida] = struct.unpack('f´'Datos_recibidos[4:8])

#el encorchetar la variable sirve para que el tipo de la misma sea float y no una tupla
#'f' indica que es un float lo que se va a desempaquetar.
eso era para leer; para escribir
en la parte de la RPI

Code: Select all

Datos_enviar = struct.pack('2f', TEMP1_enviar, TEMP2_enviar)
with SMBus(canal) as bus:
    msd = i2c_msg.write(esclavo, Datos_enviar)
    bus.i2c_rdwr(msg)
igualmente que antes he podido enviar 124 bytes, seguramente se pueda mas pero no he probado.

y para unirlos en la parte de arduino con este codigo

Code: Select all

union TEMP1_tag{
byte TEMP1_b[4];
float TEMP1_fval;
}
TEMP1_Union;
TEMP1_Union.TEMP1_b[0]=Datos_recibir[0];
TEMP1_Union.TEMP1_b[1]=Datos_recibir[1];
TEMP1_Union.TEMP1_b[2]=Datos_recibir[2];
TEMP1_Union.TEMP1_b[3]=Datos_recibir[3];
TEMP1=TEMP1_Union.TEMP1_fval;

union TEMP2_tag{
byte TEMP2_b[4];
float TEMP2_fval;
}
TEMP2_Union;
TEMP2_Union.TEMP2_b[0]=Datos_recibir[4];
TEMP2_Union.TEMP2_b[1]=Datos_recibir[5];
TEMP2_Union.TEMP2_b[2]=Datos_recibir[6];
TEMP2_Union.TEMP2_b[3]=Datos_recibir[7];
TEMP2=TEMP2_Union.TEMP2_fval;
lo pongo por si a alguien le puede servir

Erikblade
Posts: 13
Joined: Wed Jul 22, 2020 10:58 pm

Re: variables float con i2c

Mon May 31, 2021 9:00 am

si me explican como poner el tema como solucionado se lo agradeceria

Me corrijo ya lo he puesto como solucionado

Return to “Español”