Compte Rendu – TP STM32/Arduino : GPIO, PWM, Temporisation, Interruptions, UART, Ordonnancement
Compte Rendu de Travaux Pratiques
Prise en main des plateformes embarquées
Entrées/Sorties, GPIO, PWM et Temporisation
Plateforme utilisée : Arduino MEGA
Introduction
Ce compte rendu présente la réalisation des travaux pratiques portant sur la prise en main de la
plateforme embarquée Arduino MEGA. L'objectif global est de mettre en œuvre les fonctionnalités de
base d'une carte embarquée au travers de la commande d'un servomoteur.
Les fonctionnalités étudiées sont :
• Configuration des entrées/sorties numériques (GPIO)
• Lecture d'une entrée analogique (ADC)
• Génération d'un signal PWM
• Utilisation des temporisations non-bloquantes
• Conception des algorigrammes associés
Partie 1 : Présentation des cartes et environnements de
développement
1.1 Présentation matérielle – Arduino MEGA
Caractéristique Valeur
Microcontrôleur ATmega2560 (AVR, RISC 8-bit)
Fréquence d'horloge 16 MHz
Flash (programme) 256 KB
SRAM 8 KB
EEPROM 4 KB
Broches GPIO numériques 54 (dont 15 PWM)
Entrées analogiques (ADC) 16 (résolution 10 bits, 0–5V)
Timers / PWM 4 timers (Timer0 8-bit, Timer1/3/4/5 16-bit)
Interfaces communication 4× UART, 1× I2C, 1× SPI
Connecteur USB USB-B (programmation via USB-to-serial)
Alimentation 7–12V (Vin) ou 5V (USB)
Plateforme : Arduino MEGA | Page 1
Compte Rendu – TP STM32/Arduino : GPIO, PWM, Temporisation, Interruptions, UART, Ordonnancement
1.2 Ressources principales identifiées
• Broches PWM : 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 44, 45, 46
• Bouton Reset : présent sur la carte
• LEDs intégrées : LED_BUILTIN sur la broche 13
• Connecteur ICSP disponible pour programmation SPI
1.3 Environnement logiciel – Arduino IDE
• Edition du programme : éditeur de code intégré avec coloration syntaxique
• Compilation : outil avr-gcc intégré, génération du fichier .hex
• Téléversement : upload via USB (port série virtuel)
• Moniteur série : outil de débogage via UART (115200 bauds)
1.4 Étapes de développement sur Arduino
• Écriture du programme en C/C++ dans l'IDE
• Vérification/Compilation : Ctrl+R
• Téléversement sur la carte : Ctrl+U
• Observation des résultats via le moniteur série
1.5 Comparaison STM32 vs Arduino
Critère STM32 (Cortex-M) Arduino MEGA (AVR)
Architecture ARM Cortex-M (32-bit) AVR RISC (8-bit)
Fréquence Jusqu'à 480 MHz 16 MHz
IDE STM32CubeIDE + CubeMX Arduino IDE
Configuration Graphique (CubeMX) Code (pinMode)
HAL HAL STM32 Fonctions Arduino
Complexité Plus élevée Accessible/simple
Partie 2 : Gestion des E/S numériques (GPIO) – Commande
Marche/Arrêt
2.1 Objectif
Commander le fonctionnement d'un moteur via un bouton poussoir.
Principe : Bouton appuyé → sortie logique = 1 → transistor saturé → moteur en marche. Bouton relâché
→ sortie = 0 → transistor bloqué → moteur arrêté.
2.2 Schéma de câblage
• Bouton poussoir : broche 2 (entrée avec résistance de tirage interne activée)
• Sortie vers transistor MOSFET/IGBT : broche 8
• Moteur + diode de roue libre connectés côté drain du MOSFET
2.3 Programme Arduino
const int btnPin = 2;
const int motorPin = 8;
void setup() {
Plateforme : Arduino MEGA | Page 2
Compte Rendu – TP STM32/Arduino : GPIO, PWM, Temporisation, Interruptions, UART, Ordonnancement
pinMode(btnPin, INPUT_PULLUP);
pinMode(motorPin, OUTPUT);
}
void loop() {
int state = digitalRead(btnPin);
digitalWrite(motorPin, !state); // actif bas
}
2.4 Questions d'analyse
Polling vs Événement
Le polling consiste à interroger en permanence l'état d'une entrée dans la boucle principale. L'événement
(interruption) déclenche une action uniquement lors d'un changement d'état. Le polling est simple mais
consomme du temps CPU ; les interruptions sont plus efficaces pour les systèmes réactifs.
Résistance de tirage interne
Sans résistance de tirage (pull-up ou pull-down), une entrée non connectée est en état flottant, ce qui
provoque des lectures aléatoires. La résistance interne (INPUT_PULLUP sur Arduino) maintient la broche
à un niveau logique défini au repos.
Rebond mécanique des boutons
Lors de l'appui, les contacts métalliques du bouton vibrent pendant quelques millisecondes, générant des
transitions parasite. Cela produit de multiples fronts au lieu d'un seul, pouvant fausser le comptage ou le
déclenchement.
Solutions matérielles d'anti-rebond
• Filtre RC (résistance + condensateur) en parallèle sur le bouton
• Circuit dédié (ex. trigger de Schmitt 74HC14)
Solution logicielle d'anti-rebond (comptage)
unsigned long lastDebounce = 0;
const unsigned long debounceDelay = 50; // ms
int lastState = HIGH;
int count = 0;
void loop() {
int reading = digitalRead(btnPin);
if (reading != lastState) lastDebounce = millis();
if ((millis() - lastDebounce) > debounceDelay && reading == LOW) count++;
lastState = reading;
}
Partie 3 : Commande de vitesse par PWM
3.1 Objectif
Régler la vitesse d'un servomoteur par un potentiomètre via un signal PWM. La valeur analogique du
potentiomètre contrôle le rapport cyclique du PWM.
3.2 Programme Arduino
const int potPin = A0;
const int pwmPin = 9; // broche PWM
void setup() { pinMode(pwmPin, OUTPUT); }
void loop() {
int val = analogRead(potPin); // 0–1023
int duty = map(val, 0, 1023, 0, 255);
analogWrite(pwmPin, duty);
Plateforme : Arduino MEGA | Page 3
Compte Rendu – TP STM32/Arduino : GPIO, PWM, Temporisation, Interruptions, UART, Ordonnancement
3.3 Fréquence PWM
Sur Arduino MEGA, la fréquence PWM par défaut de la broche 9 (Timer1) est environ 490 Hz. La
résolution ADC est de 10 bits (0–1023) et la résolution PWM de 8 bits (0–255).
Partie 4 : Acquisition des grandeurs analogiques
4.1 Objectif
Mesurer la tension et le courant du servomoteur, calculer et afficher la puissance et l'énergie
consommées.
4.2 Programme Arduino
const int voltPin = A1;
const int currPin = A2;
float energy = 0;
unsigned long lastTime = 0;
void loop() {
float volt = analogRead(voltPin) * (5.0 / 1023.0) * facteurV;
float curr = analogRead(currPin) * (5.0 / 1023.0) * facteurI;
float power = volt * curr;
unsigned long now = millis();
energy += power * (now - lastTime) / 1000.0;
lastTime = now;
[Link]("V="); [Link](volt);
[Link](" I="); [Link](curr);
[Link](" P="); [Link](power);
[Link](" E="); [Link](energy);
delay(500);
}
4.3 Résolution ADC
L'ADC de l'Arduino MEGA a une résolution de 10 bits : 1024 niveaux sur une plage 0–5V, soit une
résolution de 4,88 mV/bit. Des capteurs de tension (pont diviseur) et de courant (shunt ou capteur à effet
Hall) sont utilisés pour ramener les grandeurs dans la plage 0–5V.
Partie 5 : Temporisation bloquante et non bloquante
5.1 Objectif
Comprendre l'impact des méthodes de temporisation sur le comportement d'un système embarqué
multitâche.
5.2 Temporisation bloquante (delay())
void loop() {
digitalWrite(LED1, !digitalRead(LED1));
delay(1000); // Bloque tout pendant 1s
digitalWrite(LED2, !digitalRead(LED2));
delay(250);
}
Problème observé : LED1 (2s) et LED2 (0,5s) ne peuvent pas fonctionner indépendamment. La
temporisation longue bloque entièrement le microcontrôleur, rendant impossible toute autre exécution
pendant ce délai.
Plateforme : Arduino MEGA | Page 4
Compte Rendu – TP STM32/Arduino : GPIO, PWM, Temporisation, Interruptions, UART, Ordonnancement
5.3 Temporisation non bloquante (millis())
unsigned long t1=0, t2=0;
void loop() {
if (millis()-t1 >= 2000) { t1=millis(); digitalWrite(LED1,!digitalRead(LED1));
}
if (millis()-t2 >= 500) { t2=millis(); digitalWrite(LED2,!digitalRead(LED2));
}
}
Résultat : les deux LEDs clignotent indépendamment aux périodes demandées, sans qu'aucune ne
bloque l'autre.
5.4 Analyse comparative
Critère Bloquante (delay) Non bloquante (millis)
CPU pendant attente Bloqué Libre
Multi-tâche Impossible Possible
Réactivité Faible Élevée
Complexité code Simple Légèrement plus complexe
5.5 Application : arrêt/redémarrage automatique du moteur
Implémentation d'un système gérant simultanément plusieurs tâches périodiques avec millis() :
Fonction Période
Fonctionnement moteur (10s ON / 5s OFF) 15 s
Mise à jour PWM 50 ms
Mesure des grandeurs 500 ms
Affichage UART 500 ms
Gestion des interruptions – Marche/Arrêt par interruption
Objectif
Ajouter un bouton de fin de course qui inverse l'état du moteur (Toggle) à chaque appui, en utilisant les
interruptions externes.
Programme Arduino
volatile bool motorState = false;
void setup() {
pinMode(motorPin, OUTPUT);
attachInterrupt(digitalPinToInterrupt(2), toggleMotor, RISING);
}
void toggleMotor() { motorState = !motorState; }
void loop() { digitalWrite(motorPin, motorState); }
Questions d'analyse
Pourquoi déclarer certaines variables en volatile ?
Les variables partagées entre le programme principal et une ISR (Interrupt Service Routine) doivent être
déclarées volatile pour empêcher le compilateur de les mettre en cache dans un registre. Sans volatile, le
programme principal pourrait lire une ancienne valeur sans voir les modifications faites par l'ISR.
Ce qu'il faut éviter dans une routine d'interruption
Plateforme : Arduino MEGA | Page 5
Compte Rendu – TP STM32/Arduino : GPIO, PWM, Temporisation, Interruptions, UART, Ordonnancement
• Opérations longues ou bloquantes (delay, [Link] volumineux)
• Accès à des ressources partagées sans protection
• Appels à des fonctions non réentrantes
Une ISR doit être la plus courte et rapide possible.
Applications industrielles
• Détecteur de fin de course sur machine-outil : arrêt immédiat en cas de dépassement
• Réception de trame UART : déclenchement à chaque octet reçu pour traitement temps-réel
Communication série : UART et I2C
Partie 1 : Supervision UART
Commande du moteur depuis le PC par envoi des caractères '1' (démarrage) et '0' (arrêt). Affichage
périodique des grandeurs mesurées.
void loop() {
if ([Link]()) {
char cmd = [Link]();
if (cmd=='1') motorOn=true;
if (cmd=='0') motorOn=false;
}
if (millis()-tUart>=1000) {
[Link]("Moteur:"); [Link](motorOn?"ON":"OFF");
[Link](" PWM:"); [Link](duty);
[Link](" V:"); [Link](volt);
[Link](" I:"); [Link](curr);
[Link](" P:"); [Link](power);
tUart = millis();
}
}
Partie 2 : Bus I2C
Scan et utilisation d'un périphérique I2C (capteur ou terminal).
// Scan I2C
#include <Wire.h>
void setup() { [Link](); [Link](115200); }
void loop() {
for (byte addr=1; addr<127; addr++) {
[Link](addr);
if ([Link]()==0)
[Link](addr, HEX);
}
}
Différence UART / I2C
Critère UART I2C
Fils 2 (TX, RX) 2 (SDA, SCL)
Topologie Point à point Bus (multi-esclaves)
Adressage Non (physique) Oui (7 bits)
Vitesse Configurable (9600–1Mbps) 100k / 400k / 1Mbps
Usage typique PC ↔ microcontrôleur Capteurs, périphériques
Plateforme : Arduino MEGA | Page 6
Compte Rendu – TP STM32/Arduino : GPIO, PWM, Temporisation, Interruptions, UART, Ordonnancement
Rôle maître/esclave : le maître (Arduino) initie les communications, génère l'horloge SCL et adresse les
esclaves. Les esclaves répondent uniquement lorsqu'ils sont sollicités.
Ordonnancement coopératif
Objectif
Concevoir un système multitâche sans système d'exploitation, basé sur un ordonnanceur coopératif
utilisant millis() comme base de temps.
Tableau des tâches
Tâche Période
Clignotement LED 500 ms
Lecture potentiomètre 50 ms
Mise à jour PWM moteur 50 ms
Mesure tension et courant 200 ms
Envoi UART 1s
Structure d'ordonnancement
unsigned long tLed=0, tPot=0, tPwm=0, tMes=0, tUart=0;
void loop() {
unsigned long now = millis();
if (now-tLed >= 500) { tLed=now; taskLed(); }
if (now-tPot >= 50) { tPot=now; taskPot(); }
if (now-tPwm >= 50) { tPwm=now; taskPwm(); }
if (now-tMes >= 200) { tMes=now; taskMesure();}
if (now-tUart >= 1000) { tUart=now; taskUart(); }
}
Analyse
• Surcharge processeur : si la somme des temps d'exécution des tâches dépasse leur période la
plus courte, des glissements temporels apparaissent.
• Dérive temporelle : l'utilisation de tX = millis() au lieu de tX += période évite l'accumulation de drift
sur le long terme.
• Avantage : cette approche simule un ordonnancement temps-réel sans RTOS, accessible sur
Arduino.
Conclusion
Ces travaux pratiques ont permis de maîtriser les fonctionnalités essentielles de la plateforme Arduino
MEGA pour les systèmes embarqués :
• Configuration et utilisation des GPIO numériques et analogiques
• Génération de signaux PWM pour la commande de vitesse
• Gestion du temps non bloquante avec millis() pour le multitâche coopératif
• Utilisation des interruptions externes pour une réactivité maximale
• Communication série UART et I2C avec des périphériques
• Implémentation d'un ordonnanceur coopératif structuré
La méthode de temporisation non bloquante (millis()) constitue la base d'une programmation embarquée
robuste, permettant de gérer plusieurs tâches simultanément sans système d'exploitation.
Plateforme : Arduino MEGA | Page 7