Variables & Constantes


Lorsqu’une LED est connectée par exemple à la broche 13 de la carte ; plutôt que d’indiquer 13 dans le code à chaque fois que l’on fait référence à la LED, il est plus logique et facile à la compréhension d’utiliser l’appellation « LED ». Cela permet de rendre le code plus lisible. On comprend plus facilement de quoi on parle avec des mots qu’avec un chiffre… C’est quoi déjà sur la broche 13 ?

 

Cette appellation LED dans le code est donc soit une variable (lorsqu’elle peut changer), soit une constante (quand elle est fixe).

 

Dans notre cas, celui de la LED, il s’agira d’une constante, puisqu’elle ne changera pas. On lui affectera alors le numéro d’une broche de la carte Arduino, qui du coup est un chiffre fixe (donc ici le chiffre 13, si vous suivez toujours).


I. Notions de poids


Les variables permettent donc de stocker des données dont le programme aura besoin pour son exécution.

 

Un peu comme des boîtes de rangement sur des étagères. La taille de la boîte définit le nombre de choses maximum que l’on peut y mettre. En règle générale, dans le monde réel cette contenance est estimée en litre.

 

En informatique on exprime ces valeurs en bits et en octets.

 

Les bits seraient les boîtes de rangement, et les octets le nombre d’étagères où l’on peut y ranger 8 boîtes.

1) Notion de bits & langage binaire


Un bit, provenant de Binary Digit (qui veut dire élément binaire en français) est la plus petite unité d’information utilisée par une machine numérique.

 

Pour comprendre ce qu’est un bit, il faut juste imaginer que tout matériel informatique est constitué de composants électroniques, comme des relais, des transistors, des LED…

 

La plupart de ces composants ne possèdent que 2 états : éteint ou allumé. C’est ce qui a donné naissance au langage binaire composé soit de 0 ou de 1.

 

Imaginons par exemple, que l’on associe 2 LED ensemble. Dans ce cas-là nous n’avons plus 2 possibilités (ouvert/fermé) mais 4 possibilités :

 

Donc sur le même principe, avec 2 bits on peut coder 4 combinaisons différentes. Et avec 3 bits nous aurions 8 combinaisons différentes, avec 4 bits se serait 16 combinaisons, avec 5 bits 32 combinaisons, avec 6 bits 64 combinaisons, 7 bits 128 combinaisons, avec 8 bits 256 combinaisons…

2) Notion d’octets


Un octet est donc une association de 8 bits, ce qui nous donne 256 combinaison différentes !

 

Notre système mathématique est sur une base 10 (chiffres de 0 à 9), nous utilisons donc les unités, les dizaines et les centaines… 168 est donc formé de 1 centaine, 6 dizaines et 8 unités.

En informatique, on utilise le système binaire, composé que de 0 et de 1, sur 1 octet (8 bits). En effet, en électronique les données circulent sous forme de courants électriques. Or, la tension parcourant les composants électroniques n’est pas toujours stable, ce qui rend difficilement réalisable un système détectant dix valeurs différentes. Par contre, une chose est sûr, soit il y a du courant ou il n’y en a pas ! Ce qui donne un système sur 2 valeurs, comme vu précédemment avec la lampe (soit allumée, soit éteinte).

 

Par exemple, dans ce système binaire le chiffre 168 correspond donc à 10101000.

 

Pour trouver cette correspondance, il faut décomposer le nombre (168 = 128 + 32 + 8), en mettant un « 1 » dans les colonnes correspondantes, en utilisant par exemple un tableau comme celui-ci-dessous.

Voici d’autres exemples de chiffres sur 1 octet de 8 bits :

Evidemment 1 octet ne peut stocker qu’une combinaison de 256 valeurs (de 0 à 255), Pour stocker plus d’informations, il sera nécessaire d’utiliser plusieurs octets.

 

Par exemple 2 octets représentent 16 bits soit 65 536 valeurs (de 0 à 65 535) et 4 octets représentent 32 bits soit plus de 4 milliards de valeurs/possibilités.   

Le nombre décimal 300, représentera en binaire : 00000001 00101100, et sera donc stocker sur 2 octets. Il peut également s’écrire : 0b100101100. On retire tous les 0 devant (car inutile) et on ajoute 0b pour indiquer que c’est du binaire.

 

Le processeur de la carte Arduino UNO quant à lui, est de type 8 bits, il est donc optimisé pour faire des traitements sur des variables de taille 8 bits, un traitement par exemple sur une variable 32 bits prendra donc beaucoup plus de temps.

 

Je vous conseille d’ailleurs ces excellentes vidéos expliquant certainement beaucoup mieux de moi : https://www.youtube.com/watch?v=NTrt79bWl64 et celle-ci : https://www.youtube.com/watch?v=tlbA0Cuo1LI.  

3) Comment différencier une valeur écrite en Binaire, d’une écrite en décimale ?


Si on parle de la valeur 101 par exemple, s’agit-il de 101 en décimal, ou 101 en binaire ?

 

Si on écrit simplement 101, on considéra qu’il s’agit de 101 en décimal, donc le nombre 101.

 

Si on souhaite parler de la valeur 101 en binaire, on l’écrira précéder de : 0b (zéro suivi de la lettre b) afin de montrer que l’on parle d’une valeur binaire. Ainsi, 0b101 est bien un nombre binaire qui équivaut à 5 en décimal, dans notre système de tous les jours.

4) Et en hexadécimal ça donne quoi ?


Comme pour le binaire (avec 0b), pour indiquer qu’il s’agisse d’une valeur en hexadécimal, on ajoute le préfixe 0x devant.

 

On écrira donc par exemple 0xF6 (ce qui correspond au nombre 246).

 

Mais à la différence du binaire qui s’écrit avec une succession de 0 et de 1, sur une base de 8 (8 bits, soit 8 chiffres de 0 ou de 1, comme par exemple 10101000 qui correspond par exemple au nombre 168) ; l’hexadécimal est une succession de chiffres et/ou de lettres, sur 16 valeurs :

 

0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, F

 

Dans notre exemple 168, en hexadécimal s’écrit : 0xA8.

 

Pour comprendre il faut repartir du binaire (10101000) et le diviser en 2 parties, que l’on nomme quartet.

 

Le premier quartet, celui de gauche (donc : 1010) se nomme le quartet de poids fort, alors que le second, celui de droite (ici : 1000) se nomme le quartet de poids faible.

Chaque quartet se décompose en 4 parties, représentant les valeurs suivantes : 8, 4, 2 et 1.

Dans le quartet fort on a 8 et 2, ce qui fait 10, et la dixième valeur en hexadécimal est le : A. Le 0 comptant pour 0, on commence à compter à partir de 1.

 

Dans le quartet faible, on a seulement un 8, la huitième valeur en hexadécimal est le : 8. Le 0 comptant toujours pour 0, on commence à compter à partir de 1.

 

Ce qui nous donne bien 0xA8 pour représenter le nombre décimal 168.

 

Evidemment lorsque la valeur décimale que l’on veut convertir en hexadécimal est supérieur à 255, il faut comme pour le binaire, passer sur un nombre d’octet supérieur.

Reprenons notre exemple du nombre décimal 300, qui s’écrira 0x12C, le premier quartet représentant 0, on en tient pas compte.

 

Le second quartet, représente le chiffre 1. Le troisième quartet, représente le chiffre 2.

 

Et le quatrième quartet représente la valeur 12 (8 + 4), ce qui correspond à la lettre C.


II. Définir une Variable


Pour définir une variable, il faut d’abords lui donner un nom et préciser en amont son type.

En ce qui concerne son nom, celui-ci doit respecter un certain nombre de critères :

  •  Le nom d’une variable doit être unique. Il ne peut pas y avoir 2 variables portant le même nom.
  • Il n'accepte que l'alphabet alphanumérique (les lettres de : A à Z).
  • Ainsi que les chiffres (0 à 9).
  • Mais il ne doit pas commencer par un chiffre.
  • Il ne doit pas comporter d’accents ou de caractères spéciaux (point, virgule, point-virgule…)
  • Et doit être en un seul mot, sans espace. Ou alors comporter un underscore qui uni ses termes comme par exemple : ma_variable.

Pour le type de variable, je vous renvoie au chapitre IV] les Types de variables & de constantes.


III. Définir une Constantes


Il est préférable lorsque cela est possible d’utiliser une constante au lieu d’une variable : 

  • Tout d’abord, parce qu’une constante n’occupe pas de place dans la mémoire de l’Arduino qui rappelons le est très petite. Alors qu’une variable oui… 
  • Ensuite parce que le compilateur C qui est caché sous l’Arduino IDE peut utiliser des optimisations qui ne sont pas possibles pour des variables.
  •  Enfin, une constante ne peut être modifiée par le programme (puisqu’elle est constante !), ce qui réduit la possibilité d’erreurs.

 Il existe plusieurs façons de déclarer des variables :

  •  Par le mot-clé « const »
  •  Par la macro « #define »

1) Déclaration par le mot-clé « const »


Pour ce faire, nous utilisons dans l’En-tête du code (zone de déclaration des constantes et des variables) l’instruction const suivi du type de constante, de son nom, ainsi que de sa valeur précédée par le symbole égale. Et on n’oublie pas de terminer la ligne par un point-virgule.

Ce qui donnerait, par exemple, pour notre cas : 

Ici le type de constante déclaré est : byte. Utilisé pour des entiers naturels de 0 à 255 (largement suffisant puisque par exemple l’Arduino Uno ne possède que 13 broches), et ne prenant que 8 Bit de mémoire (comparé à un type int qui est très utilisé mais qui prend 16 Bit). 

Attention : la forme de ce type d’instruction est importante :

  •  Ne pas oublier le symbole égale, qui ne veut pas dire égale, mais qui représente l’affectation.
  •  Ne pas oublier non plus le point-virgule à la fin de la ligne de code.
  •  Il est d’usage de mettre en majuscule le nom de la constante/variable, mais il n’y a pas d’obligation.
  •  Le signe « égale » ne veut pas dire égale, mais « à qui on affecte ».

 Voici ce que cela donne :

2) Déclaration par la macro « #define »


Une autre façon de déclarer une constante est d’utiliser la macro #define.

 

Pour ce faire, nous utilisons dans l’En-tête du code (zone de déclaration des constantes et des variables) l’instruction #define suivi du nom de la constante, ainsi que de sa valeur.

 

Ce donnerait pour notre exemple : 

Attention : sa mise en forme est particulière :

  •  Cette instruction ne termine pas par un point-virgule car elle n’est pas considérée comme une ligne de code (ce n’est pas du C ou C++).
  •  Il ne faut pas mettre de signe égale entre le nom de la constante et sa valeur.

Attention : ce type de déclaration est une macro (elle est prise en charge par le préprocesseur : qui effectue son travail avant le compilateur) et qui n’est pas du langage C ni du C++. C’est pour cela qu’il n’y a pas de point-virgule à la fin.


IV. Les types de Variables & Constantes


Les variables et les constantes peuvent recouvrir bon nombre de choses : des chiffres, des nombres, nombres décimaux (à virgule), des lettres, des mots, des chaînes de caractères…

 

En fonction de cela, elles vont peser plus ou moins lourd.

 

Hors, les cartes Arduino, ne disposent pas d’énormément de mémoire pour stocker leurs variables ou leurs constantes.

 

Il est donc important de bien choisir le type de variables et de constantes pour à la fois déterminer ce qu’elles peuvent stocker (la forme) mais aussi quel poids elles peuvent supporter.

 

Voici un tableau reprenant les types de variables/constantes, leurs noms, ce qu’elles peuvent stocker (le type d’information) et leurs poids (en bits et en octets).

Par exemple si l’on veut créer une variable pour y stocker les résultats d’un capteur de température, nous aurons besoin d’y stocker un nombre à virgule (décimale), nous utiliserons donc une variable de type Float.

 

Si par contre nous souhaitons créer une variable ne pouvant être que 0 ou 1, pour par exemple l’utilisation d’un bouton poussoir qui ne peut, être que « ouvert ou fermé » (donc 0 ou 1), nous choisirons alors une variable de type Boolean.

 

Il en va de même naturellement pour les constantes. Du moins lorsqu’on les déclare à partir du mot-clé « const » comme vu au paragraphe II.

 

Voici un petit rappel des principaux types de variables et de constantes :

  • Int (integers) est certainement le type le plus rependu. Il permet de stocker des valeurs allant de -32 768 à +32 767.
  • Long permet de stocker de grandes valeurs
  • Char est un type particulier de constantes et de variables, car il permet de stocker des caractères, des lettres de l’alphabet ou des mots.
  • Float permet de stocker des valeurs décimales, en d’autres termes des chiffres à virgule, pouvant aller jusqu’à 6 ou 7 chiffres derrière la virgule. Le type Float peut également stocker des valeurs négatives.
  • Double est identique au type Float, si ce n’est qu’il permet d’aller beaucoup plus loin dans les décimales (chiffres après la virgules) allant jusqu’à 15 à 16 chiffres. Le type Double peut également stocker des valeurs négatives.
  • Byte, lui ne stocke que des valeurs positives, allant de 0 à 255. Il est fortement employé avec certains capteurs, moteurs ou pour convertir des données sur une échelle plus facilement gérable. En effet certains capteurs analogiques fonctionnent sur 10 bits, soit 1024 valeurs (de 0 à 1023), alors que le numérique comme nous l’avons vu fonctionne sur 1 octet de 8 bits, soit 256 valeurs (de 0 à 255).
  • Word ressemble au type Int mais sans la possibilité de stocker des valeurs négatives, il ne stocke que des valeurs entières positives (sans virgule et au-dessus de zéro).
  • Bolean est un type très particulier car il ne permet de stocker que 2 types de valeurs des 0 et des 1.

V. Les Variables & Constantes Unsigned


Il existe des constantes et des variables nommées : Unsigned. Elles sont un peu particulières, car elles s’associent à certains autres types, tel que : int, long ou char, afin de ne prendre en compte que des entiers naturels non négatifs.

 

Dans ce cas-là, on place le terme unsigned avant le type de variable/constante. Ce qui donne par exemple unsigned int, unsigned long et unsigned char.

 

Ces variables et constantes ne sont pas plus légères que celles à qui elles sont associées (une variable unsigned int ne prendra pas moins de place dans la mémoire de la carte Arduino, qu’une même variable de type int).

 

En effet, une variable/constante classique de type int permet de stocker une valeur allant de - 32 768 à + 32 767, sur 2 octets, ce qui prend 8 bits.

 

Alors qu’une variable/constante de type unsigned int ; comme elle ne prend en compte que les entiers ; permettra de stocker toujours sur 2 octets soit 8 bits, une valeur allant de 0 à 65 535. 

Ces types de variables et de constantes ne permettent donc pas de gagner de la place dans la mémoire de la carte Arduino, mais permettent de modifier la plage de valeurs qu’elles peuvent stocker, en ne prenant donc pas en compte les valeurs négatives.


VI. Les Variables & Constante : Globales et Locales


Il existe 2 façons, 2 endroits pour déclarer des variables ou des constantes.

1) Variables & constantes : globales


Lorsque vous déclarez vos variables & vos constantes dans l’En-tête (la zone de déclaration des constantes et des variables) au début du programme avant la fonction Void Setup.

 

Celles-ci sont prises en compte pour l’ensemble du code, elles peuvent donc être utilisé par n’importe quelle fonction dans le programme.

 

Ce sont des variables et des constantes globales.

2) Variables & constantes : locales


A l’inverse, il arrive que vous n’ayez besoin de certaines variables ou constantes que pour une partie du code, et pas dans l’ensemble du code.

 

Vous pourrez donc les déclarer directement dans le code, par exemple dans une boucle for ou avec une condition if.

 

Ce sont des variables et des constantes locales.

 

Par exemple dans le code qui suit, provenant de l’exemple KeyboardAndMouseControl (de l’Arduino IDE, voir dans Fichier, Exemple, puis rubrique 09.USB) l’auteur du code a déclaré dans le loop une variable de type char qu’il a appelé inChar.

 

Il faut dire que le programme comporte déjà 5 constantes déclarées dans l’En-tête.

Ce qui est important à comprendre, c’est que l’endroit où vous les déclarez doit se trouver entre des accolades et que vos variables et vos constantes ne seront prises en compte qu’entre ces accolades au risque d’avoir une erreur dans le code lors de la compilation.


VII. Les Qualificateurs de Variables « Static » & « Volatile »


Certaines variables possèdent parfois des mots-clés connus sous le nom de qualificateur de variable, utilisés généralement avant le type de données d'une variable, pour modifier la manière dont le compilateur et le programme traitent cette variable.

1) Variables : static


Comme expliqué sur le site mon-club-elec (http://www.mon-club-elec.fr/pmwiki_reference_arduino/pmwiki.php?n=Main.Static), les variables static sont des variables locales qui ont la particularité de conserver leurs valeurs, là où les simples variables locales sont détruites à chaque fois qu’une nouvelle fonction est appelée.

 

Elles se déclarent donc localement au sein d’une boucle, comme toutes variables locales, mais à la différence de celles-ci qui sont détruites lorsque la fonction se termine et recréées lorsque la fonction est appelée ; les variables static sont conservées tant que le programme s'exécute.

 

En d’autres termes : au prochain rappel de la fonction (lorsque par exemple le programme se répète dans le loop), cette variable n’est pas recréée, elle est toujours là stockant la dernière valeur obtenue.

 

Ces variables associent donc l’aspect permanent des variables globales et le fait que cette variable soit isolée des autres fonctions, comme avec les variables locales.

 

Concernant leur forme, le terme « static » se place juste avant le type de variable, comme dans l’exemple ci-dessous : 

Voici un code de Paul BADGER, créé en 2007 intitulé « RandomWalk » reprenant le qualificateur « static ». Le code créé des valeurs qui montent et descendent au hasard entre deux points (« randomWalkLowRange » et « randomWalkHigh »). Le mouvement maximum dans une boucle est régi par la variable "stepsize".

 

Une variable statique est alors utilisée pour garder en mémoire la valeur précédente. 

2) Variables : volatile


Les variables dites « volatiles » possèdent également un qualificateur de variable, le mot-clé : volatile qui se place avant le type et le nom de la variable et change auprès le compilateur et le programme, la façon dont ceux-ci gèrent cette variable.

 

Ces variables ont la particularité d’être stocké directement dans la mémoire vive du microcontrôleur, sa RAM, à la différence des autres variables qui sont stockées dans le registre de stockage (emplacement de mémoire pour stocker momentanément les variables).

 

Ce sont des variables globales amenées à être modifiées par un processus extérieur au programme principal. Le mot « volatile » est une indication donnée au compilateur de ne pas simplifier son code et de ne pas supprimer cette variable même si elle semble inutile.

Attention : Si la variable volatile est plus grande qu'un octet (par exemple une variable de type « int » de 16 bits ou de type « long » de 32 bits), le microcontrôleur ne pourra pas la lire en une seule étape. En effet, comme il s'agit d'un microcontrôleur de 8 bits, cela signifie que pendant que votre section de code principale (par exemple le loop) lit les 8 premiers bits de la variable, l'interruption peut déjà modifier les bits 8 suivants. Cela risque alors de produire des valeurs aléatoires pour votre variable volatile.

 

Résolution :

Pendant que la variable est lue, les interruptions doivent être désactivées, afin qu'elles ne puissent pas perturber les bits pendant leur lecture. Pour cela on peut :

Utiliser la fonction « noInterrupts ( ) » qui désactive les interruptions (celles-ci permettent à certaines tâches importantes de se produire en arrière-plan et sont activées par défaut. Certaines fonctions ne fonctionnent pas lorsque les interruptions sont désactivées et les communications entrantes peuvent être ignorées. Cependant, les interruptions peuvent légèrement perturber la synchronisation du code et peuvent être désactivées pour des sections de code particulièrement critiques.)

 

Les interruptions peuvent alors être réactivées avec l’instruction « interrupts ( ) ».


VIII. Difficultés de compréhension


Lorsque j’ai débuté l’Arduino j’ai eu beaucoup de mal avec certains éléments, et les variables en était un. 

J’avais beau savoir que lorsqu’on déclarait la LED sur une broche, la 13 par exemple. Le chiffre 13 représenté le numéro de la broche de la carte Arduino. Comme dans l’exemple ci-contre.

Ce qui me perturbais, c’était que l’on pouvait associer n’importe quel chiffre à une variable ou à une constante. On peut donc faire des maths du style x = quelque chose, et l’intégrer dans nos calculs.

 

Mais si l’on peut donner n’importe quel nom à notre variable ou à notre constante, on peut également faire des maths dans le programme en utilisant des mots à la place de x. Donc à la place de x = quelque chose je peux m’amuser à dire LED = quelque chose.

 

Et donc en poussant le bouchon encore plus loin on peut imaginer avoir cette même ligne de code pour une opération mathématique.

 

Je sais, je sais c’est tordu comme réflexion !

 

Mais alors comment savoir ? Comment le programme sait, quand le chiffre associé à une variable est pour un calcul mathématique, ou quand il correspond à une broche de l’Arduino ?

           

Eh bien, il fait comme nous ! Je m’explique :

 

Imaginons une institutrice qui à la récréation, rejoint sa collègue. Celle-ci lui demande comment c’est passé sa journée. L’institutrice lui répond alors : « houlà ! J’en ai deux qui étaient très dissipés et qui ont perturbé ma classe ! »

 

Comment fait donc sa collègue et nous même d’ailleurs pour comprendre que l’institutrice parle de ses élèves ?

 

La réponse est simple, nous replaçons cela dans le contexte. L’institutrice se trouve dans l’école, elle discute avec une collègue de travail, il donc tout à fait logique qu’elle parle de ses élèves et non de ses chats !

 

Le programme Arduino fait de même ! Lorsque vous déclarez une variable, celle-ci est affectée à un chiffre. Dans notre cas, c’est le chiffre 13.

 

Pour le code, ce n’est qu’un chiffre. Mais cela devient une broche de la carte Arduino, avec une ligne de code supplémentaire, qui est situé dans la partie setup du programme. Il s’agit de pinMode.

Cette instruction va associer notre variable LED à une pin, une broche de la carte Arduino. Et comme dans la déclaration celle-ci avait reçu le chiffre 13, cela indique au logiciel qu’il s’agit de la broche 13.

 

Le programme tient donc compte de tous les éléments qui le constitue pour interpréter les choses en fonction du contexte. Un peu comme nous.

Sources :


Rappel :


les images présentent appartiennent au Domaine public et sont l’œuvre de Peggy_Marco sur le site Pixabay : https://pixabay.com/fr/users/Peggy_Marco-1553824/   ou proviennent du projet Fritzing : http://fritzing.org/home/