pentru a trimite date înainte și înapoi prin Things Network va trebui să utilizați bytes. Acest ghid vă va ajuta să codificați diferite tipuri de date în cât mai puțini octeți posibil.
gama fără precedent a tehnologiei LoRaWAN pe care o construim vine la costul lățimii de bandă reduse și al timpului de antenă limitat (numărul de ori dimensiunea pachetelor pe care le trimiteți). Din fericire, nu aveți nevoie de o imagine a acelui coș de garaj inteligent care trebuie golit. Chiar și un singur bit
1
ar face!,
ce este un octet?
un octet este un grup de 8 biți. Un bit este unitatea cea mai de bază și poate fi 1 sau 0. Un octet este nu doar 8 valori între 0 și 1, dar 256 (28) diferite combinații (mai degrabă permutări), variind de la 00000000
de exemplu, prin 01010101
și 11111111
. Astfel, un octet poate reprezenta un număr zecimal între 0 (00) și 255.
nedumerit? Amintiți-vă că 3 numere zecimale nu reprezintă doar 3 valori între 0 și 9, ci 1000 (103) permutări de la 0(00) la 999.,
Aflați mai multe despre cum funcționează lucrurile: cum funcționează biții și octeții și tutorialul Arduino bit Math pentru a afla mai multe despre el.
ce este un tampon de octeți?
gândiți-vă la buffer ca la un alt cuvânt pentru o matrice, o listă, orice rezonează cu experiența dvs. de programare. Ca un octet este un grup de 8 biți, un tampon este un grup de un număr predefinit de octeți. Dacă avem un grup de 3 octeți, aceasta ar putea reprezenta fie 3 valori între 0 și 255, dar și o singură valoare între 0 și 16777216 (2563).
a se vedea modelul?, Numărul de alegeri pe poziția (n) la puterea a numărului de posturi (r) este numărul de permutări: nr. Afla mai multe pe MathIsFun.com.
Ce hex?
de multe ori, veți vedea un grup de octeți afișate ca:
FF F0 0F 11
nu a Fost un octet, un grup de 8 0
s și 1
– uri?, 🤔 Ai dreptate, dar așa cum am văzut deja 11111111
se traduce la 255 în bun vechi sistem zecimal, putem traduce, de asemenea, la FF în hexazecimal sistem în care fiecare poziție are 16 (0-9 a-F) valori posibile. Avantajul este că este mai scurt și explicit cu privire la valoarea maximă (257 nu este o opțiune).,
exemplul De mai sus tradus în sistemul zecimal și căptușit pentru lizibilitate ar fi:
255 240 015 017
Pentru a indica faptul că vrei să spui 11
în hex și nu doi biți sau numărul unsprezece, te prefix cu 0x
de formatare. Pentru a spune că vrei să spui utilizarea binară B
.,h>Code
11
0x11
B11
An example for Arduino:
Yeah, I know… 0x
kind of blows the shorter-to-write advantage of hex., 🙃
câți octeți pot trimite?tehnic, puteți trimite 51 de octeți. Dar, cu cât veți trimite mai mulți octeți, cu atât mai mult timp de emisie vă va costa pachetul și cu atât mai repede veți atinge timpul maxim alocat. Deci, nu vă întrebați câte puteți trimite, ci mai degrabă întrebați cât de puțini ar putea face treaba.
cum să trimiteți numere mari?
o întrebare mai bună ar fi cum să trimiteți intervale mai mari decât 255.
Index
dacă valorile posibile pe care trebuie să le acceptați nu încep de la 0 și cunoașteți valoarea minimă, începeți prin indexarea acelui număr.,
de exemplu, imaginați-vă că ne-am aștepta la valori între 3400 și 3600.,
de Pe aparat ne-ar codifica acest ca:
int myVal = 3450;const int myBase = 3400;byte payload = { myVal - myBase };
Și în aplicație utilă funcții face:
var myBase = 3400;decoded.myVal = bytes + myBase;
invers, în aplicarea encoder utilă funcția vom avea:
var myVal = 3450;var myBase = 3400;var bytes = ;
Și pe dispozitiv decoda cu:
int myBase = 3400;int myVal = payload + myBase;
după Cum puteți vedea cât de mult valoarea minimă este cunoscut și gama de valoarea noastră este de 256 sau mai puțin, putem folosi un singur octet fără a rupe o sudoare., Asigurați-vă că pentru a verifica valoarea nu este mai mare decât 3655 pentru a preveni bug-uri urât.😅
Round
acum ce se întâmplă dacă intervalul este mai mare decât 256? Următoarea întrebare ar fi dacă trebuie să știți valoarea exactă. Dacă senzorul dvs. are o gamă de 400 și o marjă de eroare de 2, nu veți pierde niciun sens prin rotunjirea valorii. Atât 299 cât și 300 ar rotunji la 150, ceea ce este bine.
de Pe aparat ne-ar codifica acest ca:
int myVal = 300;int errorMargin = 2byte payload = { round(myVal / errorMargin) };
Și în aplicație utilă funcții face:
var errorMargin = 2;decoded.myVal = bytes * errorMargin;
Veți obține ideea de invers.,
utilizați cuvinte
un cuvânt este de 2 octeți (cu excepția plăcilor datorate, Zero și similare, unde este de 4 octeți), ceea ce vă oferă deja o gamă uriașă de 65536 (2562). Int tip de date este un cuvânt și Arduino vine cu highByte()
și lowByte()
pentru a extrage stânga și la dreapta octet dintr-un cuvânt. Acest lucru face foarte ușor pentru a codifica și decoda.
Codifica (Arduino):
int myVal = 20000;byte payload;payload = highByte(myVal);payload = lowByte(myVal);
Decoda (sarcină utilă funcții):
decoded.myVal = (bytes << 8) + bytes;
vă Întrebați la ce
<<
este vorba?, Acest Stânga schimbă 8 biți ai primului octet 8 poziții spre stânga. Confuz? Gândiți-vă cum am putea codifica numărul 11 ca două 1 și decoda prin schimbarea primul 1 sus o poziție (făcându-l 10) înainte de a adăuga alte. Vom vorbi mai multe despre schimbarea pic următoare.
Codifica (sarcină utilă funcții):
var myVal = 20000;var bytes = ;bytes = (myVal & 0xFF00) >> 8;bytes = (myVal & 0x00FF);
mai văzut
&
folosit în acest fel înainte? Acesta este un pic și., Folosit în acest fel, partea dreaptă a expresiei va acționa ca o mască pentru a elimina un octet, astfel încât să putem lucra doar cu celălalt.
Decoda (Arduino):
int myVal = ((int)(payload) << 8) + payload;
Shift biți
Dacă intervalul de așteptat valori este mai mare decât 65536 putem folosi același truc. Singura diferență este că trebuie să schimbăm manual biți atunci când codificăm pe Arduino, la fel cum am făcut în funcția de sarcină utilă.să presupunem că avem nevoie pentru a codifica o lungă care utilizează 4 octeți pentru un interval de până la 4294967296.,
Encode (Arduino):
Decode (funcții de sarcină utilă):
decoded.myVal = ((long)(bytes) << 24) + ((long)(bytes) << 16) + ((long)(bytes) << 8) + ((long)(bytes));
cum să trimiteți numere negative?
pentru a face diferența între -100 și 100, veți avea nevoie de un tip de date semnat. Acestea setează cel mai mare (cel mai din stânga) bit la 1
pentru a indica faptul că este un număr negativ. Aceasta înseamnă că, de exemplu, într-un cuvânt, doar 15 din cei 16 biți sunt disponibili pentru numărul real, limitând intervalul de la 65536 la 32768.,
Index, round și shift
tipurile de date pe care le-am folosit până acum sunt toate semnate, ceea ce înseamnă că toate trucurile funcționează la fel de bine pentru valorile negative. Doar să fie conștienți de valoarea maximă.
Unsigned tipuri de date
Dacă nu se aștepta la numere negative și au nevoie de o gamă mai mare, în mod explicit utilizarea unsigned int
sau unsigned long
.
cum se trimit zecimale?până acum ne-am ocupat doar de numere rotunjite. Ce se întâmplă dacă aveți nevoie de mai multă precizie? Răspunsul este foarte similar cu modul în care am indexat sau rotunjit numere mari., Pur și simplu multiple și împărțiți valoarea pe măsură ce codifica și decodifica.
Codifica (Arduino):
float myVal = 1.22;byte payload;payload = round(myVal * 100);
Decoda (sarcină utilă funcții):
decoded.myVal = bytes / 100;
Codifica (sarcină utilă funcții):
bytes = Math.round(1.22 * 100);
Decoda (Arduino):
float myVal = payload / 100.00;
Cum de a trimite mai multe numere?
în multe cazuri, veți dori să trimiteți mai multe valori într-un singur mesaj. Începeți prin codificarea fiecărui număr individual într-un tampon de octeți și apoi combinați-le într-un singur tampon.,
Codifica (Arduino):
s-ar putea întreba de ce
memcpy()
acceptăpayload + sizeOfPayloadA
cum par 🍏 și 🍊. Gândiți-vă la aceasta ca la o instrucțiune de copiere în tamponulpayload
, dar după mutarea punctului pe care îl va copia, cu lungimea sarcinilor utile pe care le-am adăugat până acum.,
Decoda (sarcină utilă funcții)
decoded.myValA = bytes.slice(0, 2);decoded.myValB = bytes.slice(2, 5);// Decode both byte arrays as we did before
Codifica (sarcină utilă funcția)
// Encode both values as we did beforevar bytes = bytesA.concat(bytesB);
Decoda (Arduino):
var payloadA;var payloadB;memcpy(payloadA,
Cum de a trimite mesaje text?
răspunsul scurt este: nu. Textul folosește o mulțime de octeți. Unicode definește mai mult de 128000 de caractere, astfel încât să ia 3 octeți pe caracter! Rareori există motive întemeiate pentru a utiliza text în loc de numere, în afară de transmiterea unor date de utilizator., De cele mai multe ori doar caracterele alfa-numerice sunt suficiente, în acest caz puteți scăpa folosind caractere ASCII care utilizează doar un singur octet per caracter. Fiecare șir trebuie terminat cu un caracter nul (0x00, ‘\0’) pentru a indica că șirul s-a încheiat.
nu ați auzit de la mine, Dar iată cum ați codifica un șir:
pe care l-ați decodifica cu:
decoded.myVal = String.fromCharCode.apply(null, bytes);