UEF1212 Cahier TD - TP 2024

Télécharger au format pdf ou txt
Télécharger au format pdf ou txt
Vous êtes sur la page 1sur 90

Ces TD/TP se composent de 3 parties:

1- Partie I : Programmation du microcontroleur ATmega 2560 en utilisant le langage et


l’IDE Arduino.
a. TD/TP1 : Prise en main de l’IDE Arduino
b. TD/TP2 : Le langage Arduino (I) : Les E/S digitales(timing, multitasking)
c. TD/TP3 : Le langage Arduino (II) : Les Entrées analogiques/Sorties PWM
d. TD/TP4 : Le langage Arduino (III) : Les Librairies Arduino (mini projet)
e. TD/TP : Le langage Arduino (IV) : Les interruptions
f. TD/TP : Le langage Arduino (V) : Les modes de veilles
g. TD/TP : Le langage Arduino (VI) : Multitasking avec RTOS
2- Partie II : Programmation du microcontroleur ATmega 2560 avec Atmel Studio.
a. TD/TP : Prise en main de l’Atmel Studio 7 (Limitations de l’IDE Arduino)
b. TD/TP5 : Les E/S digitales - Les interruptions
c. TD/TP6 : Les timers (temporisations matérielles - générateurs PWM)
d. TD/TP7 : Les convertisseurs analogiques numériques
e. TD/TP8: Les modules de communications série
3- Partie III : L’utilisation d’un noyau temps réel avec Atmel Studio.
a. TD/TP9 : Configuration et utilisation de RTOS
b. TD/TP10 : Applications
Partie I
Programmation du microcontrôleur ATmega 2560 en utilisant
le langage Arduino.
TP N°1
Prise en main de l’IDE Arduino

1. Etudier les caractéristiques de la carte Arduino Mega;


2. S’initier à l’utilisation de l’IDE Arduino.

1. La carte Arduino Mega


2. L’IDE Arduino
3. Manipulation
Dans ce TP, nous découvrirons la carte Arduino Mega et l’IDE Arduino. Nous
apprendrons comment alimenter la carte puis la programmer à travers une application
simple : faire clignoter une LED (Blinking LED).

1.1 Materiel Arduino


1.1.1 La carte Arduino Mega 2560 R3

Figure 1.1 : La carte Arduino Mega 2560

1
Les principales caractéristique de la carte Arduino Mega:
 Microcontrôleur : ATmega2560
 Tension de fonctionnement : 5 V
 Gamme de tension d’entrée recommandée: 7-12 V
 Gamme de tensions d’entrée limite: 6-20 V
 Fréquence d’horloge de l’oscillateur à quartz : 16 MHz
 Mémoire flash : 256 KB dont 8 KB réservé au Bootloader (il permet de télécharger
les programmes entre l’IDE Arduino (Environnemnt de développement dédié).
 Mémoire SRAM : 8 KB
 Mémoire EEPROM : 4 KB
 Ports digitaux I/O : 54 dont 14 PWM
 Ports d’entrée analogique : 16
 Ports série UART: 4
 Bus I2C et SPI
 6 entrées à interruptions
 Port USB (fiche B) géré par le MCU ATmega 16U
 Un connecteur ICSP (programmation "in-circuit"),
 Un bouton de réinitialisation (Reset)
Visualisation
 LED ‘ON’ : indique que la carte est sous tension.
 LED ‘Tx’ et LED ‘Rx’: servent à visualiser l'activité sur la voie série (pendant
l'émission et la réception de données ou le chargement du programme dans le
microcontrôleur par le port USB).
 LED ‘L’: elle est connectée à la broche 26 du microcontrôleur (port 13
d’Arduino). Cette LED clignote quelques secondes après l’initialisation de la
carte ( et après le branchement de la carte au PC). Cette LED peut être utilisée
dans des applications et sert souvent comme LED de signalisation pour vérifier
le fonctionnement de la carte.
Les ports d’entrées/sorties :
 Les ports E/S numérique 0-53 peuvent être configurés en entrée ou en sortie
 Les ports PWM 0-13 codée sur 8 bits (0 à 255)
 Les ports d’entrée analogiques A0-A15 (résolution 10bits)
 Ports de communication : UART1/USB utilise les broches : 0(RX0), 1(TX0),
UART2 : 18(TX1), 19(RX1), UART3: 16(TX2), 17(RX2), UART4 : 14(TX3), 15(RX3).
 SPI est accessible via les broches ICSP ou les broches: 50(MISO), 51(MOSI),
52(SCK), 53(SS).
 I²C accessible via les broches: 20(SDA), 21(SCL).

Shéma
La figure 1.2 donne le shéma électrique de la carte Mega 2560 montrant les différents
éléments de la carte et leurs interconnexions.

2
Figure 1.2 : Shéma de la carte Arduino Mega 2560

3
1.1.2 Alimentation de la carte Arduino
la carte Arduino, qui demande une alimentation de fonctionnement de 5v, peut être
alimentée via le port USB ou avec une alimentation externe. Les figure 1.1 et 1.2 montre les
différentes entrées d’alimentation. L’entrée d’alimentation est sélectionnée
automatiquement et doit fournir l’intensité de courant nécessaire:
 à l’alimentation de l’Arduino et aux entrées/sorties ;
 aux shields et modules alimentés par la carte ;
 au régulateur 3.3V.
Pour mieux comprendre les interdépendances entre les différentes entrées et sorties
d’alimentation, on se reportera au schéma de la figure 1.3, qui rassemble les circuits
d’alimentation de la carte Arduino Mega:

Figure 1.3 : Circuits d’alimenation de la carte Arduino Mega 2560


L'alimentation externe (non-USB) peut être soit un adapteur secteur (pouvant fournir
typiquement de 7V à 12V sous 500mA) ou des piles. L'adaptateur secteur peut être
connecté en branchant une fiche 2.1mm positif au centre au connecteur jack de la carte. En
défaut d’alimentation dotée de la fiche adéquate, il est possible d’insérer les fils (+) et (-)
d'un bloc d’alimentation ou de piles dans les broches de la carte appelées Gnd (masse ou
0V) et Vin (Tension positive en entrée) du connecteur d'alimentation (POWER).
NB : les limites de la tension d’alimentation externe est 6 et 20 volts . En cas
d’utilisation de plus de 12V, le régulateur de tension peut surchauffer et endommager la
carte. La plage recommandée est de 7 à 12V. Si la carte est alimentée avec moins de 7V, la
broche 5V peut fournir moins de 5V et la carte peut être instable. L’origine de ces tensions
limites est :

4
Pour 6V : le régulateur utilisé possède une chute de tension minimum de 1V. Par
conséquent, en deçà de 6V de tension d’entrée, la tension de sortie sera égale à la tension
d’entrée moins la chute de tension et l’Arduino sera alimenté en dessous de la tension
nominale de 5V. La conséquence est un fonctionnement qui peut être erratique.
Pour 20V : la carte Arduino fonctionne sous 5V, le régulateur qui reçoit cette tension
d’entrée l’abaisse pour fournir du 5V. la puissance que ce régulateur dissipe est la
différence de tension entre Vin et 5V multipliée par le courant que consomme la carte et
les dispositifs externes alimentés par elle. Par conséquent plus la différence de tension est
élevée et plus le régulateur se chauffe. Le régulateur ayant une protection contre la
surchauffe, il coupe l’alimentation si la température devient trop élevée.
Desciption du connecteur POWER : Les broches d’alimentation pour la carte Arduino
Mega sont les suivantes:
 Vin Tension d'entrée positive lorsque la carte Arduino est utilisée avec une source
de tension externe (à distinguer du 5V de la connexion USB ou autre source 5V
régulée).
 5V tension de sortie régulée fournie par le régultaur intégré
 3V3 tension de sortie régulée fournie par le adaptateur intégré
 GND Broche de masse (ou 0V).
Pour plus de comodité d’utilisation, la carte contient d’autres broches d’alimentation
(5V, Gnd) disponibles avec les connecteurs d’E/S (figure 1.4).

Figure 1.4 : Toutes les broches d’alimentation de la carte Arduino Mega 2560

1.1.2.1 Alimentation par USB avec ou sans ordinateur


Dans ce cas, la tension 5v (régulée) sera fourni directement, en passant par un transistor
MosFET T1 dont le rôle est la selection automatique de la source d’alimentation entre
USB et Vin (Jack) (figure 1.3). L’ensemble des composants de la carte et les modules
externes connectés ne devront pas consommer plus de 500mA. Cette limitation protège le
port USB de l’ordinateur à travers l’utlisation d’un fusible électronique à réarmement
automatique qui coupe l’alimentation si la limite de 500mA est dépassée. Cette méthode
limite donc la consommation totale du montage à 500mA (figure 1.2). Cette alimentation
peut être générée à partir d’un PC ou une alimentation régulée (d’un smartphone par
exemple).

1.1.2.2 Alimentation par connecteur Jack


la carte comprend un connecteur d’alimentation de type Jack femelle. Il faut donc un
connecteur jack mâle. Ce type de connecteur possède 2 fils dont le fil + est à l’intérieur et
le fil - à l’extérieur. Sur cette entrée, une diode de protection, évite les mauvais

5
branchements (inversion de polarité). Comme source, il faut appliquer une tension entre 7
et 12V continu (tension recommandée). Nous pouvons utiliser plusieurs sources :
 un bloc d’alimentation AC/DC, 9V est une tension fréquente et idéale ;
 une pile 9V ;
 un ensemble de 7 piles 1.5V…
La tension 5V est obtenu par le régulateur et les intensités acceptable seront les mêmes,
en tenant compte toutefois de la puissance dissipée par la diode. Pour le régulateur 5V de
l’Arduino utilisé, la limite d’intensité délivrable sont:
 Alimentation 12 V: I = 2 / (12-5) = 2 / 7 = 285mA
 Alimentation 9 V: I = 2 / (9-5) = 2/4 = 500mA
 Alimentation 7 V: I = 2 / (7-5) = 2/2 = 1A

1.1.2.3 Alimentation par les broches Vin et GND du connecteur POWER


Cette méthode nécessite une vigilance accrue compte tenu des possibilités d’erreur de
branchement. Il va falloir vérifier le branchement à plusieurs reprises avant de mettre sous
tension. Il faut relier le fil + à la borne Vin de l’arduino et le fil – à une des broches GND.
Une erreur de branchement risque d’endommager la carte. Après avoir répéré les fils + et -,
il faut les relier à l’arduino par les deux broches nommées, à savoir :
 le + (habituellement le fil rouge) est relié à la broche Vin
 le – (habituellement le fil noir) est relié à GND.
Tout comme le cas d’alimentation par connecteur Jack , la tension optimale de ce
courant continu se situe entre 7 et 12V. Dans ce contexte et afin de protéger l’arduino d’un
mauvais branchement le + sur le – et le – sur le +, nous pouvons intercaler une diode qui
ne laissera passer le courant que si il est dans le bon sens. La référence de diode est de type
1N400x.

1.1.2.4 Alimentation par les broches 5V et GND du connecteur POWER


Dans ce cas, il faut impérativement que le jack ne soit pas alimenté, mais l’USB peut
l’être (utilisation de la transmission de données), le circuit constitué du comparateur IC7B
et du MOSFET T1 évitera le court-circuit entre la tension 5v du port USB et la tension
délivrée sur la broche 5V. Il faudra protéger l’entrée contre les surtensions, inversions, ….
Aucun régulateur ne limite la puissance fournie par cette entrée 5v.

1.1.2.5 Les sources de la carte


 si la carte est alimentée par Vin ou le jack d’alimantation, on pourra alimenter des
composants extérieurs via le 5v dans la limite des intensités vues plus haut
(échauffement du régulateur)
 si la carte est alimentée par USB, on pourra alimenter des composants extérieurs
via le 5v dans la limite de la capacité de l’appareil connecté et du fusible, soit
500mA maximum.
 si la carte est alimentée par le 5v, on pourra relier celui-ci aux éléments extérieurs
sans influence sur la carte.
Dans tous les cas, on pourra utiliser la sortie 3.3V pour alimenter des éléments qui
necessitent une telle tension , mais l’intensité de sortie est très limitée (50mA).

6
1.2 L’IDE Arduino
1.2.1 Description
Avant de commencer, installer l’IDE Arduino et le pilote de la carte si c’est necessaire. Cet
environnement de développement intégré, dédié à la programmation des cartes Arduino,
permet :
 d’écrire et compiler des programmes pour la carte Arduino en langage Arduino, en
langage C/C++ et même en assembleur.
 de programmer la carte Arduino ( y transférer les programmes )
 de communiquer avec la carte Arduino (transmision et reception de données pour
debogage…)
Comme pour tout logiciel à interface graphique (GUI), l’IDE Arduino comporte les
éléments suivants :
 une Barre de Menus
 une Barre de Boutons qui donne un accès direct aux fonctions essentielles.
 un Editeur (à coloration syntaxique) pour écrire le code des programmes, avec
onglets de navigation, Le programme écrit avec le logiciel Arduino est appelé
sketch (ou croquis - en français), le fichier correspondant est d’extension « .ino ».
L’IDE permet de gérer un projet de plus d'un fichier. Ces fichiers doivent être des
fichiers Arduino normaux, des fichiers C (extension .c ), des fichiers C++ (.cpp) ou
des fichiers d'entête (.h).
 une Zone de messages indiquant l'état des actions en cours (compilation, transfert
du programme vers la carte ..)
 une Console d’affichage qui affiche les messages concernant le résultat de la
compilation du programme( taille programme compilé, erreurs …).

Barre de Menu

Barre de Boutons

Onglets de fichiers ouverts

Fenêtre d’édition des programmes

Zone de messages des action en cours

Console d’affichage des messages de compilation

Informations sur la carte et le port utilisés

Figure 1.5 : Les éléments de l’interface d’Arduino IDE


Le logiciel Arduino intègre également un Moniteur et un Traceur série (fenêtres
séparées) qui permettent principalement d'afficher des données reçus de la carte Arduino
sous formes de listes ou de graphes. L’utilisation de ces outils sera détaillée aux prochains
TPs.

7
1.2.2 Description de la barre des boutons
Vérifier/Compiler Sauvegarder sketch Moniteur série

Nouveau sketch

Ouvrir sketch

Téléverser

 Vérifier/compiler : Vérifie le code à la recherche d'erreur de syntaxe.


 Nouveau : Crée un nouveau code (ouvre une fenêtre d'édition vide)
 Ouvrir : Ouvre la liste de tous les programmes exemples
 Sauvegarder : Enregistre le programme.
 Téléverser : Compile le code et le transfère vers la carte Arduino.
 Moniteur Série : Ouvre la fenêtre du moniteur série.

1.2.3 Description des menus


Des commandes complémentaires sont disponibles dans cinq menus : Fichier - Edition –
Croquis - Outils - Aide.
Menu Fichier: Propose toutes les
fonctionnalités usuelles pour
gérer les fichiers :
 Carnet de croquis: est une
fonctionnalité permettant
d'avoir accès direct à tous les
programmes réalisés et
sauvegarder dans le repertoire
de travail (par defaut :
doduments/Arduino).
 Exemples: Ce menu déroulant
vers une série de programmes
d'exemples disponibles.
Menu Edition : On y trouve tous
les outils d’édition des
programmes : copier, sélectionner,
commenter et indenter les
instructions….

8
Menu Croquis :
 Vérifier/compiler: Vérifie le
code à la recherche d'erreurs
 Téléverser : permet de charger
le programme dans le
microcontrôleur de la carte
 Inclure une bibliothèque :
permet de voir les bibliothèques
déjà installées , les gérer, et aussi
en inclure de nouvelles.
 Afficher le dossier des croquis :
Ouvre le répertoire courant du
programme .
 Ajouter un fichier…: Ajoute un
fichier source au programme (il
sera copier à partir de sa
localisation courante. Le
nouveau fichier apparaît dans
un nouvel onglet.
Menu Outils:
 Formatage Automatique: Cette
fonction formate le code de
façon à le rendre plus clair.
 Moniteur série : permet d’ouvrir
le moniteur de l’IDE (voir
figure) qui est une fenêtre dans
laquelle on peut afficher des
données reçu de la carte
Arduino (dans le cadre bleu) ou
d’envoyer des données à la carte
(à partir du cadre jaune).
 Traceur série : permet d’afficher
une représentation graphique
Moniteur série
des données reçu de la carte.
 Type de carte : pour
sélectionner la carte Arduino
utilisée.
Traceur série  Port Série: Ce menu contient
tous les ports séries (réels ou
virtuels) présents sur
ordinateur.
Menu Aide
 Le menu d’aide permet d’ouvrir
le site Arduino, notamment la
référence du langage en anglais,
qui permet de retrouver la
syntaxe des différentes
fonctions et leurs modes
d’utilisation.

9
1.3 Manipulation
1.3.1 Programmation de la carte Arduino
1. Saisir le programme et vérifier le code.
Pour commencer nous utilisons un programme très simple qui consiste à faire clignoter
la LED L de la carte. Le programme correspondant est le suivant :

Programme : Blink
/* by Colby Newman
This example code is in the public domain.
http://www.arduino.cc/en/Tutorial/Blink */
// the setup function runs once when you press reset or power the board
void setup() {
// initialize digital pin LED_BUILTIN as an output.
pinMode(LED_BUILTIN, OUTPUT);
}
// the loop function runs over and over again forever
void loop() {
digitalWrite(LED_BUILTIN, HIGH); // turn the LED on (HIGH is the voltage level)
delay(1000); // wait for a second
digitalWrite(LED_BUILTIN, LOW); // turn the LED off by making the voltage LOW
delay(1000); // wait for a second
}
Ce programme peut aussi être ouvert à partir Fichier>Exemples>Basics>Blink ou à partir
de la barre d’outils:

2. Sélectionner le bon port série (et la bonne carte Arduino...)


Avant de transférer votre programme vers la carte Arduino, vous devez vérifier que
vous avez bien sélectionné la bonne carte Arduino depuis le menu Outils>Type de carte. la
carte doit évidemment être connectée à l'ordinateur via un câble USB.
Vous devez également sélectionner le bon port série depuis le menu Outils > Port
(Outils > Port Série) : delectionner le port COMx dédié à la carte.

10
Appuyez alors sur le bouton Verifier de la barre d'outils pour lancer la vérification du
code: Si tout va bien, aucun message d'erreur ne doit apparaître dans la console et la zone
de message doit afficher Compilation terminé attestant que la vérification s'est bien
déroulée.

3. Transfert du programme (Programmation de la carte)


Une fois le bon port série et la bonne carte Arduino sélectionnés, cliquer sur le bouton
" Téléverser" (Transfert vers la carte) dans la barre d'outils, ou bien sélectionner le menu
Croquis>téléverser : La carte Arduino alors se réinitialise automatiquement et démarre le
transfert. Sur la carte, vous devez voir les LEDs des lignes RX et TX clignoter
rapidement, témoignant que le programme est bien transféré. Le logiciel Arduino affiche
un message indiquant que le transfert est en cours.

Après le transfert du programme, le logiciel Arduino affiche un message indiquant que


le transfert est bien réalisé, ou afficher des messages d'erreurs... (Reprendre dans ce cas la
procédure). A la fin, le message "Téléversement terminée" indique la fin du transfert du
programme suivi d'un rapport sur la taille des mémoires occupées.

11
TP N°2
Le langage Arduino (I) :
Les E/S digitales

1. Se familiariser avec le langage Arduino;


2. Manipuler les ports d’entrée/sortie numériques;
3. Apprendre à utiliser le moniteur série (comme un moyen de debogage).

1. Eléments de base du langage Arduino;


2. Exemples (Manipulation des Entrées/sorties numériques)
3. Moniteur série
4. Applications
5. Exercices

2.1 Eléments de base du langage Arduino


Le langage Arduino est basé sur le langage C/C++. l’ensemble des éléments qui constitu
un programme Arduino peuvent être classés en 3 parties : la structure , les
variables/constantes et les fonctions.
Une référence des éléments de base est disponible à partir de l’IDE Arduino :
AideRéférence (figure 2.1)

Fig 2.1 : Référence langage Arduino

12
2.1.1 Structure
Dans le langage Arduino, le programme est constitué de deux fonctions qui doivent
toujours être présentes et porter exactement les noms setup() et loop(). Un programme
Arduino comporte alors les trois parties suivantes:

Fig 2.2 : Structure d’un programme Arduino

1. La partie déclaration des variables (optionnelle)


2. la partie initialisation et configuration des entrées/sorties : la fonction setup()
3. la partie principale qui s'exécute en boucle infinie: la fonction loop()
Ces parties du programme utilisent différentes instructions issues de la syntaxe du
langage Arduino. La raison pour laquelle tout programme Arduino rend obligatoire la
présence des deux fonctions setup() et loop() est que cela permet de séparer les actions
qui ne doivent être réalisées qu'une fois au démarrage du croquis (configuration) de celles
qui doivent se dérouler en permanence (traitement).
La coloration syntaxique du code permet de clarifier le type des différents éléments:
 En orange, apparaissent les mots-clés reconnus par le langage Arduino comme des
fonctions existantes : un clic droit sur la fonction permet d’afficher sa description en
choisissant « trouver dans référence » : cette commande ouvre directement la
documentation de la fonction sélectionnée.
 En bleu, apparaissent les mots-clés reconnus par le langage Arduino comme des
constantes.
 En gris, apparaissent les commentaires. Il est utile de bien commenter son code pour s'y
retrouver facilement ou pour le partager.

13
La syntaxe du langage est celle du langage C :
 toute ligne de code se termine par un point-virgule « ; »
 le contenu d'une fonction est délimité par des accolades « { » et « } »
 les paramètres d'une fonction sont délimités par des parenthèses « ( » et « ) ».
 « // » est un commentaire ligne.
 « /* » et « */ » encadrer des commentaires sur plusieurs lignes.
 Tous les opérateurs du langage C sont utlisables : les opérateurs arithmétiques,
logiques, bit par bit, de comparaison, composés, pointeurs et références.

2.1.2 Les variables et les constantes


Les valeurs litérales de type entier peuvent être exprimé en :
 decimal - exemple : 123
 binary avec le prefixe (B) - exemple : B1111011 avec les valeurs 8bits seulement
 hexadecimal avec le prefixe (0x) - exemple : 0x7B
Les valeurs réelles peuvent être exprimées en notation normale ou sicientifique, exemples :
 10.0 (10)
 .005 (0.005)
 2.34E5 (234000)
 67e-6 (0.000067)
En langage Arduino, on peut utliser tous les types de données du C simples et composés.
Le tableau suivant donne l’étendu de chaque type :

Type Etendu de valeurs Abrégé


boolean (1octet) true ou false, 1 ou 0, HIGH ou LOW (notations
équivalentes). Occupe un octet de mémoire pas 1 bit.
char (1 octet) Entier non signé 8bits ou caractère donné entre ' ' uint8_t
int (2 octet) Entier signé 16bits, soit une valeur de -32 768 à 32 767. int16_t
Unsigned(2octet) Entier non-signé 16bits, soit une valeur: 0 à 65535. uint16_t
Long (4 octet) Entier signé 32bits : -2 147 483 648 à +2 147 483 647. int32_t
unsigned long Entier non signé 32bits : 0 à 4 294 967 295 uint32_t
Float (4 octet) Réels 32bits : -3.4028235E+38 à +3.4028235E+38.
Double (4 octet) Equivalent à float
Chaine " " Tableau d’éléments de type char
Chaine String Chaînes de caractères
Byte (1 octet) Entier non-signé 8bits : 0 à 255. uint8_t
Word (2 octet) Entier 16bits non signée : 0 à 65535. Uint16_t

2.1.3 Les fonctions


En langage Arduino, certaines fonctions sont préprogrammées, telles que
digitalWrite() et delay() qui seront utilisées ultérieurement, mais on peut aussi définir
d’autes fonctions personalisées. Les deux fonctions setup() et loop() sont particulières:
leurs noms sont invariables, mais leur contenu est défini selon l’application.

14
En langage Arduino, on peut utiliser les fonctions mathématiques suivantes (voir
référence Arduino pour leur description détaillée) :

Math
 min(x, y)
 max(x, y)
 abs(x)
 constrain(x, a, b)
 map(valeur, fromLow, fromHigh, toLow, toHigh)
 pow(base, exposant)
 sq(x)
 sqrt(x)

Trigonométrie
 sin(rad)
 cos(rad)
 tan(rad)
 degrees(rad)
 radians(deg)
 PI

Les fonctions les plus imporantes sont les fonctions qui permettent de manipuler les
différents périphériques intégrés au microcontrôleurs (tels que les ports d’E/S, les
convertisseurs analogique/numérique…) et les périphériques externes les plus utilisé tels
que les moteurs, les afficheurs…. Les fonctions pour les périphériques externes (modules
matérielles) sont organinées en bibliothèques.

Les fonctions de bases sont les fonctions de manipulations des E/S digitales. Grâce à
ces fonctions on peut par exemple allumer des lampes, contrôler des moteurs ou encore
vérifier l’état d’un capteur. Dans ce TP nous introduisons ces fonctions avec quelques
fonctions utiles pour réaliser des temporisations.

Fonctions de Maniplations des Entrées/sorties numériques


Les ports d’E/S sont utilisée librement pour échanger les données avec
l’environnement extérieur du µC, afin de réaliser des commandes, comme par exemple,
allumer des LED, commander des moteurs, des afficheurs LCD, l’état d’un bouton...
La carte Arduino mega possède 54 entrées/sorties numériques, repérées de 0 à 53;
chacune d’entre elles pouvant fonctionner en entrée ou en sortie sous le contrôle du
programme. Ces entrées/sorties admettent et délivrent des signaux logiques compatibles
TTL ( tension comprise entre 0 et 5V ). Elles peuvent fournir ou délivrer un courant
maximum de 40 mA , mais l’ensemble des sorties ne peuvent pas en aucun cas délivrer 200
mA (5 sorties à 40mA ou 10 sorties à 20mA….). En langage Arduino, nous utilisons les
fonctions suivantes :
 pinMode - prototype: void pinMode(uint8_t pin, uint8_t mode)
 Cette fonction sert à définir une broche spécifique de l’Arduino, par le biais de
son numéro dans la carte, comme étant une entrée (sans ou avec résistance de
pull up) ou une sortie en utlisant les constantes: INPUT , INPUT _PULLUP
et OUTPUT respectivement. Exemple : pinMode(4,OUTPUT)
 digitalWrite – prototype: void digitalWrite(uint8_t pin,uint8_t val)

15
 Cette fonction sert à définir l’état d’une sortie en utilisantles constantes : HIGH
( ou 1 logique) ou LOW (0 logique). Exemple: digitalWrite (4,HIGH)
 digitalRead – prototype: int16_t digitalRead(uint8_t pin)
 sert à lire l’état d’une broche. Si celle-ci est reliée à un potentiel 5V, le résultat
de la lecture sera HIGH (1) ou LOW (0) si elle est reliée à un potentiel nul.
Exemple : X=digitalRead(5).

Fonctions de Temporisations
les fonctions définies qui permettent de réaliser des temporisations en langage Arduino
utilisent les timers du microcontrôleur (temporisations matérielles):
 void delay(uint32_t ms).
 Cette fonction sert à insérer une temporisation d’une certaine durée exprimée
en millisecondes et fixée par un paramètre passé lors de son appel. Cette
fonction est une fonction bloquante : c-à-d les opérations de manipulation des
ports ne sont pas possible pendant le déroulement de la temporisation.
Exemple : delay(1000) insère une temporisation de 1 seconde.
 void delayMicroseconds(uint16_t us)
 Identique à la fonction delay(), sauf que l’entier passé en paramètre reprérente
la temporisation en microsecondes non en millisecondes.
 void uint32_t millis()
 permet de retourner un nombre de millisecondes qui correspond au temps
depuis lequel le programme a été démarré (revient à zero après des centaines
d’heures de fonctionnement).
 void uint32_t micros()
 exactement la même fonctino que millis(), sauf que micro() renvoi un entier
qui correspond à des microsecondes.

2.2 Manipulation
2.2.1 Exemples de manipulation des ports d’E/S
1) Toujours le programme Blink
L’instruction de configuration du port par pinMode() est insérée dans la fonction
setup() parce qu'il n'est nécessaire qu'une seule fois. Cela fonctionnerait toujours si nous
déplacions l'appel dans la boucle, mais il serait inutile de répéter cette action de
configuration . les instructions qui aggissent sur le port pour faire clignoter la LED sont
insérées dans Loop ( exécution répétée).
Programme 1:
/* clignoter une LED */
void setup()
{
pinMode(13, OUTPUT); // port 13 = builtin LED ( La LED L)
digitalWrite(13, HIGH);
}
void loop()
{
digitalWrite(13, HIGH);
delay(1000);
digitalWrite(13, LOW);
16
delay(1000);
}
2) Quelques bonnes manières de programmation
Dans l’exemple précédent, la broche 13 est utilisée en trois endroits différents du
programme. Pour travailler avec une autre broche, il faudrait donc modifier le numéro de
broche à trois endroits. De même, pour modifier la vitesse de clignotement (utilisée
comme argument de la fonction delay()), il faudrait modifier la valeur 1000 à deux
endroits différents.
L’utilisation des variables et des constantes est une bonne manière de programmation car
elle permet de produire des programmes plus génériques qui faciliteront les modifications:
Programme 2:
/* clignoter une LED */
const byte brocheLED = 13;
const unsigned dureePause = 1000; // la valeur de dureePause est fixée
void setup()
{
pinMode(brocheLED, OUTPUT); // port 13 = builtin LED ( La LED L)
}
void loop()
{
digitalWrite(brocheLED, HIGH);
delay(dureePause);
digitalWrite(brocheLED, LOW);
delay(dureePause);
}
Avec ce programme, pour faire clignoter la LED avec une autre vitesse ou un autre port,
il suffit de changer à un seul endroit les valeurs affectées aux constantes dureePause et
brocheLED. Ici le type de brocheLED est const byte: le type byte est suffisant pour
représenter tous les broches de la carte car leur nombre ne dépasse pas 256, et constante
puisqu’elle ne changera pas de valeur au cours du programme. De même, le type unsigned
de dureePause est largement suffisant pour notre application.
dans l’exemple suivant, la déclaration de dureePause est changée (n’est plus une
constante) car on veut modifier la vitesse de clignotement au cours d’exécution du
programme : le clignotement commence à une vitesse élevée, puis ralentisse.
Programme 3:
/* clignoter une LED */
const byte brocheLED = 13;
unsigned dureePause = 100; // la valeur de dureePause peut pas être changée
int i;
void setup() {
pinMode(brocheLED, OUTPUT);
}
void loop()
{
for (i=0;i<=3;i++){
digitalWrite(brocheLED, HIGH);
delay(dureePause);
digitalWrite(brocheLED, LOW);
delay(dureePause);}

17
dureePause = dureePause + 100;
if (dureePause==2000) {dureePause=100;}
}

L’utilisation des fonctions personalisées est une très bonne manière de programmation. Le
Programme 4 donné ci-dessous montre une restructuration du programme 3 avec
l’utilisation d’une fonction personalisée appellé Blinking :
Programme 4:
/* clignoter une LED */
const int brocheLED = 13;
unsigned dureePause = 100;
void setup()
{
pinMode(brocheLED, OUTPUT); // port 13 = builtin LED ( La LED L)
}
void loop()
{
Blinking(brocheLED, dureePause);
dureePause = dureePause + 100;
if (dureePause==2000)
{
dureePause=100;
}
}
void Blinking(const int LED, int delai )
{
int i;
for (int i=0;i<3;i++)
{
digitalWrite(LED, HIGH);
delay(delai);
digitalWrite(LED, LOW);
delay(delai);
}
}

2.3 Le Moniteur Série


Le moniteur série intégré à l'environnement Arduino assure une communication entre
l’ordinateur et la carte Arduino les ports arduino 0 (RX) et 1 (TX) via le connecteur USB.
Ainsi, si vous utilisez ces fonctions, vous ne pouvez pas utiliser les broches 0 et 1 pour E/S
numériques. Le lancement du Moniteur série se fait simplement à partir de la barre
d'outils en sélectionnant le même débit en bauds que celui configuré dans le programme
(Fig 2.3 et 2.4).

18
Fig 2.3 : La fenêtre du moniteur série

Fig 2.4 : Réglage de la vitesse de communication


Notez bien que la carte Arduino se réinitialisera quand vous lancez le moniteur Série. Il
existe plusieurs instructions pour réaliser une communiation série à travers le moniteur,
nous introduisons aujourd’hui les 3 fonctions suivantes :
- void Serial.begin(uint8_t rate)
 fixe la vitesse de transmission entre PC et la carte
- void Serial.print("message")
 affiche le "message" dans la fenêtre du moniteur série
- void Serial.println("message")
 affiche le "message" sur une nouvelle ligne
Exemple :
Ce programme nous permet de suivre l’exécution des tâches « en direct ». Quand on se
trouve dans la fenêtre du moniteur série et que le programme est lancé sur l’Arduino, on
peut voir s’afficher les différents messages.
Programme 3:
/* clignoter une LED */
const byte brocheLED = 13;
unsigned dureePause = 100;
void setup() {
pinMode(brocheLED, OUTPUT);
Serial.begin(9600);
}
void loop() {
digitalWrite(brocheLED, HIGH);
Serial.print(" LED allumée…"); // Affiche le message " LED allumée"
Serial.print(" Lancement de la 1ere temporisation…");

19
delay(dureePause);
digitalWrite(brocheLED, LOW);
Serial.println(" LED éteinte…");
Serial.print(" Lancement de la 2eme temporisation.");
delay(dureePause);
}
La ligne « Serial.begin(9600) » qui se trouve dans le setup est obligatoire, et sert à
initialiser la liaison série de l’Arduino, en lui affectant une vitesse de transmission. Cette
vitesse peut évidemment être changée, mais il faudra aussi modifier cette valeur dans le
moniteur série pour que la lecture des informations se fasse à la même fréquence que leurs
envois.

20
2.4 Applications :
2.4.1 Rappels sur les composants requis :
 Plaque d’essai
 Résistances
 LEDs
 interrupteurs
 Fils de connexion

2.4.1.1 Plaque d’essai


Permet de tester un montage électronique sans réaliser de cirtuit imprimé. Grâce à cet
petit outil, il n'y a pas besoin de souder, il suffit juste de placer les composants dans les
trous organisés en rangés de points connectés entre eux (Fig. 2.5):
 Les point de rangés marqués en vert sont connectés et forment un même point
(Fig. 2.6). L’espace au milieu sépare deux ensembles de connections est permet
de placer des circuits intégrés.
 Les rangés marquées en rouge et représentées par un "+", conviennent à y
connecter la source de tension (Fig. 2.7). De cette façon, le montage est plus
propre et vous pourrez connecter un fil à cette source d'alimentation à chaque
fois qu'il en sera nécessaire. Les rangées en bleu et symbolisé par un "-" servent à
relier les composants facilement à la masse.

Points
connectés

Fig 2.5 : Les connexions de la plaque d’essai

Fig 2.6 : Connecter 2 composants en mettant les bornes sur la même ligne

Fig 2.7 : Relier les composants au plan d’alimentation et de masse

21
2.4.1.2 Les résistances
Une résistance est un composant électronique ou électrique dont la principale
caractéristique est d'opposer à la circulation du courant électrique. Ce composant est
caractérisée par sa valeur exprimée en Ohm et ces multiple( Ω, KΩ, MΩ) codée en couleur
de la manière suivante :

Fig 2.8 : Code couleur des résistances

2.4.1.3 Les LEDs


Les LEDs sont des diodes qui produisent de la lumière lorsque le courant y passe en
polarisation directe de l’anode vers la cathode. Tout comme toute diode, la polarisation
inverse bloque le courant et la LED dans ce cas n’émet aucune lumière.

Anode + − Cathode
(A) (K)

Fig 2.9 : Symbole d’une LED

22
Avant l’utilisation de tous composant semiconducteur, il faut toujours consulter sa
fiche de spécifications techniques (Datasheet), qui présente les différentes informations et
les valeurs nominales de courant et de tension, afin d’utiliser correctement le composant.
La LED est caractérisée par des propriétés électriques, optiques, thermiques et
géométriques. (constitue toujours un bon point de départ pour comprendre tout
dispositif)Les principaux termes que nous retrouvons dans les documentations techniques
sont décrits brièvement dans ce qui suit à travers un exemple de datasheet d’une LED
rouge 5mm classique .

Les principales caractéristiques de cette LED sont


 Forward Current IF (Courant direct) : c’est le courant direct maximal que la
LED est capable de supporter en régime continu ou permanent. Cette valeur
nominale est donnée pour une température ambiante de 25°C. Dans le cas de
l’exemple, le courant direct admissible est égal à 20mA, cela signifie que le
courant qui traverse cette LED doit être ≤ 20mA et que la luminosité maximale
est obtenue avec cette valeur.
 Forward voltage VF (Tension directe) : c’est la différence de potentiel présente
aux bornes de la LED en polarisation directe et en température ambiante de
25°C. Cette valeur de tension permet de dimensionner les composants du circuit
à LEDs.
Les tensions directes étant très basses (1,5 V à 3,3 V) il faut choisir une tension
d’alimentation adéquate et ajouter un ou plusieurs composants (résistances…) pour faire
fonctionner correctement la LED.
Pour le circuit à une seule LED (IF, VF) de la figure ci dessous, la résistance R permet de
limiter le courant à la valeur préconisée par le constructeur en correspondance à la tension
de la LED.

23
I

VR R

VLED

Figure 2.10 : Circuit à une seule LED


Le calcul de la résistance de limitation R est une simple application de la loi d'Ohm et
se fait en deux étapes:
1. Nous calculons d'abord la chute de tension aux bornes de la résistance de limitation
nécessaire pour que la diode LED soit soumise à une tension directe :
VR=E-VLED=E-VF
2. Nous calculons maintenant la valeur de la résistance en tenant compte de la valeur
du courant qui traversera la LED (soit IF).
R= VR/I= VR/IF
Exemple de calcul pour une LED (20mA, 1.8V) :

I = IR = IF
= 20mA

VR E - VF
= 10.2V R=
IF
= 510 Ohms
E
= 12V

VF
= 1.8V

Les sorties microcontrôleurs peuvent à la fois générer et évacuer des quantités utiles de
courant, donc peuvent être utilisés pour contrôler directement une LED. La figure 2.11
donne les 2 montages de base pour contrôler l’allumage d’une LED avec ‘ 1’ ou ‘0’.
Vcc La LED s’allume si la sortie
S est égale à 1

IF IF

Micro- Micro-
contrôleur S contrôleur S
R R

La LED s’allume si la sortie


S est égale à 0

Figure 2.11 : Commander une LED avec un port de microcontrôleur


24
2.4.1.3 Les interrupteurs
L’interrupteur est un composant qui permet d'interrompre ou d'autoriser le passage du
courant dans un circuit électrique (d’ouvrir et de fermer le circuit). Il existent une très
grande variété d’ntérrupteurs mais les principales sont les suivants :
1. Intérupteur maintenu : maintien son état (position) jusqu'à ce qu'il soit activé pour
le positionné dans l’autre état qui sera aussi maintenu jusqu’à une autre action de
modification de l’état. Cet intérrupteur peut avoir plusieur formes :
Fermé/Ouvert, Position 1/Position2 …
2. Intérrupteur momentané (bouton poussoir): les commutateurs restent actifs
uniquement s'ils sont actionnés (appuyés). Si le commutateur n’est pas actionné, il
reste à état "ouvert" (comme les touches de clavier)

Bouton Bouton
ouvert fermé

Interrupteur Interrupteur
ouvert fermé

Interrupteur Interrupteur
position 1 position 2

Figure 2.12 : Commander une LED avec un port de microcontrôleur


Les intérrupteurs sont souvent utilisés avec les ports du microcontrôleurs pour imposer un
‘1’ ou ‘0’ à une broche configurée comme une entrée. Si on connecte un intérrupteur
seulement relié à la masse (à Vcc) on se trouve à 2 cas :
 Intérrupteur fermé : l’entrée = ‘0’ (‘1’)
 Intérrupteur ouvert : l’entrée = indéfini (flottante)
Pour éviter cet état indéfni, une résistance de pull-up ou pull-down assurera que la
broche soit dans un état haut ou bas, tout en limitant le courant au courant admissible au
port d’entrée. les résistances pull-up et pull-down fonctionnent selon les mêmes concepts,
sauf que la résistance de pull-up est connectée à l’alimentation (Vcc) et la résistance pull-
down est connectée à la masse.
Vcc Vcc

Interrupteur ouvert:
→ E=0
R Interrupteur fermé:
Micro- Micro- → E=1
contrôleur E contrôleur E

Interrupteur ouvert:
→ E=1
R
Interrupteur fermé:
→ E=0

Figure 2.13 : Commander une LED avec un port de microcontrôleur


25
Avec une résistance de pull-up, la broche d'entrée lira un état haut lorsque le bouton
n'est pas enfoncé. En d'autres termes, une petite quantité de courant circule entre VCC et la
broche d'entrée (pas à la masse), ainsi la tension de la broche d'entrée est proche de VCC.
Lorsque le bouton est enfoncé, la broche d'entrée sera directement connectée à la masse. Le
courant passe à travers la résistance à la masse, ainsi la broche d'entrée lit un état bas.
Gardez à l'esprit que, si la résistance n’est pas utlisée, la femeture du bouton relie VCC à la masse, ce
qui provoque une court circuit.
La valeur de la résistance pull-up doit être choisie pour satisfaire deux conditions:
 Lorsque le bouton est enfoncé, la broche d'entrée est tirée à la masse. La valeur
de la résistance R contrôle la quantité de courant transmis à partir de VCC, via le
bouton, à la masse.
 Lorsque le bouton n'est pas enfoncé, la broche d'entrée est tirée vers le haut. La
valeur de la résistance de pull-up contrôle la tension sur la broche d'entrée.
Pour la condition 1, la valeur de la résistance ne doit pas être trop basse : plus la
résistance est faible, plus la puissance sera dissipée lorsque le bouton est appuyé. Cette
valeur de résistance ne doit pas être aussi trop grande pour satisfaire la condition 2: La
règle générale pour la condition 2 est d'utiliser une résistance de rappel (R) qui est
inférieure d'un ordre de grandeur (1/10ème) à l'impédance d'entrée (Re) de la broche
d'entrée (figure 2.14). Une broche d'entrée d’un microcontrôleur a une impédance qui peut
varier de 100k-1MΩ. Ainsi, lorsque le bouton n'est pas enfoncé, une très petite quantité de
courant circule de VCC à R et dans la broche d'entrée. La résistance de rappel R et
l'impédance de broche d'entrée R divisent la tension, et cette tension doit être
suffisamment élevée pour que la broche d'entrée lise un état haut: une résistance de 10k à
100kΩ pour R devrait éviter la plupart des problèmes.

Vcc

Micro- R
Contrôleur
E

Re

Figure 2.14 : Commander une LED avec un port de microcontrôleur


Vu que les résistances pull-up sont si souvent utilisées, la majorité des microcontrôleurs
intègrent des résistances de pull-up internes qui peuvent être activés et désactivés par le
programme.

26
2.4.2 Circuits de LEDs clignotantes
Toute les applications de ce TP sont basées sur le premier skecth (Blink) que nous
modifierons pour obtenir des circuits avec plus de fonctionnalités en utilisant les variables,
les tableaux, les boucles et les fonctions pour écrire des programmes compacts qui
correspondent au fonctionnement décrit pour chaque application.
Le compte rendu de ce TP, à remettre à la fin de la séance, comprend à la demande:

- le schéma du circuit utilisé (fritzing)

- le programme écrit, modifié ou corrigé (commenté)

- la description du fonctionnement demandée.

Application 1 - Changer le port et la vitesse de clignotement


1/ Brancher une LED rouge à une broche de votre choix puis modifier le sketch Blink
précédent pour avoir une led clignotante avec une fréquence de 10Hz.

cycle

Sortie éteinte allumée éteinte allumée

0.1 0.2 t(s)

Figure 2.15: signal de contôle de la LED


2/ Visualiser le signal de sortie ( généré par le port qui commande la LED) avec un
oscilloscope et vérifier sa fréquence.
Application 2 - commander plusieurs LEDs
1/ Ajouter 2 autres LEDs au circuit de l’applications 1 , puis modifier le programme
précédent pour faire clignoter les LEDs notées Led1, Led2, Led3 à des vitesses différentes
(0.5Hz, 1Hz et 2Hz respectivement).
2/ Améliorer le programme précédent en réalisants les affectations répétitifs avec une
boucle en utilisant la fonction suivante :
 bitRead - prototype: uint8 bitRead(uint8_t X, uint8_t n)
 Cette fonction sert à extraire le bit n (avec n=0..7) d’une valeur X composée de
8bits (octet).
Exemple : X= 5 ; //X=B00000101
Bita = bitRead(X,0) ; // Bita = 1
Bitb = bitRead(X,3) ; // Bitb = 0
3/ La difficulté que vous avez rencontré pour faire clignoter les 3 LEDs « en même
temps » avec des vitesses différentes (3 tâches) est causée par l’utilisation de la fonction
délay. En effet, delay est une fonction bloquante , c-à-d , elle ne permet pas l’exécution
d’autre instruction tant que la temporisations n’est pas achevée. L’autre manière d’insérer
une temporisation dans le programme, tout en ayant la possibilité d’exécuter d’autre
instructions, est l’utilisation des fonctions micros() et millis() (d’ailleurs la fonction
delay utilise micros() en boucle) :

27
 micros - prototype: unsigned long micros()
 retourne le nombre de microsecondes depuis que lancement du programme.
cette fonction est basée sur le timer integré au microcontrôleur et comporte un
compteur de microsecondes (variable non sigée 32bits qui s’incrémente tous les
microsecondes). Vu sa taille (32 bits), ce compteur déborde et revient à zéro
tous les 70 minutes.
 millis - prototype: unsigned long millis()
 même principe que la fonction micros, mais retourne le nombre de
millisecondes depuis que lancement du programme.
à l’inverse de la fonction delay, millis (ou micros) ne permet pas d’insérer
directement une temporisation mais permet de le faire d’une manière indirecte comme le
montre le programme Blink suivant :
Programme 4:
/* Blink sans delay */
uint32_t tempoStart;
uint8_t ledState;
void setup() {
pinMode(13, OUTPUT); // configure LED as output
digitalWrite(13, HIGH); // initialization LED as output
ledState = 1; // save LED status
timeReference = millis(); // starting temporisation
}
void loop() {
if (millis()-tempoStart >= 1000) { // temporization end detection
ledState = !ledState; // toggle LED status
tempoStart = millis(); // re-starting temporisation
digitalWrite(ledPin, ledState); // LED state actualisation
}
}
les programmes 5,6 et 7 suivants sont presque équivalents au programme précédent.
Programme 5:
/* Blink sans delay */
uint32_t tempoStart, currenttime;
uint8_t ledState;
void setup() {
pinMode(13, OUTPUT); // configure LED as output
digitalWrite(13, HIGH); // initialization LED as output
ledState = 1; // save LED status
timeReference = millis();} // starting temporisation
void loop() {
currenttime = millis();
if (currenttime- tempoStart >= 1000) { // tempo end detection
ledState = !ledState; // toggle LED status
tempoStart = currenttime; // re-starting temporisation
digitalWrite(ledPin, ledState); } // LED state actualisation
}

28
/* Blink sans delay */
uint32_t tempoStart, currenttime;
void setup() {
pinMode(13, OUTPUT); // configure LED as output
digitalWrite(13, HIGH); // initialization LED as output
ledState = 1; // save LED status
timeReference = millis(); // starting temporisation
}
void loop() {
currenttime = millis();
if (currenttime- tempoStart >= 1000) { // tempo end detection
digitalWrite(ledPin, digitalRead(13)); // LED state
actualisation timeReference = currenttime; // re-starting
temporisation
}
}

Programme 7:
/* Blink sans delay */
uint32_t tempoEnd;
void setup() {
pinMode(13, OUTPUT); // configure LED as output
digitalWrite(13, HIGH); // initialization LED as output
ledState = 1; // save LED status
tempoEnd = millis() + 1000;
}
void loop() {
currenttime = millis();
if (currenttime >= tempoEnd) { // tempo end detection
digitalWrite(ledPin, digitalRead(13)); // LED state actualisation
tempoEnd = currenttime + 1000; // Next
}
}
4/ Tester le programme 4, puis comparer-le avec les autres programmes. Réécrire le
programme de contôle des 3 leds sans l’utlisation de delay.
Application 3 - Commander une Led avec un bouton poussoir
Le programme suivant illustre un exemple d’utilisation d’un port d’entrée. Le circuit à
réaliser comprend une LED, un boutton poussoir et une résistance de pull down . Réaliser
le circuit correspondant et tester le programme pour décrire le fonctionnement en
complétant le tableau 2.1.

Bouton 1 lesPin LED


Appuyé  0  1
Relâché  0  1
Tableau 2.1 : état de la LED en fonction de l’état du bouton

29
Programme 8:
/* utilisation d’un bouton */
const uint8_t buttonPin = 2; // the number of the pushbutton port
const uint8_t ledPin = 12; // the number of the LED port
uint8_t buttonState; // variable for reading the pin status can be
boolean
void setup() {
pinMode(ledPin, OUTPUT); // configure LED as output
pinMode(buttonPin, INPUT); } // configure pushbutton as input
void loop() {
buttonState = digitalRead(buttonPin);
if (buttonState == HIGH)
digitalWrite(ledPin, HIGH); // turn LED on
else
digitalWrite(ledPin, LOW); } // turn LED off

Application 4 - Ajouter une entrée de commande de vitesse de clignotement


1/ Adapter le circuit précédent et le programme correspondant pour contrôler la vitesse de
clignotement de la LED de la manière suivante:
 Si le bouton est relâché (Entrée correspondante=1: Vitesse de clignotement = 0.5HZ)
 Si le bouton est appuyé (Entrée correspondante=0: Vitesse de clignotement = 2HZ)
2/ Modifier le programme et le circuit précédent pour avoir le même fonctionnement en
exploitant les résistances pull up intégrées aux ports d’entrées utilisées.
3/ Modifier le ciruit et le programme pour pouvoir choisir entre 4 vitesses de clignotement
differente (0.5HZ , 1HZ, 2HZ et 10HZ) en utlisant 2 boutons de selection.
Application 5 - Commander la LED par transition
Dans les applications précédentes, la LED est commandée par état du bouton (appuyé ou
relâché) c-à-d par le niveau de l’entrée correspondante (1 ou 0). Pour les applications
pratiques, les boutons poussoirs sont aussi utilisés pour créer des actions associés à des
appuis sans maintien, c-à-d, des actions associées aux transitions du signal d’entrée (front
montant ou déscendant). Reprenons l’application 3. Le programme est modifiée pour
permettre d’allumer la LED par un appui sans maintien sur le bouton (programme 9).
Programme 9:
/* Commander une LED par un bouton */
const uint8_t buttonPin = 2; // pushbutton port number
const uint8_t ledPin = 12; // LED port number
boolean currentButtonState; // variable to save button status
boolean previousButtonState; // variable to save button old status
boolean ledState; // variable to save LED status
void setup() {
pinMode(ledPin, OUTPUT); // configure LED port as output
pinMode(buttonPin, INPUT); // configure pushbutton port as input
previousButtonState = digitalRead(buttonPin); //initialization
digitalWrite(ledPin, LOW); //initialization
currentLedState = 0; } //initialization
void loop() {
currentbuttonState = digitalRead(buttonPin);

30
if (currentbuttonState!= PreviousbuttonState) { //transition detection
PreviousbuttonState = CurrentButtonState; // update button state
if (buttonState==1) { // rising edge detected
ledState = !currentLedState;
digitalWrite(ledPin, ledState); }} // toggle the LED

2/ Etudier et tester le programme. selon ce programme, est ce que l’état de la led s’actualise
suite à la détection d’un front montant ou descendant du signal d’entrée ?

3/ Modifier le programme de l’application 4 pour obtenir le fonctionnement suivant: à


chaque appui sur le seul bouton de sélection, la vitesse de clignotement change dans l’ordre
suivant : 0.5HZ  1HZ 2HZ 10HZ0.5HZ…

Application 6 - Etudier le fonctionnement d’un circuit


1/ Dérouler le programme suivant pour déterminer l’état de LED selon les conditions
données par le tableau 2.2 et la figure 2.16 (les 2 boutons sont utlisés avec des pull up)
Programme 10:
/* utilisation de 2 boutons */
const uint8_t ledPin = 13; // choose the port for the LED
const uint8_t inputPin1 = 2; // choose the input port (button 1)
const uint8_t inputPin2 = 3; // button 2
void setup() {
pinMode(ledPin, OUTPUT); // configure LED as output
pinMode(inputPin1, INPUT); // configure pushbutton as input
pinMode(inputPin2, INPUT); // configure pushbutton as input
digitalWrite(ledPin, LOW); }
void loop() {
if (digitalRead(inputPin1) == LOW)
digitalWrite(ledPin, LOW); // turn LED OFF
else if (digitalRead(inputPin2) == LOW)
digitalWrite(ledPin, HIGH); // turn LED ON
}

Bouton 1 Bouton 2 inputPin1 inputPin2 LED


appuyé relâché
appuyé appuyé
relâché relâché
relâché appuyé
Tableau 2.2 : état de la LED en fonction des différents cas

bouton1

bouton2
allumée
LED
éteinte
t
Figure 2.16: chronogramme à compléter en fonction des états de bouton1 et bouton2
31
2/ Réaliser le circuit et vérifier la réponse.
Si vous remarquez une divergence par rapport au fonctionnement théorique, ce ci est
certainement dû au problème de rebonssiment du bouton poussoir. En effet, le contact
mécanique, suivant l’appui ou le relachement d’un bouton, peut rebondir plusieurs fois ce
qui engendre l‘scillation de la valeur du port associé entre 0 et 1 avant de se stabiliser à une
valeur comme le montre la figure 2.17. Ces oscillation peuvent perturber le bon
fonctionnement du circuit.
Le remède à ce problème consiste à utiliser une technique d’anti-rebond (debouncing)
matériel ou logiciel. L’anti-rebond matériel consiste à intégrer ou associer un filtre passe
bas au bouton. Le filtrage le plus simple consiste à placer un condensateur en parallèle avec
le bouton poussoir (utilisé en pull up ou pull down)(Fig. 2.18.a). D’autre montage de
filtrage sont donnés par la figure 2.18. La solution logicielle consiste à ignorer la durée de
rebondissement et de considérer l’entrée quand le signal devient stable comme le montre le
programme 7.

Figure 2.17: Effet de rebondissement d’un bouton poussoir

(a) (b) ©

Figure 2.18: Anti-rebond à (a) Circuits RC (b) circuits logiques et (c) circuits intégrés
Question : Considérons le circuit 2.18.a. Quelle est la valeur de la constante de temps de
charge et de décharge du condensateur pour R1= 10k, R2=500 C=100nF. Donner l’allure du
signal Vb en réponse à Va donné par la figure 2.19.

32
Va

0.1
T(ms)

Figure 2.16: Vb en fonction des états de bouton B


3/ Reprenons le ciruit de l’application 4 pour utiliser des anti-rebonds RC simple en
plaçant des condensateurs céramique de 10 nF en parallèle avec les boutons. Réaliser le
circuit et vérifier le fonctionnement du circuit. Quel est l’inconvinient de cette méthode ?
4/ Reprenons le ciruit de l’application 4 pour utiliser des anti-rebonds logiciels en insérant
une temporisation après la détection du changement de l’état de l’entrée comme le montre
le programme 8. Charger ce programme et vérifier le fonctionnement du circuit. Quel est
l’inconvinient de cette méthode ?
Programme 11:
/* utilisation de 2 boutons avec anti-rebonds*/
const uint8_t ledPin = 13; // port 13 for the LED
const uint8_t inputPin1 = 2; // Button1 port
const uint8_t inputPin2 = 3; // button2 port
void setup() {
pinMode(ledPin, OUTPUT); // configure LED as output
pinMode(inputPin1, INPUT); // configure pushbutton1 port as input
pinMode(inputPin2, INPUT); // configure pushbutton2 port as input
digitalWrite(ledPin, LOW); //iniialization
}
void loop() {
if (digitalRead(inputPin1) == LOW)) {
delay(10); // bouncing period to ignore
if (digitalRead(inputPin1) == LOW)) // check input again
digitalWrite(ledPin, LOW); // turn LED OFF
}
else if (digitalRead(inputPin2) == LOW)) {
delay(10); // bouncing period to ignore
if (digitalRead(inputPin2) == LOW) ) // check input again
digitalWrite(ledPin, HIGH); // turn LED ON
}
}
Une autre méthode d’anti-rebon logiciel consiste à séparer la surveillance des états des
boutons de l’utilisation réelle de ces états. Dans la programme 12, la variable pinState
sauvegarde la valeur de pin d’entrée sujet à des oscillations. Les instructions rajoutées
permettent de filtrer les oscillations de l’entrée pour n’activer/désactiver le boutton
(buttonState = 1/0) que lorsque le signal d’entrée devienne stable. Le programme 12
comporte ce genre d’anti-rebond pour bien utiliser le bouton de l’application 3 (en pull
down).

33
Programme 12:
/* utilisation d’un bouton avec anti-rebond*/
const uint8_t buttonPin = 2; // the number of pushbutton port
const uint8_t ledPin = 12; // the number of LED port
uint8_t buttonState = 0; // variable to save button
state
uint8_t pinState, counter = 0; // variable to save pin state
void setup() {
pinMode(ledPin, OUTPUT); // configure LED as output
pinMode(buttonPin, INPUT); } // configure pushbutton as input
void loop() {
pinState = digitalRead(buttonPin);
if (pinState == HIGH){
if (buttonState == 0)
counter++;
delay(1);}
else {
counter = 0;
buttonState = 0;
}
if (counter>10) {
buttonState = 1;
counter = 0;
}
if (buttonState == 1)
digitalWrite(ledPin, HIGH); // turn LED on
else
digitalWrite(ledPin, LOW); } // turn LED off
}

Application 7 – débogage lors de l’exécution


1/ Pratiquer le débogage pour corriger le programme suivant, de sorte que la LED clignote
comme il se doit.
Programme 13:
/* utilisation d’un bouton */
const uint8_t buttonPin = 2; // the number of the pushbutton port
const uint8_t ledPin = 13; // the number of the LED port
uint8_t buttonState = 0; // variable for reading the pin status
void setup() {
pinMode(ledPin, OUTPUT); // configure LED as output
pinMode(buttonPin, INPUT);} // configure pushbutton as input
void loop() {
buttonState = digitalRead(buttonPin);
if (buttonState = HIGH)
Blinking(brocheLED); // LED Blinking
else
Offing(brocheLED); // LED off

34
}
void Blinking(const int LED){
digitalWrite(LED, HIGH);
delay(1000);
digitalWrite(LED, LOW);
delay(1000);
}
void Offing(const int LED ){
digitalWrite(LED, LOW);
}

2/ Dans les applications temps réel, il est utile d’estimer le temps d’exécution des
différentes instructions et fonctions du programme. Le programme suivant permet
d’estimer le temps d’exécution de l’instruction « buttonState = digitalRead(buttonPin) »
en utilisant le moniteur série.

Programme 13:
/* utilisation d’un bouton */
const uint8_t buttonPin = 2;
const uint8_t ledPin = 13;
uint8_t buttonState;
void setup() {
pinMode(ledPin, OUTPUT);
pinMode(buttonPin, INPUT);
Serial.begin(9600);
}
void loop() {
uint32_t start = millis();
buttonState = digitalRead(buttonPin);
Serial.println(millis()-start);
if (buttonState == HIGH)
Blinking(brocheLED);
else
Offing(brocheLED);
}
void Blinking(const int LED){
digitalWrite(LED, HIGH);
delay(1000);
digitalWrite(LED, LOW);
delay(1000);
}
void Offing(const int LED ){
digitalWrite(LED, LOW);
}

35
Application 8 - Augmenter le nombre de LEDs et varier le motif de clignotement
Connecter 8 LEDs à des ports d’entrée puis écrire un programme pour faire clignoter les
LEDs de la façon suivante : après la mise sous tension de la carte, les LEDs clignotent 10
fois selon motif1 avec une période d’une seconde. Après, les LEDs clignotent infiniment
selon motif2 en basculant l’état des LEDs chaque 500ms.

Motif1 Motif2

Application 9 - Améliorer le programme avec l’utilisation de boucles et de tableaux


Si vous avez écris le programme de l’application 7 en utilisant les boucles et les tableaux
passez directement à l’application suivante.
Dans le cas de manipulations de plusieurs ports, les instructions de déclaration de
constantes de pin, de configuration et de traitement deviennent trop nombreuses :
const int Pin23 = 23; pinMode(Pin23, OUTPUT); digitalWrite(Pin23, HIGH);
const int Pin24 = 24; pinMode(Pin24, OUTPUT); digitalWrite(Pin24, HIGH);
const int Pin25 = 25; pinMode(Pin25, OUTPUT); ...
const int Pin26 = 26; pinMode(Pin26, OUTPUT);
const int Pin27 = 27; pinMode(Pin27, OUTPUT);
const int Pin28 = 28; pinMode(Pin28, OUTPUT);
...
Procéder ainsi est exact au regard de la programmation. Mais c’est long, fastidieux,
source d’erreurs et cela rend la modification et la correction problématiques. En général,
lorsqu’il faut rédiger des lignes de code répétitives, il est toujours possible de simplifier le
programme en utilisant des boucles et des tableaux. Dans le cas donné en exemple, on peut
utiliser un tableau pour les constantes de numéro de pin:
Exemple :
const byte pin[] = {22, 23, 24, 25, 26, 27, 28};
// Déclaration et initialisation d'un tableau : Ce tableau facilitera la
configuration et la manipulation des ports en utilisant les boucles:
for (int i = 0; i < 7; i++)
{
pinMode(pin[i], OUTPUT); // Les ports utilisées sont des entrées
digitalWrite(pin[i], HIGH); // Appliquer 1 pour chaque port
}
Ou simplement :
Exemple :
for (int i = 22; i <= 28; i++)
{
pinMode(i, OUTPUT); // Les ports utilisées sont des entrées
digitalWrite(i, HIGH); // Appliquer 1 pour chaque port
}
Ici toutes les broches se suivaient, mais cela reste applicable lorsque c’est pas le cas :

36
Exemple :
const byte OutPin[] = {23, 25, 27, 29, 31, 33, 35};
const byte InPin[] = {5, 7, 11};
void setup() {
for (int i = 0; i < 7; i++) {
pinMode(OutPin[i], OUTPUT); // congigurés en sorties
digitalWrite(Outpin[i], LOW); // initialisés à 0
}
for (int i = 0; i < 3; i++) {
pinMode(InPin[i], INPUT); // configurés en entrées
}
}

Application 10 - Un chenillard simple


Le chenillard est un mouvement lumineux qui se produit en allumant et éteignant
successivement une série de lampes ou LEDs. L'effet se traduit par un déplacement de
la/les lumières dans un sens choisi. Réaliser un chenillard simple de 8 LEDs: une seule
LED est allumée à la fois, la lumière se déplace de gauche à droite ( ou de haut en bas ….).

Réaliser le circuit et écrire le programme correspondant.

Application 11 - un chenillard à plusieurs motifs


1/ Réaliser un chenillard doté de 2 entrées de sélection afin de choisir le motif selon la
description suivante :
 E1E2=00 : un chenillard simple (une seule LED allumée)
 E1E2=01 : un chenillard double (défilement double)
 E1E2=10 : un chenillard simple inverse (une seule LED éteinte)
 E1E2=11 : un chenillard bouble inverse (2 LEDs éteintes)
E1E2=00 E1E2=01 E1E2=10 E1E2=11

2/ Modifier le circuit et le programme de cette application pour obtenir le fonctionnement


suivant: à chaque appui sur le seul bouton de sélection, le motif change dans l’ordre
suivant: motif1  motif2  motif3  motif4  motif1 …

37
2.5 Exercices
Exercice 1 - un chennillard à entassement
Réaliser un chenillard à entassement de 8 LEDs à 2 sens (gauche ou droite) et à 2
vitesses (rapide et lente). L’effet d’entassement : les lumières se déplacent et s'accumulent.

Exercice 2 - Un chennillard simple 8 LEDS avec moins de ports


On désire réaliser un chenillard simple de 8 LEDs avec un délai de 500ms (durée
d’allumage d’une LED), mais supposons que nous sommes contraints par le nombre de
ports à utiliser. Réaliser ce chenillard en utilisant :
1- Trois ports seulement en utilisant:
a. un décodeur 3 entrées 74HC238
b. le registre à décalage 74HC595
2- Deux ports seulement et le registre à décalage 74HC164
3- Un port seulement et les composants nécessaires.

38
TP N°3
Le langage Arduino (II):
Les Entrées/Sorties analogiques

1. Manipuler les ports d’entrée analogiques;


2. Manipuler les ports de sortie "analogiques" (PWM);
3. Applications avec des capteurs, LED RVB et un moteur courant continu (CC).

3.1 Rappels sur les composant à utiliser


Les composants requis pour ce TP sont :
 Potentiomètre
 Photoresistance
 Capteurs de température
 LED RVB
 Moteur courant continu 6V

3.1.1 Le potentiomètre
un potentiomètre est à la base un diviseur de tension reglable qui possède 2 bornes
d’extrémité et une borne centrale (Figure 3.1). Si on applique 0V et 5v aux bornes
d’extrémité, la tension collectée à la borne centrale est une tension analogique comprise 0V
et 5V et varie en fonction de la variation de la position de la tige de reglage (exemple : 2.5V
au milieu). Pour ce TP le potentiomètre sera utilisé pour générer des tensions analogiques
comprises 0V et 5V pour manipuler les entrées analogiques de la carte Arduino.

Équivalent à:

Figure 3.1 : Symbole et différents type de potentiomètres

39
3.1.2 La photorésistance
La photorésistance est un composant électronique dont la résistance varie en fonction
de la l’intensité lumineuse incidente (Figure 3.2). Plus cette luminosité est élevée, plus la
résistance diminue. À l’inverse, plus il fait sombre, plus la résistance augmente (Figure
3.3). Malheureusement, les photorésistances sont des transducteurs peu précis, non linéaire
et ayant un temps de réponse élevé et une grande tolérance. Nous les utiliserons donc pour
des applications qui ne demandent que peu de précision (pour des applications de détection
pas de mesure).

Figure 3.2 : Symbole et types de photorésistance

Figure 3.3 : Caractéristiques d’une photorésistance( extrait de datasheet)


40
La photorésistance est principalement utilisée dans un montage en pont diviseur de
tension. Le schéma de montage généralement utilisé pour relier une photorésistance à une
entrée analogique d’une carte Arduino est le suivant :
Vcc

Port Arduino
analogique

10K VR

Figure 3.4 : Exemple de montage d’utilisation d’une photorésistance avec Aduino.

3.1.3 Capteurs de température analogiques


Les capteurs de la série LM3x sont des capteurs de température électroniques de
précision et faciles à calibrer. Les LM34, LM35 et LM335 par exemple, fonctionnent selon le
même principe. La différence entre eux est qu'ils fournissent une sortie analogique
proportionnelle calibrée à différentes unités de mesure:
 Le LM34 : sortie  degrés Fahrenheit, entre -50 ° F et 300 ° F(-45 ° C et 149 ° C ).
 Le LM35 : sortie  degrés Celsus, entre -55 ° C et 150 ° C.
 Le LM335 : sortie  degrés Kelvin, entre 218 ° K et 423 ° K (-55 ° C et 150 ° C).
Le capteur LM35 fonctionne avec des tensions d'alimentation comprise entre 4 volts et
30 volts (figure 3.5) et capable de mesurer des températures allant de -55°C à +150°C (selon
le modèle) avec une precision d’environ +/-0.5°C. Ces capteurs produisent une tension
lineairement proportionnel à la temperature : Donc, il suffit de mesurer la tension en
sortie du capteur pour en déduire la température : Chaque degré Celsius correspond à une
tension de +10mV (Figure 3.6). Donc, la relation entre la tension fournie par le capteur (en
Volts) et la température T (en °C) est :

Sortie
analogique
LM35

Figure 3.5: Symbole, brochage et types de LM35

41
Figure 3.5: Caractéristiques de LM35 (Extrait data sheet)
Le capteur de temperature LM35 a une tension de decalage de zero, ce qui signifie que la
sortie est 0V Iorsque la temperature est à 0°C. Ainsi, pour la valeur de temperature
maximale (150 °C), la tension de sortie maximale du capteur serait 150 * 10 mV = 1,5V. Le
montage suivant permet de mesurer la température directement sur un port d’arduino ( le
condensateur dit de decouplage est optionnel et permet d’améliorer la mesure).
Vcc

100nF
Port Arduino
LM35
analogique

Fig 3.6 : Montage simple de mesure de la température avec Aduino.


Le LM335 similairement à LM35 possède 3 broches et il est facilement interfacé à un
microcontrôleur à travers ses entrées analogiques.

Sortie
analogique

broche
d’étalonnage

Figure 3.7: Symbole, brochage et types de LM335

42
Ces principales caractéristiques sont (Figure 3.8) :
 La tension de sortie du capteur est linéairement proportionnelle à la mesure de la
température à +10mV/°K. Pour avoir la température en °C, il faut convertir la
valeur mesurée en utlisant la formule suivante : T(°C)≈T(°K)-273.
 À 0°K, la tension de sortie est de 0V et le capteur est étalonné à 2,982V à
298,15°K (25 °C).
 L’équation qui relie la tension fournie V (en Volts) à la température à mesurer
T (en °K) est : .

Figure 3.8: Principales caractéristiques de LM335 (extrait de datasheet)


La figure 3.9 donne un montage typique de mesure de la température avec un port
analogique d’arduino. La résistance R1 dépend de la tension d’alimentaion noté V+ et se
calcule de la manière suivante :
 Selon le datasheet, l’étalonnage de la sortie à 2.98V pour la température de 25C
est réalisé sous la condition Ir=1mA.
 Donc pour 5V et I=1mA et Vcapteur=2.98V la valeur de R1 sera :

Figure 3.9: Montage basique de l’utlisation de LM335 (extrait de datasheet)

43
3.1.3 Les LED RVB
Cette LED est composée de trois LEDs de couleurs rouge, verte et le bleue. Elle possède
donc 4 broches et existe en deux modèles : à anode commune et à cathode commune
(Figure 3.10 et 3.11).

Common
cathode

Équivalent à:
Common
anode

Fig 3.10 : Types de LED RVB.

Fig 3.11 : Caractéritiques d’une LED RVB.

La couleur de la lumière émise résulte de la composition des trois couleurs primaires : il


est donc possible de créer n’importe quelle couleur du spectre lumineux visible en
mélangeant ces lumières de couleurs mais de différentes intensités (analogiques).
Généralement les intensités des trois LEDs sont contrôlées par des ports de
microcontrôleur malgé que le signal généré par un port d’un microcontrôleur est un signal
numérique pouvant pendre uniquement les valeurs 0 et 5V ( un port numérique ne peut
fournir une autre valeur de tension). Ce ci est possible grace à l’utilisation des signaux à
Modulation de Largeur d’Impulsion (MLI) communément appelée PWM (Pulse Width
Modulation) dont le principe est le suivant : Pour un signal carré périodique (porteuse) de
période T et de rapport cyclique (exprimé en %) appliqué à une charge ( LED,
lampe, moteur ….), la puissance est fonction de la valeur moyenne (Figure 3.12). Donc,
cette technique permet d’obtenir une allure analogique en variant la largeur d’impulsion.

44
U(t)
t
E
Umoy(a) =aE

T
Fig 3.12 : Valeur moyenne d’un signal PWM.
En appliquant ce signal de rapport cyclique à une LED par exemple, le résultat est
semblable à celui que l’on obtiendrait en contrôlant la luminosité de la LED avec une
tension analogique continu égale à .

Fig 3.13 : Principe de contôle de la luminosité d’une LED par PWM


La figure 3.13 donne un exemple de montage pour contrôler une LED RVB à cathode
commune avec la carte Arduino (Les valeurs des résistances de protection à calculer en
fonctions des caractéristique des LEDs).

Rr

Ports PWM
Arduino
Rv

Rb

Fig 3.13 : Exemple de montage pour contrôler une LED RVB avec Arduino
45
3.1.5 Les moteurs CC
Le moteur courant continu (CC) est un composant qui assure la conversion d’énergie
électrique en énergie mécanique de rotation et la transmission du mouvement à l’ensemble
mécanique qui lui est associé en aval ; souvent par l’intermédiaire d’un réducteur qui
diminue la vitesse de rotation tout en augmentant le couple (figure 3.12). Le moteur
courant continu (DC) est caractérisé par une constante de vitesse, et une pente
vitesse/couple. Le courant est proportionnel à la charge ; et la vitesse est proportionnelle à
la tension d’alimentation.

Figure 3.12 : Exemple de moteur CC 5V

1.3.2 Principe de commande d’un moteur CC


En réalité, les moteurs à courant continu sont des convertisseurs de puissance:
 Soit ils convertissent l’énergie électrique absorbée en énergie mécanique lorsqu’ils
sont capables de fournir une puissance mécanique suffisante pour démarrer puis
entraîner une charge en mouvement. On dit alors qu’ils ont un fonctionnement en
moteur.
 Soit ils convertissent l’énergie mécanique reçue en énergie électrique lorsqu’ils
subissent l’action d’une charge entraînante. On dit alors qu’ils ont un
fonctionnement en générateur.
En mode « moteur », l'énergie électrique est convertie en énergie mécanique. En mode
« générateur » ou « dynamo », l'énergie mécanique est convertie en une énergie électrique
capable de se comporter comme un frein.

1.3.3 Montages de commande d’un moteur CC


Nous présentons 3 montages de commande de base:
 Commander le moteur dans un seul sens à une vitesse constante :
M

UM

Ue

Figure 3.13: montage de base de commande d’un moteur CC.

46
Principe de fonctionnement : si l’on applique une tension continu positive à la base
du transistor, ce dernier commute en conduction ce qui permet d’alimenter le
moteur avec la tension continu et commencera à tourner à une vitesse qui dépend
de la tension appliqué à ces borne ( ). La tension d’alimentation étant fixe, ce
circuit ne permet pas de changer la vitesse de rotation ni d’inverser son sens (il faut
inverser la polarité de la tension pour avoir ce dernier comportement).
La diode placée en parallèle du moteur, appelée diode de roue libre, sert d’une
part à protéger le transistor de la surtension induite par le moteur, et d’autre part à
permettre l’autofreinage du moteur :
 si on supprime l’alimentation d’un moteur en marche, ce dernier ne s’arretera
pas instantanément et continuera à tourner par la trainée de son inertie. Cela va
engendrer une tension au bornes du moteur (mode générateur). Cette tension
induite, qui peut atteindre plusieurs dizaines ou centaines de Volts est très
dangereuse pour le transistor. L’utilisation de diode en mode passant permet
d’empecher l’accumulation de la tension induite et la garde proche de la tension
d’alimentation du moteur en faisant circuler un courant « de décharge ».
 d’un autre côté, la tension induite par le moteur est opposée à celle que fournit
l’alimentation qui était appliqué à ce dernier. Or, étant donné que la la tension
induite est réappliquée à ses bornes, le couple et la tension s’opposent et cela a
pour effet de ralentir le moteur.

 Commander le moteur dans un seul sens à une vitesse variable :


Pour faire varier la vitesse du moteur avec le montage précédent on peut faire
varier la tension d'alimentation pour faire varier la tension à ses bornes.
Cependant, avec cette technique, une partie importante de l'énergie est consommée
par le dispositif d’alimentation. L’alternative consiste à utliser des signaux PWM.

UM(t)
Ue(t)
TON
TON E
M

UM(t)
UMmoy

t E T
T

Ue(t)

Figure 3.14: Commande de vitesse d’un moteur CC avec PWM


Dans ce cas, la vitesse de rotation du moteur dépendra de la valeur moyenne de
la tension appliquée à ses bornes , si est un signal à rapport cyclique
égale à ⁄ , la vitesse du moteur sera égale à avec
est la vitesse maximale du moteur obtenu lorsque on applique une tension à
rapport cyclique égale à . De ce fait, la vitesse du moteur est variée par la variation
du rapport cyclique du signal de commande .

47
 Commander le moteur dans deux sens à une vitesse variable :
Pour contrôler la polarité aux bornes du moteur afin de changer le sens de
rotation, on utilise le montage appelé pont en H donné par la figure 3.15. Dans son
principe de base, le pont H est un assemblage de 4 transistors bipolaires (ou
MOSfet) monté de telle façon que le courant puisse passer soit dans un sens, soit
dans l'autre dans la charge (le moteur par exemple).

T1 T2

Tensions de
E M commandes
T3 T4

Figure 3.15 : Le pont H de commande de moteur CC


Les 4 transistors, symbolisés par des interrupteurs T1, T2, T3 et T4 dans la
figure 3.16, sont montés en pont et permettent de commander le sens de rotation du
moteur : Lorsque T1 et T4 sont fermés ( transistors saturés), le moteur tourne dans
un sens (sens 1). Lorsque T2 et T3 sont fermés, le moteur tourne dans l'autre sens
(sens 2)(Figure 3.16). Pour varier la vitesse, il faut appliquer le signal PWM de
commande au premier transistor de la branche activée et une tension continue au
deuxième transistor (figure 3.17).

T1 T2 T1 T2

M M

T3 T4 T3 T4

Figure 3.16: principe de la variation du sens de rotation.

T1 T2

T3 T4

Figure 3.17 : Variation de la vitesse avec le montage H


48
Il existe des circuits intégrés qui servent de pont en H tel que L293 (Figures 3.18 et 3.19).
Ce circuit intègre 2 ponts en H , donc 4 demi-ponts , ce qui permet de contrôler 2 moteurs
en double sens ou 4 moteurs en sens unique. Ce circuit existe en 2 versions : le L293 et le
L293D. Le D fait référence aux diodes qui protège le circuit L298 des courants induits par
les bobinages du moteur CC. La différence entre la L293 et la L293D est donc simple : la
L293 ne contient pas ces diodes.

Pont A
Pont B

Figure 3.18 : Brochage du circuit L293

(a) (b)

Figure 3.19 : Structure interne (a) de L293 et structure simplifiée de L293D (b)

49
Les broches d’alimentation :
VSS Alimentation de la logique de commande (5V).
(A connecter par exemple, à la borne +5V d'Arduino).
VS Alimentation de puissance des moteurs. (à connecter par
exemple, la borne + d’une batterie 9V)
GND Doit être raccorder à la masse (GND) de la source
d'alimentation de puissance VS et à la masse de la source
d'alimentation de VSS (donc GND Arduino).
La partie gauche commande le premier pont (Pont A: demi-pont 1 et 2) (Idem pour la
partie droite qui commande le deuxième pont (Pont B: demi-pont 3 et 4) :
OUTPUT1/OUTPUT2 Broches à raccorder à la charge (le moteur).
(1Y, 2Y)
INPUT1/INPUT2 Broche de commande du Pont H :
(1A, 2A) - INPUT1 commande demi-pont 1
- INPUT2. Commande demi-pont 2.
(à connecter aux ports de commande d’Arduino)
ENABLE1 Commande l'activation du premier Pont H (Pont A : demi-
(1,2EN ou ENA) pont 1 et 2). Permet d'envoyer (ou pas) la tension
d’alimentation sur les sorties de raccordement du moteur
(OUTPUT1/OUTPUT2) :
 Si ENABLE1 = 0, le pont H (A) est déconnecté et le
moteur ne fonctionne pas.
 Si ENABLE1 = 1, le pont H (A) est connecté aux
sorties et le moteur fonctionne dans un sens ou l'autre
ou pas en fonction des tensions appliquée sur INPUT1
et INPUT2.
(à connecter à un port de commande d’Arduino)
Les tableaux des figures 3.20 et 3.21 détaillent le comportement du circuit en fonction
des niveaux logiques sur les broches de commande du circuit (ENABLE1 , ENABLE2,
INPUT1 , INPUT2, INPUT3, INPUT4) pour 2 applications (Figure 3.22) :

Figure 3.20 : Commandes des demi-pont (1) et (2) avec ENABLE1(EN)

Figure 3.21 : Commandes des demi-pont (3) et (4) avec ENABLE2(EN)


2- Commande de moteur en double sens: pour faire fonctionner le moteur dans les
sens right ou left, il faut appliquer 1 aux entrées INPUT1 ou INPUT2 respectivement

50
en plus de l’application de 1 à l’entrée d’activation ENABLE1. Si INPUT1 et INPUT2
sont à 0 le moteur s’arrête mais de 2 manières très différente selon l’état de
ENABLE1 :
 Si ENABLE1=0 : arrêt sans freinage ( sortie en haute impedance (Z) →
moteur déconnecté ) le moteur tourne librement jusqu’à s’arrêter de
lui-même (Free running motor stop)
 Si ENABLE1=1 : arrêt avec freinage de la tension induite et les diodes
de roues libre. (Fast motor stop)
3- Commande de moteur en sens unique: pour faire fonctionner le moteur dans un seul
sens (right ou left), il faut appliquer 1 à l’entrée adéquate (INPUT1 ou INPUT2) en
plus de l’application de 1 à l’entrée d’activation ENABLE1. Pour changer la vitesse on
applique un signal PWM à ENABLE. Si INPUTx et à 0 le moteur s’arrête selon de 2
manières déjà expliqué.

Figure 3.22 : Commandes en simple et double sens.


Enfin, la figure 3.23 donne un exemple de commande avec Arduino de 2 moteurs en
double sens et avec vitesse variable :
Alimenté
par la carte
Port PWM
Vitesse
Port digital Port digital
Sens 1 Sens 1

Port digital Port digital


Sens 2 Sens 2
Port PWM
Vitesse
Pile 9V

51
Figure 3.23 : Exemple de montage de commande avec Arduino

3.2 Ports d’entrée analogiques


Le Microcontrôleur de la carte Arduino Mega comporte un convertisseur
analogique/numérique multiplexé (partagé) par 16 cannaux (Les ports notés A0…A15 de la
carte Arduino mega). Ce convertisseur fournie une valeur numérique de 10 bits ce qui
correspond à 1024 niveaux distincts dans l’intervalle par défaut [0V 5V]. Il est possible
aussi de changer la tension de référence qui pemet de changer cet intervalle à [0V Vref] : la
tension Vref peut être une tension interne (1.1V ou 2.56V) ou externe appliquée au port
Aref.
Par défaut, le résultat de conversion est donc un entier Vc entre 0 et 1023 (autrement
dit une précision de 5/1023≈0.0049 Volts c-à-d 4.9mV) ). Pour retrouver la tension
analogique mesurée Vm on applique la règle de trois :
Vm=Vc*5/1023
En langage Arduino, la fonction analogRead est utilisée pour lire les entrées
analogiques:
- analogRead – prototype: Uint16_t analogRead(uint8_t pin) : Lit la valeur
numérique fournie par le convertisseur après la conversion de la tension analogique
présente sur la broche (pin) spécifiée. Les broches analogiques sont utilisées en
entrée. Il n'est pas nécessaire de les configurer avant d’utiliser la fonction
analogRead.

Exemples:
A- mesurer une tension analogique :
Le programme suivant illustre la correspondance entre la valeur analogique mesurée
périodéquement, comprise entre 0V et 5V appliquée à l’entrée analogique A0 avec un
potentiomètre, et sa valeur numérique fournie par le convertisseur analogique numérique
(comprise entre 0 et 1023). (Réaliser le circuit et visualiser les valeurs de la tesion
mesurées et les valeurs numériques correspondantes):
Programme 1:
/* mesurer et afficher une tension */
uint16_t ValueConv; // variable to save the converted digital value
float ValueMes; // variable to save the calculated analog value
void setup()
{
Serial.begin (9600);
}
void loop()
{
ValueConv = analogRead(A0);
ValueMes = ValueConv * 5.0 / 1023 ;
Serial.print("valeur fournie par le convertisseur = ");
Serial.println(ValueConv);
Serial.print("tension mesurée= ");
Serial.print(ValueMes);
Serial.println(" V");

52
Serial.println();
delay(1000); // an acquisition every 1s
}
Le délai introduit à la fin de Loop() reflète la fréquence d’échantillonnage de l’entrée. Ici
nous avons choisis de prendre une mesure toutes les secondes ce qui correspond à une
fréquence de 1Hz. Cette fréquence est approximative car la période d’acquisition est égale à
1s plus le temps d’exécution des instructions de la fonctions loop(). Ce temps peut être
mesuré approximativement avec la fonction millis (voir référence du langage). La
fréquenced’échantillonage doit être adaptée à la dynamique de l’entrée.
Le traceur série (Outils→Traceur série) permet aussi de visualiser l’évolution d’une entrée
analogique sous la forme graphique. Son utilisation est similaire au moniteur série :
insérer les instructions pour envoyer sur le port série la valeur à visualiser (nombre entier
ou à virgule) avec un retour chariot. Le programme suivant trace les valeurs fournies par le
convertisseur (on peut aussi visualiser les valeurs mesurées en remplaçant
Serial.println(ValueConv) par Serial.println(ValueMes).

Programme 2:
/* mesurer et afficher une tension */
uint16_t ValueConv; // variable to save the converted digital value
float ValueMes; // variable to save the calculated analog value
void setup()
{
Serial.begin (9600); }
void loop()
{
ValueConv = analogRead (A0);
ValueMes = ValueConv * 5.0 / 1023 ;
Serial.println(ValueConv);
delay(1000); } // an acquisition every 1s
On note que pour visualiser plusieurs courbes, il suffit d'envoyer la série de valeurs
séparées par des espaces, des tabulations ou des virgules terminé par un retour chariot :
Programme 3:
/* mesurer et afficher une tension */
uint16_t ValueConv; // variable for saving the converted digital value
float ValueMes; // variable for saving the calculated analog value
void setup()
{
Serial.begin (9600); }
void loop()
{
ValueConv = analogRead (A0);
ValueMes = ValueConv * 5.0 / 1023 ;
Serial.print(ValueConv);
Serial.print(",");
Serial.println(ValueMes);
delay(1000); } // an acquisition every 1s

53
B- Utiliser un capteur de lumière
L’exemple suivant montre l’utilisation d’une photorésistance connectée au port analogique
A0. Ce programme contrôle l’allumage d’une LED en fonction de la luminosité ambiante :
Programme 4:
/* détecter la lumière avec une photorésistance*/
const uint8_t LedPin=13;// variable of LED controlling port
uint16_t ValueConv; // variable to save the converted value
uint16_t threshold=0.1*1023; // thershold of detection = 10% of maximum
void setup()
{
pinMode(LedPin,OUTPUT);
Serial.begin (9600);
}
void loop()
{
if (analogRead(A0)>threshold) // if light level detected>10% of maximum
digitalWrite(LedPin, HIGH)
else
digitalWrite(LedPin, LOW)
delay(100); // an acquisition every 100ms
}
1- Réaliser le circuit selon la figure 3.4 puis observer l’état de la LED en fonction des
différents niveaux de lumière appliquée afin de décrire le fonctionnement.
2- Utiliser le traceur série pour observer le niveau de la tension d’entrée. Sur la (les)
figure(s) capturées reportée la condition de l’illuménation appliquée et l’état correspondant
de la LED.
2- Déterminer par raisonnement (sans la carte) le fonctionnement du circuit si on inverse
les polarités ( la photorésistante connectée à la masse et la résistance à Vcc) puis vérifier la
réponse avec la carte.
C- Utiliser un capteur de température
Le programme suivant affiche sur le moniteur série la température mesurée avec LM35 :
Programme 5:
/* mesurer la température avec LM35 */
uint16_t ValueConv; // variable to save the converted digital value
float Temp; // variable to save the calculated temperature
void setup()
{
Serial.begin (9600); }
void loop()
{
ValueConv = analogRead (A0);
Temp = 100*(ValueConv * 5.0 / 1023);
Serial.print("Température mesurée= ");
Serial.print(Temp);
Serial.println(" °C");
delay(1000); // an acquisition every 1s
}
54
3.3 Ports de sortie PWM ("Sorties Analogiques")
Le microcontrôleur de la carte Arduino possède des sorties qui permettent de générer des
signaux PWM. Ces sorties sont les ports 2 – 12 de la carte Arduino Mega (ils sont repérés
par le symbole ~). Ces ports sont physiquement liés à des compteurs/Timers. Ces timers
après configuration fonctionnent indépendamment du processeur. La génération d’un
signal s’effectue avec la fonction suivante :
- analogWrite(uint8_t pin, uint8_t largeur_impulsion) : Génère sur la pin spécifiée un
signal de 500Hz et de largeur d’impulsion spécifiée. La largeur d’impulsion est comprise
entre 0 et 255 tel que (Figure 3.24): 0  rapport cyclique = 0% et 255  rapport cyclique =
100%.

Fig 3.24 : Exemples de PWM généré avec analogWrite


Exemple: Générer et visualiser un signal PWM:
Ce programme génère un signal PWM sur le port 12. Téleverser ce programme et
visualiser le signal avec l’oscilloscope pour vérifier la période du signal PWM et le rapport
cyclique.
Programme 6:
/* générer PWM */
const uint8_t pwmPin = 12; // the number of the PWM pin
float rapport_cyclique=0.3; // variable for reading the converted
void setup()
{
pinMode(pwmPin, OUTPUT);
analogWrite (pwmPin,rapport_cyclique*255);
}
void loop() { }
55
3.4 Applications
Application 1 - Allumer graduellement et périodiquement une LED:
Ce programme allume une LED graduellement jusqu’à la brillance maximale:
Programme 1:
/* brillance graduelle */
const uint8_t pwmPin = 12; // the number of the PWM pin
uint8_t Pulse=0; // variable to change Ton of PWM signal
void setup()
{
pinMode(pwmPin, OUTPUT);
}
void loop()
{
Pulse ++;
analogWrite (pwmPin,Pulse);
delay(5);
}
1/ Tester le programme avec la carte,
2/ Déterminer puis vérifier l’effet de remplacement de Pulse ++ par Pulse += 50 et
delay(5)par delay(500)
3/ Ecrire un programme qui alume et éteint graduellement une LED par l’appui sur un
bouton poussoir (sans maintien).
Application 2 - Contrôler la luminosité d’une LED avec un potentiomètre
Ecrire un programme qui permet de varier la luminosité de la LED L en utilisant un
potentiomètre. Réaliser le circuit et vérifier le programme.
Modifier ce programme pour varier la vitesse de clignotement de la LED L en utilisant le
potentiomètre.
Application 3 - Contrôler une LED RVB en fonction
La couleur émise d’une LED RVB résultante de la combinaison de 3 valeurs comprises
entre 0 et 255 est très similaire au résultat obtenu par combinaison de couleurs dans les
logiciels de dessin :

Fig 3.25 : Exemple de composantes R, V et B d’une couleur

56
Programme 2:
/* Contrôler une LED RVB */
const uint8_t led_verte = 9;
const uint8_t led_bleue = 10;
const uint8_t led_rouge = 11 ;
void setup()
{
pinMode(led_verte, OUTPUT);
pinMode(led_bleue, OUTPUT);
pinMode(led_rouge, OUTPUT);
}
void loop()
{
analogWrite(led_rouge, X);
analogWrite(led_verte, Y);
analogWrite(led_bleue, Z) ;
}
1 / Réaliser le circuit puis observer le résultat pour différente valeur de X , Y et Z.
2/ Si on note redlntensity , greenlntensity et bluelntensity les composantes R V et B
respectivement (comprise entre 0 et 255), des effets de changement graduel entre 2 couleur
sont obtenu de la manière suivante :
a) Du rouge au vert : augmenter greenIntensity de 0 à 255 avec
redIntensity=255-greenIntensity et blueIntensity=0
b) Du vert au bleu : augmenter bluelntensity de 0 à 255 avec
greenIntensity=255-blueIntensity et redIntensity=0
c) Du bleu au rouge : augmenter redIntensity de 0 à 255 avec
blueIntensity=255-greenIntensity et greenIntensity=0
Ecrire un programme pour produire ces effets séquentiellement et périodiquement.
Application 5 : Différents cas de contrôle moteur CC
En utilisant le circuit L293D et un moteur CC alimenté par une pile de 9V, élaborer
puis vérifier les montages et les programmes de commande pour chacun des cas suivant :
 Commande de moteur dans le sens horaire uniquement à vitesse maximale
admissible.
 Commande de moteur dans les 2 sens à vitesse maximale en fonction d’une entrée
de sélection de sens de rotation.
 Commande de moteur dans le sens antihoraire à vitesse variable reglée par un
potentiomètre
 Commande de moteur dans les 2 sens à vitesse variable reglée par un
potentiomètre. Le basculement d’un sens à un autre sev fait par un appui sur un
bouton poussoir (sans maintien).
 Commande de moteur dans les 2 sens à vitesse variable reglée par un
potentiomètre. Le basculement d’un sens à un autre sev fait par un appui sur un
bouton poussoir (sans maintien).
 Commande de moteur selon la séquence suivante : tourne dans le sens horaire à
vitesse maximale pendant 5 scondes, puis continue dans le même sens à petite
vitesse (20% de la vitesse maximale) pendant 3 secondes et enfin tourne dans le
sens contraire à vitesse maximale pendant 8 secondes et ainsi de suite….

57
3.5 Exercices
Traiter un seul exercice au choix.
Exercice 1
On désire réaliser un circuit de commande de store automatique composé de 2 capteurs
(lumière et vent) et un moteur. Le principe de fonctionnement est le suivant :
- Lorsque la luminosité du soleil dépasse le seuil fixé pendant au moins 3 minutes le
store descend. Si la luminosité retombe en dessous du seuil réglé le store remonte au
bout d'un quart d'heure.
- Si la vitesse du vent dépasse le seuil fixé pendant 10 secondes consécutives, la
remontée du store s’effectue pour sa protection. Lorsque cette vitesse retombe en
dessous du seuil, le store reste relevé pendant une durée de 12 minutes avant
d'autoriser une redescente. A l'issue de cette temporisation, le store redescendra si la
luminosité du soleil dépasse le seuil de température et la vitesse du vent ne dépasse
pas le seuil du vent.

Des capteurs de fin de course sont utilisés pour détecter


Exercice 2
On désire réaliser une application basée sur le capteur sonore KY-037. Ce capteur de
haute sensibilité fourni une tension analogique proportionnelle au bruit détecter par le
microphone.

- Donner les caractéristiques et le principe de fonctionnement de ce capteur.


- Réaliser une commande d’allumage de LED avec le claquement des mains.

58
TP N°4
Le langage Arduino (III) :
Les Librairies Arduino (mini projet)

1. Découvrir les librairies Arduino;


2. Utiliser des bibliothèques intégrées : LiquidCrystal, keyboard, SPI, Wire;
3. Installer une nouvelle bibliothèque : Keypad, DC_Motor, …
4. Réaliser une interface homme machine avec LCD et boutons/clavier

Les composants requis pour ce TP sont :


 L’afficheur LCD
 Mini clavier 16 touches
 Moteur pas à pas, ServoMoteur , moteur DC
 Modules SPI et I2C.

1.1 Librairies Arduino


Comme toute autre platforme, Arduino permet l’utilisation de bibliothèques dédiées à
des périphériques intégrés (Timer, interface série, …) et à l’utilisation de modules
externes tels que les afficheurs, les moteurs, les capteurs…. Certaines bibliothèques
usuelles sont déjà intégrées à Arduino IDE mais une infinité de bibliothèques développées
par la communauté Arduino peuvent être rajoutées (installées). Ces bibliothèques facilite
la progrommation des applications lorsque ces dèrnières augmentent en complexité.
Parmis ces bibliothèques, on cite les bibliothèques standard intégrées à Arduino IDE:

59
1.2 librairie d’afficheur LCD
La majorité des systèmes embarqués sont dotés d’un afficheur pour permettre
l’intéraction de l’utlisateur avec le système (interface homme machine IHM ou HMI). les
types d’afficheurs « de base » regroupent les afficheurs LCD (Liquid Crystal Display), les
afficheurs OLED (Organic LED), les afficheurs tactiles TFT(Thin Film Transistor) et les
afficheurs 7 segments (figure 4.1).

LCD (4x20 caractères) OLED(128x64 pixels, 1 pouce)

TFT(240x320 pixels, 2.4 pouces) 7 segments (4 digits)


Fig 4.1 : Quelques types d’afficheurs

1.2.1 Rappels sur les afficheurs LCD


Les afficheurs LCD sont monochromes et existent sous différentes formes et tailles : 8,
16, 20, 24, 32 et 40 caractères et plusieurs lignes. Ces afficheurs sont disponibles, selon le
modèle, en 14 et 16 pins ou 4pins seulement (interface série I2C). La figure 4.3 donne le
brochage d’un LCD 2x16.

(a) (b) (c)


Fig 4.2 : Afficheur LCD (a) à 16 pins (b) à 4 pins avec interface série, (c) détails

60
Fig 4.3 : Brochage de LCD 2x16

Le tableau ci-dessous présente la définition des pins et leurs fonctions (modèle à 16pins):
Pin Description
Vss Masse
Vdd Alimentation (5V)
Vee réglage du contraste d'affichage (connecté à la troisième borne
du potentiomètre de réglage) (fonction facultative : Reliée à masse si pas de réglage ).
RS (Registre Select) :
0 les bits transférés via D7..D0 sont interprétés comme une commande.
1 les bits transférés via D7..D0 sont interprétés comme une donnée (un caractère à
afficher). ( Reliée à un port de microcontrôleur ).
R/W (Read/Write) :
0 envoi de commandes ou de données à l’afficheur LCD
1 lecture des informations à partir du LCD
La lecture à partir du LCD n’est pas beaucoup utilisée. Donc, Cette pin est généralement
reliée à la masse (écriture seulement).
En (Enable) : utilisé pour initier le transfert de commandes ou de données entre le
module et le microcontrôleur :
- écriture : les données sont transférées uniquement sur un front descendant sur
cette patte.
- lecture : les données sont valides après le front montant, et ces données demeurent
tant que cette patte de validation est au niveau logique haut.
( Reliée à un port de microcontrôleur ).
D7…D0 sont les huit lignes de données (D0 à D7) qui peuvent être utilisées selon 2 modes :
- Mode 8bits : les données sont transférées un octet à la fois.
- Mode 4 bits : les données sont transférées en deux fois 4-bits. Dans ce cas, seules les
quatre lignes de données supérieures (D4 à D7) sont reliée à des ports de microcontrôleur.
Le mode 4-bits est fréquemment utilisé car il a l'avantage de nécessiter moins de
ports d'E/S du microcontrôleur pour communiquer avec l'écran LCD.
K , A Bornes de la LED de rétroéclairage (intégrée)
A -> Anode ( Reliée à 5V à travers une résistance )., K -> Cathode ( Reliée à la masse).

61
Pour commander un afficheur LCD il faut implémenter (programmer) des procédures
pour initialiser et envoyer les commandes ou les données à afficher avec des délais très
strictes. A titre d’exemple, la figure 4.4 montre la procédure d’initilisation de l’afficheur
après la mise sous tension. La programmation de ces procédures est possible mais
fastidieux, par consequent il vaut mieux utiliser directement une bibliothèque spécialisée.

Fig 4.4 : Routine d’initialisation d’n afficheur LCD 16x2

1.2.2 bibliothèque LiquidCrystal


Cette librairie ne demande pas une installation et permet à une carte Arduino de
contrôler un afficheur LCD basé sur le circuit intégré Hitachi HD44780 (ou compatible),
ce qui est le cas de la plupart des afficheurs alphanumériques LCD disponibles. La librairie
est intégrée à l’IDE Arduino et fonctionne aussi bien en mode 4 bits qu'en mode 8 bits. Les
fonctions de base sont (Voir Références):

62
Fonctions d'initialisation
begin()
Fonctions d'écriture
print()
write()
Fonctions de gestion de l'écran
clear()
display()
noDisplay()
Fonctions de positionnement du curseur
home()
clear()
setCursor()
Fonctions modifiant l'aspect du curseur
cursor()
noCursor()
blink()
noBlink()
Fonctions de contrôle du comportement du curseur
autoscroll()
noAutoscroll()
leftToRight()
rightToLeft()
Fonctions d'effets visuels
scrollDisplayLeft()
scrollDisplayRight()
Fonction de création de caractère personnalisé
createChar()

63
Le tableau suivant rappelle le constructeur de classe et les fonctions les plus utilisée :
LiquidCrystal - Constructeur de création
Description: Crée un objet de type LiquidCrystal en définissant les ports utilisées avec le
LCD et son mode de fonctionnement.
Prototype: LiquidCrystal nom(rs, enable, d4, d5, d6, d7); // mode 4 bits - RW non utilisé
(le plus simple!)
LiquidCrystal nom(rs, rw, enable, d4, d5, d6, d7); // mode 4 bits - RW utilisée
LiquidCrystal nom(rs, enable, d0, d1, d2, d3, d4, d5, d6, d7); // mode 8 bits -
RW non connectée
LiquidCrystal nom(rs, rw, enable, d0, d1, d2, d3, d4, d5, d6, d7); //mode 8
bits - RW utilisée
Description:  nom: le nom de la variable LiquidCrystal déclarée
 rs: le numéro de la broche de l'Arduino qui est connecté à la broche RS
de l'afficheur LCD.
 rw: le numéro de la broche de l'Arduino qui est connecté à la broche
RW de l'afficheur LCD (optionnel)
 enable: le numéro de la broche de l'Arduino qui est connecté à la broche
E(nable) de l'afficheur LCD

d0, d1, d2, d3, d4, d5, d6, d7: les numéros des broches de l'Arduino qui
sont connectées aux broches correspondantes des broches de données de
l'afficheur LCD.
Retourne: --
Exemple: #include <LiquidCrystal.h>

LiquidCrystal lcd(12, 11, 10, 5, 4, 3, 2); // déclare une


variable LiquidCrystal appelée lcd
// mode 4 bits et RW n’est pas utilisée

Begin() – fonction d’initialisation


Prototype: nom.begin(colonnes, lignes)
Description: - nom: une variable de type LiquidCrystal
- colonnes: le nombre de colonnes de l'afficheur LCD utilisé
- lignes: le nombre de lignes de l'afficheur LCD utilisé
Retourne: --
Exemple: void setup() {
lcd.begin(20,2); // Initialise le LCD avec 20 colonnes x 2
lignes

}

print() – fonction d’affichage


Prototype: nom.print("texte")
nom.print(data)
nom.print(data, BASE)
Description: - nom : une variable de type LiquidCrystal
- "texte" : une chaîne de caractères
- data : la donnée à afficher (char, byte, int, long, float ou string)
- BASE (optionel): la base dans laquelle vous voulez afficher les nombres :
BIN , DEC pour décimal ( base par défaut) et HEX pour hexadécimal.
Retourne: --
Exemple: lcd.print("hello, world!");

64
clear() – fonction d’effacement
Prototype: nom.clear()
Description: nom: une variable de type LiquidCrystal
Retourne: --
Exemple: lcd.clear(); // // efface écran et met le curseur en haut à
gauche
delay(10); // pour laisser temps effacer écran

setCursor() – fonction de positionnement


Prototype: nom.setCursor(colonne, ligne)
Description: - nom: une variable de type LiquidCrystal
- colonne: la colonne à laquelle positionner le curseur (ATTENTION : Les
numéros de colonnes sont 0..15.
- ligne: la ligne à laquelle positionner le curseur (ATTENTION : 0 est le
1ère ligne, 1 la 2ème, etc..).
Retourne: --
Exemple: lcd.print("UEF1212...") ;
// affiche le texte à (0,0)=(1er caractère, 1ère ligne)
delay(2000); // pause de 2 secondes

lcd.setCursor(9, 1) ;
// positionne le curseur à (9,1) = (10ème caractère, 2ème ligne)
lcd.print("...TP4") ; // puis affiche le texte

1.2.3 Applications
Application 1 – manipuler les fonctions principales
Ce programme de manipuler les 4 fonctions de base qui sont:
- Begin
- Clear
- Print (et write)
- setCursor
Afin d’utiliser ces fonctions, il faut d’abord inclure la bibliothèque LiquidCrystal au début
du programme avec des méthodes suivantes :
- l’inclure directement en saississant : #include <LiquidCrystal.h>
- l’inclure à partir de croquisinclure une bibliothèqueLiquidCrystal
Programme 1:
/* affichage */
#include <LiquidCrystal.h>
LiquidCrystal afficheur(11, 12, 4, 5, 6, 7); // mode 4 bits
//RW not used (le plus simple!)
Byte i=0;
void setup()
{
afficheur.begin(16,2); // LCD type set
afficheur.print("Start"); // text display
delay(3000) ;
afficheur.print("continue at last position"); // text display
delay(3000);
afficheur.clear (); // clear display

65
afficheur.print("after clear"); // text display
delay(3000);
afficheur.clear (); // clear display
afficheur.print("* <-- (0,0)"); // text display
delay(3000);
afficheur.setCursor(4,1); // text display
afficheur.print("(15,1) --> *"); // text display
delay(3000);
afficheur.clear(); // clear display
afficheur.write(" write '65': ");
afficheur.write("65");
afficheur.setCursor(0,1); // text display
afficheur.print(" print '65': ");
afficheur.print("65");
delay(3000);
afficheur.clear(); // clear display
afficheur.write(" write 65: ");
afficheur.write(65);
afficheur.setCursor(0,1); // text display
afficheur.print(" print 65: ");
afficheur.print(65);
delay(3000);
}
void loop()
{
afficheur.clear (); // clear display
afficheur.print("i= ");
afficheur.print(i);
afficheur.setCursor(0,1); // text display
afficheur.print("also i= 0x");
afficheur.print(i,HEX);
delay(1000);
i++ ;
}
1/ Réaliser le circuit puis charger le programme et observer l’affichage pour bien assimiler
le contrôle de l’afficheur avec les différentes fonctions.
2/ Compléter le circuit pour commander l’état d’une led (éteinte/ allumée) avec l’appui
sans maintien d’un bouton poussoir avec affichage de l’état de la Led sur LCD.
3/ Modifier le système précédent pour réaliser un thermomètre (mesurer et afficher la
température). Ce système active la Led de rétroéclairage lorsqu’il fait sombre pour rendre
l’affichage plus lisible.
Composants à utiliser :
- Capteur de température LM35
- Une photorésistance

66
1.3 Bibliothèque pour clavier matriciel
Le clavier matriciel (Keypad en anglais) permet d’introduire des valeurs numériques et
des symboles. Les claviers matriciels se composent de plusieurs boutons arrangés sous
forme d’une matrice contenant une ou plusieurs lignes (notées L1, L2, …) et plusieurs
colonnes (notées C1, C2, …) (figure 4.5).

Fig 4.5 : Exemples de claviers matriciels de type 1x6, 3x4 et 4x4

1.3.1 Rappels sur les keypad 4x4


Le clavier matriciel 4X4 est commandé de la manière suivante (avec des résistances pull
up):

1- Connexions matérielles :
a. des pins du microcontrôleur configurées en sorties sont connectées aux
colonnes (C1, C2, C3, C4) du clavier.
b. D’autres pins configurées en entrées sont connectées aux lignes (L2, L1, L3,
L4) du clavier. Pour fonctionner correctement des résistances de pull up sont
placés sur ces pins.

67
Fig 4.5 : Brochage d’un clavier matriciel 4x4

Selon cette configuration :

 Les valeurs par défaut (aucune touche appuyée) des entrées sont 1.
 si une touche est appuyé et si la colonne correspondante est à 0 alors
sa ligne est à 0.

Fig 4.5 : Principe de détection d’un appui de touche

2- Programmation :
a. A travers les 4 sorties, le programme active les colonnes à 0
séquentiellement une par une.
b. Pour chaque colonne activée, le programme lit l’état des entrées (lignes) :
lorsque aucune touche n’est pressée la valeurs lue est 0b1111. Quand on
appuie sur une touche ; la ligne correspondante sera détectée (égale à 0)
lorsque sa ligne est activée (mise à 0),

68
1.3.2 Utilisation de la bibliothèque KeyPad
La bibliothèque KeyPad demande une installation et offre des fonctions permettant de
simplifier l’utilisation du clavier matriciel 4x4 mais peut être adapté à des claviers de type
4x1, 4x2, ou 4x3. L’installation d’une bibliothèque peut s’effectuer de 2 manières
différentes :
1- Télécharger le fichier .zip de la bibliothèque à partir de (lien) puis l’’installer à
partir de croquisinclure une bibliothèqueAjouter à la
bibbliothèque .ZIP
2- Installer directement à partir de croquisinclure une bibliothèquegérer
les biliothèques . Taper keypad dans la zone de recherche puis selectionner la
biliothèque Keypad by Mark Stanly et lancer l’installation.

La principale fonction de Keypad library est getKey()


Keypad - Constructeur de création
Description: Crée un objet de type Keypad en définissant les broches utilisées avec le
clavier et son type.
Prototype: Keypad nom = Keypad( makeKeymap(keys), rowPins, colPins,
rows, cols )
 nom: le nom de l’objet clavier.
 keys: matrice rowsxcols qui définie les valeurs des
touches.
 rowPins: la liste des ports Arduino connectés aux
lignes du clavier.
 colPins: la liste des ports Arduino connectés aux
colonnes du clavier.
 rows, cols: le nombres de ligne et de colonnes
respectivement
ce constructeur configure les ports d’E/S utilisés lors de création de
l’objet.
Exemple: #include <Keypad.h>

const byte rows = 4; //four rows


const byte cols = 3; //three columns
char keys[rows][cols] = {
{'1','2','3'},
{'4','5','6'},
{'7','8','9'},
{'#','0','*'}
};
const byte rowPins[rows] = {5, 4, 3, 2}; // row ports
const byte colPins[cols] = {8, 7, 6}; // column portsKeypad

69
clavier = Keypad( makeKeymap(keys), rowPins, colPins,
rows, cols )
getKey - fonction de détection de touche appuyée
Description: Renvoie le code ASCII de la touche appuyé, sinon la valeur retournée est 0.
Cette fonction n’est pas blaquante et retourne une seule valeur si la touche
est appuyé en permanance.
Prototype:
char nom.getKey();
Exemple: touche = clavier.getKey();

1.3.3 Applications
Application 1 – Saisir et afficher la touche appuyé sur un keypad 4x4
Ce programme montre comment saisir simplement la touche appuyé qui sera affichée en
utlisant le moniteur série.
Programme 1:
/* saisi */
#include <Keypad.h>

const byte rows = 4; //four rows


const byte cols = 4; //three columns
char keys[rows][cols] = {
{'1','2','3','A'},
{'4','5','6','B'},
{'7','8','9','C'},
{'#','0','*','D'}
};
const byte rowPins[rows] = {5, 4, 3, 2}; // row ports
const byte colPins[cols] = {9, 8, 7, 6}; // column ports
Keypad clavier = Keypad(makeKeymap(keys), rowPins, colPins, rows, cols);
void setup()
{
Serial.begin(9600);
}
void loop()
{
char key = clavier.getKey();

if (key){
Serial.println(key);
}
}
1/ Réaliser le circuit puis tester le programme.

70
Application 2 – attribuer des actions aux touches
Ce programme montre comment saisir simplement la touche appuyé qui sera affichée en
utlisant le moniteur série.
Programme 1:
/* un affichage d’acceuil */
#include <Keypad.h>

const byte rows = 4; //four rows


const byte cols = 4; //three columns
char keys[rows][cols] = {
{'1','2','3','A'},
{'4','5','6','B'},
{'7','8','9','C'},
{'#','0','*','D'}
};
const byte rowPins[rows] = {5, 4, 3, 2}; // row ports
const byte colPins[cols] = {9, 8, 7, 6}; // column ports
Keypad clavier = Keypad(makeKeymap(keys), rowPins, colPins, rows, cols);
void setup() {
Serial.begin(9600);
pinMode(13,OUTPUT);
digitalWrite(13, LOW);
}
void loop() {
char key = clavier.getKey();
if(key) // Check for a valid key.
{
switch (key)
{
case '*':
digitalWrite(13, LOW);
Serial.println("eteindre");
break;
case '#':
digitalWrite(13, HIGH);
Serial.println("allumer");
break;
default:
Serial.println("pas de changement");
}
}
}
1/ Tester ce programme.
2/ Modifier le programme précédent pour allumer la Led avec le code "13" et l’éteindre
avec le code "89".
Rappelons qu’il est utile d’utiliser le type String, afin de construire facilement des chaines de
caractères comme le montre l’exemple suivant :
String code="" ; // déclaration : code est une chaine de caractère vide
code = code+"a" ; // code ="a"

71
code = code+"b" ; // code ="ab"

1.4 Application en automatique (Micro projet)


On se propose de réaliser un mini système comme l’on pourrait retrouver dans un
milieu industriel (en plus simple ici, bien sûr !) ou dans d’autres applications. Le but sera
de :
1- Acquérir des informations à partir de capteurs, clavier, boutons …
2- De faire un traitement en fonction des données pour contôler, superviser … les
résultat de ce traitement est une action : démarrer/arrêter un actionneur, affichage
de message sur un afficheur, déclenchement alarme …
3- Réaliser une interface homme machine pour intéragir avec le système (voir le micro
projet type).
Ce système doit être autonome et non connecté au PC pendant le fonctionnement (il
faut prévoir une alimentation et un affichage indépendant). Une réalisation miniature
soignée sera bien notée . Aucun rapport à préparer mais un exposé détaillé est demandé.
La date de l’exposé sera fixée selon les délais imposés par le département.
Le matériel disponible:

72
73
1.5 Réalisation de sheild Arduino (Micro projet facultatif)
Vu les grands problèmes rencontrés dans la manipulation des TPs spécialment à la
réalisation des monatages, nous étions obligés de remplacer les manipulatiosn pratiques
par la simulation afin de gagner du temps. Afin de permettre aux étudiants d’utiliser les
cartes matérielles tout en limitant le problèmes liés aux montages, il est indispensable
d’utiliser des sheilds dédiés aux différents TPs (voir l’exemple ci-dessous) . Donc , les
étudiants désirants réaliser des Sheilds Arduino mega, qui seront utilisés dans les TPs de
ce module, peuvent présenter leurs propositions.

74
TP N°5
Le langage Arduino (V) :
Les interruptions externes

Apprendre à utiliser les interruptions externes

1.1 Rappels sur le mecanisme et les sources d’interruption


En général, le principe de fonctionnement des interruptions est le suivant : à un
moment donné (aléatoire), un évènement interne ou externe particulier déclenche une
interruption. cet évènement peut être changement de la valeur d’une entrée, un
débordement d’un compteur, fin de conversion analogique numérique, réception de
donnée par le port série, …etc. L’exécution normale du programme (routine principale ou
loop()) est alors interrompue, et le microcontrôleur appelle une fonction particulière
appellée la routine d’interruption (ou Interrupt Service Routine ISR). Celle-ci exécute
alors un traitement particulier en réponse à l’événement déclencheur de l’interruption.
Après la fin d’exécution de L’ISR, le microcontrôleur reprend l’exécution du programme à
partir de l’endroit où c’est produit l’interruption .
Les sources d’intérruptions des microcontrôleurs sont très nombreuses et peuvent être
externes, à travers les ports d’E/S, ou interne générées par les périphériques intégrés tels
que les timers, converstisseurs analogiques numériques etc.
Pour les ports d’E/S, l’utilisation des interruptions externes et une bonne alternative à
la méthode de polling (interrogation) des ports pour détecter les évènements. Ceci permet
aussi d’éviter les risques de blocage et bien gérer l’energie de l’alimentation du système en
utilisant les modes de veille en attendant un évènement.

1.2 L’utilisation des interruptions externes


Pour le microcontrôleur de la carte Arduino mega. Les interruptions externes, notées
INTx, sont déclenchées par des ports spéciaux. Si autorisé, un changement de niveau sur
ces pins (changement d’état ou front) provoquera l’interruption. Les ports capables de
générer des interruptions externes sont les ports PD0..PD3 PE4 .. PE7 du microcontroleur
ATmega2560. Ces interruptions sont notées INT0..INT7 respectivement et correspondent
aux ports 21..18 2..3 de la carte Arduino mega (INT6 et INT7 ne sont pas accessibles).
L’utilisation d’interruption consiste à :
1- Autoriser l’interruption du port selectionné.
2- Ecrire la fonction qui comporte les instructions du traitement à effectuer en
réponse à l’évenement. Il est très important que les ISR aient un temps
d’exécution le plus court possible. On ne fera donc aucun calcul compliqué,

75
aucun appel à des fonctions longues comme un affichage sur un écran LCD
ou des temporisations. Une ISR ne peut pas être pas interrompue par une
nouvelle interruption. La nouvelle interruption ne sera prise en compte que
lorsque l’ISR en cours se terminera.
Dans le cas du compilateur AVR-GCC pour l’ATmega2560, il existe un ensemble de
fonction prédifinies pour gérer les interruptions appartenant à la bibliothèque
«avr/interrupt.h » (incluse par défaut) . Les fonctions de base sont (Voir Références):
attachInterrupt – fonction d’autorisation d’interruption
Prototype: void attachInterrupt(uint8_t INTnumber, void (*ISR_name)(void), int
mode);
void attachInterrupt(digitalPinToInterrupt(port), void
(*ISR_name)(void), int mode);
Description: - INTnumber: le numéro d’interruption concernée. Sur un Arduino mega, les
numéros 0 à 5 seront possibles et correspondent, dans l’ordre, aux ports
Arduino 21, 20, 19, 18, 2 et 3. On peut aussi utiliser directement le port
Arduino, la fonction digitalPinToInterrupt permet de déterminer le
numéro d’interruption correspondant.
- ISR_name: est la routine d’interruption qui sera appelée lorsque
l’interruption surviendra. Cette routine d’interruption est une fonction qui
ne renvoit rien et qui ne prend aucun argument: void ISR_name() { ... }.
Toutes les variables utilisées dans un ISR doivent être déclarées comme
«volatiles». Le compilateur n'optimisera pas le code en les attachant à des
registres, mais les stockera toujours dans la RAM.
- mode: indique le type de changement (évenement) qui provoquera
l’interruption. Les valeurs possibles pour mode sont :
 CHANGE : l’interruption est déclenchée quand la broche concernée
change d’état, c’est à dire passe de 0 à 1 ou bien de 1 à 0.
 RISING : l’interruption est déclenchée quand la broche concernée
passe de 0 à 1.
 FALLING : l’interruption est déclenchée quand la broche concernée
passe de 1 à 0.
 LOW : l’interruption est déclenchée quand la broche concernée est
0. Comme il s’agit d’un état et non d’un événement,
l’interruption sera déclenchée tant que la broche est 0. Par
conséquent, dès que l’ISR aura terminé son exécution, elle la
recommencera. L’exécution de loop() reprendra quand l’entrée
pass à 1.
Exemple: volatile uint8_t state = LOW;
void setup() {
pinMode(13, OUTPUT);
attachInterrupt(digitalPinToInterrupt(2), LedCont, RISING);
}
void loop() {}
void LedCont () {
state = !state;
}

detachInterrupt – fonction de désactivation d’interruption


Prototype: void detachInterrupt(uint8_t INTnumber)
void detachInterrupt(digitalPinToInterrupt(port));
Description: Cette fonction désactive l’interruption externe d’un port.
INTnumber: le numéro d’interruption autorisée à désactiver.
Exemple: detachInterrupt(0) ;

76
Les interruptions permettent aussi une meilleure gestion de l’energie de l’alimentation
spécialement pour les système à batterie. Ainsi , en attendant l’évènement, il sera possible
d’activer un mode de veille pour réduire la consommation.
Les microcontrôleurs supportent différents modes de veille permettant à l’utilisateur
d’adapter la consommation électrique aux besoins de l’application. Ceci est possible grâce
au système d’horloges indépendantes des différents modules intégrés. La figure 5.1
présente les différents systèmes d’horloge de l’ATmega 2560 et les sources de reprise (wake
up). Cette figure est utile pour comprendre les différents modes de veille afin de
sélectionner le mode approprié.

Fig 5.1 : Les différents modes de veille et les sources de réveil

Ainsi, le microcontrôleur ATmega possède 6 modes de veille qui permettent d’arrêter le


CPU et/ou modules périphériques (les Timer/Compteurs, l’interface SPI ….) pour réduire
la consommation en attente d’un évènement (extérieur ou intérieur) qui interrompe la
veille du système pour reprendre le fonctionnement normal. Les modes de gestion de
l’alimentation sont :
1. Idle mode stops the CPU while allowing the SRAM, Timer/Counters, SPI port,
and interrupt system to continue functioning.
2. Power-down mode saves the register contents but freezes the Oscillator, disabling
all other chip functions until the next interrupt or Hardware Reset.
3. Power-save mode, the asynchronous timer continues to run, allowing the user to
maintain a timer base while the rest of the device is sleeping.
4. ADC Noise Reduction mode stops the CPU and all I/O modules except
Asynchronous Timer and ADC, to minimize switching noise during ADC
conversions.
5. Standby mode, the Crystal/Resonator Oscillator is running while the rest of the
device is sleeping. This allows very fast start-up combined with low power
consumption.
6. Extended Standby mode, both the main Oscillator and the Asynchronous Timer
continue to run while the rest of the device is sleeping.

77
Les fonctions de la bibliothèque <avr/sleep.h> à inclure (ne demande pas
d’installation) permettent d’activer ces différents modes. Les principales fonctions sont:
set_sleep_mode et sleep_mode.
set_sleep_mode – fonction de configuration
Prototype: void set_sleep_mode(byte mode) ;
Description: Configure le mode de veille préciser par mode. Les valeurs que peut prendre
mode sont :
 SLEEP_MODE_PWE_IDLE.
 SLEEP_MODE_PWE_ADC
 SLEEP_MODE_PWR_DOWN
 SLEEP_MODE_PWR_SAVE
 SLEEP_MODE_STANDBY
 SLEEP_MODE_EXT_STANDBY

Exemple: set_sleep_mode(SLEEP_MODE_PWR_DOWN);

sleep_mode – fonction de mise en veille


Prototype: void sleep_mode() ;
Description: Met le microcontrôleur en veille selon le mode configuré par set_sllp_mode.
Exemple: set_sleep_mode(SLEEP_MODE_PWR_DOWN);

1.2.1 Applications
Application 1 – Comparer les mecanismes de polling et d’interruption
Etudier et tester ces programmes ces 3 programmes qui permettent le contrôl d’une Led
avec un bouton poussoir (la Led change d’état suite à un appui sans maintien) de trois
manières différentes :
Programme 1:
/* LED control by polling */
uint8_t state = LOW, PreviousButtonState, CurrentButtonState;
void setup() {
pinMode(13, OUTPUT); digitalWrite(13, LOW);
pinMode(18, INPUT);
PreviousButtonState = digitalRead(18);
digitalWrite(13,LOW);
}
void loop() {
CurrentButtonState = digitalRead(18);
if (CurrentButtonState != PreviousButtonState){
PreviousButtonState = CurrentButtonState;
if(CurrentButtonState == 1){
state = !state;
digitalWrite(13, state);
}
}
}

78
Programme 2:
/* LED control by interruption */
volatile uint8_t state = LOW;
void setup() {
pinMode(13, OUTPUT); digitalWrite(13, LOW);
attachInterrupt(digitalPinToInterrupt(18), IsrToggle, RISING);}
void loop() {
digitalWrite(13, state);
}
void IsrToggle() {
state = !state;
}

Programme 3:
/* LED control by interruption */
#include <avr/sleep.h>
volatile uint8_t state = LOW;
void setup() {
pinMode(13, OUTPUT); digitalWrite(13, LOW);
attachInterrupt(digitalPinToInterrupt(18), IsrToggle, RISING);
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
}
void loop() {
sleep_mode();
}
void IsrToggle() {
state = !state;
digitalWrite(13, state);}

79
TP N°6
Le langage Arduino (V) :
Noyau temps réel

1. Apprendre à utiliser un noyau temps réel

Les composants requis pour ce TP sont :


 L’afficheur LCD
 Mini clavier 16 touches
 Moteur pas à pas, ServoMoteur , moteur DC
 Modules SPI et I2C.

1.3 Présentation de FreeRTOS


Contrairement aux systèmes d'exploitation en temps réel typiques, FreeRTOS est
spécialement conçu pour les microcontrôleurs. Étant donné que les microcontrôleurs
disposent de ressources limitées, nous avons donc besoin d'un système d'exploitation
adapté aux ressources disponibles des microcontrôleurs. Il s'agit d'un noyau open source,
ce qui signifie qu'il peut être téléchargé gratuitement et utilisé dans des applications basées
sur RTOS. Cependant, il existe également deux variantes commerciales telles que
OpenRTOS et SafeRTOS.
Comme nous l'avons mentionné précédemment, en utilisant FreeRTOS, nous pouvons
nous assurer que chaque tâche d'Arduino aura un modèle d'exécution déterministe et que
chaque tâche respectera son délai d'exécution. En d'autres termes, il s'agit d'un
planificateur qui attribue des ressources CPU Arduino à chaque tâche selon un algorithme
de planification. Le système d'exploitation en temps réel dispose de différents algorithmes
de planification tels que :
1. Différence entre la planification préemptive et non préemptive
2. Qu'est-ce qu'un algorithme de planification
3. Ordonnancement monotone de taux
4. Date limite au plus tôt d'abord
5. Moins de laxisme d'abord

6. Difference Between Preemptive and Non-Preemptive Scheduling


7. What is a Scheduling Algorithm
8. Rate Monotonic Scheduling
9. Earliest Deadline First
10. Least Laxity First

80
1.4 Fonctionnalités FreeRTOS
Voici les principales fonctionnalités du noyau :

1. Programmateur de tranche de temps préemptif à priorité fixe


2. Communication inter-processus via les files d'attente
3. Gestion des tâches telles que la définition de la priorité des tâches, la suspension
des tâches, la suppression des tâches et le retard des tâches
4. Synchronisation des tâches avec les tâches Gatekeeper, Sémaphore et Mutex
5. Crochet de mesure du temps
6. Crochets de traçage du temps d'exécution
7. Logiciel de gestion des timers
8. Gestion des interruptions

1.5 Gestion des tâches FreeRTOS


Dans un système multitâche, une application peut comprendre de nombreuses tâches.
Si nous utilisons un processeur à un seul cœur, une seule tâche peut s'exécuter sur le
processeur à un moment donné. Par conséquent, une seule tâche sera en état d'exécution et
toutes les autres tâches seront en état de non-exécution. Cela signifie que dans les
applications basées sur RTOS, les tâches peuvent être en cours d'exécution ou non en
cours d'exécution.
L'état d'exécution d'une tâche peut être divisé en trois sous-états tels que l'état bloqué,
l'état prêt et l'état suspendu. La figure ci-dessous montre la durée de vie de transition d'une
tâche dans un système multitâche.

81
1.5.1 États des tâches FreeRTOS
 État bloqué : Une tâche peut être dans un état bloqué pour de nombreuses
raisons. Par exemple, une tâche est retardée en raison de la nature périodique de
la tâche et elle deviendra disponible périodiquement après chaque retard spécifié.
Une autre raison peut être due à une interruption d'attente ou à une attente de
ressource. Une tâche attend l'interruption externe ou une ressource telle qu'un
sémaphore binaire, un sémaphore de comptage et un mutex.
 État suspendu : Un état suspendu est également un substrat d'une tâche qui ne
s'exécute pas. Le programmeur d'application peut suspendre la tâche à l'aide de la
fonction API FreeRTOS vTaskSuspend() et reprendre la tâche à l'aide de la
fonction API vTaskResume(). Les tâches dans les états bloqués ou suspendus ne
peuvent pas être planifiées par un planificateur.
 État Prêt : Si une tâche n'est ni bloquée ni suspendue, elle sera prête. Les tâches
qui sont dans un état prêt sont prêtes à être exécutées dès que le processeur les
sélectionne conformément à une politique de planification.
Chaque fois qu'une tâche passe d'un état d'exécution à un état de non-exécution, un
changement de contexte se produit. Cela signifie qu'il enregistre ses valeurs de registres,
ses valeurs de variables temporaires, etc. dans son bloc de contrôle de tâche et la prochaine
fois qu'il entrera à nouveau dans l'état de fonctionnement, il commencera l'exécution à
partir du même point où il a quitté l'exécution. Pour démarrer l'exécution à partir du
même emplacement, il chargera à nouveau les valeurs du TCB dans les registres du
processeur.

1.6 Utlisation de FreeRTOS avec Arduino


Le RTOS utilisé dans ce TP est FreeRTOS. FreeRTOS est développé par Real Time
Engineers Ltd. Il s'agit d'un noyau de système d'exploitation en temps réel populaire et
open source. En outre, il est utilisé pour les appareils embarqués qui, en tant que
microcontrôleurs, Arduino. Il est principalement écrit en C mais certaines fonctions sont
écrites en assembleur. Il existe également SafeRTOS et OpenRTOS disponibles en ligne
qui sont similaires à FreeRTOS.

1.6.1 Installation FreeRTOS dans Arduino IE


L’installation de FreeRTOS s’effectue par la procedure usuelle d’ajout de bibliothèque
en utlisant le gestionnaire de bibiothèque (figure 6.1).

Fig 6.1 : Installation de FreeRTOS

82
1.6.2 Création des tâches
Les avantages du multitâche ne peuvent être obtenus qu'en effectuant chaque exécution
à l'aide de tâches. Par exemple, dans votre projet arduino, vous souhaitez mesurer la
température et afficher sa valeur sur l'écran LCD. Nous pouvons diviser ce projet en trois
tâches telles que :
1. Lire la valeur Arduino ADC
2. Convertisseur valeur ADC en température
3. Température d'impression sur l'écran LCD

De cette façon, nous pouvons également attribuer une priorité à chaque tâche en
fonction de la nature critique de la tâche. Par exemple, la lecture de la valeur ADC est la
plus importante et l'impression de la valeur de la température sur l'écran LCD est la tâche
la moins importante. Par conséquent, nous pouvons attribuer la priorité la plus élevée à la
tâche ADC et la plus faible à la tâche LCD.
La fonction xCreateTask est utilisée pour créer des tâches et les ajoute à la file
d'attente prête. Il faut 5 arguments comme entrées pour définir les caractéristiques de la
tâche :
xTaskCreate(MyTask_pointer, "task_name", 100, Parameter, Priority,
TaskHandle);
MyTask_pointer : Pointeur vers la fonction de tâche : ce premier argument de la
fonction de création de tâche est un pointeur vers une définition de fonction d'une tâche.
Parce que nous devons définir une tâche avec la fonction d'aide. Nous verrons plus loin
comment définir une fonction et passer ce pointeur vers une fonction en argument.
 task_name : cet argument est simplement le nom de la fonction/tâche que nous
allons créer.
 StackDepth : Taille de la pile en multitâche, chaque tâche/thread a sa propre
pile. Il définit la taille de pile d'une tâche en octets. Par conséquent, vous devez
vous assurer de sélectionner la taille de la pile en fonction de la complexité du
calcul. Par exemple, nous sélectionnons une taille de 100 octets dans cet exemple.
 Parameter: si nous voulons passer un pointeur vers une variable en tant
qu'argument de la fonction de tâche, nous pouvons utiliser cet argument. Sinon,
nous pouvons passer la valeur NULL. Cet argument est un pointeur vers une
variable que la tâche (fonction) peut recevoir.
 Priority : C'est un paramètre important car il est utilisé pour définir la priorité
des tâches. Nous définissons la priorité en passant des nombres comme
argument. Par exemple, si nous créons quatre tâches et leur assignons la priorité
0, 1,2 et 3. Par conséquent, zéro signifie la priorité la plus basse et 3 signifie la
priorité la plus élevée.
 TaskHandle : cet argument conserve le handle de la fonction que nous pouvons
utiliser pour modifier les fonctionnalités de la fonction telles que la suppression
d'une tâche, la modification de sa priorité, etc.
En résumé, nous pouvons créer plusieurs threads en utilisant xCreatTask. Mais il faut
fournir un nom et un nom de pointeur uniques pour chaque tâche.

83
1.6.3 Définition du modèle d'exécution des tâches
vTaskDelayUntil est utilisé pour définir une séquence déterministe d'exécution des
tâches. Par exemple, si nous avons quatre tâches et que nous voulons exécuter chaque
tâche après 100, 120, 130 et 140 ms, vTaskDelayUntil bloque la tâche pendant un temps
défini après sa première exécution. vTaskDelayUntil est différent de delay() de l'IDE
Arduino. Parce que delay() cale (stalls ) l'exécution du CPU. D'autre part,
vTaskDelayUntil retarde une tâche spécifique et le processeur continue d'exécuter d'autres
threads.

1.7 Exemple de démarrage FreeRTOS Arduino


1.7.1 Exemple de changement de tâche
Dans cet exemple de code, nous allons créer quatre tâches différentes à l'aide de
xTaskCreate avec des priorités différentes. 3 LED indiquent trois tâches et une LED
indique l'état inactif. Trois tâches sont libellées respectivement Tâche1, Tâche2 et Tâche3.
Ce code montre un exemple simple où nous contrôlons trois LED avec trois tâches
différentes. Chaque tâche s'exécute après un certain temps. Ce programme est similaire au
code Arduino typique, sauf que nous incluons le fichier de bibliothèque de FreeRTOS.
FreeRTOS suit à la fois la planification préventive et la planification coopérative (pre-
emptive scheduling and cooperating scheduling). Mais par défaut, cette API implémente
une planification de tranches de temps préemptive (pre-emptive time-slicing scheduling).
Cela signifie que les tâches à priorité élevée prévalent sur les tâches à faible priorité et que
les tâches à priorité égale utilisent une politique à temps partagé pour obtenir des
ressources CPU. Ce code crée quatre tâches avec des priorités différentes. Mais les trois
tâches sont périodiques. En raison de la fonction vTaskDelay(), chaque tâche passe à un
état de blocage pendant une durée spécifiée.

#include <Arduino_FreeRTOS.h>
void setup()
//Initialize the Serial Monitor with 9600 baud rate
{
Serial.begin(9600);
Serial.println(F("In Setup function"));
//Set the digital pins 8 to 11 as digital output pins
pinMode(8,OUTPUT);
pinMode(9,OUTPUT);
pinMode(10,OUTPUT);
pinMode(11,OUTPUT);

//Create three tasks with labels Task1, Task2 and Task3 and assign
the priority as 1, 2 and 3 respectively.
//We also create the fourth task labeled as IdleTask when there is no
task in
//operation and it has the highest priority.

xTaskCreate(MyTask1, "Task1", 100, NULL, 1, NULL);


xTaskCreate(MyTask2, "Task2", 100, NULL, 2, NULL);
xTaskCreate(MyTask3, "Task3", 100, NULL, 3, NULL);
84
xTaskCreate(MyIdleTask, "IdleTask", 100, NULL, 0, NULL);}

//We can change the priority of task according to our desire by


changing the numeric’s //between NULL texts.

void loop()

{
//There is no instruction in the loop section of the code.
// Because each task executes on interrupt after specified time
}

//The following function is Task1. We display the task label on


Serial monitor.

static void MyTask1(void* pvParameters)


{

while(1)

{
digitalWrite(8,HIGH);
digitalWrite(9,LOW);
digitalWrite(10,LOW);
digitalWrite(11,LOW);
Serial.println(F("Task1"));
vTaskDelay(100/portTICK_PERIOD_MS);
}
}

//Similarly this is task 2

static void MyTask2(void* pvParameters)

{
while(1)

{ digitalWrite(8,LOW);
digitalWrite(9,HIGH);
digitalWrite(10,LOW);
digitalWrite(11,LOW);
Serial.println(F("Task2"));
vTaskDelay(110/portTICK_PERIOD_MS);
}
}

//Similarly this is task 3

static void MyTask3(void* pvParameters)


{
while(1)

85
{
digitalWrite(8,LOW);
digitalWrite(9,LOW);
digitalWrite(10,HIGH);
digitalWrite(11,LOW);
Serial.println(F("Task3"));
vTaskDelay(120/portTICK_PERIOD_MS);
}
}

//This is the idle task which has the lowest priority and calls when
no task is running.

static void MyIdleTask(void* pvParameters)

{
while(1)
{
digitalWrite(8,LOW);
digitalWrite(9,LOW);
digitalWrite(10,LOW);
digitalWrite(11,HIGH);
Serial.println(F("Idle state"));
delay(50);
}
}
Dans cet exemple, task3 a la priorité la plus élevée et task_idle a la priorité la plus basse.
Par conséquent, vous verrez sur votre moniteur série que task3 s'exécutera en premier lors
de la première mise sous tension de la carte Arduino. Au contraire, task_idle qui est la
tâche la moins prioritaire s'exécutera à la fin ou lorsqu'aucune autre tâche n'est disponible
pour s'exécuter.
Comme vous pouvez le voir sur la sortie du moniteur série, la tâche de priorité la plus
basse (tâche inactive) s'exécute uniquement lorsque le processeur est libre et qu'aucune
autre tâche n'est disponible pour s'exécuter.
1. T1 : la tâche 3 commence à s'exécuter en premier, étant la tâche la plus prioritaire
qui est de trois. Après cela, il entre dans l'état de blocage pendant 120 ms.
2. T2 : après cela, la tâche 2 commence à s'exécuter car elle atteint maintenant la
priorité la plus élevée car la tâche 3 est en état de blocage. De même, il termine
également son exécution et passe à un état bloqué et y reste pendant 110 ms.
3. T3 : actuellement, Tâche3 et Tâche2 attendent la fin de l’état de blocage. Par
conséquent, la tâche 1 commence à s'exécuter car sa priorité est supérieure à la
tâche inactive. Par conséquent, il entre également dans l'état de fonctionnement
et termine son exécution et passe en mode de blocage pendant 120 ms.
4. T4 : maintenant, toutes les tâches de haute priorité ont terminé leur exécution et
elles sont dans un état bloqué en attente de la fin de leur temps de blocage. Par
conséquent, le processeur continue d'exécuter, idle_task jusqu'à ce qu'une tâche
de haute priorité sorte d'un état de blocage.

86
De plus, le temps de blocage le plus court est utilisé pour la tâche 1 qui est de 100 ms. Par
conséquent, il entrera dans l'état d'exécution avant les autres tâches prioritaires et de
même pour la tâche2 et la tâche3.
Après cela, tous les threads continuent à s'exécuter en fonction de leur priorité et de
leur temps de blocage.

87

Vous aimerez peut-être aussi