Dans « La programmation, qu’est ce que c’est », nous avons vu un premier programme très simple permettant de faire clignoter une DEL. Comparé à de l’électronique classique, ce n’est pas vraiment un grand pas en avant. Si la force des micro-contrôleurs est justement de permettre de faire des choses beaucoup plus complexes que ce qui est faisable en électronique classique, cette complexité se traduit forcément par un programme plus élaboré. Une des briques de base est la capacité d’exécuter les instructions selon une condition.
Instructions conditionnelles : le if ... else
.
Par :
DIFFICULTÉ :★☆☆
Un premier exemple simple d’utilisation du if
Pour prendre un exemple concret, supposons que vous vouliez que l’Arduino signale sur une DEL la présence d’un train dans une gare cachée. Les constituants de ce système sont :
- bien évidemment un Arduino ;
- un capteur qui va donner une information de nature tout ou rien : le train est présent ou il ne l’est pas ;
- la DEL qui permet de signaler la présence du train.
Le capteur fournit la condition : le train est présent. La série d’instructions à exécuter correspond à on allume la DEL.
L’instruction permettant d’allumer la DEL si le train est présent est le if ... else
, « si ... sinon » en français. La syntaxe générale est la suivante :
if (condition) {
// instruction(s) exécutée(s) si la condition est vraie
}
else {
// instruction(s) exécutée(s) si la condition est fausse
}
Si il n’est pas nécessaire d’exécuter une série d’instruction si la condition est fausse, il suffit d’omettre la partie else
comme ceci :
if (condition) {
// instruction(s) exécutée(s) si la condition est vraie
}
Notez bien les paires d’accolades ouvrantes et fermantes qui délimitent les séries d’instructions. Notez également les parenthèses autour de la condition.
Pour revenir à notre système, supposons que le capteur soit connecté à la broche 2 de l’Arduino et qu’il fournisse HIGH
, c’est à dire 5V, si le train est présent et LOW
, c’est à dire 0V, si il n’est pas présent. La condition pour allumer la DEL est donc que le capteur fournisse HIGH
.
Pour commencer en respectant les bonnes pratiques, définissons la constante pinCapteur
et donnons lui la valeur 2.
const byte pinCapteur = 2;
Evidemment pour que tout cela puisse fonctionner il faut que la broche 2 soit programmée en entrée et que le programme lise la valeur fournie par le capteur. Nous avons déjà vu dans « La programmation, qu’est ce que c’est » comment programmer une broche en sortie pour allumer une DEL et comment écrire une valeur sur cette broche. Ici nous devons faire l’inverse. Pour programmer la broche 2 en entrée, la fonction pinMode(...)
est également employée mais son second argument doit être INPUT
, « entrée » au lieu de OUTPUT
. Ceci vient se loger dans setup()
:
void setup() {
pinMode(pinCapteur, INPUT);
}
Pour lire la valeur fournie par le capteur, nous allons utiliser la fonction digitalRead(...)
. L’unique argument de digitalRead(...)
est le numéro de broche. Jusqu’ici nous n’avons vu que des fonctions qui ne retournent aucune valeur, c’est à dire dont le type est void
. digitalRead(...)
retourne une valeur, un int
, qui est l’état de la broche, HIGH
ou LOW
[1].
Dans notre cas, la condition du if
est une simple comparaison, on veut comparer la valeur renvoyer par digitalRead(pinCapteur)
avec HIGH
. La condition est vraie si les deux sont identiques. Cette comparaison est effectuée avec l’opérateur ==
[2]. Ainsi :
digitalRead(pinCapteur) == HIGH
sera vrai si digitalRead(pinCapteur)
retourne HIGH
et faux si il retourne LOW
.
Sous le capot. On a parlé de vrai ou faux. Sur l’Arduino, deux constantes sont définies et disponible :true
(vrai) etfalse
(faux). Un typeboolean
[3] existe également. Toutefois, il s’agit en fait de nombres.false
vaut 0 ettrue
vaut 1. Une comparaison retourne donc un nombre, 0 ou 1
Vous savez déjà allumer une DEL, le programme complet est :
const byte pinCapteur = 2; // le capteur est connecté sur la broche 2
const byte pinDEL = 13; // on utilise la DEL de la carte sur la broche 13
void setup() {
pinMode(pinCapteur, INPUT); // on veut lire le capteur
pinMode(pinDEL, OUTPUT); // on veut piloter la DEL
}
void loop() {
if (digitalRead(pinCapteur) == HIGH) { // si un train est détecté
digitalWrite(pinDEL, HIGH); // allume la DEL
}
else { // sinon
digitalWrite(pinDEL, LOW); // éteint la DEL
}
}
Les if
imbriqués
le if
étant une instruction, il peut tout à fait être utilisé à l’intérieur d’un autre if
. Supposons que notre capteur ait des sautes d’humeur, de temps en temps il déraille et envoie de courtes impulsions de moins de 10ms comme si un train était présent alors que ce n’est pas le cas. Ce genre de problème arrive plus souvent qu’on ne croit.
Pour corriger ce problème, il suffit de lire une seconde fois le capteur après un délai de 10ms et si il renvoie à nouveau HIGH
alors il y a bien un train. sinon ce n’est pas le cas [4]. loop()
deviendrait donc :
void loop() {
if (digitalRead(pinCapteur) == HIGH) {
// si un train est détecté
// on attend 10 ms avant de vérifier que
// ce n'est pas une détection erronée
delay(10);
if (digitalRead(pinCapteur) == HIGH) {
// le train est toujours là, allume la DEL
digitalWrite(pinDEL, HIGH);
}
else {
// sinon, éteint la DEL
digitalWrite(pinDEL, LOW);
}
}
else {
// sinon, éteint la DEL
digitalWrite(pinDEL, LOW);
}
}
Les opérateurs de comparaison
Nous venons de voir l’égalité, l’opérateur ==
, il existe d’autres opérateurs de comparaison.
!=
est l’opérateur différent de. La comparaison est vraie si les deux opérandes sont différents. On peut par exemple écrire digitalRead(pinCapteur) != LOW
comme ceci :
if (digitalRead(pinCapteur) != LOW) { // le train est toujours là
digitalWrite(pinDEL, HIGH); // allume la DEL
}
else { // sinon
digitalWrite(pinDEL, LOW); // éteint la DEL
}
>
est l’opérateur supérieur à. La comparaison est vraie si le le premier opérande est plus grand que le second opérande.
>=
est l’opérateur supérieur ou égal à. La comparaison est vraie si le le premier opérande est plus grand que ou égal au second opérande.
<
est l’opérateur inférieur à. La comparaison est vraie si le le premier opérande est plus petit que le second opérande.
<=
est l’opérateur inférieur ou égal à. La comparaison est vraie si le le premier opérande est plus petit que ou égal au second opérande.
Les opérateurs logiques
On peut composer les comparaisons avec des opérateurs logiques. Par exemple, si nous avons maintenant deux capteurs, l’un branché sur pinCapteur1
et l’autre sur pinCapteur2
et que nous voulons allumer la DEL si les deux capteurs renvoient HIGH
tous les deux en même temps, nous écrirons :
if (digitalRead(pinCapteur1) == HIGH && digitalRead(pinCapteur2) == HIGH) {
digitalWrite(pinDEL, HIGH); // allume la DEL
}
else { // sinon
digitalWrite(pinDEL, LOW); // éteint la DEL
}
&&
est donc le et logique. La condition est vraie si les deux opérandes sont vrais. Dans tous les autres cas, la condition est fausse.
||
est le ou logique. La condition est vraie si l’un des deux ou les deux opérandes sont vrais. Lorsque les deux opérandes sont faux, la condition est fausse.
!
est l’opérateur de négation. Si son unique opérande est vrai, la condition est fausse et inversement. Par exemple, disposant de 3 capteurs branchés sur pinCapteur1
, pinCapteur2
et pinCapteur2
, on peut allumer si le premier et le deuxième sont HIGH ou si le troisième est LOW, on écrirait :
if ((digitalRead(pinCapteur1) == HIGH && digitalRead(pinCapteur2) == HIGH)
|| digitalRead(pinCapteur3) == LOW)
{
digitalWrite(pinDEL, HIGH); // allume la DEL
}
else { // sinon
digitalWrite(pinDEL, LOW); // éteint la DEL
}
Bien que dans les exemples nous nous soyons limités à la comparaison du résultat renvoyé par digitalRead(...)
à une constante, HIGH
ou LOW
, cela ne signifie pas que les opérateurs de comparaison et les opérateurs logiques se limitent à ça. Tout résultat de fonction, toute constante, toute variable, peuvent être employés à gauche ou à droite des opérateurs présentés.
Une comparaison retournant un nombre, 0 ou 1, les opérateurs logiques opèrent donc sur des nombres. En réalité, tout nombre différent de 0 est compris comme vrai et tout nombre égal à 0 est compris comme faux. Toutefois une bonne pratique consiste à ne pas trop mélanger les booléens avec les entiers et éviter de faire de l’arithmétique avec les opérateurs logiques.
Dans le prochain article, nous verrons une autre instruction conditionnelle : le switch
.
La suite de la série d’articles avec « Calculer avec l’Arduino (1) ». Si ce n’est pas déjà fait lisez également « La programmation, qu’est ce que c’est » et « Types, constantes et variables ».
[1] Sous le capot, LOW
vaut et HIGH
vaut 1
.
[2] et non =
tout seul qui est l’affectation, attention c’est une erreur fréquente.
[3] Nommé ainsi d’après George Boole, mathématicien anglais du 19e siècle, créateur de la logique moderne.
[4] Effectivement dans notre petit exemple, ça ne serait pas très grave de faire une fausse détection, on ne fait qu’allumer une DEL mais supposons maintenant que l’on manœuvre un aiguillage.