Afin de mieux expliquer à quoi sert l'union et comment l'utiliser il me semble plus simple procédé par la résolution d'un problème concret par l'utilisation d'une structure et d'un union.
Le problème à résoudre : Je souhaite faire communiquer deux arduino entre eux reliée ensemble en uart chacune via un module bluetooth . ( Mais valable avec tout type de communication, I2C, SPI uart filaire, même aussi pour une arduino et un RPi etc...)
On va prendre le cas d'une station météo qui est dehors, équipé d'un capteur de luminosité, de température, et d'hygrométrie.
Une station d'affichage qui est à l'intérieur qui reçoit les données et les affiches sur un écran LCD.
hygrométrie et luminosité : variable sur uint8_t variant de 0 à 100%
température variable à virgule sur un float.
Si je veux envoyer depuis la station météo l'hygrométrie et la luminosité je peux faire :
Côté station météo
Plus qu'à faire pareil pour " tempValue" ! Easy me direz vous !
Et bien non... tempValue est un float... et Serial.write est fait pour envoyer des bytes, et donc des variables sur 8 bits. Autrement dit des uint8_t ou des int8_t ( les char en font partie ) ! Chance pour nous que nos deux autres valeurs étaient bien des sur 8 bits car sinon ça marchait pas comme il faut ...
Du coup comment faire ?
Comme toujours il y a plusieurs façon de faire.
On pourrait reconvertir notre float " tempValue " en int8_t int8TempValue, avec une opération mathématique ! ça marche bien mais on risque de perdre en résolution sur notre mesure...
exemple tempValue = 25.25 on choisit de toujours multiplier par 4 par exemple du coup on obtient un int8TempValue = 101; on enverra donc 101 qui est bien sur 8 bit et ensuite on oubliera pas de diviser par 4 avant d'afficher car la valeur qui nous intéresse est bien 25.25 et pas 101 dans ce cas concret.
On peut imaginer transformer les float en une chaîne de caractère
exemple 25,25 = "2" "5" "," "2" "5" envoyer la chaîne de 5 caractère dans ce cas ( vu que chacun des caractères est sur 8 bits on peut les envoyer ) par contre après la station d'affichage doit recomposer la chaîne de caractère et traduire l'ensemble ... Ce qui fonctionne mais est gourmand en opérations ...
On a un bel exemple implémenté ici ! =)
Ou on peut aussi utiliser un union qui aura par exemple cette forme :
Pour cela il vous suffit de créer le même union dans vos deux codes côté station d'affichage et côté station météo et de faire :
Côté station météo
Maintenant pour ceux qui le souhaitent rentrons un plus dans le détail et si vous voulez suivre accrochez vous :
L'union en fait c'est rien de plus que plusieurs types de variable qui sont allouées sur un même espace mémoire ! Et le principe c'est de joueer avec le fait de voir de différentes façon ce même espace mémoire.
Cas concret : je prend un float de valeur z. Dans le micro contrôleur il sera stocké dans 4 bytes ( 4 *8 bits ) qui auront pour valeur a b c et d ( sur 8 bits ).
Si sur le même espace mémoire que là ou je stock z je dit qu'il y a un tableau de 4 bytes alors les valeurs qui seront contenu dans ce tableau de 4 bytes seront bien les valeur a b c d.
Dans l'exemple précédent puisque je ne peux pas envoyer directement z d'un coup par ma fonction Serial.write, je décide de voir non pas z mais le tableau contenant a b c d , et j'envois a b c et d que je peux envoyer car ce sont des bytes... Côté station je reçois alors a b c d et je les stock dans " l'espace mémoire adéquate " et du coup une fois que c'est rangé correctement en mémoire je peux alors voir z !
Maintenant vous savez ce qu'est un union et vous avec eu un exemple d'utilisation avec un float, mais sachez que, ça peut s'utiliser avec d'autre types de variable, même avec des structures !
exemple :
Il est possible de définir des unions avec des variables qui ne sont pas de même tailles
exemple
Et beaucoup d'autres usages encore sont possible ! Et vous comment allez vous utiliser les unions ?
J'espère que cette présentation vous a plu !
N'hésitez pas à commenter ce " tutoriel " avec vos propositions de cas d'applications !
Le problème à résoudre : Je souhaite faire communiquer deux arduino entre eux reliée ensemble en uart chacune via un module bluetooth . ( Mais valable avec tout type de communication, I2C, SPI uart filaire, même aussi pour une arduino et un RPi etc...)
On va prendre le cas d'une station météo qui est dehors, équipé d'un capteur de luminosité, de température, et d'hygrométrie.
Une station d'affichage qui est à l'intérieur qui reçoit les données et les affiches sur un écran LCD.
hygrométrie et luminosité : variable sur uint8_t variant de 0 à 100%
température variable à virgule sur un float.
Si je veux envoyer depuis la station météo l'hygrométrie et la luminosité je peux faire :
Côté station météo
Serial.write ( lumValue); Serial.write ( huValue);Côté station d'affichage
if(Serial.available()>1) { lumValue= Serial.read(); huValue = Serial.read(); displayValues ( lumValue,huValue ); }Chouette ça marche je récupère bien mes valeurs et je peux les envoyer dans ma fonctions qui les affiche ! Cool !
Plus qu'à faire pareil pour " tempValue" ! Easy me direz vous !
Et bien non... tempValue est un float... et Serial.write est fait pour envoyer des bytes, et donc des variables sur 8 bits. Autrement dit des uint8_t ou des int8_t ( les char en font partie ) ! Chance pour nous que nos deux autres valeurs étaient bien des sur 8 bits car sinon ça marchait pas comme il faut ...
Du coup comment faire ?
Comme toujours il y a plusieurs façon de faire.
On pourrait reconvertir notre float " tempValue " en int8_t int8TempValue, avec une opération mathématique ! ça marche bien mais on risque de perdre en résolution sur notre mesure...
exemple tempValue = 25.25 on choisit de toujours multiplier par 4 par exemple du coup on obtient un int8TempValue = 101; on enverra donc 101 qui est bien sur 8 bit et ensuite on oubliera pas de diviser par 4 avant d'afficher car la valeur qui nous intéresse est bien 25.25 et pas 101 dans ce cas concret.
On peut imaginer transformer les float en une chaîne de caractère
exemple 25,25 = "2" "5" "," "2" "5" envoyer la chaîne de 5 caractère dans ce cas ( vu que chacun des caractères est sur 8 bits on peut les envoyer ) par contre après la station d'affichage doit recomposer la chaîne de caractère et traduire l'ensemble ... Ce qui fonctionne mais est gourmand en opérations ...
On a un bel exemple implémenté ici ! =)
Ou on peut aussi utiliser un union qui aura par exemple cette forme :
union FLOATTOBYTESCONVERTER { float floatValue; uint8_t bytes[SIZEOFFLOAT]; // SIZEOFFLOAT =4 car un float est sur 4 bytes. } tempValue;Et qui nous permettra de convertir sans y penser un float en bytes puis des bytes en float comme par magie !
Pour cela il vous suffit de créer le même union dans vos deux codes côté station d'affichage et côté station météo et de faire :
Côté station météo
tempValue.floatValue = 25,25; for(uint8_t i=0; i<SIZEOFFLOAT; i++) { Serial.write( tempValue.bytes[i] ); }et côté station d'affichage
if (Serial.available()>3) { for(uint8_t i=0; i<SIZEOFFLOAT; i++) { tempValue.bytes[i] = Serial.read( ); } displayFloat (tempValue.floatValue) ;abracadabra le tour est joué ! C'est pas beau la vie ?
Maintenant pour ceux qui le souhaitent rentrons un plus dans le détail et si vous voulez suivre accrochez vous :
L'union en fait c'est rien de plus que plusieurs types de variable qui sont allouées sur un même espace mémoire ! Et le principe c'est de joueer avec le fait de voir de différentes façon ce même espace mémoire.
Cas concret : je prend un float de valeur z. Dans le micro contrôleur il sera stocké dans 4 bytes ( 4 *8 bits ) qui auront pour valeur a b c et d ( sur 8 bits ).
Si sur le même espace mémoire que là ou je stock z je dit qu'il y a un tableau de 4 bytes alors les valeurs qui seront contenu dans ce tableau de 4 bytes seront bien les valeur a b c d.
Dans l'exemple précédent puisque je ne peux pas envoyer directement z d'un coup par ma fonction Serial.write, je décide de voir non pas z mais le tableau contenant a b c d , et j'envois a b c et d que je peux envoyer car ce sont des bytes... Côté station je reçois alors a b c d et je les stock dans " l'espace mémoire adéquate " et du coup une fois que c'est rangé correctement en mémoire je peux alors voir z !
Maintenant vous savez ce qu'est un union et vous avec eu un exemple d'utilisation avec un float, mais sachez que, ça peut s'utiliser avec d'autre types de variable, même avec des structures !
exemple :
union METEODATA { struct METEO { uint8_t huValue; uint8_t lumValue; float tempValue; } meteo; uint8_t bytes[6]; } myData; myData.meteo.huValue = 100;Sachez aussi que l'usage de l'union n'est pas uniquement pour faciliter les process de communications bytes par bytes.
Il est possible de définir des unions avec des variables qui ne sont pas de même tailles
exemple
union SHORTER { char nameComplete[20]; char nameReduced[3]; } profile;Vous pouvez par exemple choisir d'afficher un nom réduit composé des 3 lettres d'un prénom ...
Et beaucoup d'autres usages encore sont possible ! Et vous comment allez vous utiliser les unions ?

J'espère que cette présentation vous a plu !
N'hésitez pas à commenter ce " tutoriel " avec vos propositions de cas d'applications !

- Oliver17 aime ceci