Como separar int o long en bytes

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

DRicote: 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.

Gracias anv, he estado probando lo siguiente y modificando varias cosas pero no me funciona :blush:, me salen caracteres raros.

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(){
}

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.

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?

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(){
}

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:

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

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

  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... :blush:

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

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

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).

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

Gracias de nuevo ;)

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.

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];

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

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

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.

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

[u]Nota.-[/u] 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???

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:

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

Hola Juantreras, intenta probar con el siguiente código en el emisor:

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('S', BYTE);
  Serial.print(byte_bajo,BYTE);
  Serial.print(byte_alto,BYTE);
  Serial.print('F', BYTE);
  delay (2000);
}

Y el siguiente en el lado del receptor:

byte byte_bajo;
byte byte_alto;
unsigned int contadorPulsos;

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

void loop() {
  //Compruebo si han llegado datos por el puerto serie
  if (Serial.available() > 0) {
    //Si el dato que ha llegado es S significa que comienza la transmisión
    //del contador de pulsos.
    if (Serial.read() == 'S') {
      byte_bajo = Serial.read(); //Leo el byte_bajo del puerto serie
      byte_alto = Serial.read(); //Leo el byte_alto del puerto serie
      contadorPulsos = ((byte_alto << 8) && (byte_bajo)); //Junto todo en una variable
      Serial.read(); //Como el protocolo envia una F la leo y en este caso la
                      //desecho porque no la necesito para nada
    }
  }
}

En este caso las tramas se envían con un protocolo como ha dicho Igor_R que es Sbyte_bajobyte_altoF.

Espero que te pueda ayudar.

Saludos chato_sat

Lo unico que:
contadorPulsos = ((byte_alto << 8 ) && (byte_bajo));
deberia ser una OR, no una AND. Y de operaciones bitwise => http://arduino.cc/en/Reference/BitwiseAnd (quieres sumar la parte alta a la baja).
&& devuelve true or false (es una operacion logica que devuelve boolean). Es diferente “&” que “&&”.
Y es bueno comprobar que llegaba una F a lo ultimo ( para eso te “curras” el protocolo… :wink: ) y asi validar que puedes “confiar” que has recibido bien los datos.

:smiley:

Para el caso de leer o escribir en EEPROM busca las funciones: http://www.arduino.cc/playground/Code/EEPROMWriteAnything

No se por que no están "de serie" en arduino.

Bueno chicos ,primero un saludo para todos,disculpar la tardanza en contestar, he estado muy liado.Bueno al lío ,efectivamente, Igor, el código funciono perfectamente pero no con && si no con | como decías , además el implementar ese sencillo protocolo da un control “total” sobre el flujo de datos, me ha venido de perlas para otra parte del proyecto que se dedica a recopilar datos y que no acababa de ir como debiera, así es que ha sido un “math” en toda regla.
Bien ahora , ya solo por culturilla general ¿que diferencia hay entre esta expresión? :RPM = ( Wire.receive()<<8) +Wire.receive(); y esta otra: RPM = ((byte_alto << 8) | (byte_bajo)); por supuesto a parte de que una es usada en comunicación I2c y la otra en Serial.
Gracias a todos

mmm, ninguna 8)