Arduino : Le cahier de programmation

De Wikidebrouillard.

Traduction par Lény Gonzalez et Antony Auffret du "Arduino Programming Notebook", écrit et compilé par Brian W. Evans

Ce cahier est une référence de programmation pratique, facile a utiliser pour la structure des programmes et les bases de la syntaxe du microcontroleur Arduino.

Pour le garder simple, certaines exclusions ont été faites pour faire de ce cahier une référence, pour les débutants. Il est très utile comme source complémentaire de d'autres sites web, livres, ateliers ou classes.

Cette décision a conduit à une sélection d'utilisations autonomes d'Arduino ce qui, par exemple, exclue les usages les plus complexes des tableaux ou des formes avancées de communication série.

Ce livre débute avec les structure de base du langage de programme Arduino dérivé du C. Il se poursuit en décrivant la syntaxe des éléments les plus commun, et illustre leurs utilisations avec des exemples et morceaux de programmes. Cela inclue plusieurs fonctions de la bibliothèque principale, suivie par un appendice avec des schémas et des débuts de programmes.

Sommaire

Structure

La structure de base du langage de programmation Arduino est assez simple et comprend au moins deux parties. Ces deux parties, ou fonctions, contiennent des blocs d'instructions.

void setup()
{
blocs d'instructions;
}

void loop()
{
blocs d'instructions;
}

Setup() est la préparation, l'initialisation du programme et loop est l'exécution du programme. Ces deux fonctions sont impérativement requises pour que le programme fonctionne.

La fonction setup() doit suivre la déclaration des variable au tout début du programme. Il s'agit de la première fonction à exécuter dans le programme. Elle est exécutée une seule fois et sert à établir le mode d'une broche (pinMode) ou à initialiser la communication série.

La fonction loop() suit immédiatement et comprend le code à exécuter en continue - lisant les capteurs en entrée et déclenchant les actionneurs en sortie, etc. Cette fonction est le noyau de tout programme Arduino et réalise l'essentiel du travail.

initialisation du programme : setup()

La fonction setup() n'est appelée qu'une fois au démarrage du programme. Utilisez-là pour initialiser le mode des broches ou fixer le débit de communication série. Il doit être dans tout les programmes même si il n'y a aucune instruction à jouer.

void setup()
{
pinMode(broche, OUTPUT); //met la "broche" comme sortie
}

Boucle du programme : loop()

Après avoir appelé la fonction void setup(), la fonction void loop() fait une boucle (loop en anglais) infinie permettant de contrôler la carte arduino, tant que le programme ne change pas.

void loop() 
{
digitalWrite(broche, HIGH);  //met la broche en "ON"
delay(1000);                        //pause pendant une seconde
digitalWrite(broche, LOW);   //met la broche en "OFF"
delay(1000);                        //pause pendant une seconde
}

Les fonctions : blocs de code particuliers

Une fonction est un bloc de code possédant un nom et exécutant ses instructions à chaque appel. Les fonctions void setup() et void loop() sont les 2 fonctions obligatoires en arduino, mais d'autres peuvent être créées.

Il est possible de créer des fonctions afin d'améliorer des programmes répétitifs et pour rendre plus compréhensif un programme. On commence par donner un type aux fonctions. Il s'agit du type de valeur qui sera renvoyée par la fonction, par exemple un "int" donnera une fonction de type entier (integer). Si aucune valeur n'est renvoyée, le type est void (void setup()/void loop() ). Après le type, on attribue un nom à la fonction puis, dans les parenthèses, on donne les paramètres passées à la fonction.

type nomFonction(paramètres)
{
instructions;
}

La fonction entière (int) suivante, delayVal(), va permettre de changer l'intervalle de la valeur lue sur le potentiomètre. On commence par déclarer une variable locale v, elle contient la valeur du potentiomètre, c'est à dire entre 0 et 1023. On divise cette valeur par 4 afin de passer à une valeur comprise entre 0 et 255 puis on renvoie cette valeur au programme.

int delayVal()
{
int v;      //création de la variable locale "v"
v = analogRead(pot);      //lecture de la valeur du potentiomètre
v /= 4;      //conversion de 0-1023 à 0-255
return v;      //renvoie de la valeur finale
}

Les accolades : {}

Les accolades (ouvrantes ou fermantes) définissent le début et la fin d'une fonction ou d'un bloc d'instructions, comme pour la fonction void loop() ou les instructions if et for.

type fonction()
{
instructions;
}

Une accolade ouvrante { est toujours suivie par une accolade fermante }. Une accolade non fermée donne des erreurs ou des programmes lors de la compilation mais peut être dure à corriger en cas de programmes très longs.

L'environnement arduino inclue un système de vérification des accolades. Il suffit de cliquer sur une accolade pour voir sa "paire" se sur-ligner.

Le point-virgule : ;

Le point-virgule est utilisé pour finir une instruction et séparer les éléments d'un programme. On l'utilise, par exemple, pour séparer les éléments de la boucle for.

int x = 13;     //on déclare la variable x comme un entier valant 13

Note : Oublier le point-virgule à la fin d'une ligne donne une erreur de compilation. Le message d'erreur peut parfois faire référence au point-virgule oublié, mais pas toujours. Si le message d'erreur est illogique et incompréhensible, une des premières choses à faire est de vérifier s'il n'y a pas un point-virgule manquant.

Les paragraphes de commentaire/*...*/

Un commentaire (sur une ligne ou sur plusieurs) est une zone de texte qui est ignoré par le programme lors de la compilation et qui est utilisé afin de décrire le code ou pour le commenter pour faciliter sa compréhension auprès de personnes tiers. Un commentaire commence par /* et fini avec */ et peut faire plusieurs ligne.

/*  ceci est un paragraphe de commentaire commencé
     ne pas oublier de le refermer
*/

De par le fait que les commentaires soient ignorés et qu'ils ne prennent pas d'espace mémoire, ils peuvent être utilisés généreusement, par exemple pour débuger une partie du code.

Note : Il est possible de faire un paragraphe d'une seule ligne avec /* */ mais on ne peut pas inclure un second bloc dans le premier.

Les lignes de commentaires : //

Une seule ligne de commentaire commence par // et fini à la fin de la ligne de code. Tout comme le paragraphe de commentaires, la ligne est ignorée lors de la compilation et ne prend pas de mémoire.

//ceci est une ligne de commentaires

La ligne de commentaire est souvent utilisée pour donner des informations ou pour rappeler quelque chose à propos d'une ligne.

Variables

Les variables

Une variable est une façon de nommer et de stocker une information/valer afin de l'utiliser plus tard dans le programme. Comme leur nom l'indique, une variable est une valeur qui peut être continuellement modifiée à l'opposé d'une constante qui ne change jamais de valeur. Une variable a besoin d'être déclarée et on peut lui assigner une valeur que l'on veut stocker, mais cela est optionnel. Le code suivant déclare une variable nommé inputVariable et lui assigne une valeur lue via analogRead sur la broche 2.

int inputVariable = 0;   //déclare la variable et lui assigne la valeur 0

inputVariable = analogRead(2);   //assigne la valeur de la broche analogique 2 à la variable

"inputVariable" est une variable. La première ligne donne le type de la valeur contenue : int (diminutif de integer, entier). La seconde ligne assigne la valeur de la broche analogique 2 à cette variable. Cela permet de rendre accessible dans le code la valeur de la broche analogique 2.

Une fois que la variable a été assignée ou ré-assignée, il est possible de la tester pour voir si elle remplie certaines conditions ou de l'utiliser directement. Afin d'illustrer 3 opérations habituelles sur les variables, le code suivant vérifie si inputVariable est plus petit que 100, si oui elle lui assigne la valeur 100 et le programme marque une pause de inputVariable millisecondes, au minimum 100 donc.

if (inputVariable < 100)     //on vérifie si la variable est plus petite que 100
{
   inputVariable = 100;      //si oui, on lui attribue la valeur 100
}
delay(inputVariable);        //on utilise la variable comme temps de pause (fonction delay() )

Note : Pour rendre le code plus lisible, on peut donner aux variable un nom explicatif. Les noms de variables tels que boutonAppuie (pushButton) ou mouvementCapteur (tiltSensor) aident le programmateur ainsi que les personnes lisant le code afin de savoir ce que représentent les variables. Les noms de variables tels que var (pour variable) ou valeur (value) ne rendent pas vraiment le code plus lisible et ne sont utilisés que dans les exemples. Une variable peut avoir n'importe quel mot comme nom tant que celui-ci n'est pas un mot clé du langage arduino.

La déclaration des variables

Toutes les variables doivent être déclarées avant d'être utilisées. La déclaration d'une variable définie son type, tel que int, long, float, ... lui attribue un nom spécifique et peut lui assigner une valeur initiale. Cela ne doit être fait qu'une seule dans le programme, mais on peut modifier la valeur tout au long du programme par des assignations ou des opérations arithmétiques.

L'exemple suivant déclare inputVariable comme un int, ou type entier (integer) et lui assigne 0 comme valeur initiale. C'est ce qu'on appelle une simple assignation.

int inputVariable = 0;

Une variable peut être déclarée à de nombreux endroits dans le programme, l'emplacement de sa déclaration détermine quelles parties du programme auront accès à cette variable.

Visibilité des variables pour le programme

Une variable peut être déclarée au début du programme avant l'initialisation (Void setup() ), à l'intérieur de fonctions et parfois au sein d'un bloc d'instruction comme les boucles. La zone où la variable est déclarée détermine la "visibilité" de celle-ci, autrement dit la possibilité pour certaines parties d'un programme à utiliser cette variable.

Une variable globale est une variable qui peut être vue et utilisée par l'ensemble du programme. Cette variable doit être déclarée au début du programme, avant la fonction void setup().

Une variable locale est une variable définie à l'intérieur d'une fonction ou dans une partie d'une boucle for. Elle est uniquement visible et utilisable à l'intérieur de la fonction où elle a été déclarée. Il est de ce fait possible d'avoir 2 variables ou plus ayant le même nom dans différentes parties du programme avec des valeurs différentes. Permettre à une seule fonction d'avoir accès à ses variables permet de réduire les erreurs potentielles de programmation.

L'exemple suivant montre comment déclarer les différents types de variables et expliquent leur visibilité :

int value;           //"value" est visible par toutes les fonctions

void setup()
{
   //no setup needed
}

void loop()
{
  for (int i=0 ; i<20 ;)   //"i" est uniquement visible à l'intérieur de la boucle for
  {
     i++;
  }
  float f;   //"f" est uniquement visible dans la fonction void loop()
}

type de données

byte

Byte permet de stocker une valeur entière sur 8 bits (pas de chiffre à virgule donc). Cela permet d'aller de 0 à 255.

byte someVariable = 180;    //déclare "someVariable" en tant que byte

int

Int (pour integers, entier) est le type de base pour les chiffres (sans virgule) des variables. Le stockage se fait sur 16 bits, permettant d'aller de 32 767 à - 32 768.

int someVariable = 1500;  //déclare "someVariable" en tant que int

Note : Si la valeur maximale ou minimale est passée pour le type int, sa valeur sera reportée. C'est à dire, si x = 32767 et que l'on y ajoute 1, x = x + 1 ou x ++, x vaudra alors - 32768.

long

Il s'agit d'un type de variable de grande taille : la donnée (chiffre sans virgule) est stockée sur 32 bits. Cela permet d'aller de 2 147 483 647 à - 2 147 483 648.

long someVariable = 90000;   //déclare "someVariable" en tant que long

float

Ce type permet de stocker les chiffre "flottant" ou chiffre à virgule. Les float bénéfice d'une meilleure résolution que les entiers (int) : ils sont stockés sur 32 bits, soit de 3,4028235^38 à - 3,4028235^38.

float someVariable = 3,14;   //déclare "someVariable" en tant que chiffre flottant

Note : Les chiffres flottants ne sont pas exacts et il arrive que des résultats étranges ressortent de leur comparaison. De plus, réaliser des opérations mathématiques dessus est plus lents que sur des entiers, il est conseillé d'éviter si possible.

bool

Le type bool prend 2 valeurs : Vrai (true) ou Faux (false). Il est stocké sur 8 bits et se comporte ainsi :

  • si la valeur est 0, il sera vu comme Faux
  • si la valeur est 1 ou plus, il sera vu comme Vrai
bool someVariable = false;  //la valeur est 0 donc false (faux)

char

Le type char est utilisé pour stocker une lettre. Le stockage se fait sur 8 bits et permet de stocker une seule lettre.

char someVariable = 'A';    //déclare someVariable en tant que lettre

Note : Pour assigner une valeur à la variable char, on l'écrira entre '.

unsigned

Il ne s'agit pas d'un type de variable à proprement dit mais d'un ajout permettant de supprimer les chiffres négatifs (on ne garde que les chiffres non-signés, les positifs). Cela permet d'avoir plus de place pour stocker les chiffres positifs. Par exemple :

  • au lieu d'aller de 32 767 à - 32 768, un int couvrira l'intervalle de 0 à 65 535
  • au lieu d'aller de 2 147 483 647 à - 2 147 483 648, un long couvrira l'intervalle de 0 à 4 294 967 295
  • ...
unsigned int someVariable = 65534;  //la variable est un entier non-signé valant 65534

arrays

Un tableau est une collection de valeur dont on accède via un index. Afin d'avoir accès aux valeur contenues dans le tableau, il faut appeler le nom du tableau et le numéro d'index de la valeur. Les tableaux possèdent l'index 0 : il s'agit de la première valeur stockée. Un tableau, comme une variable, a besoin d'être déclaré mais l'assignation est facultative avant son utilisation.

int monTableau[] = {valeur0, valeur1, valeur2, ... };

Il est également possible de déclarer le tableau uniquement en lui donnant un type et une taille et d'assigner plus tard des valeurs aux index.

int monTableau[5];      //déclaration d'un tableau d'entier avec 6 cases
monTableau[3] = 10;    //on assigne à la 4e case la valeur 10

Pour sortir une valeur d'un tableau, on assigne à une case du tableau une variable :

x = monTableau[3];     //x vaut maintenant 10

Les tableaux sont souvent utilisés dans la boucle for, où le compteur est utilisé pour choisir la case du tableau et atteindre la valeur. L'exemple suivant utilise un tableau pour modifier l'éclairage d'une LED. Le compteur, dans la boucle for, commence à 0, écrit la valeur contenu dans la case 0 du tableau eclairage[], c'est à dire 180, à la broche 10. Puis marque une pause de 200ms et continue à la case suivante.

int brocheLED = 10;      //la LED est sur la broche 10
byte eclairage[] = {180, 30, 255, 200, 10, 90, 150, 60};
               //tableau avec 8 cases contenant des valeurs différentes

void setup()
{
  pinMode(brocheLED,OUTPUT);
}

void loop ()
{
  for(int i=0;i<7;i++)   //chaque valeur du tableau
  {                      //est envoyée à la broche où
    analogWrite(brocheLED, eclairage[i]); //est reliée la LED
    delay(200);          //avant de faire une pause de 200 millisecondes
  }          
}

String

Il ne s'agit pas exactement d'un type de variable, il s'agit d'une classe. La classe String est comparable a une variable possédant ses propres fonctions. String permet de stocker une chaîne de caractères, comme pourrait le faire un tableau de caractère.

String someVariable = "Aux sciences, citoyens";    //someVariable contient la chaîne de caractères

String permet de réaliser des opérations sur les chaînes de caractères plus complexes que ce qui se ferait sur un tableau de caractères. Dans l'exemple qui suit, on va passer un nombre en String, compter le nombre de caractère qui le compose et réaliser la comparaison avec un second String.

String chaineDeNombre = String(245);  //chaineDeNombre contient "245"

int nombreCaractère = chaineDeNombre.length();   //nombreCaractère vaut 3

int compare = someVariable.compareTo(chaineDeNombre);
                //compare vaudra :
                //un nombre négatif si someVariable vient avant chaineDeNombre
                //0 si someVariable et chaineDeNombre sont égaux
                //un nombre positif si someVariable vient après chaineDeNombre

Quand on parle de "venir avant", cela est lié à la place de chaque caractère en informatique : les chiffres viennent avant les lettres et les majuscules avant les minuscules.

Note : Les String fonctionnent en allocation dynamique de mémoire : la taille maximale n'est pas définie à la création, il faut donc faire attention à ne pas dépasser la taille maximum de mémoire autorisé par une carte/par une machine.

arithmétique

L'arithmétique

Les opérations d'arithmétique incluent les additions, les soustractions, les multiplications et les divisions. Elles retournent respectivement la somme, la différence, le produit et le quotient des 2 opérants.

y = y + 3;
x = x - 7;
r = r / 5;
i = j * 6;

L'opération est réalisée en utilisant les types de données des opérants, de façon à ce que, par exemple, 9 / 4 donnera 2 plutôt que 2,25 car 9 et 4 sont des entiers (int), or le type "int" ne peut être un chiffre à virgule. Cela veut aussi dire que le résultat peut être trop grand pour le type de variable initiale.

Si les opérants sont de différents types, le type le plus grand est utilisé pour le calcul. Par exemple, si un des nombres (opérant) est de type "float" et l'autre de type "int", c'est le type "float" qui sera utilisé lors de l'opération.

Il faut donc faire bien attention lors du choix des types de variables afin que le résultat ne soit pas trop grand lors du calcul. Il faut donc savoir jusqu'à combien (aussi bien dans les positifs que dans les négatifs) la variable peut aller, par exemple 0 ou 1 ou de 0 à - 32768. Pour réaliser des opérations sur des fractions, on utilisera des "float", l'inconvénient étant que des grandes variables entrainent des calculs lents.

Note : Pour passer d'un type de variable à un autre, on utilisera l'opérateur de cast, c'est à dire (int)monFloat convertira monFloat en int. Par exemple :

i = (int)3,6

fixera i à la valeur 3.

Opérateurs d'incrémentation

Les opérateurs d'incrémentation permettent de réaliser une opération simple, ils sont communément utilisés dans la boucle for, voir plus bas. Il en existe 2 : l'incrémentation et la décrémentation.

x ++    //équivaut à x = x + 1 ou d'incrémenter x par 1
x --     //équivaut  à x = x - 1 ou de décrémenter x par 1

Opérateurs d'assignation

Les opérateurs d'assignations sont la combinaison entre une assignation et une opération, de la même sorte que les opérateurs d'incrémentation.

x += y  //équivaut à x = x + y ou d'incrémenter x par y
x -= y   //équivaut à x = x - y ou de décrémenter x par y
x *= y   //équivaut à x = x * y ou de multiplier x par y
x /= y   //équivaut à x = x / y ou de diviser x par y

Note : Par exemple, x *= 3 va multiplier l'ancienne valeur de x par 3 et ré-assigner la nouvelle valeur à x.

Opérateur de comparaison

La comparaison d'une variable ou d'une constante avec une autre est souvent utilisée afin de tester si une condition spécifique est vraie ou non. Dans les exemples suivants, l'opérateur est utilisé pour indiqué une condition :

x == y  //x est égal à y
x != y   //x n'est pas égal à y
x < y   //x est plus petit que y
x > y   //x est plus grand que y
x <= y //x est plus petit ou égal à y
x >= y //x est plus grand ou égal à y

Opérateurs logiques

Les opérateurs logiques sont utilisés pour comparer deux expressions/conditions. Ils renvoient TRUE (vrai) ou FALSE (faux) selon l'opération. Il y a trois opérateurs logiques : AND (et), OR (ou) et NOT (contraire), ils sont souvent utilisés dans les if (voir plus bas) :

AND :

if (x > 0 && x < 5)    //vrai seulement si les deux conditions sont vraies

OR :

if (x > 0 || y > 0)    //vrai si une des condition est vraie

NOT :

if (!x > 0)    //vrai seulement si la condition est fausse

Constantes

Les constantes

Le langage arduino possède des valeurs prédéfinies; elles sont appelée constantes. Elles sont utilisées pour rendre un programme plus simple à lire. Il en existe différent groupe.

Vrai/faux (true/false)

Il s'agit de variable du type booléen. FALSE signifie que la constante est à 0 alors que TRUE désigne l'état différent de 0 : cela peut être 1 (par convention) mais cela peut aussi être -1, 2, -200, ...

if (b == TRUE)
{
   doSomething;
}

Haut/bas (high/low)

Il s'agit des constantes utilisées pour lire ou pour écrire sur les broches, soit le niveau HIGH (ON, 1, 5 volts) soit le niveau LOW (OFF, 0, 0 volts).

digitalWrite(13,HIGH);

Entrée/sortie (input/output)

Ces constantes sont utilisées avec la fonction pinMode(), elles définissent le type de broche digitale :

  • INPUT pour entrée
  • OUTPUT pour sortie
pinMode(13, OUTPUT);

Structures de contrôle

if

La structure de test "if" (si) vérifie si une certaine condition est atteinte, par exemple si une valeur est égale à un certain nombre, et exécute des instructions contenu dans la structure. Si la condition est fausse, le programme quitte la structure et reprend à la ligne suivante. Le format du if est :

if (someVariable ?? valeur)
{
   doSomething;
}

L'exemple précédent compare someVariable avec une autre valeur pouvant être une variable ou une constante. Si la comparaison, ou la condition entre parenthèse est vraie, les instructions entre les accolades sont exécutées. Sinon, le programme quitte la structure et continue après l'accolade fermante.

Note : Attention à l'utilisation du "=" tel que
if( x = 10 )
, qui est grammaticalement valide, cela assigne la valeur 10 à la variable x et le résultat est toujours vraie. Cependant, il faut utiliser "==" tel que
if( x == 10 )
afin de tester si x est égal à 10. Moyen mémo-technique : "=" est "égale" alors que "==" est "est-il égale à".

if... else

if... else (si...sinon) est utilisé pour dire "sinon fait...". Par exemple, si on veut tester une entrée digitale et faire ne action si elle vaut HIGH et d'autres actions si elle vaut LOW, on écrira :

if (inputPin == HIGH)
{
   doThingA;
}
else
{
   doThingB;
}

else peut précéder un autre test avec un "if", on peut ainsi en mettre une multitude qui seront exécutés les uns après les autres. Il est aussi possible d'avoir un nombre infini de branche "else". Cependant, il faut garder à l'esprit qu'une seule partie des instructions sera exécutée, selon les conditions vérifiées.

if (inputPin < 500)
{
  doThingA;
}
else if (inputPin >= 1000)
{
  doThingB;
}
else
{
  doThingC;
}

Note : Un "if" test si la condition entre parenthèse est vraie ou fausse. Ainsi, le premier exemple ne vérifiera que si la variable vaut HIGH (ou +5V) mais pas il n'est pas possible d'avoir un autre état différent de vrai ou faux.

switch... case

La structure switch... case (commutateur de cas) permet de dresser une lister de test ou de cas (comme le "if") et d'exécuté le code correspondant si un des cas du test est vrai. La principale différence entre le switch... case et le if... else est que le switch... case permet de continuer les tests même si un des cas est vrai, contrairement au if...else qui quittera dans le même cas.

switch (someVariable) 
{
  case A : doSomething;
  case B : doOtherSomething;
}

someVariable sera comparée à A, si le test est vrai, doSomething sera exécuté. Une fois le code exécuté (ou si le test est faux), "someVariable" sera comparé à B et ainsi de suite. Dans le cas où on voudrait s'arrêter à un des cas, on ajoutera l'instruction break;. De plus, si aucun des cas n'est vérifié, on peut ajouter le cas default qui sera exécuté si aucun test n'est vrai.

switch (someVariable)
{
  case A : doSomethingA;      //si someVariable vaut A, doSomethingA est exécuté
               break;          //une fois le code exécuté, on sort de la structure
  case B : doSomethingB;     //en l'absence de "break", si someVariable est égale à B puis à C
  case C: doSomethingC;     //doSomethingB et doSomethingC seront exécutés

 default : doSomethingByDefault  //dans le cas où aucun cas ne serait vérifié, 
                                   //doSomethingByDefault sera exécuté puis on sortira de la structure
}

Note : Il n'est pas nécessaire que les cas soit dans l'ordre chronologique ou du plus petit au plus grand.

for

La structure for (pour) est utilisée afin de répéter une série d'instructions (comprise entre les accolades) le nombre de fois voulu. Un compteur à incrémenter est souvent utilisé afin de sortir de la boucle une fois le nombre de tour fait. Cette structure est composée de trois parties séparées par un point-virgule (;) dans l'entête de la boucle :

for (initialisation; condition; expression d'incrémentation)
{
  doSomething;
}

L'initialisation d'une variable locale, ou compteur d'incrémentation, permet d'avoir une variable ne servant qu'une fois dans le programme. A chaque tour de boucle, la condition de l'entête est testée. Si cette condition est vraie, doSomething est exécuté ainsi que l'expression d'incrémentation et la condition est de nouveau testée. Quand la condition devient fausse, la boucle prend fin.

L'exemple suivant commande avec un entier i à 0, on vérifie s'il est inférieur à 20 et si c'est vrai, on l'incrémente de 1 et on exécute le programme contenu dans les accolades :

for (int i = 0; i<20; i++)
{
  digitalWrite(13, HIGH);
  delay(250);
  digitalWrite(13,LOW);
  delay(250);
}

Note : Dans le langage C (d'où découle arduino), la boucle for est beaucoup plus flexible que dans les autres langages (par exemple le Basic). Certains (voire tous) éléments parmi les 3 de l'entête peuvent être oublié, seuls les points-virgules sont indispensables. Chacune des expressions (initialiation, condition et incrémentation) peut être une expression en C avec des variables différentes. Ce genre de cas rares peut être la solution pour certains problèmes de programmations également rares.

while

La boucle "while" (tant que) continuera infiniment tant que l'expression entre parenthèse est vraie. Quelque chose doit changer afin de modifier la condition sinon le programme ne sortira jamais de la boucle while. Cela peut être dans le code, comme l'incrémentation d'une variable, ou une condition extérieur, comme le test d'un capteur.

while (someVariable ?? valeur)
{
  doSomething;
}

L'exemple suivant test si "someVariable" est inférieur à 200 et si c'est vrai, le code entre les accolades est exécuté et la boucle continue tant que "someVariable" est inférieur à 200.

while (someVariable < 200)    //test si "someVariable" est inférieur à 200
{
  doSomething;            //exécution du code
  someVariable++       //incrémentation de "someVariable" par 1
}

do... while

La boucle do... while (faire... tant que) fonctionne de la même façon que la boucle while, à la seule exception que la condition est testée à la fin de la boucle, de ce fait le code dans la boucle s'exécute toujours au moins une fois.

do
{
  doSomething;
} while (someVariable ?? valeur);

L'exemple suivant assigne à la variable "x" la valeur lireCapteur() (readSensors() ), puis fait une pause de 50 milli-secondes et continue infiniment tant que x est plus petit que 100.

do
{
  x = lireCapteur();    //assignation de la valeur de lireCapteur à x
  delay(50);               //pause durant 50 milli-secondes
} while (x < 100);     //on recommence la boucle si x est inférieur à 100

Entrées et Sorties numériques (digital i/o)

pinMode(pin, mode)

Utilisée dans le void setup(), cette fonction permet de configurer une broche soit en entrée (INPUT) soit en sortie (OUTPUT).

pinMode(broche, OUTPUT);  //fixe la broche en sortie

Les broches digital d'arduino sont par défaut configurées en entrée, il n'est pas nécessaire de les déclarer explicitement comme telle avec pinMode(). Les broches configurées en entrée, sont dans un état de haute impédance.

Il y a également une résistance pullup de 20kΩ installée à l'intérieur de l'Atmega (puce programmable de la carte arduino) accessible depuis le software (le programme). Pour y accéder, on utilisera :

pinMode(broche, INPUT);       //fie la broche en entrée
digitalWrite(broche, HIGH);    //active la résistance pullup

Les résistances pullup sont normalement utilisées pour connecter ensembles des entrées, comme un commutateur. A noter qu'il ne faut pas convertir la broche en sortie, car il s'agit de la méthode pour activer la résistance pullup interne.

Les broches configurées en sortie sont en état de basse impédance et fournissent du 40 mA (milliAmpère) aux autres circuits/dispositifs. C'est assez pour faire briller fort une LED (ne pas oublier les résistances en série) mais c'est insuffisant pour les relais, solénoïdes ou les moteurs.

Les petits circuits sur les broches d'arduino et les courant extrêmes peuvent endommager voire détruire les broches de sorties ou la puce Atmega entière. C'est pour cela que l'on ajoute souvent aux sorties des résistances en série (principalement 470Ω ou 1kΩ) entre elles et les composants externes.

digitalRead(pin)

Cette fonction permet de lire la valeur à la broche digitale indiquée. La valeur lue étant soit HIGH soit LOW. La broche ciblée ne peut être qu'une variable ou une constante comprise entre 0 et 13 (pour les arduino uno).

valeur = digitalRead(broche);   //assigne à "valeur" la valeur lue à la broche

digitalWrite(pin, value)

Il s'agit du contraire de digitalRead() : cette fonction permet de fixer une sortie digitale soit au niveau HIGH soit au niveau LOW. Cette sortie est comprise entre 0 et 13 sur arduino uno et doit être spécifiée soit par une variable soit par une constante.

digitalWrite(broche, HIGH)   //fixe la sortie "broche" à HIGH

L'exemple suivant va lire la valeur sur une broche digitale à laquelle est reliée un bouton. Lors de l'appuie sur le bouton, la valeur renvoyée sera HIGH alors qu'au repos ça sera LOW. Ainsi, il suffira d'affecter cette valeur à une LED afin de l'allumer quand le bouton est appuyée :

int led = 13;   //la led est reliée à la broche 13
int broche = 7;  //le bouton est reliée à la broche 7
int valeur = 0;   //la variable où ça sera stockée la valeur lue

void setup()
{
  pinMode(led, OUTPUT);    //la broche 13 est une sortie
  pinMode(pin, INPUT);   //la broche 7 est une entrée
}

void loop()
{
  valeur = digitalRead(broche);  //assignation de la valeur lue à la variable "valeur"

  digitalWrite(led, valeur);  //on fixe à la LED la même valeur qu'au bouton
}

Entrées et Sorties analogiques (analog i/o)

analogRead(pin)

Cette fonction permet d'aller lire la valeur sur une sortie analogique avec 10 bits de résolution. Elle ne fonctionne que sur les broches analogiques (0-5) et renvoie un résultat compris entre 0 et 1023.

valeur = analogRead(broche);   //assigne à "valeur" ce qui est lue sur la broche

Note : Les broches analogiques ne sont pas des broches digitales, elle ne nécessite pas d'être déclarée comme des sorties ou des entrées.

analogWrite(pin, value)

analogWrite permet d'envoyer un pseudo-signal analogique en utilisant le matériel via les broches possédant un "pulse width modulation" (PWM ou modulation de largeur d'impulsions). Sur les arduino les plus récents (équipé du contrôleur ATmega168), cette fonctionnalité se trouve sur les broches 3, 5, 6, 9, 10 et 11. Sur les plus anciennes (ATmega8), seules les broches 9, 10 et 11 étaient équipées. Ce signal est envoyé sous forme de valeur, comprise entre 0 et 255.

analogWrite(broche, valeur);  //envoie "valeur" sur la "broche" analogique

La valeur 0 va générer un courant stable de 0 volts en sortie; la valeur 255 générera un courant stable de 5 volts en sortie. Pour les valeurs comprises entre 0 et 255, la broche va rapidement alterner entre 0 et 5 vots - c'est à dire la plus grande valeur possible, celle correspondant au HIGH. Par exemple, pour une valeur de 64, sera en fait composé de 0 volts durant les trois quarts du temps et de 5 volts pendant le quart restant. De même pour 128, la moitié du temps la valeur sera 0 volts et l'autre moitié à 5 volts. Et pour une valeur de 192, pendant un quart du temps, la valeur sera à 0 volts et pendant les trois quarts restant à 5 volts.

Etant donné que l'on utilise le matériel, le signal généré par une fonction analogWrite ne s'arrêtera que si on appelle une seconde fois analogWrite (ou digitalRead ou digitalWrite sur la même broche), autrement le signal restera en fond.

Note : Les broches analogiques ne doivent pas être déclarées comme des broches digitales : on ne les déclare ni en sortie ni en entrée.

L'exemple suivant lit la valeur analogique sur une entrée analogique, divise la valeur par 4 et génère un signal PWM en sortie sur une broche PWM :

int led = 10;   //LED branchée à une résistance 220Ω sur la broche 10
int broche = 0;   //broche 0 où est reliée un potentiomètre
int valeur;   //variable où sera stockée la valeur lue sur le potentiomètre

void setup() {}   //pas de paramètre ici

void loop()
{
  valeur : analogRead(broche);   //on assigne à "valeur" le résultat lu sur "broche"
  valeur /= 4;    conversion de 0-1023 à 0-255
   analogWrite(led, valeur);    //envoi du signal en sortie PWM sur la broche "led"
}

Gestion de la durée

delay(ms)

delay permet de marquer une pause dans le programme, le temps est en milli-secondes (1000 ms donnant 1 seconde).

delay(1000);   //pause d'une seconde

millis()

Cette fonction renvoie le nombre de milli-secondes écoulé depuis que l'arduino a commencé à exécuté le programme actuel sous l'état d'un unsigned long.

valeur = millis();  //assigne à "valeur" le nombre de milli-secondes écoulé

Note : Le nombre est remis à 0 (par dépassement de tailles de variables) au bout d'environ 9 heures.

math

min(x,y)

Calcule le plus nombre le plus petit entre x et y, quelque soit le type de variable utilisé et le renvoie.

valeur = min(valeur,100);   //assigne le nombre le plus petit entre "valeur" et 100 à la place
                        //de la valeur de départ contenu dans "valeur"

max(x,y)

Calcule le plus nombre le plus grand entre x et y, quelque soit le type de variable utilisé et le renvoie.

valeur = max(valeur,100);   //assigne le nombre le plus grand entre "valeur" et 100 à la place
                        //de la valeur de départ contenu dans "valeur"

hasard

randomSeed(seed)

Cette fonction permet de fixer un point de départ comme base/graine pour la fonction random().

randomSeed(valeur);  //affecte "valeur" comme base de l'aléatoire

La carte arduino est incapable de créer un vrai nombre aléatoire c'est pourquoi la fonction randomSeed() permet d'aider à la génération d'un nombre aléatoire via une variable, une constante ou une fonction servant de base. Il y a différent type de bases de fonctions pouvant servir de bases telles que millis() ou analogRead() permettant de lire le bruit statique sur la broche analogique.

random(min, max)

La fonction random() renvoie un nombre pseudo-aléatoire dans un intervalle défini par un minimum et un maximum.

valeur = random(100,200);   //affecte à "valeur" une valeur aléatoire entre 100 et 200

Note : La fonction random() est a utilisée après randomSeed().

L'exemple suivant créé un nombre entre 0 et 255 et l'envoi ensuite sur une sortie PWM :

int nbrAleatoire;    //variable pour stocker une valeur aléatoire
int led = 10;   //LED branchée à une résistance 220Ω sur la broche 10

void setup() {}    //pas de paramètre nécessaire

void loop()
{
  randomSeed(millis());    //affecte millis() comme base
  nbrAleatoire = random(255);     //génération d'un nombre aléatoire entre 0 et 255
  analogWrite(led, nbrAleatoire);    //envoi du signal sur une broche PWM
  delay(500);     //on marque une pause d'une demi-seconde
}

Communication avec le port série

serial.begin(débit)

Permet le port série et donne la vitesse de transmission (ou débit, en bits par seconde ou bauds). La vitesse usuelle est de 9600 bauds avec les ordinateurs mais d'autres vitesses sont supportées.

void setup()
{
  Serial.begin(9600);    //Ouvre le port série et fixe le débit à 9600 bauds
}

Note : Lorsque la liaison série est utilisée, les broches digitales 0 (RX) et 1 (TX) ne peuvent être utilisées en même temps.

serial.println(donnée)

Permet d'envoyer des données sur le port série et d'automatiquement retourner à la ligne ensuite. La commande Serial.print() fonctionne de la même façon mais sans le retour à la ligne, pouvant être moins facile à lire via le moniteur série.

Serial.println(analogValeur);    //envoi la valeur contenue dans "analogValeur"

Note : Pour davantage d'informations sur la différentre entre Serial.println() et Serial.print, vous référez au site Arduino.

L'exemple suivant permet de lire les valeurs sur la broche analogique 0 et l'envoi vers l'ordinateur à chaque seconde.

void setup()
{
  Serial.begin(9600);     //affecte le débit à 9600 bauds
}

void loop()
{
  Serial.println(analogRead(0));     //envoi la valeur analogique
  delay(1000);       //marque une pause d'une seconde
}

appendice

sortie numérique

Image:LED_resistance.png

Il s'agit du programme de base : le "hello world" permettant d'activer et de désactiver quelque chose. Dans cette exemple, une LED est connectée sur la broche 13 et elle clignote à chaque seconde. La résistance peut être omis sur cette broche, depuis qu'arduino en possé une.

int brocheLED = 13;       //LED sur la broche 13

void setup()      //ne sera exécuté qu'une seule fois
{
  pinMode(brocheLED, OUTPUT);    //affecte la sortie 13 comme une sortie
}

void loop()      //sera exécuté encore et encore
{
  digitalWrite(brocheLED, HIGH);    //allume la LED
  delay(1000);    //pause d'une seconde
  digitalWrite(brocheLED, LOW);    //éteint la LED
  delay(1000);    //pause d'une seconde
}

Entrée numérique

Image:Entrée_numérique.png

Il s'agit de la plus simple forme d'entrée avec uniquement 2 état : ON ou OFF. Cette exemple permet de lire un simple changement d'état ou un appuie sur un bouton relié à la broche 2. Quand le circuit est fermé (c'est à dire le bouton appuyé), la broche lit HIGH et allume la LED.

int brocheLED = 13;     //broche où est reliée la LED
int brocheEntree = 2;    //broche d'entrée (pour un bouton par exemple)

void setup()
{
  pinMode(brocheLED, OUTPUT);   //déclare la broche LED comme une sortie
  pinMode(brocheEntree,INPUT);    //déclare la broche 2 comme une entrée
}

void loop()
{
  if (digitalRead(brocheEntree) == HIGH)  //vérification si l'entrée est en HIGH (état haut)
  {
     digitalWrite(brocheLED,HIGH);   //allume la LED
     delay(1000);    //pause d'une seconde
     digitalWrite(brocheLED, LOW);    //éteint la LED
     delay(1000);    //pause d'une seconde
   }      //fermeture du if()
}    //fermeture du loop()

Courant de sortie haut

Image:Courant_de_sortie_haut.png

Il est parfois nécessaire de contrôler plus de 40mA via une arduino. Dans ce cas, un MOSFET ou transistor peut être utilisé pour les contrôler. L'exemple suivant permet de changer un transistor entre marche et arrêt cinq fois par seconde.

Note : Le schéma montre un moteur et une diode de protection mais un autre système non-inductif peut être utilisé à la place de la diode.

int brocheSortie = 5;     //sortie vers le transistor

void setup()
{
  pinMode(brocheSortie,OUTPUT);   //affecte la broche 5 en sortie
}

void loop()
{
  for (int i=0; i<=5; i++)   //on fait 5 tours de boucles
  {
     digitalWrite(brocheSortie, HIGH);   //met le transistor en ON
     delay(250);    //pause d'un quart de seconde
     digitalWrite(brocheSortie, LOW);    //met le transistor en OFF
     delay(250);    //pause d'un quart de seconde
   }
   delay(1000);    //pause d'une seconde
}

Sortie pwm(Pulse Width Modulation - modulation de largeur d'impulsions)

Image:Sortie_pwm.png

Arduino permet de synthétiser un signal analogique grâce à la modulation de largeur d'impulsions(Pulse Width Modulation ou PWM). On peut utiliser ce système pour faire varier la luminosité d'une LED ou pour contrôler un servomoteur. L'exemple suivant modifie lentement la luminosité d'une LED via des boucles.

int brocheLED = 9;    //broche PWM où est reliée la LED

void setup() {}     //pas de paramètre nécessaire

void loop() 
{
   for (int i=0; i<=255; i++)    //on augmente la valeur de i à chaque tour
   {
       analogWrite(brocheLED, i);   //fixe la luminosité à la valeur de i
       delay(100);      //pause de 100ms
   }
   for (int i=255; i>=0; i--)     //on diminue la valeur de i à chaque tour
   {
       analogWrite(brocheLED, i);    //fixe la luminosité à la valeur de i
       delay(100);      //pause de 100ms
   }
}

Entrée potentiomètre

Image:Entrée_potentiomètre.png

Si on relie à une broche analogique (analog-to-digital conversion ou ADC) de la carte arduino un potentiomètre, il est possible de lire la valeur analogique sur l'intervalle à-1024. L'exemple suivant utilise un potentiomètre pour contrôler à quel rythme la LED clignote.

int brochePot = 0;    //broche d'entrée reliée au potentiomètre
int brocheLED = 13;   //broche de sortie pour la LED

void setup()
{
   pinMode(brocheLED, OUTPUT);    //déclare brocheLED en sortie
}

void loop()
{
   digitalWrite(brocheLED, HIGH);     //allume la LED
   delay(analogRead(brochePot));     //fait une pause
   digitalWrite(brocheLED, LOW);      //éteint la LED
   delay(analogRead(brochePot));     //fait une pause
}

Entrée résistance variable

Image:Entrée_résistance_variable.png

Les résistances variables incluses les photorésistances, les thermorésistances, les capteurs de flexions, et bien d'autres. L'exemple suivant utilise une fonction pour lire la valeur analogique et l'affecter au temps de pauses, permettant ainsi de contrôler la vitesse de clignotement de la LED.

int brocheLED = 9;     //broche PWM reliée à la LED
int brocheAnalogique = 0;    //résistance variable reliée à la broche analogique 0

void setup() {}    //pas de paramètre nécessaire

void loop()
{
   for (int i=0; i<=255; i++)    //on augmente la valeur de i à chaque tour
   {
       analogWrite(brocheLED, i);   //fixe la luminosité à la valeur de i
       delay(pause());    //Marque une pause selon la valeur renvoyée par la fonction pause()
   }
   for (int i=255; i>=0; i--)     //on diminue la valeur de i à chaque tour
   {
       analogWrite(brocheLED, i);   //fixe la luminosité à la valeur de i
       delay(pause());    //Marque une pause selon la valeur renvoyée par la fonction pause()
   }
}

int pause()
{
   int v;     //créé une variable temporaire
   v = analogRead(brocheAnalogique);    //lecture de la valeur analogique
   v /= 8;     //convertie la valeur comprise entre 0 et 1024 en une valeur entre 0 et 128
   return v;    //renvoi la valeur finale
}

Sortie Servo-moteur

Image:Sortie_Servo-moteur.png

Les servomoteurs Hobby sont un type de moteur indépendant pouvant tourner à 180°. Ils nécessitent une pulsation envoyée toute les 20ms. L'exemple suivant utilise la fonction pulsationServo pour faire avancer le servomoteur de 10° à 170° puis revenir en arrière.

int brocheServo = 2;      //servomoteur connecté en broche digitale 2
int monAngle;     //angle réalisé par le servo, de 0 à 180°
int pulsation;      //variable servant à la fonction pulsationServo

void setup()
{
   pinMode(brocheServo, OUTPUT);     //affecte la sortie 2 comme une sortie
}

void pulsationServo(int brocheServo, int monAngle)
{
    pulsation = (monAngle*10) + 600;     //détermine la pause (delay)
    digitalWrite(brocheServo, HIGH);      //active le servomoteur
    delayMicroseconds(pulsation);        //pause en microseconde
    digitalWrite(brocheServo, LOW);       //désactive le servomoteur
}

void loop()
{
   //le servomoteur commence à 10° et tourne jusqu'à 170°
   for (monAngle=10; monAngle<=170; monAngle++)
   {
       pulsationServo(brocheServo, monAngle);    //envoi à la fonction la broche et l'angle
       delay(20);      //ralentie le cycle
   }
   //le servomoteur commence à 170° et tourne jusqu'à 10°
   for (monAngle=170; monAngle>=10; monAngle--)
   {
       pulsationServo(brocheServo, monAngle);    //envoi à la fonction la broche et l'angle
       delay(20);      //ralentie le cycle
   }
}

Crédits

Ce livre a été écrit à partir d'inspirations et d'informations tirées des sites web suivants :

Incluant des éléments écrits par :

  • Massimo Banzi
  • Hernando Barragan
  • David Cuartielles
  • Tom Igoe
  • Daniel Jolliffe
  • Todd Kurt
  • David Mellis
  • and others...

Première édition publiée en août 2007 sous licence CC-By-Nc-Sa

Portail des ExplorateursWikidébrouillardLéon DitFLOGPhoto mystèreJ'ai FaitPortraitsAnnuaire
AR

Arduino : Le cahier de programmation

Rechercher

Page Discussion Historique
Powered by MediaWiki
Creative Commons - Paternite Partage a l

© Graphisme : Les Petits Débrouillards Grand Ouest (Patrice Guinche - Jessica Romero) | Développement web : Libre Informatique