ARDUINO
Tu ne copies pas du code.
Tu comprends chaque ligne que tu écris.
Tout expliqué depuis la base — sans rien supposer.
Qu'est-ce que Arduino ?
Arduino est une plateforme de prototypage électronique open source créée en 2005 en Italie. Elle se compose d'une carte matérielle (microcontrôleur + connecteurs) et d'un environnement de développement (IDE). L'objectif : rendre la programmation de microcontrôleurs accessible à tous — étudiants, artistes, makers, ingénieurs.
ATmega328P
Microcontrôleur 8 bits, 16 MHz. Le cerveau de l'Arduino Uno — simple, robuste, bien documenté.
14 GPIO Digital
Broches programmables en entrée ou sortie. 6 d'entre elles font du PWM (≈).
6 entrées ADC
Lire des capteurs analogiques : potentiomètre, LDR, thermistance...
UART/I2C/SPI
Communiquer avec capteurs, afficheurs, modules Bluetooth, WiFi.
32 KB Flash + 2 KB RAM
Stockage programme et mémoire vive. Limité mais suffisant pour la plupart des projets.
5V logique
Tension standard 5V — compatible avec beaucoup de modules et capteurs.
La famille Arduino — choisir la bonne carte
| CARTE | CPU | FLASH | RAM | GPIO | SPÉCIALITÉ |
|---|---|---|---|---|---|
| Arduino Uno R3 | ATmega328P 16MHz | 32KB | 2KB | 14 digital, 6 ADC | Débutant — référence absolue |
| Arduino Nano | ATmega328P 16MHz | 32KB | 2KB | 22 broches | Compact — même que Uno |
| Arduino Mega 2560 | ATmega2560 16MHz | 256KB | 8KB | 54 digital, 16 ADC | Grands projets, beaucoup d'I/O |
| Arduino Leonardo | ATmega32U4 16MHz | 32KB | 2.5KB | 20 digital | USB natif — émule clavier/souris |
| Arduino Due | AT91SAM3X8E 84MHz | 512KB | 96KB | 54 digital | Haute performance, 3.3V |
| Arduino Nano 33 IoT | SAMD21 + Nina W10 | 1MB | 256KB | 22 + WiFi/BLE | IoT compact |
Comment ça fonctionne — du code au mouvement
le code C++
compile
avrdude
Flash 32KB
exécute en boucle
Arduino Uno — Anatomie Complète
Comprendre l'intérieur de l'Arduino Uno permet d'éviter les erreurs et d'exploiter toutes ses capacités. L'ATmega328P est un microcontrôleur 8 bits de la famille AVR d'Atmel.
🗺️ Carte des Broches Arduino Uno
| BROCHE | ALIAS | FONCTION SPÉCIALE | REMARQUE |
|---|---|---|---|
| D0 | RX | UART réception | NE PAS UTILISER si câble USB branché |
| D1 | TX | UART émission | NE PAS UTILISER si câble USB branché |
| D3,5,6,9,10,11 | ~ | PWM 8 bits (analogWrite) | Fréquence : 490Hz (5,6,9,10) ou 980Hz (3,11) |
| D10 | SS | SPI Slave Select | Doit être OUTPUT même si non utilisé comme SS |
| D13 | LED_BUILTIN | LED intégrée | LED orange sur la carte — allumée = HIGH |
| A0–A5 | – | ADC 10 bits 0–5V | Peuvent aussi être utilisés comme GPIO digital |
| A4 | SDA | I2C données | Pull-up 4.7kΩ externe vers 5V recommandé |
| A5 | SCL | I2C horloge | Pull-up 4.7kΩ externe vers 5V recommandé |
• Maximum 40mA par broche GPIO (LED directement : ok. Moteur directement : NON)
• Maximum 200mA total sur toutes les broches ensemble
• Broche 5V : max 500mA depuis USB, plus depuis alimentation externe
• Pour piloter moteurs, relais, LEDs puissantes → toujours utiliser un transistor ou un driver
GPIO — Entrées & Sorties Digitales
Un GPIO digital ne connaît que deux états : HIGH (5V = logique 1) et LOW (0V = logique 0). En sortie, tu commandes une LED, un relais. En entrée, tu lis un bouton, un capteur digital.
OUTPUT : tu contrôles l'interrupteur. En INPUT : tu lis si quelqu'un d'autre l'a actionné.Structure de base — setup() et loop()
// Tout programme Arduino a exactement ces 2 fonctions : // setup() : exécutée UNE SEULE FOIS au démarrage // loop() : exécutée EN BOUCLE INFINIE ensuite // La LED intégrée est sur la broche 13 (LED_BUILTIN) const int LED = 13; // constante — plus lisible que mettre 13 partout const int BTN = 7; // bouton sur broche 7 void setup() { Serial.begin(9600); // démarrer la communication série à 9600 baud pinMode(LED, OUTPUT); // broche 13 en SORTIE pinMode(BTN, INPUT_PULLUP); // broche 7 en ENTRÉE avec résistance interne Serial.println("Arduino démarré !"); } void loop() { // Lire l'état du bouton int etat = digitalRead(BTN); // INPUT_PULLUP → logique inversée ! // Bouton relâché : broche à HIGH (5V via résistance interne) // Bouton appuyé : broche à LOW (connectée à GND) if (etat == LOW) { // LOW = appuyé avec INPUT_PULLUP digitalWrite(LED, HIGH); // allumer LED Serial.println("Appuyé!"); } else { digitalWrite(LED, LOW); // éteindre LED } }
Clignotement non-bloquant avec millis()
delay() que dans des exemples simples. Dès que tu as plusieurs choses à faire simultanément (lire un capteur ET faire clignoter une LED ET lire un bouton), utilise millis() — la montre interne de l'Arduino.// Clignotement non bloquant — millis() comme chronomètre // Pendant que la LED clignote, tu peux faire autre chose ! const int LED = 13; unsigned long tDernierClignotement = 0; // horodatage du dernier bascule bool etatLED = false; const int INTERVALLE = 500; // clignoter toutes les 500ms void setup() { pinMode(LED, OUTPUT); } void loop() { unsigned long maintenant = millis(); // ms depuis le démarrage // Est-ce que l'intervalle est écoulé ? if (maintenant - tDernierClignotement >= INTERVALLE) { tDernierClignotement = maintenant; // mémoriser l'heure etatLED = !etatLED; // inverser digitalWrite(LED, etatLED); } // ← Ici : tout autre code continue à tourner ! // lecture capteur, affichage LCD, traitement bouton... }
Anti-rebond hardware/software pour boutons
// Les boutons mécaniques rebondissent 5–50ms à chaque appui // Sans anti-rebond : 1 appui = 10–50 déclenchements parasites const int BTN_PIN = 2; const int DEBOUNCE_MS = 50; unsigned long tDernier = 0; int etatBrut = HIGH; int etatStable = HIGH; int compteurPressions = 0; void setup() { Serial.begin(9600); pinMode(BTN_PIN, INPUT_PULLUP); } void loop() { int lecture = digitalRead(BTN_PIN); if (lecture != etatBrut) tDernier = millis(); // signal a changé → reset timer if ((millis() - tDernier) > DEBOUNCE_MS) { // stable depuis 50ms if (lecture != etatStable) { etatStable = lecture; if (etatStable == LOW) { // front descendant = appui compteurPressions++; Serial.print("Appui #"); Serial.println(compteurPressions); } } } etatBrut = lecture; }
Gestion des interruptions (INT0, INT1)
// Les interruptions permettent de réagir INSTANTANÉMENT // sans vérifier en permanence dans loop() // Arduino Uno : INT0=D2, INT1=D3 volatile int compteur = 0; // volatile = modifié par l'interruption void setup() { Serial.begin(9600); pinMode(2, INPUT_PULLUP); // attachInterrupt(pin_INT, fonction, mode) // mode : RISING = front montant, FALLING = front descendant // CHANGE = tout changement, LOW = niveau bas attachInterrupt(digitalPinToInterrupt(2), surClic, FALLING); // digitalPinToInterrupt(2) = 0 (INT0) } void surClic() { // Exécutée IMMÉDIATEMENT quand D2 tombe à LOW // ⚠️ NE PAS mettre de Serial, delay, ou code long ici // ⚠️ NE PAS faire d'opération sur des entiers > 1 octet sans cli()/sei() compteur++; } void loop() { noInterrupts(); // désactiver IRQ temporairement int copie = compteur; // lire la variable partagée interrupts(); // réactiver IRQ static int dernierCompte = 0; if (copie != dernierCompte) { Serial.print("Compteur: "); Serial.println(copie); dernierCompte = copie; } }
ADC & PWM — Signaux Analogiques
Le monde physique est analogique — les grandeurs varient continuellement. L'ADC (Analog-to-Digital Converter) convertit une tension en nombre. Le PWM simule une sortie analogique en variant la durée des impulsions.
🔢 ADC — Convertisseur Analogique-Numérique (10 bits)
Formule :
tension = valeur × 5.0 / 1023Exemple : valeur = 512 → tension = 512 × 5.0 / 1023 ≈ 2.50V
// Potentiomètre sur A0 — câblage : pin 1→5V, pin 3→GND, pin 2→A0 // La broche centrale (curseur) donne une tension proportionnelle const int POT_PIN = A0; // A0 est aussi un alias pour la broche analogique 0 void setup() { Serial.begin(9600); // Par défaut : référence interne = 5V (alimenté par USB) // analogReference(INTERNAL) → 1.1V (plus précis pour faibles tensions) // analogReference(EXTERNAL) → tension sur broche AREF (0 à 5V) } void loop() { int brut = analogRead(POT_PIN); // 0 à 1023 float tension = brut * 5.0 / 1023.0; // convertir en Volts int pourcent = map(brut, 0, 1023, 0, 100); // map() : rééchelonner Serial.print("Brut: "); Serial.print(brut); Serial.print(" Tension: "); Serial.print(tension, 2); Serial.print("V"); Serial.print(" Pourcent: "); Serial.println(pourcent); delay(200); } // ── FONCTION map() EXPLIQUÉE ──────────────────────────────── // map(valeur, inMin, inMax, outMin, outMax) // map(512, 0, 1023, 0, 255) → 127 (pour PWM) // map(200, 0, 1023, 0, 180) → 35° (pour servo) // map(100, 0, 1023, 20, 80) → 25 (température calibrée)
Lire un capteur de lumière (LDR — photorésistance)
// LDR (Light Dependent Resistor) en diviseur de tension // Câblage : 5V → R10kΩ → A0 → LDR → GND // Plus il fait clair : LDR basse résistance → tension sur A0 élevée // Plus il fait sombre : LDR haute résistance → tension sur A0 faible const int LDR_PIN = A1; const int LED_PIN = 9; // LED sur broche PWM void setup() { Serial.begin(9600); pinMode(LED_PIN, OUTPUT); } void loop() { int lumiere = analogRead(LDR_PIN); // 0 (sombre) → 1023 (lumineux) // Inverser : plus sombre = LED plus brillante (veilleuse) int luminosited = map(lumiere, 0, 1023, 255, 0); analogWrite(LED_PIN, luminosited); // PWM automatique ! Serial.print("Lumière: "); Serial.print(lumiere); Serial.print(" LED: "); Serial.println(luminosited); delay(100); }
🌊 PWM — Pulse Width Modulation
255 = 100% HIGH = pleine puissance | 128 = 50% = mi-puissance | 0 = 0% = éteint
analogWrite(pin, 0–255) sur les broches ~// analogWrite() → disponible sur broches marquées ~ : 3,5,6,9,10,11 // Résolution : 8 bits (0 à 255) void setup() { pinMode(9, OUTPUT); // broche PWM pinMode(10, OUTPUT); // broche PWM pinMode(11, OUTPUT); // broche PWM } void loop() { // ── Fondu d'une LED ──────────────────────────────────── for (int i = 0; i <= 255; i++) { analogWrite(9, i); delay(8); // 256 pas × 8ms ≈ 2 secondes } for (int i = 255; i >= 0; i--) { analogWrite(9, i); delay(8); } // ── LED RGB (3 LEDs dans un même boîtier) ───────────── // Câblage : pin commune → GND (LED commune cathode) analogWrite(9, 255); // Rouge = plein analogWrite(10, 0); // Vert = éteint analogWrite(11, 128); // Bleu = mi // Résultat visuel : rose/violet delay(1000); // ── Servo moteur avec PWM ────────────────────────────── // MIEUX : utiliser la bibliothèque Servo.h (voir section capteurs) }
DHT11 — Température & Humidité
Le DHT11 est un capteur numérique de température (0–50°C, ±2°C) et d'humidité relative (20–90%, ±5%). Il communique via un protocole série 1 fil propriétaire. Simple, bon marché, parfait pour débuter.
📦 DHT11 (bleu)
- Temp : 0–50°C précision ±2°C
- Humidité : 20–90% précision ±5%
- 1 mesure maximum par seconde
- Prix : ~1–3€
- Idéal : projets débutants, stations météo simples
📦 DHT22 (blanc)
- Temp : -40–80°C précision ±0.5°C
- Humidité : 0–100% précision ±2–5%
- 1 mesure toutes les 2 secondes
- Prix : ~3–7€
- Idéal : projets avancés, mesures précises
🔌 Câblage DHT11 — 3 fils
Comment fonctionne le protocole DHT11 (1 fil)
PROTOCOLE DHT11 — Communication 1 fil série asynchrone 1. SIGNAL DE DÉMARRAGE (Arduino → DHT11) Arduino tire DATA à LOW pendant >18ms (signal 'réveil') Arduino relâche DATA (HIGH via pull-up) pendant 20-40µs 2. RÉPONSE DHT11 (DHT11 → Arduino) DHT11 tire DATA à LOW pendant 80µs DHT11 relâche DATA à HIGH pendant 80µs (confirme qu'il est prêt) 3. TRANSMISSION 40 BITS (5 octets) Octet 1 : Humidité entière (ex: 65) Octet 2 : Humidité décimale (toujours 0 pour DHT11) Octet 3 : Température entière (ex: 23) Octet 4 : Température décimale(toujours 0 pour DHT11) Octet 5 : Checksum = somme des 4 premiers octets 4. ENCODAGE DES BITS Bit 0 : LOW 50µs → HIGH 26-28µs Bit 1 : LOW 50µs → HIGH 70µs (durée du HIGH détermine 0 ou 1) → La bibliothèque DHT gère tout ça automatiquement !
Code Arduino avec bibliothèque DHT
// Installer la bibliothèque : Outils → Gérer les bibliothèques // Rechercher 'DHT sensor library' par Adafruit → Installer // Installer aussi 'Adafruit Unified Sensor' (dépendance) #include "DHT.h" // bibliothèque pour DHT11 et DHT22 const int DHT_PIN = 2; // broche DATA du DHT11 const int DHT_TYPE = DHT11; // DHT11 ou DHT22 selon ton capteur DHT dht(DHT_PIN, DHT_TYPE); // créer l'objet capteur void setup() { Serial.begin(9600); dht.begin(); // initialiser le capteur Serial.println("Capteur DHT11 initialisé"); delay(2000); // laisser le DHT11 se stabiliser au démarrage } void loop() { // ⚠️ DHT11 : attendre au minimum 1 seconde entre les mesures ! delay(2000); float humidite = dht.readHumidity(); // en % float temperature = dht.readTemperature(); // en °C par défaut // .readTemperature(true) → en Fahrenheit // Vérifier si la lecture est valide (NaN = Not a Number = erreur) if (isnan(humidite) || isnan(temperature)) { Serial.println("❌ Erreur lecture DHT11 !"); Serial.println("Vérifier câblage et résistance 10kΩ"); return; // arrêter ce cycle, passer au suivant } // Calcul de l'indice de chaleur (ressenti) float indiceRessenti = dht.computeHeatIndex(temperature, humidite, false); Serial.print("Humidité : "); Serial.print(humidite); Serial.println(" %"); Serial.print("Température : "); Serial.print(temperature); Serial.println(" °C"); Serial.print("Ressenti : "); Serial.print(indiceRessenti); Serial.println(" °C"); Serial.println("---"); }
DHT11 avec alarme sonore et LED
#include "DHT.h" const int DHT_PIN = 2; const int BUZZER = 8; const int LED_ROUGE= 7; const int LED_VERTE= 6; const float SEUIL_TEMP = 28.0; // alarme si > 28°C const float SEUIL_HUMI = 75.0; // alarme si humidité > 75% DHT dht(DHT_PIN, DHT11); void setup() { Serial.begin(9600); pinMode(BUZZER, OUTPUT); pinMode(LED_ROUGE, OUTPUT); pinMode(LED_VERTE, OUTPUT); dht.begin(); } void loop() { delay(2000); float t = dht.readTemperature(); float h = dht.readHumidity(); if (isnan(t) || isnan(h)) { Serial.println("Erreur capteur"); return; } Serial.printf("T=%.1f°C H=%.1f%%", t, h); // printf non dispo sur Uno : // Serial.print(t,1); Serial.print(' C'); Serial.print(h,1); Serial.println('%'); bool alarme = (t > SEUIL_TEMP) || (h > SEUIL_HUMI); digitalWrite(LED_VERTE, !alarme); digitalWrite(LED_ROUGE, alarme); if (alarme) { Serial.println(" ⚠️ ALARME !"); tone(BUZZER, 2000, 500); // 2000Hz pendant 500ms } else { Serial.println(" OK"); noTone(BUZZER); } }
Afficher le DHT11 sur un écran LCD I2C
// Installer : 'LiquidCrystal I2C' par Frank de Brabander // Câblage LCD I2C : VCC→5V, GND→GND, SDA→A4, SCL→A5 // Trouver l'adresse I2C : utiliser le scanner I2C (voir section I2C) #include "DHT.h" #include "LiquidCrystal_I2C.h" DHT dht(2, DHT11); LiquidCrystal_I2C lcd(0x27, 16, 2); // adresse 0x27, 16 colonnes, 2 lignes void setup() { dht.begin(); lcd.begin(); lcd.backlight(); // allumer le rétroéclairage lcd.print("Station Meteo"); delay(2000); } void loop() { delay(2000); float t = dht.readTemperature(); float h = dht.readHumidity(); if (!isnan(t) && !isnan(h)) { lcd.clear(); lcd.setCursor(0, 0); // colonne 0, ligne 0 lcd.print("Temp : "); lcd.print(t, 1); lcd.print("C"); lcd.setCursor(0, 1); // colonne 0, ligne 1 lcd.print("Humi : "); lcd.print(h, 1); lcd.print("%"); } }
Protocoles — I2C, SPI, UART
L'Arduino peut communiquer avec des centaines de capteurs et modules via trois protocoles série principaux. Choisir le bon dépend du nombre de fils disponibles et de la vitesse requise.
| PROTOCOLE | FILS | VITESSE | APPAREILS MAX | USAGE TYPIQUE |
|---|---|---|---|---|
| UART | 2 (TX+RX) | 1200–115200 bps | 1 à 1 seulement | GPS, Bluetooth HC-05, GSM |
| I2C | 2 (SDA+SCL) | 100–400 kHz | 127 | Capteurs, OLED, RTC, ADC |
| SPI | 4 (MOSI+MISO+SCK+SS) | jusqu'à 8 MHz | plusieurs (1 SS par esclave) | Carte SD, écran TFT, Flash |
🔗 I2C — Scanner et utilisation
#include "Wire.h" void setup() { Wire.begin(); // SDA=A4, SCL=A5 sur Uno (défaut) Serial.begin(9600); Serial.println("=== Scan I2C ==="); int nb = 0; for (byte addr = 1; addr < 127; addr++) { Wire.beginTransmission(addr); if (Wire.endTransmission() == 0) { Serial.print("Trouvé à 0x"); Serial.println(addr, HEX); nb++; } } Serial.print(nb); Serial.println(" appareil(s)"); } void loop() {}
📡 UART — Communication série
// Module Bluetooth HC-05 via UART logiciel (SoftwareSerial) // Câblage : HC-05 TX → D10, HC-05 RX → D11 // (Ne pas utiliser D0/D1 = UART matériel = interfère avec USB) #include "SoftwareSerial.h" SoftwareSerial btSerial(10, 11); // RX=10, TX=11 void setup() { Serial.begin(9600); // moniteur série PC btSerial.begin(9600); // HC-05 en 9600 par défaut Serial.println("Bluetooth prêt. Connecter depuis smartphone."); } void loop() { // Relayer PC → Bluetooth if (Serial.available()) { btSerial.write(Serial.read()); } // Relayer Bluetooth → PC if (btSerial.available()) { char c = btSerial.read(); Serial.write(c); // Traiter les commandes reçues : if (c == 'A') digitalWrite(13, HIGH); if (c == 'E') digitalWrite(13, LOW); } }
💾 SPI — Carte SD
#include "SD.h" // bibliothèque SD intégrée à Arduino IDE #include "SPI.h" const int SD_CS = 4; // Chip Select — peut être changé selon le shield // Câblage SD : MOSI=11, MISO=12, SCK=13, CS=4 void setup() { Serial.begin(9600); if (!SD.begin(SD_CS)) { Serial.println("Carte SD non trouvée !"); while (true); } Serial.println("Carte SD OK !"); // Écrire dans un fichier File f = SD.open("data.txt", FILE_WRITE); if (f) { f.println("Température,Humidité,Timestamp"); // entête CSV f.close(); Serial.println("Entête écrit"); } } void loop() { // Lire le contenu du fichier File f = SD.open("data.txt"); while (f.available()) { Serial.write(f.read()); } f.close(); delay(5000); }
Capteurs — Le Monde Physique
Les capteurs sont les sens de l'Arduino — ils convertissent une grandeur physique en signal électrique mesurable. Voici les plus utilisés avec leur câblage et code complets.
| CAPTEUR | GRANDEUR | PROTOCOLE | BIBLIOTHÈQUE | PRÉCISION |
|---|---|---|---|---|
| DHT11 | Temp + Humidité | 1 fil propriétaire | DHT sensor library (Adafruit) | ±2°C ±5% |
| DHT22 | Temp + Humidité | 1 fil propriétaire | DHT sensor library (Adafruit) | ±0.5°C ±2% |
| DS18B20 | Température | 1-Wire | DallasTemperature | ±0.5°C |
| BMP180/280 | Pression + Temp | I2C | Adafruit BMP280 | ±1 hPa ±1°C |
| HC-SR04 | Distance ultrasons | 2 GPIO | NewPing (optionnel) | ±3mm |
| PIR HC-SR501 | Mouvement | 1 GPIO digital | Aucune — digitalRead suffit | Oui/Non |
| LDR | Luminosité | ADC (pont diviseur) | Aucune — analogRead suffit | Relative |
| MPU6050 | Gyro + Accéléro | I2C | MPU6050 (ElectronicCats) | ±0.1°/s |
| DS3231 | Horloge temps réel | I2C | RTClib (Adafruit) | ±2ppm |
📏 HC-SR04 — Capteur ultrasonique
// Câblage HC-SR04 : VCC→5V, GND→GND, TRIG→D9, ECHO→D10 // Principe : émettre une impulsion ultrasonique et mesurer le temps de retour // distance = (temps × vitesse_son) / 2 // vitesse du son ≈ 340 m/s = 0.034 cm/µs const int TRIG = 9; const int ECHO = 10; void setup() { Serial.begin(9600); pinMode(TRIG, OUTPUT); pinMode(ECHO, INPUT); } float mesurerDistance() { // 1. S'assurer que TRIG est LOW digitalWrite(TRIG, LOW); delayMicroseconds(2); // 2. Émettre impulsion 10µs digitalWrite(TRIG, HIGH); delayMicroseconds(10); digitalWrite(TRIG, LOW); // 3. Mesurer la durée du rebond (en µs) // pulseIn() attend que ECHO passe HIGH, mesure combien de temps long duree = pulseIn(ECHO, HIGH, 30000); // timeout 30ms = ~5m max if (duree == 0) return -1.0; // timeout = rien détecté // 4. Calculer la distance float distance = duree * 0.034 / 2.0; // en centimètres return distance; } void loop() { float d = mesurerDistance(); if (d < 0) { Serial.println("Hors portée (>4m)"); } else { Serial.print("Distance: "); Serial.print(d, 1); Serial.println(" cm"); if (d < 10.0) { Serial.println("⚠️ Obstacle proche !"); tone(8, 1000); } else { noTone(8); } } delay(100); }
🌡️ DS18B20 — Température précise (1-Wire)
// DS18B20 : capteur étanche, haute précision ±0.5°C // Installer : 'OneWire' + 'DallasTemperature' // Câblage : VCC→5V, GND→GND, DATA→D2 + résistance 4.7kΩ entre DATA et 5V // Avantage : plusieurs DS18B20 sur le même fil (adressage unique 64 bits) ! #include "OneWire.h" #include "DallasTemperature.h" OneWire oneWire(2); DallasTemperature sensors(&oneWire); void setup() { Serial.begin(9600); sensors.begin(); Serial.print("Capteurs trouvés: "); Serial.println(sensors.getDeviceCount()); } void loop() { sensors.requestTemperatures(); // demander mesure à tous les capteurs // Lire le 1er capteur (index 0) float t = sensors.getTempCByIndex(0); if (t == DEVICE_DISCONNECTED_C) { Serial.println("Capteur déconnecté !"); } else { Serial.print("Température: "); Serial.print(t, 2); Serial.println("°C"); } delay(1000); }
💾 EEPROM — Sauvegarder des données
#include "EEPROM.h" // bibliothèque intégrée // EEPROM Arduino Uno : 1024 octets (adresses 0 à 1023) // Durée de vie : 100 000 cycles d'écriture par adresse void setup() { Serial.begin(9600); // Écrire un octet (0–255) int adresse = 0; EEPROM.write(adresse, 42); // écrire la valeur 42 à l'adresse 0 // Lire un octet byte valeur = EEPROM.read(adresse); Serial.print("Lu de l'EEPROM: "); Serial.println(valeur); // Sauvegarder un float (4 octets) avec put() float temperature = 23.5; EEPROM.put(10, temperature); // adresse 10 à 13 // Lire un float avec get() float tLue; EEPROM.get(10, tLue); Serial.print("Temp EEPROM: "); Serial.println(tLue); // IMPORTANT : utiliser update() au lieu de write() // update() n'écrit QUE si la valeur a changé → préserve les 100k cycles EEPROM.update(0, 43); // écrit seulement si différent de 42 } void loop() {}
Afficheurs — LCD & OLED
Afficher des données en temps réel sans passer par le moniteur série. Deux solutions principales : le LCD 16×2 (texte simple, économique) et l'écran OLED SSD1306 (graphique, compact).
📟 LCD 16×2 avec module I2C (LCM1602)
// Installer : 'LiquidCrystal I2C' par Frank de Brabander #include "LiquidCrystal_I2C.h" LiquidCrystal_I2C lcd(0x27, 16, 2); // Créer un caractère personnalisé (ex: signe degré °) byte degre[8] = { 0b00110,0b01001,0b01001,0b00110, 0b00000,0b00000,0b00000,0b00000 }; void setup() { lcd.begin(); lcd.backlight(); lcd.createChar(0, degre); // stocker le caractère à l'indice 0 lcd.setCursor(0, 0); lcd.print("Station Meteo"); delay(2000); } void afficherTemp(float temp, float humi) { lcd.setCursor(0, 0); // ligne 1 lcd.print("T:"); lcd.print(temp, 1); lcd.write(byte(0)); // afficher le caractère ° (index 0) lcd.print("C "); lcd.setCursor(0, 1); // ligne 2 lcd.print("H:"); lcd.print(humi, 0); lcd.print("% "); } void loop() { afficherTemp(23.5, 65.0); delay(2000); }
🖥️ OLED SSD1306 128×64 pixels (I2C)
// Installer : 'Adafruit SSD1306' + 'Adafruit GFX Library' // Câblage : VCC→3.3V (ou 5V selon module), GND→GND, SDA→A4, SCL→A5 #include "Wire.h" #include "Adafruit_GFX.h" #include "Adafruit_SSD1306.h" #define LARGEUR 128 #define HAUTEUR 64 #define OLED_RESET (-1) // -1 = pas de broche reset Adafruit_SSD1306 display(LARGEUR, HAUTEUR, &Wire, OLED_RESET); void setup() { Serial.begin(9600); if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { Serial.println("OLED introuvable"); while (true); } display.clearDisplay(); display.setTextColor(SSD1306_WHITE); } void afficherDonnees(float temp, float humi) { display.clearDisplay(); // Titre — grande police display.setTextSize(2); // 2× = grands caractères 12×16 px display.setCursor(0, 0); display.print("Station"); // Température display.setTextSize(1); // 1× = caractères 6×8 px display.setCursor(0, 25); display.print("Temp: "); display.print(temp, 1); display.print(" C"); // Humidité display.setCursor(0, 37); display.print("Humi: "); display.print(humi, 0); display.print(" %"); // Barre de progression pour l'humidité int largeurBarre = map(humi, 0, 100, 0, 128); display.fillRect(0, 55, largeurBarre, 8, SSD1306_WHITE); display.drawRect(0, 55, 128, 8, SSD1306_WHITE); display.display(); // ← INDISPENSABLE : envoyer le buffer à l'écran } void loop() { afficherDonnees(23.5, 65.0); delay(2000); }
Moteurs & Actionneurs
L'Arduino ne peut pas alimenter directement un moteur — ses broches fournissent max 40mA. Il faut toujours passer par un circuit de puissance (transistor, driver L298N, MOSFET).
🔄 Servo-moteur
// Servo standard : SG90 (180°), MG996R (torque élevé) // Câblage : fil marron/noir→GND, rouge→5V, orange/jaune→D9 // La bibliothèque Servo gère le PWM 50Hz automatiquement #include "Servo.h" Servo monServo; void setup() { Serial.begin(9600); monServo.attach(9); // attacher servo à la broche D9 // Paramètres fins : .attach(9, 544, 2400) // 544µs = 0°, 1472µs = 90°, 2400µs = 180° } void loop() { // Balayage 0° → 180° → 0° for (int angle = 0; angle <= 180; angle += 5) { monServo.write(angle); Serial.print("Angle: "); Serial.println(angle); delay(50); } for (int angle = 180; angle >= 0; angle -= 5) { monServo.write(angle); delay(50); } // Contrôle par potentiomètre // int angle = map(analogRead(A0), 0, 1023, 0, 180); // monServo.write(angle); }
⚡ Moteur DC avec L298N
// L298N : driver double pont en H — pilote 2 moteurs DC // Câblage moteur A : IN1=D2, IN2=D3, ENA=D9(PWM) // Alimentation : 5V→5V_L298N, GND→GND_L298N, moteur→12V_IN const int IN1 = 2; const int IN2 = 3; const int ENA = 9; // broche Enable A (PWM pour vitesse) void avancer(int vitesse) { // vitesse : 0–255 digitalWrite(IN1, HIGH); digitalWrite(IN2, LOW); analogWrite(ENA, vitesse); } void reculer(int vitesse) { digitalWrite(IN1, LOW); digitalWrite(IN2, HIGH); analogWrite(ENA, vitesse); } void stopper() { digitalWrite(IN1, LOW); digitalWrite(IN2, LOW); analogWrite(ENA, 0); } void setup() { pinMode(IN1, OUTPUT); pinMode(IN2, OUTPUT); pinMode(ENA, OUTPUT); } void loop() { avancer(200); delay(2000); stopper(); delay(500); reculer(150); delay(2000); stopper(); delay(500); }
Projet — Station Météo Complète
Projet de A à Z : Arduino Uno + DHT11 mesure température et humidité toutes les 2 secondes, affiche sur LCD I2C, alerte si seuil dépassé, sauvegarde sur carte SD, et affiche un graphique sur OLED.
Matériel nécessaire
Arduino Uno, DHT11, LCD 16×2 + module I2C, écran OLED SSD1306, buzzer, 2 LEDs, carte SD + module, breadboard, fils dupont
Connexions
DHT11 DATA→D2, LCD I2C SDA→A4 SCL→A5, OLED SDA→A4 SCL→A5, Buzzer→D8, LED rouge→D6, LED verte→D7, SD CS→D4
Bibliothèques
Installer : DHT sensor library, LiquidCrystal I2C, Adafruit SSD1306, Adafruit GFX, SD (incluse)
Téléverser le code
Copier le code ci-dessous dans Arduino IDE, vérifier le port COM correct, téléverser
Calibrer les seuils
Modifier SEUIL_TEMP et SEUIL_HUMI selon l'environnement
Tester
Ouvrir le moniteur série à 9600 baud, souffler sur le DHT11 pour changer l'humidité
// ════════════════════════════════════════════════════════════ // STATION MÉTÉO COMPLÈTE — Arduino Uno + DHT11 + LCD + OLED // ════════════════════════════════════════════════════════════ #include "DHT.h" #include "LiquidCrystal_I2C.h" #include "Wire.h" #include "Adafruit_GFX.h" #include "Adafruit_SSD1306.h" #include "SD.h" #include "SPI.h" // ── Broches ───────────────────────────────────────────────── #define DHT_PIN 2 #define DHT_TYPE DHT11 #define BUZZER 8 #define LED_ROUGE 6 #define LED_VERTE 7 #define SD_CS 4 #define OLED_W 128 #define OLED_H 64 // ── Seuils d'alarme ───────────────────────────────────────── const float SEUIL_TEMP = 28.0; // °C const float SEUIL_HUMI = 75.0; // % const long INTERVALLE = 2000; // ms entre mesures // ── Objets ────────────────────────────────────────────────── DHT dht(DHT_PIN, DHT_TYPE); LiquidCrystal_I2C lcd(0x27, 16, 2); Adafruit_SSD1306 oled(OLED_W, OLED_H, &Wire, -1); // ── Variables globales ─────────────────────────────────────── unsigned long tDerniereLecture = 0; float historiqueTemp[10] = {0}; // 10 dernières valeurs int indexHistorique = 0; bool sdOk = false; // ── Caractère degré pour LCD ───────────────────────────────── byte degre[8] = {0b00110,0b01001,0b01001,0b00110,0b00000,0b00000,0b00000,0b00000}; void setup() { Serial.begin(9600); Serial.println("=== Station Météo ==="); // Broches pinMode(BUZZER, OUTPUT); pinMode(LED_ROUGE, OUTPUT); pinMode(LED_VERTE, OUTPUT); digitalWrite(LED_VERTE, HIGH); // tout OK au démarrage // DHT11 dht.begin(); // LCD lcd.begin(); lcd.backlight(); lcd.createChar(0, degre); lcd.setCursor(0,0); lcd.print("Station Meteo"); lcd.setCursor(0,1); lcd.print("Initialisation..."); // OLED if (oled.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { oled.clearDisplay(); oled.display(); Serial.println("OLED: OK"); } // Carte SD sdOk = SD.begin(SD_CS); Serial.println(sdOk ? "SD: OK" : "SD: non trouvée"); if (sdOk) { File f = SD.open("meteo.csv", FILE_WRITE); if (f) { f.println("temps_s,temperature,humidite,alarme"); f.close(); } } delay(2000); } void mettreAJourLCD(float t, float h) { lcd.setCursor(0,0); lcd.print("T:"); lcd.print(t,1); lcd.write(byte(0)); lcd.print("C "); lcd.setCursor(0,1); lcd.print("H:"); lcd.print(h,0); lcd.print("% "); } void mettreAJourOLED(float t, float h) { oled.clearDisplay(); oled.setTextSize(1); oled.setTextColor(WHITE); oled.setCursor(0,0); oled.print("STATION METEO"); oled.drawLine(0,10,127,10,WHITE); oled.setCursor(0,14); oled.setTextSize(2); oled.print(t,1); oled.print(" C"); oled.setTextSize(1); oled.setCursor(0,36); oled.print("Humidite: "); oled.print(h,0); oled.print("%"); // Graphique mini historique température for (int i=0; i<9; i++) { int y1 = map(historiqueTemp[i], 15,40,63,48); int y2 = map(historiqueTemp[i+1],15,40,63,48); oled.drawLine(i*14,constrain(y1,48,63),(i+1)*14,constrain(y2,48,63),WHITE); } oled.display(); } void sauvegarderSD(float t, float h, bool alarme) { if (!sdOk) return; File f = SD.open("meteo.csv", FILE_WRITE); if (f) { f.print(millis()/1000); f.print(","); f.print(t,2); f.print(","); f.print(h,2); f.print(","); f.println(alarme ? 1 : 0); f.close(); } } void loop() { if (millis() - tDerniereLecture < INTERVALLE) return; tDerniereLecture = millis(); float t = dht.readTemperature(); float h = dht.readHumidity(); if (isnan(t) || isnan(h)) { Serial.println("Erreur DHT11"); return; } // Historique historiqueTemp[indexHistorique % 10] = t; indexHistorique++; // Alarme bool alarme = (t > SEUIL_TEMP) || (h > SEUIL_HUMI); digitalWrite(LED_ROUGE, alarme); digitalWrite(LED_VERTE, !alarme); if (alarme) tone(BUZZER,1500,200); else noTone(BUZZER); // Affichage mettreAJourLCD(t, h); mettreAJourOLED(t, h); sauvegarderSD(t, h, alarme); Serial.printf("T=%.1f H=%.1f%s\n", t, h, alarme ? " ⚠️ALARME" : ""); }
Quiz 40 Questions
Du niveau débutant à expert — Arduino Uno, GPIO, ADC, DHT11, I2C, mémoire, optimisation. Chaque erreur expliquée en détail.
analogRead(A0) sur Arduino Uno ?pinMode(7, OUTPUT) ?INPUT_PULLUP pour un bouton plutôt que INPUT ?delay(1000) et millis() ?Serial.begin(9600) ?map(val, 0, 1023, 0, 180) ?loop() sans être globale ?Wire.begin() sur Arduino Uno ?pulseIn(pin, HIGH) mesure ?volatile devant une variable partagée avec une interruption ?analogWrite() sur les broches D3 et D11 de l'Arduino Uno ?millis() après environ 49 jours ?F() et pourquoi est-ce important sur Arduino Uno ?EEPROM.write() et EEPROM.update() ?PROGMEM et dans quel cas est-il indispensable ?Serial.print() et Serial.println() ?Serial.print() ?Cheat Sheet Arduino
GPIO DIGITAL
pinMode(pin, OUTPUT); pinMode(pin, INPUT_PULLUP); digitalWrite(pin, HIGH/LOW); int v = digitalRead(pin); // pull-up : repos=HIGH, appui=LOW // Max 40mA par broche // Max 200mA total toutes broches
ADC & PWM
int v = analogRead(A0); // 0-1023 float V = v * 5.0 / 1023.0; int p = map(v, 0, 1023, 0, 100); // PWM sur ~3,5,6,9,10,11 : analogWrite(9, 0-255); // Fréquence : 490Hz (ou 980Hz D3/D11)
DHT11
#include "DHT.h" DHT dht(2, DHT11); dht.begin(); // Dans loop() : delay(2000); // min 1s entre lectures float t = dht.readTemperature(); float h = dht.readHumidity(); if (isnan(t)) // toujours vérifier!
I2C (Wire.h)
#include "Wire.h" Wire.begin(); // SDA=A4, SCL=A5 // Scanner pour trouver adresses : Wire.beginTransmission(addr); byte err = Wire.endTransmission(); // err==0 → appareil trouvé // pull-up 4.7kΩ entre SDA/SCL et 5V
MILLIS NON-BLOQUANT
unsigned long tDernier = 0; // Dans loop() : if (millis() - tDernier >= 2000) { tDernier = millis(); // ... action toutes les 2s } // Ne JAMAIS utiliser delay() // dans les projets avancés
EEPROM
#include "EEPROM.h" // Écrire (100 000 cycles max) EEPROM.update(addr, valeur); // update() = write si changé byte v = EEPROM.read(addr); float f; EEPROM.get(10, f); EEPROM.put(10, f); // Uno: 1024 octets (0-1023)
SERIAL DEBUG
Serial.begin(9600); Serial.print(F("message")); // économise SRAM Serial.print(valeur, 2); // 2 décimales Serial.println(valeur); // + newline // Mémoire libre : // extern int __heap_start, *__brkval; // int v; return (int)&v - (__brkval==0)
BROCHES SPÉCIALES UNO
// D0/D1 : RX/TX USB → ne pas utiliser // D2/D3 : INT0/INT1 interruptions // D3,5,6,9,10,11 : PWM ~ // D10,11,12,13 : SPI SS/MOSI/MISO/SCK // D13 : LED_BUILTIN // A4/A5 : I2C SDA/SCL // A0-A5 : ADC 10 bits (aussi GPIO)