para enviar datos de ida y vuelta a través de la red Things necesitarás usar bytes. Esta guía le ayudará a codificar diferentes tipos de datos en la menor cantidad de bytes posible.
La gama sin precedentes de la tecnología LoRaWAN en la que construimos se produce a costa de un ancho de banda bajo y un tiempo de uso limitado (el número de veces que el tamaño de los paquetes que envía). Afortunadamente, no necesita una imagen de ese contenedor de garaje inteligente que necesita vaciarse. ¡Incluso un solo bit
1
serviría!,
¿Qué es un byte?
un byte es un grupo de 8 bits. Un bit es la unidad más básica y puede ser 1 o 0. Un byte no es solo 8 valores entre 0 y 1, sino 256 (28) combinaciones diferentes (más bien permutaciones) que van desde 00000000
a través de, por ejemplo, 01010101
a 11111111
. Por lo tanto, un byte puede representar un número decimal entre 0(00) y 255.
Perplejo? Recuerde que 3 números decimales también no solo representan 3 valores entre 0 y 9, sino 1000 (103) permutaciones de 0(00) a 999.,
Obtenga más información sobre cómo funcionan las cosas: cómo funcionan los Bits y los Bytes y el tutorial de matemáticas de bits de Arduino para obtener más información al respecto.
¿qué es un búfer de bytes?
piense en buffer como otra palabra para una matriz, lista, Lo que resuene con su experiencia de programación. Al igual que un byte es un grupo de 8 bits, Un búfer es un grupo de un número predefinido de bytes. Si tenemos un grupo de 3 bytes, esto podría representar 3 valores entre 0 y 255, pero también un solo valor entre 0 y 16777216 (2563).
Ver el patrón?, El número de opciones por posición (n) A la potencia del número de posiciones (r) es el número de permutaciones: nr. MathIsFun.com.
¿Cuál es el hex?
a Menudo, usted verá un grupo de bytes muestra como:
FF F0 0F 11
no Era un byte a un grupo de 8 0
y 1
s?, You tienes toda la razón, pero al igual que ya vimos 11111111
se traduce a 255 en el viejo sistema decimal, también podemos traducirlo a FF en el sistema hexadecimal donde cada posición tiene 16 (0-9 A-F) valores posibles. La ventaja es que es más corto y explícito sobre el valor máximo (257 no es una opción).,
El ejemplo anterior se traduce al sistema decimal y acolchado para mejorar la legibilidad sería:
255 240 015 017
Para indicar que significa 11
en hexadecimal y no dos bits o el número once, el prefijo es con la etiqueta 0x
formateador. Para decirle que quiere decir binario use B
.,h>Code
11
0x11
B11
An example for Arduino:
Yeah, I know… 0x
kind of blows the shorter-to-write advantage of hex.,
¿cuántos bytes puedo enviar?
técnicamente, puede enviar 51 bytes. Pero, cuantos más bytes envíe, más tiempo de aire le costará el paquete y más pronto alcanzará su tiempo máximo asignado. Por lo tanto, no se pregunte cuántos puede enviar, sino más bien pregunte cuántos podrían hacer el trabajo.
¿cómo enviar números grandes?
una mejor pregunta sería cómo enviar rangos mayores de 255.
Index
Si los posibles valores que necesita admitir no comienzan en 0 y conoce el valor mínimo, comience indexando en ese número.,
por ejemplo, imagine que esperaríamos valores entre 3400 y 3600.,
en el dispositivo codificaríamos esto como:
int myVal = 3450;const int myBase = 3400;byte payload = { myVal - myBase };
y en las funciones de carga útil de la aplicación hacemos:
var myBase = 3400;decoded.myVal = bytes + myBase;
al revés, en la función de carga útil del codificador de la aplicación tendríamos:
var myVal = 3450;var myBase = 3400;var bytes = ;
y en el dispositivo decodifique esto con:
int myBase = 3400;int myVal = payload + myBase;
como puede ver, siempre y cuando se conozca el valor mínimo y el rango de nuestro valor sea 256 o menos, todavía podemos usar un solo byte sin sudar., Asegúrese de comprobar que su valor no es mayor que 3655 para evitar errores desagradables.Round
Round
Ahora, ¿Qué pasa si el rango es mayor que 256? La siguiente pregunta sería si necesita saber el valor exacto. Si su sensor tiene un rango de 400 y un margen de error de 2, no perderá ningún significado redondeando el valor. Tanto 299 como 300 redondearían a 150, lo cual está bien.
En el dispositivo que había codificar esta como:
int myVal = 300;int errorMargin = 2byte payload = { round(myVal / errorMargin) };
Y en la aplicación de carga funciones:
var errorMargin = 2;decoded.myVal = bytes * errorMargin;
Usted tendrá la idea de la otra manera alrededor.,
Use palabras
una palabra es de 2 bytes (excepto en Due, Zero y tableros similares donde es de 4 bytes), lo que ya le da un amplio rango de 65536 (2562). El tipo de datos int es una palabra y Arduino viene con highByte()
y lowByte()
para extraer el byte izquierdo y derecho de una palabra. Esto hace que sea muy fácil de codificar y decodificar.
Encode (Arduino):
int myVal = 20000;byte payload;payload = highByte(myVal);payload = lowByte(myVal);
Decode (carga de funciones):
decoded.myVal = (bytes << 8) + bytes;
Preguntando lo que el
<<
se acerca?, Esta izquierda desplaza los 8 bits del primer byte 8 posiciones a la izquierda. Confundido? Piense en cómo podríamos codificar el número 11 como dos 1 y decodificar cambiando el primer 1 hacia arriba en una posición (haciéndolo 10) antes de agregar el otro. Hablaremos más sobre bit shifting a continuación.
Encode (capacidad de carga funciones:
var myVal = 20000;var bytes = ;bytes = (myVal & 0xFF00) >> 8;bytes = (myVal & 0x00FF);
Nunca había visto
&
utilizado de esta manera antes? Esto es un poco y., Utilizado de esta manera, el lado derecho de la expresión actuará como una máscara para poner a cero un byte para que podamos trabajar solo con el otro.
Decode (Arduino):
int myVal = ((int)(payload) << 8) + payload;
Cambio de bits
Si el rango de valores esperados es más grande que 65536 podemos usar el mismo truco. La única diferencia es que tenemos que cambiar manualmente los bits cuando codificamos en Arduino, al igual que hicimos en la función de carga útil.
digamos que necesitamos codificar un long que usa 4 bytes para un rango de hasta 4294967296.,
codificar (Arduino):
decodificar (funciones de carga útil):
decoded.myVal = ((long)(bytes) << 24) + ((long)(bytes) << 16) + ((long)(bytes) << 8) + ((long)(bytes));
¿cómo enviar números negativos?
para diferenciar entre -100 y 100 necesitará un tipo de datos firmado. Estos establecen el bit más alto (más a la izquierda) a 1
para indicar que es un número negativo. Esto significa que por ejemplo en una palabra solo 15 de los 16 bits están disponibles para el número real, limitando el rango de 65536 a 32768.,
Index, round y shift
Los tipos de datos que hemos utilizado hasta ahora están firmados, lo que significa que todos los trucos funcionan igual de bien para valores negativos. Solo tenga en cuenta el valor máximo.
tipos de datos sin signo
si no espera números negativos y necesita un rango más grande, use explícitamente unsigned int
o unsigned long
.
Cómo enviar decimales?
hasta ahora solo hemos tratado con números redondeados. ¿Qué pasa si necesitas más precisión? La respuesta es muy similar a cómo indexamos o redondeamos números grandes., Simplemente multiplique y divida el valor a medida que lo codifica y decodifica.
Encode (Arduino):
float myVal = 1.22;byte payload;payload = round(myVal * 100);
Decode (carga de funciones):
decoded.myVal = bytes / 100;
Encode (capacidad de carga funciones):
bytes = Math.round(1.22 * 100);
Decode (Arduino):
float myVal = payload / 100.00;
Cómo enviar varios números?
en muchos casos, querrá enviar varios valores en un solo mensaje. Comience codificando cada número individual a un búfer de bytes y luego combínelos en un solo búfer.,
Encode (Arduino):
Usted podría preguntarse por qué
memcpy()
aceptapayload + sizeOfPayloadA
como parecen 🍏 y 🍊. Piense en ello como una instrucción para copiar en el búferpayload
, pero después de mover el punto se copiará, con la longitud de las cargas útiles que agregamos hasta ahora.,
Decode (carga de funciones)
decoded.myValA = bytes.slice(0, 2);decoded.myValB = bytes.slice(2, 5);// Decode both byte arrays as we did before
Encode (capacidad de carga de la función)
// Encode both values as we did beforevar bytes = bytesA.concat(bytesB);
Decode (Arduino):
var payloadA;var payloadB;memcpy(payloadA,
¿Cómo enviar mensajes de texto?
La respuesta corta es: no. El texto utiliza una gran cantidad de bytes. Unicode define más de 128000 caracteres, por lo que tomaría 3 bytes por carácter! Rara vez hay buenas razones para usar texto en lugar de números, aparte de tal vez transmitir alguna entrada del usuario., La mayoría de las veces solo bastan los caracteres alfanuméricos, en ese caso puede escapar utilizando caracteres ASCII que solo usan un solo byte por carácter. Cada cadena debe terminar con un carácter NULL (0x00, ‘\0’) para indicar que la cadena ha terminado.
no oyeron de mí, pero aquí es cómo se desea codificar una cadena:
Que a usted le decodificar con:
decoded.myVal = String.fromCharCode.apply(null, bytes);