Aller au contenu


Information tutoriel

  • Ajouté le: juil. 14 2016 12:33
  • Date Updated: juil. 14 2016 02:48
  • Lectures: 4411
 


* * * * *
2 Notes

Renforcement des structures par l'Union

Puisque l'union fait la force vous découvrirez ici la force de l'union !

Posté par Mike118 on juil. 14 2016 12:33
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
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 ! ;)