Go Down

Topic: Como separar int o long en bytes (Read 21776 times) previous topic - next topic

111---111

Igual es algo obvio para muchos, pero al mismo tiempo para gente como yo que ha empezado a programar hace mas bien poco no lo es tanto y cosas que pueden ser de cajón o simplemente automáticas para muchos, se convierte en toda una odisea para otros.

Os pido si puede ser, ejemplos de como desglosar, trocear o separar enteros o longs en bytes para luego por separado meterlos en un array, enviarlos por serial, meterlos en memoria o simplemente, tratar los datos por separado.


Saludos

anv


Igual es algo obvio para muchos, pero al mismo tiempo para gente como yo que ha empezado a programar hace mas bien poco no lo es tanto y cosas que pueden ser de cajón o simplemente automáticas para muchos, se convierte en toda una odisea para otros.

Os pido si puede ser, ejemplos de como desglosar, trocear o separar enteros o longs en bytes para luego por separado meterlos en un array, enviarlos por serial, meterlos en memoria o simplemente, tratar los datos por separado.
Saludos


Yo lo haría más o menos así:

long l;
byte b[4];
.... a toma algun valor

b[0]=l & 0xff;  // hago and con 0xff para que quede solo el ultimo byte
b[1]=(l>>8) & 0xff; // roto los bits 8 veces a la derecha y de nuevo me quedo con el ultimo byte
b[2]=(l>>16) & 0xff;
b[3]=(l>>24) & 0xff;

Si el valor de l se puede perder, se puede if haciendo >>8 sobre l varias veces en lugar de hacerlo dentro de la asignacion. También se podría copiar l a una variable auxiliar. Todo depende de si en tu programa ahorrar algunos microsegundos es importante o no.

111---111

#2
Feb 01, 2011, 10:34 am Last Edit: Feb 01, 2011, 10:39 am by DRicote Reason: 1
Gracias anv, he estado probando lo siguiente y modificando varias cosas pero no me funciona :smiley-red:, me salen caracteres raros.


Code: [Select]

byte dato[3];
int datos=1234;

void setup(){
 Serial.begin(115200);

 dato[0]=datos & 0xff;
 dato[1]=(datos>>8) & 0xff;
 dato[2]=(datos>>16) & 0xff;
 dato[3]=(datos>>24) & 0xff;
 
 Serial.println(dato[0]);
 Serial.println(dato[1]);
 Serial.println(dato[2]);
 Serial.println(dato[3]);
}

void loop(){
}



xlopez

#3
Feb 01, 2011, 11:25 am Last Edit: Feb 01, 2011, 11:27 am by xlopez Reason: 1
Donde has puesto byte dato[3] debes poner byte dato[4] porque un entero ocupa 4 bytes, no 3.

Es normal que te salgan chinos, los caracteres imprimibles son los valores asciii superiores al 32, y aún así algunos son muy extraños.

111---111

#4
Feb 01, 2011, 12:00 pm Last Edit: Feb 01, 2011, 12:08 pm by DRicote Reason: 1
Lo del 3 en el array se me ha debido colar, como he estado inicializando el array de varias maneras...pero gracias por la aclaración que siempre viene bien!  XD
Acabo de hacer lo siguiente para ver si consigo verlos al imprimirlos pero nada, creo que no me queda claro el concepto...

También lo he leído con el RealTerm y me saca 02,34,30,30 en HEX y debería sacar 31,32,33,34 no?

Code: [Select]

byte dato[4];
int datos=1234;

void setup(){
 Serial.begin(115200);

 dato[0]=(datos & 0xFF) + 48;
 dato[1]=((datos >> 8) & 0xFF) + 48;
 dato[2]=((datos >> 16) & 0xFF) + 48;
 dato[3]=((datos >> 24) & 0xFF) + 48;
 
 Serial.println(dato[0]);
 Serial.println(dato[1]);
 Serial.println(dato[2]);
 Serial.println(dato[3]);
}

void loop(){
}

chato_sat

#5
Feb 01, 2011, 02:15 pm Last Edit: Feb 01, 2011, 02:24 pm by chato_sat Reason: 1
1º un número en arduino son 2 bytes.
2º estás dividiendo el número en bytes, no en caracteres ascii. El número 1234 está formado por los bytes 0x04 y 0xd2. Si lo que quieres hacer es dividirlo en los número 1, 2, 3 y 4 prueba esto:
Code: [Select]

byte dato[4];
int datos=1234;

void setup() {
 dato[0]=datos%10;
 dato[1]=(datos/10)%10;
 dato[2]=(datos/100)%10;
 dato[3]=(datos/1000)%10;
}


Aunque no tenga nada que ver con el post te tengo que preguntar si eres de Murcia?? es que por el nick parece que eres vecino mio, jeje

Saludos chato_sat

111---111

Muchas gracias por la explicación y el ejemplo, he hecho lo siguiente y he podido ver la cifra en ascii por serie perfectamente:

Code: [Select]

  dato[0]=((datos/1000)%10)+48;
  dato[1]=((datos/100)%10)+48;
  dato[2]=((datos/10)%10)+48;
  dato[3]=(datos%10)+48;


Concretamente, que hace el %10? lo he leído en el Reference, pero me he quedado igual... :smiley-red:

Por cierto, no soy de murcia, soy del centro, pero si sé que hay una ciudad que se llama Ricote por tu tierra  ;)

chato_sat


Concretamente, que hace el %10? lo he leído en el Reference, pero me he quedado igual... :smiley-red:


De nada, para una cosa en la que sí puedo ayudar lo tenía que hacer ;)

El % lo único que hace es calcular el resto de la división. Es común para todos los lenguajes de programación (por lo menos que yo conozca).

111---111

Madre mía, he tenido que hacer una división en papel para comprenderlo XD XD XD XD ya me vale...

Gracias de nuevo ;)

xlopez

Pero recuerda que un entero puede valer desde -32768 a +32767.

No te sirve un byte[4], necesitas un byte[5] para los números y antes hacer la comprobación del signo.

Code: [Select]

byte dato[5];
int datos=-12345;

void setup() {
   Serial.begin(9600);
}
void loop(){
 int absdatos;
 if (datos<0){
   absdatos=-datos;
 } else{
   absdatos = datos;
 }
 dato[0]=absdatos%10+48;
 dato[1]=(absdatos/10)%10  +48;
 dato[2]=(absdatos/100)%10 +48;
 dato[3]=(absdatos/1000)%10 +48;
 dato[4]=(absdatos/10000)%10 +48;

 if (datos < 0){
     Serial.print('-');
 }
 Serial.print(dato[4]);
 Serial.print(dato[3]);
 Serial.print(dato[2]);
 Serial.print(dato[1]);
 Serial.println(dato[0]);
 delay(500);
}

Y un long necesita un byte[10];

111---111

Ok muchas gracias!!! No había tenido en cuenta la comprobación de signo pero si me puede hacer falta, y saber los limites del int y del long también.
La verdad que me está siendo muy instructivo este hilo  ;)

Juantreras

Hola a todos,hace unas semanas abrí un hilo titulado "Enviar un dato float via serial" el cual me contesto Xlopez ofreciéndome una solución (gracias Xlopez) pero que yo no he sido capaz de adaptarla.Ahora veo esto que parece se acerca mas a lo que necesito.Os explico: tengo un Arduino "B" que lee los datos de un anemómetro,lee las revoluciones y calcula cada 10 segundos el dato "float speedwind", desde un Arduino "A" le envío a través de un xbee una orden y el Arduino "B" obedece y "Serial.print (windspeed); me envía la lectura y yo en el Arduino "A" lo visualizo en un lcd , hasta aquí sin problemas, pero, aquí viene mi problema, necesito que aparte de visualizarlo en el lcd actualice el valor "windspeed" en el Arduino A.Tengo que descomponer el dato en "B" y enviarlo a "A" y aquí volverlo a armar para actualizarlo y almacenarlo . He probado mil cosas y no he dado con la solución.¿Alguna idea?, actualmente estoy bloqueado con esto.
Muchas gracias y un saludo

igorreal

#12
Feb 11, 2011, 09:00 pm Last Edit: Feb 11, 2011, 09:03 pm by Igor R Reason: 1
Hay diferentes formas de "atacar" el problema....

1) Mandas el dato en "raw", es decir, tal cual lo lees sin hacer ninguna operacion. A ver si me explico mejor.... XD
Si estas midiento pulsos, imagino que estaras usando una variable de tipo byte o unsigned int (2 bytes) como contador, no?
Puedes enviar este byte o estos dos, y en el otro lado haces la operacion de dividir entre el tiempo y el numero de pulsos por vuelta, etc.
2) Mandas el float tal cual (4 bytes).

Para mandar el dato en ambas opciones, descompones en bytes (depende del tipo de variable que quieras descomponer) con las operaciones bitwise que han explicado mas arriba y usa Serial.print(mibyte,BYTE).
En el otro lado, tienes que "componerlo" consecuentemente a como lo has "descompuesto".
Imaginemos un unsigned int (ocupa dos bytes):

unsigned int micontadorpulsos;   //la variable que aumento cada vez que recibo un pulso nuevo
byte byte_bajo;
byte byte_alto;
byte_bajo=micontadorpulsos & 255;
byte_alto=(micontadorpulsos >> 8 ) & 255;

Serial.print(byte_bajo,BYTE);
Serial.print(byte_alto,BYTE);


En el otro Arduino, ya sabes que primero te va a llegar la parte baja, y luego la alta.
Por lo cual tienes que hacer (asumo que has leido los dos bytes con Serial.read() ):

unsigned int mivariablerecepcion;
mivariablerecepcion=(byte alto << 8 ) ¦ (byte_bajo);


Espero que sirva



Saludos




Igor R.

igorreal

#13
Feb 11, 2011, 09:11 pm Last Edit: Feb 11, 2011, 09:14 pm by Igor R Reason: 1
Lo suyo es que implementases un pequenyo miniprotocolo, para saber cuando empieza un nuevo dato, y cuando acaba.
Es decir, algo como SminumeroF
* "S" de start (lo mandas en Ascii)
* minumero el dato a enviar, lo mandas con la opcion byte (tantos bytes como kieras). Es decir Byte0Byte1Byte2.....
* "F" de fin (lo mandas en Ascii).

Asi es facil hacerte una "maquina de estados" => http://real2electronics.blogspot.com/2009/10/linksys-arduino.html
Puedes coger de ahi la "idea". Solo el tema del diagrama de estados y el mini programa de Arduino de ejemplo.

Espero no haberte liado mas.... ]:D

Nota.- Cuando escribo un post largo, el textbox  de crear el mensaje se me sube siempre hacia arriba, por lo que tengo que andar bajando con el scroll.... alguien sabe como evitar esto???

Juantreras

Hola a todos: parece que veo luz al final del tunel,o no....He sido capaz de descomponer el dato enviarlo y volverlo a montar al otro lado pero en... I2c , no en Serial.
Vamos a ver el la parte del emisor:
Quote

unsigned int micontadorpulsos=1550;   //la variable que aumento cada vez que recibo un pulso nuevo
byte byte_bajo;
byte byte_alto;
void setup() {

  Serial.begin(9600);
}

void loop(){
 byte_bajo=micontadorpulsos & 255;
byte_alto=(micontadorpulsos >> 8 ) & 255;
 
  
Serial.print(byte_bajo,BYTE);
Serial.print(byte_alto,BYTE);
delay (2000);
}


Pero tengo problemas a la hora de recepcionarlo.Esta linea me da error al compilar"mivariablerecepcion =((byte_alto << 8 )| (byte_bajo));"no acabo de dar con la solución.




Juan


Go Up