Programmer un système en sciences de l'ingénieur, c'est écrire une boucle qui lit les capteurs, décide, puis commande les actionneurs, sans fin. Sur une carte Arduino, cette boucle s'écrit dans la fonction loop() : une veilleuse lit la lumière sur l'entrée A0 et allume sa LED dès que la valeur lue passe sous 300. Python, le langage proposé par le programme de SI, sert à écrire tes algorithmes et à traiter les mesures.
La boucle lire, décider, agir
Un capteur transforme une grandeur physique (lumière, température) en signal électrique. Un actionneur, comme un moteur, transforme un ordre en action. Entre les deux, le micro-contrôleur exécute ton programme : un petit ordinateur sur une seule puce, avec ses broches d'entrée et de sortie, au cœur de la carte Arduino.
Avant de coder, écris l'algorithme, en pseudo-code ou en algorigramme (des rectangles pour les actions, des losanges pour les tests). Pour la veilleuse :
répéter sans fin :
lire la lumière
si lumière < 300 : allumer la LED
sinon : éteindre la LED
Un système à plusieurs modes (veille, marche, alarme) se décrit plutôt par un diagramme d'états-transitions : chaque mode est un état, et un événement (un appui sur un bouton) fait passer de l'un à l'autre.
Conseil : teste ton algorithme à la main avec une valeur pile sur le seuil : à 300, la veilleuse reste éteinte, car le test est « strictement inférieur ».
Python et Arduino, deux écritures
Le programme de sciences de l'ingénieur propose Python et permet de présenter d'autres langages. Une carte Arduino en utilise un autre : le logiciel Arduino transforme ton programme, appelé croquis, en C++, puis le compile, c'est-à-dire le traduit en instructions pour le micro-contrôleur. Variables, tests et boucles existent des deux côtés ; seule l'écriture change.
| Ce que tu fais | Python | Arduino (C++) |
|---|---|---|
| Créer une variable | seuil = 300 | int seuil = 300; |
| Tester | if n < seuil: puis les lignes en retrait | if (n < seuil) { … } |
| Répéter 10 fois | for i in range(10): | for (int i = 0; i < 10; i++) { … } |
| Diviser 7 par 2 | 7 / 2 donne 3.5 | 7 / 2 donne 3, 7.0 / 2 donne 3.5 |
En Arduino, chaque instruction finit par un point-virgule, et chaque variable a un type : int pour un entier, float pour un nombre à virgule.
Programmer une carte Arduino
setup() s'exécute une seule fois, à la mise sous tension : on y règle les broches. loop() tourne ensuite sans fin. Voici la veilleuse : LED sur la broche 8, capteur de lumière sur A0, monté pour que la valeur lue baisse quand il fait sombre.
const int LED = 8;
const int SEUIL = 300;
void setup() {
pinMode(LED, OUTPUT);
}
void loop() {
int lumiere = analogRead(A0); // entre 0 et 1023
if (lumiere < SEUIL) {
digitalWrite(LED, HIGH); // sombre : on allume
} else {
digitalWrite(LED, LOW); // clair : on éteint
}
delay(100); // attendre 100 ms
}
pinMode déclare une broche en entrée ou en sortie. Sur une Uno, digitalWrite met une sortie à 5 V (HIGH) ou à 0 V (LOW) ; digitalRead lit une entrée tout ou rien, comme un bouton.
Piège classique : oublier pinMode(LED, OUTPUT). La documentation Arduino prévient qu'alors la LED peut briller à peine. Tu chercheras une erreur de câblage alors qu'il manque une ligne.
Pour une grandeur qui varie, analogRead passe par le convertisseur analogique-numérique (CAN), qui change une tension en nombre entier. Sur une Uno, il code par défaut de 0 à 5 V sur 10 bits : 210 = 1024 valeurs, de 0 à 1023. Une unité vaut 5 / 1024 V, environ 4,9 mV. C'est la résolution : le plus petit écart de tension que la carte distingue.
Formule : une valeur lue N correspond à la tension U = N × 5 / 1024, en volts. Certains cours divisent par 1023 : l'écart reste sous 0,1 %.
Faire varier une vitesse avec la PWM
Une broche numérique ne connaît que 0 V et 5 V. Pour régler la vitesse d'un moteur ou l'éclat d'une LED, la carte utilise la PWM (modulation de largeur d'impulsion, ou MLI) : la broche bascule très vite entre 0 V et 5 V, et tu règles la part du temps passée à 5 V, appelée rapport cyclique et notée α.
analogWrite(broche, valeur) prend une valeur de 0 (toujours 0 V) à 255 (toujours 5 V). Sur une Uno, seules les broches 3, 5, 6, 9, 10 et 11 le permettent.
Pourquoi ça marche : sur une période T, la tension vaut 5 V pendant α × T et 0 V le reste du temps. Sa valeur moyenne vaut donc 5 × α × T / T = α × 5 V. Le moteur, freiné par son inertie, et ton œil, trop lent pour suivre ces éclats, ne réagissent qu'à cette moyenne.
Formule : α = valeur / 255, et tension moyenne = α × 5 V. Avec analogWrite(9, 51), α = 0,2 : la tension moyenne vaut 1 V.
Piège classique : analogRead renvoie de 0 à 1023, mais analogWrite attend de 0 à 255. Pour régler une LED avec un potentiomètre, divise par 4 : analogWrite(9, analogRead(A0) / 4);. Ici, la division entière tombe bien : 1023 / 4 donne 255.
Traiter les mesures avec Python
Une mesure brute fluctue d'une lecture à l'autre. Pour la stabiliser, on calcule une moyenne glissante : à chaque nouvelle mesure, la moyenne des k dernières, que mesures[-k:] sélectionne en Python.
def tension(n):
return n * 5 / 1024 # valeur lue -> volts
mesures = [480, 512, 498, 530, 505, 515]
k = 4
moyenne = sum(mesures[-k:]) / k
print(moyenne, tension(moyenne)) # affiche 512.0 2.5
Plus k est grand, plus la courbe est lisse, mais plus elle réagit tard : avec 10 mesures par seconde et k = 10, un saut met une seconde à apparaître en entier.
Faire communiquer des objets
Pour envoyer ses mesures à l'ordinateur, la carte ouvre une liaison série avec Serial.begin(9600) : 9600 bauds, c'est-à-dire ici 9600 bits par seconde. Serial.println(valeur) envoie la valeur en texte, suivie de deux caractères de fin de ligne ; le moniteur série du logiciel Arduino l'affiche.
Les deux côtés suivent un protocole, des règles communes : vitesse, format des trames (les données entourées d'informations de service). Par défaut, une Arduino règle sa liaison en 8N1 : 8 bits de données, sans bit de parité, encadrés par un bit de départ et un bit de stop. Un octet coûte donc 10 bits.
Définition : le débit maximal compte tous les bits transmis par seconde ; le débit utile, seulement les bits de données.
Un objet connecté remplace le fil par la radio : Wi-Fi, Bluetooth ou LoRa. Dans un réseau, chaque couche ajoute ses informations (adresses, contrôle d'erreurs) autour des données, comme une lettre glissée dans une enveloppe puis dans un colis : c'est l'encapsulation.
Exercices corrigés
Toujours avec une Arduino Uno.
Exercice 1 : Un capteur de température délivre 10 mV par degré Celsius (0 V à 0 °C). Branché sur A0, il donne une valeur lue de 45. Quelle tension délivre-t-il, et quelle température mesure-t-il ? De combien la température doit-elle varier pour que la valeur lue change d'une unité ?
Correction :
U = 45 × 5 / 1024 ≈ 0,2197 V, soit environ 219,7 mV.
À 10 mV par degré : 219,7 / 10 ≈ 22,0 °C.
Une unité vaut 5 / 1024 V ≈ 4,9 mV, soit 4,9 / 10 ≈ 0,49 °C. Deux températures à moins d'un demi-degré d'écart peuvent donner la même valeur lue.
Exercice 2 : On veut une tension moyenne de 3 V sur la broche 9. Quelle valeur faut-il passer à analogWrite ? Quelle tension moyenne obtient-on avec analogWrite(9, 64) ? Arrondis au centième de volt.
Correction :
Il faut α = 3 / 5 = 0,6, donc une valeur de 0,6 × 255 = 153 : analogWrite(9, 153);.
Avec 64 : α = 64 / 255 ≈ 0,25, et la tension moyenne vaut 64 × 5 / 255 ≈ 1,25 V.
Exercice 3 : Une station météo envoie la ligne T=21.5;H=48 avec Serial.println, à 9600 bauds en 8N1 (1 bit de départ, 8 bits de données, 1 bit de stop). Chaque caractère occupe un octet. Combien d'octets envoie-t-elle par ligne ? Combien de temps dure l'envoi ? Quelle part des bits transmis correspond aux données ?
Correction :
La ligne compte 11 caractères, point et point-virgule compris, et println ajoute un retour chariot et un saut de ligne : 13 octets.
À 10 bits par octet : 13 × 10 = 130 bits, envoyés à 9600 bits par seconde en 130 / 9600 ≈ 0,0135 s, soit environ 13,5 ms.
Les données font 13 × 8 = 104 bits sur 130, soit 80 % : c'est le rapport entre débit utile et débit maximal.
Exercice 4 : Pour afficher la tension lue sur A0, un élève écrit :
int n = analogRead(A0);
float u = n * 5 / 1024;
Serial.println(u);
Pour une valeur lue de 700, le moniteur série affiche 3.00. Quelle tension attendait-il ? D'où vient l'écart ? Corrige la deuxième ligne.
Correction :
Il attendait 700 × 5 / 1024 ≈ 3,42 V.
n, 5 et 1024 sont des entiers : 700 × 5 = 3500, puis 3500 / 1024 donne 3, partie décimale jetée. Ce 3 n'est converti en float qu'ensuite, d'où 3.00.
La bonne ligne : float u = n * 5.0 / 1024;. Avec 5.0, le calcul garde ses décimales, et le moniteur affiche 3.42.
À retenir
À retenir :
- Lire, décider, agir, en boucle ; l'algorithme d'abord.
setup()une fois,loop()sans fin,pinModeavantdigitalWrite.- Entrée analogique : N de 0 à 1023, U = N × 5 / 1024, environ 4,9 mV par unité.
- PWM : α = valeur / 255 et tension moyenne = α × 5 V.
- En Arduino, 7 / 2 donne 3 : écris 7.0 pour garder les décimales.
- Liaison série en 8N1 : 10 bits par octet, dont 8 de données.
Sources
- Programme de sciences de l'ingénieur de première et terminale générales (Bulletin officiel) : texte sur eduscol.
- Référence du langage Arduino : documentation officielle Arduino.