Programmation des Systemes
C/C++, Python, Arduino, interruptions et programmation temps reel
Objectifs pedagogiques
- Maitriser les bases du langage C/C++ pour systemes embarques
- Programmer un microcontroleur Arduino avec les GPIO, timers et interruptions
- Comprendre les contraintes de la programmation temps reel
- Utiliser Python pour le prototypage et la communication avec l'embarque
Introduction : Programmer le materiel
Exemple concret : Robot eviteur d'obstacles
Un robot autonome doit reagir instantanement aux capteurs ultrason pour eviter les murs. Le programme doit gerer simultanement : lecture capteurs, controle moteurs, et communication Bluetooth. C'est la programmation temps reel avec gestion des interruptions.
La programmation des systemes embarques differe de la programmation classique : ressources limitees (memoire, CPU), contraintes temporelles strictes, et interaction directe avec le materiel. Les langages privilégies sont le C/C++ pour leur efficacite, et Python pour le prototypage rapide.
Langages par niveau d'abstraction
1Bases du C/C++ pour l'Embarque
Types de donnees et memoire
| Type | Taille | Plage | Usage |
|---|---|---|---|
| bool | 1 octet | true/false | Etats logiques |
| byte/uint8_t | 1 octet | 0 a 255 | GPIO, registres |
| int | 2 octets* | -32768 a 32767 | Compteurs, CAN |
| unsigned long | 4 octets | 0 a 4.29 milliards | millis(), timers |
| float | 4 octets | ±3.4e38 | Calculs decimaux |
* Sur Arduino UNO (AVR 8 bits). Sur ESP32 (32 bits), int = 4 octets.
Structure d'un programme Arduino
// Structure de base Arduino
// Variables globales
const int LED_PIN = 13;
const int BOUTON_PIN = 2;
volatile bool boutonPresse = false;
void setup() {
// Execute UNE SEULE FOIS au demarrage
pinMode(LED_PIN, OUTPUT);
pinMode(BOUTON_PIN, INPUT_PULLUP);
Serial.begin(9600);
}
void loop() {
// Execute EN BOUCLE INFINIE
if(digitalRead(BOUTON_PIN) == LOW) {
digitalWrite(LED_PIN, HIGH);
} else {
digitalWrite(LED_PIN, LOW);
}
}
Fonctions GPIO essentielles
Entrees/Sorties numeriques
pinMode(pin, INPUT/OUTPUT)
digitalRead(pin) → HIGH/LOW
digitalWrite(pin, HIGH/LOW)
Entrees/Sorties analogiques
analogRead(pin) → 0-1023
analogWrite(pin, 0-255) // PWM
analogReference(type)
volatile : Ce mot-cle indique au compilateur que la variable peut etre modifiee par une interruption. Sans lui, l'optimisateur pourrait ignorer les changements.
2Interruptions : Reagir Instantanement
Qu'est-ce qu'une interruption ?
Une interruption est un mecanisme materiel qui suspend l'execution normale du programme pour executer immediatement une fonction speciale (ISR - Interrupt Service Routine). Elle permet de reagir a des evenements sans attendre.
Polling vs Interruptions
Polling (scrutation)
if(bouton == LOW) {...}
// CPU occupe 100%
}
Gaspille du temps CPU
Interruption
// CPU fait autre chose
// ISR execute au bon moment
Reaction immediate, CPU libre
Implementation Arduino
// Exemple : Compteur d'impulsions avec interruption
volatile unsigned long compteur = 0;
const int PIN_CAPTEUR = 2; // INT0 sur UNO
// ISR - doit etre COURTE et RAPIDE
void compterImpulsion() {
compteur++;
}
void setup() {
pinMode(PIN_CAPTEUR, INPUT_PULLUP);
// Attacher l'interruption
attachInterrupt(
digitalPinToInterrupt(PIN_CAPTEUR),
compterImpulsion,
FALLING // Front descendant
);
Serial.begin(9600);
}
void loop() {
// Desactiver interruptions pour lire compteur
noInterrupts();
unsigned long valeur = compteur;
interrupts();
Serial.println(valeur);
delay(1000);
}
Modes de declenchement
| Mode | Declenchement | Usage typique |
|---|---|---|
| LOW | Tant que niveau bas | Reveil du mode sleep |
| RISING | Front montant (0→1) | Appui bouton |
| FALLING | Front descendant (1→0) | Relachement bouton |
| CHANGE | Tout changement | Encodeur rotatif |
Regles d'or pour les ISR
- • Execution la plus courte possible (pas de delay, Serial)
- • Variables partagees declarees volatile
- • Desactiver les interruptions pour lire les variables partagees
- • Pas d'appel a des fonctions qui utilisent des interruptions
3Timers et PWM
Les Timers materiel
Un Timer est un compteur materiel qui s'incremente automatiquement a chaque cycle d'horloge. Il permet de mesurer des durees, generer des signaux PWM, ou declencher des interruptions periodiques sans mobiliser le CPU.
Timers sur Arduino UNO
| Timer | Taille | Pins PWM | Utilisation |
|---|---|---|---|
| Timer0 | 8 bits | 5, 6 | millis(), delay() - NE PAS MODIFIER |
| Timer1 | 16 bits | 9, 10 | Libre pour projets |
| Timer2 | 8 bits | 3, 11 | Libre pour projets |
PWM : Modulation de Largeur d'Impulsion
// PWM simple avec analogWrite (8 bits = 0-255)
const int PIN_LED = 9;
void setup() {
pinMode(PIN_LED, OUTPUT);
}
void loop() {
// Fade in
for(int i = 0; i <= 255; i++) {
analogWrite(PIN_LED, i); // Duty cycle = i/255
delay(10);
}
// Fade out
for(int i = 255; i >= 0; i--) {
analogWrite(PIN_LED, i);
delay(10);
}
}
// Frequence PWM par defaut Arduino UNO:
// Pins 5,6 : ~980 Hz | Pins 3,9,10,11 : ~490 Hz
Calcul du rapport cyclique
Duty Cycle (%) = (Ton / T) × 100 = (valeur / 255) × 100
analogWrite(128) = 50% duty cycle = tension moyenne = Vcc/2
Applications PWM : Variation luminosite LED, controle vitesse moteur DC, generation de sons, communication infrarouge.
4Python pour l'Embarque et la Communication
Python : Le couteau suisse
Python n'est pas adapte a l'execution directe sur microcontroleur (sauf MicroPython), mais il excelle pour communiquer avec l'embarque (serie, WiFi), analyser les donnees, et prototyper des algorithmes avant portage en C.
Communication Serie Python ↔ Arduino
Code Arduino (emetteur)
void setup() {
Serial.begin(9600);
}
void loop() {
int val = analogRead(A0);
Serial.println(val);
delay(100);
}
Code Python (recepteur)
import serial
ser = serial.Serial(
'/dev/ttyUSB0',
9600
)
while True:
ligne = ser.readline()
valeur = int(ligne)
print(f"Capteur: {valeur}")
MicroPython sur ESP32
# MicroPython - Blink LED sur ESP32
from machine import Pin
import time
led = Pin(2, Pin.OUT) # LED interne ESP32
while True:
led.value(not led.value()) # Toggle
time.sleep(0.5)
# Lecture CAN
from machine import ADC
adc = ADC(Pin(34))
adc.atten(ADC.ATTN_11DB) # Plage 0-3.3V
valeur = adc.read() # 0-4095 (12 bits)
Quand utiliser Python vs C ?
| Python | Prototypage, analyse donnees, IHM PC, scripts |
| MicroPython | ESP32/Raspberry Pi Pico, projets IoT simples |
| C/C++ | Performance critique, ressources limitees, temps reel |
Resume en 5 points cles
- 1Arduino utilise setup() (init) et loop() (boucle infinie) comme structure de base.
- 2Les interruptions permettent de reagir immediatement aux evenements sans polling.
- 3volatile est obligatoire pour les variables partagees entre ISR et loop().
- 4PWM permet de controler la puissance moyenne (LED, moteurs) via le rapport cyclique.
- 5Python sert a communiquer avec l'embarque et analyser les donnees cote PC.
Mini-Quiz
Question 1 : Quel mot-cle utiliser pour une variable modifiee par une ISR ?
a) static
b) volatile
c) const
Reponse : b) volatile indique que la variable peut changer a tout moment
Question 2 : Quel est le duty cycle pour analogWrite(191) ?
a) 50%
b) 75%
c) 100%
Reponse : b) 191/255 = 0.75 = 75%
Question 3 : Quelle fonction Arduino est executee une seule fois ?
a) loop()
b) main()
c) setup()
Reponse : c) setup() s'execute une fois au demarrage, loop() tourne en boucle
