UEF1212 Cahier TD - TP 2024
UEF1212 Cahier TD - TP 2024
UEF1212 Cahier TD - TP 2024
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:
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
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
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
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
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:
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.
11
TP N°2
Le langage Arduino (I) :
Les E/S digitales
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:
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.
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.
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);
}
}
18
Fig 2.3 : La fenêtre du moniteur série
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
Points
connectés
Fig 2.6 : Connecter 2 composants en mettant les bornes sur la même ligne
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 :
Anode + − Cathode
(A) (K)
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 .
23
I
VR R
VLED
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
Bouton Bouton
ouvert fermé
Interrupteur Interrupteur
ouvert fermé
Interrupteur Interrupteur
position 1 position 2
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
Vcc
Micro- R
Contrôleur
E
Re
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:
cycle
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.
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
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 ?
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.
(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)
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
}
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
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
}
}
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.
38
TP N°3
Le langage Arduino (II):
Les Entrées/Sorties analogiques
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 à:
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).
Port Arduino
analogique
10K VR
Sortie
analogique
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
Sortie
analogique
broche
d’étalonnage
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 : .
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
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 à .
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.
UM
Ue
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.
UM(t)
Ue(t)
TON
TON E
M
UM(t)
UMmoy
t E T
T
Ue(t)
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
T1 T2 T1 T2
M M
T3 T4 T3 T4
T1 T2
T3 T4
Pont A
Pont B
(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) :
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é.
51
Figure 3.23 : Exemple de montage de commande avec Arduino
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%.
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.
58
TP N°4
Le langage Arduino (III) :
Les Librairies Arduino (mini projet)
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).
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.
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>
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
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 croquisinclure une bibliothèqueLiquidCrystal
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).
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
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.
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 croquisinclure une bibliothèqueAjouter à la
bibbliothèque .ZIP
2- Installer directement à partir de croquisinclure une bibliothèquegérer
les biliothèques . Taper keypad dans la zone de recherche puis selectionner la
biliothèque Keypad by Mark Stanly et lancer l’installation.
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>
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>
71
code = code+"b" ; // code ="ab"
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
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;
}
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é.
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);
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
80
1.4 Fonctionnalités FreeRTOS
Voici les principales fonctionnalités du noyau :
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.
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.
#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.
void loop()
{
//There is no instruction in the loop section of the code.
// Because each task executes on interrupt after specified time
}
while(1)
{
digitalWrite(8,HIGH);
digitalWrite(9,LOW);
digitalWrite(10,LOW);
digitalWrite(11,LOW);
Serial.println(F("Task1"));
vTaskDelay(100/portTICK_PERIOD_MS);
}
}
{
while(1)
{ digitalWrite(8,LOW);
digitalWrite(9,HIGH);
digitalWrite(10,LOW);
digitalWrite(11,LOW);
Serial.println(F("Task2"));
vTaskDelay(110/portTICK_PERIOD_MS);
}
}
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.
{
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