Cours 5SIN

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

Python (haut niveau)
C++ / Arduino
C (proche materiel)
Assembleur

1Bases du C/C++ pour l'Embarque

Types de donnees et memoire

TypeTaillePlageUsage
bool1 octettrue/falseEtats logiques
byte/uint8_t1 octet0 a 255GPIO, registres
int2 octets*-32768 a 32767Compteurs, CAN
unsigned long4 octets0 a 4.29 milliardsmillis(), timers
float4 octets±3.4e38Calculs 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)

while(1) {
  if(bouton == LOW) {...}
  // CPU occupe 100%
}

Gaspille du temps CPU

Interruption

attachInterrupt(...)
// 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

ModeDeclenchementUsage typique
LOWTant que niveau basReveil du mode sleep
RISINGFront montant (0→1)Appui bouton
FALLINGFront descendant (1→0)Relachement bouton
CHANGETout changementEncodeur 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

TimerTaillePins PWMUtilisation
Timer08 bits5, 6millis(), delay() - NE PAS MODIFIER
Timer116 bits9, 10Libre pour projets
Timer28 bits3, 11Libre 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 ?

PythonPrototypage, analyse donnees, IHM PC, scripts
MicroPythonESP32/Raspberry Pi Pico, projets IoT simples
C/C++Performance critique, ressources limitees, temps reel

Resume en 5 points cles

  1. 1Arduino utilise setup() (init) et loop() (boucle infinie) comme structure de base.
  2. 2Les interruptions permettent de reagir immediatement aux evenements sans polling.
  3. 3volatile est obligatoire pour les variables partagees entre ISR et loop().
  4. 4PWM permet de controler la puissance moyenne (LED, moteurs) via le rapport cyclique.
  5. 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

Scientia