Apprenez à utiliser un capteur de mouvement PIR (infrarouge passif) avec l’ESP32 programmé avec Arduino IDE pour détecter les mouvements. Nous allons créer un exemple simple pour vous présenter les concepts de minuteries et d’interruptions.
Dans cet exemple, lorsqu’un mouvement est détecté (une interruption est déclenchée), l’ESP32 démarre une minuterie et allume une LED pendant un nombre de secondes prédéfini. Lorsque le compte à rebours termine, la LED s’éteint automatiquement.

Mis à jour le 27 octobre 2025.
Vous utilisez MicroPython ? Consultez plutôt ce tutoriel : MicroPython : Interruptions avec ESP32 et ESP8266.
Table des matières
Dans ce tutoriel, nous aborderons les sujets suivants :
Conditions préalables
Avant de poursuivre ce didacticiel, vous devez avoir installé les cartes ESP32 dans votre IDE Arduino. Suivez ce prochain tutoriel pour installer l’ESP32 sur l’IDE Arduino, si vous ne l’avez pas déjà fait.
Pièces requises
Pour suivre ce tutoriel, vous avez besoin des pièces suivantes
Vous pouvez utiliser les liens précédents ou vous rendre directement sur MakerAdvisor.com/tools pour trouver toutes les pièces pour vos projets au meilleur prix !

Présentation du capteur de mouvement PIR
Un capteur de mouvement PIR détecte les changements de lumière infrarouge dans son champ de vision provoqués par le mouvement. Cela le rend idéal pour détecter les humains ou les animaux, car il détectera les êtres vivants (ou les objets émettant de la chaleur) qui se déplacent à leur portée, mais pas les objets inanimés.
Vous pouvez programmer l’ESP32 pour qu’il réagisse aux changements de lumière infrarouge en déclenchant un événement tel que l’allumage d’une lumière, le déclenchement d’une alarme, l’envoi d’une notification ou toute autre tâche. Dans ce didacticiel, nous allons imprimer un message sur le moniteur série et allumer une LED pendant un nombre de secondes prédéfini.

Il existe différents modules de capteurs de mouvement PIR, mais tous agissent de la même manière. Habituellement, ils ont une broche d’alimentation, GND et des données.
Le capteur de mouvement PIR émet un signal ÉLEVÉ sur la broche de données lorsqu’il détecte un mouvement, ou un signal FAIBLE s’il ne le détecte pas. Habituellement, ils n’ont que trois broches : VCC, GND et Data.

Un concept important concernant les capteurs de mouvement PIR est le temps de séjour (temps de réinitialisation ou délai du capteur) : il s’agit de la durée pendant laquelle la sortie d’un capteur de mouvement PIR reste ÉLEVÉE après avoir détecté un mouvement avant de revenir à un état BAS.
Certains modèles de capteurs PIR, comme le HC-SR501, peuvent avoir deux potentiomètres (ces deux potentiomètres orange sur l’image ci-dessous) pour régler la sensibilité et le retard du capteur :

- Potentiomètre de sensibilité : il ajuste la plage de détection du capteur. Dans le sens des aiguilles d’une montre, la sensibilité augmente, dans le sens inverse des aiguilles d’une montre, la diminue.
- Potentiomètre de temporisation : il contrôle la durée pendant laquelle le capteur reste déclenché après la détection d’un mouvement. Dans le sens des aiguilles d’une montre, le délai augmente et dans le sens inverse des aiguilles d’une montre, il le diminue.
Présentation des interruptions
Pour déclencher un événement avec un capteur de mouvement PIR, vous utilisez des interruptions. Les interruptions sont utiles pour que les choses se produisent automatiquement dans les programmes de microcontrôleurs et peuvent aider à résoudre les problèmes de synchronisation.
Avec les interruptions, vous n’avez pas besoin de vérifier constamment la valeur actuelle d’une broche. Avec les interruptions, lorsqu’un changement est détecté, un événement est déclenché (une fonction est appelée).
Utiliser les interruptions avec l’ESP32
Pour définir une interruption dans l’IDE Arduino, vous utilisez la fonction attachInterrupt(), qui accepte comme arguments : la broche GPIO, le nom de la fonction à exécuter et le mode :
attachInterrupt(GPIO), callback_function, mode);
Cette instruction doit être ajoutée au setup() de votre code Arduino.
Jetons un coup d’œil aux arguments que vous devez transmettre à cette fonction.
Interruption GPIO
Le premier argument de la fonction attachInterrupt() est le numéro GPIO où nous détecterons le changement. Par exemple, si vous souhaitez utiliser GPIO 27 comme interruption, vous pouvez utiliser :
digitalPinToInterrupt(27)
Avec une carte ESP32, toutes les broches pouvant servir d’entrées peuvent être définies comme des interruptions.
Par exemple, dans le cas de la carte ESP32 DOIT V1, toutes les broches mises en évidence par un rectangle rouge dans la figure suivante peuvent être configurées comme broches d’interruption. Dans cet exemple, nous utiliserons le GPIO 27 comme interruption connectée au capteur de mouvement PIR.

Vous utilisez plutôt un ESP32S3 ? Consultez ce guide de brochage : Guide de référence du brochage ESP32-S3 DevKitC : explication des GPIO.
Fonction de rappel (ISR)
Le deuxième argument de la fonction attachInterrupt() est le nom de la fonction qui sera appelée lorsque l’interruption sera déclenchée. Cette fonction est également appelée routine de service d’interruption (ISR).
Maintenant, il y a quelques règles importantes que vous devez connaître lors de la définition de votre ISR (fonction de rappel).
- L’ISR ne devrait rien renvoyer.
- Les ISR doivent être aussi courts et rapides que possible car ils interrompent l’exécution normale du code.
- Ils doivent avoir l’attribut ARDUINO_ISR_ATTR, afin qu’ils fonctionnent dans la RAM interne de l’ESP32 et non en Flash. L’accès à l’IRAM est beaucoup plus rapide, ce qui est essentiel pour que les ISR fonctionnent de manière fiable sans problèmes de synchronisation ni plantages lors des interruptions.
- Les variables utilisées dans les ISR et dans tout le code doivent de préférence être volatiles. Cela empêche le compilateur de mettre en cache les valeurs dans les registres (et d’ignorer l’accès à la mémoire), de sorte que les lectures/écritures accèdent toujours à l’emplacement mémoire réel et reflètent les changements inattendus provoqués par l’interruption.
Voici un exemple d’ISR afin que vous puissiez vérifier sa syntaxe :
void ARDUINO_ISR_ATTR my_callback() {
// Any code you want to run
}
Une autre chose importante à propos des ISR est que vous devez garder leur code aussi rapide et simple que possible et éviter des choses comme des opérations complexes, l’écriture sur Serial Monitor ou l’utilisation de delay(). Au lieu de cela, vous devez utiliser un indicateur ou un compteur pour indiquer que l’interruption s’est produite, puis gérer tout ce que vous devez faire dans la section code principal ou loop().
Mode
Le troisième argument est le mode. Il existe 5 modes différents :
- LOW : pour déclencher l’interruption chaque fois que la broche est LOW ;
- HIGH : pour déclencher l’interruption chaque fois que la broche est HIGH ;
- CHANGEMENT : pour déclencher l’interruption chaque fois que la broche change de valeur – par exemple, de HIGH à LOW ou de LOW à HIGH ;
- FALLING : lorsque la goupille passe de HAUT à BAS ;
- RISING : à déclencher lorsque la broche passe de LOW à HIGH.
L’image suivante vous aidera à mieux comprendre les différents modes de déclenchement.

Pour cet exemple, nous utiliserons le mode RISING, car lorsque le capteur de mouvement PIR détecte un mouvement, le GPIO auquel il est connecté passe de LOW à HIGH.
Présentation des minuteries
Dans cet exemple, nous présenterons également les minuteries. Nous voulons que la LED reste allumée pendant un nombre prédéterminé de secondes après la détection d’un mouvement. Au lieu d’utiliser une fonction delay() qui bloque votre code et ne vous permet pas de faire autre chose pendant un nombre déterminé de secondes, nous devrions utiliser un timer.

La fonction delay()
Vous devez être familier avec la fonction delay() car elle est largement utilisée. Cette fonction est assez simple à utiliser. Il accepte un seul nombre int comme argument. Ce nombre représente le temps en millisecondes que le programme doit attendre avant de passer à la ligne de code suivante.
delay(time in milliseconds)
Lorsque vous appelez delay(1000), votre programme s’arrête sur cette ligne pendant 1 seconde.
delay() est une fonction bloquante. Les fonctions de blocage empêchent un programme de faire autre chose jusqu’à ce que cette tâche particulière soit terminée. Si vous avez besoin que plusieurs tâches se produisent en même temps, vous ne pouvez pas utiliser delay().
Pour la plupart des projets, vous devez éviter d’utiliser des retards et utiliser plutôt des minuteries.
La fonction millis()
L’utilisation d’une fonction appelée millis() est préférable à l’utilisation de delay(). La fonction millis() renvoie le nombre de millisecondes écoulées depuis le premier démarrage du programme.
millis()
Pourquoi cette fonction est-elle utile ? En utilisant quelques mathématiques, vous pouvez facilement vérifier combien de temps s’est écoulé depuis un certain événement sans bloquer votre code.
Faire clignoter une LED avec millis()
L’extrait de code suivant montre comment utiliser la fonction millis() pour créer un projet de LED clignotantes. Il allume une LED pendant 1 000 millisecondes, puis l’éteint.
/*********
Rui Santos
Complete project details at https://raspberryme.com
*********/
// constants won't change. Used here to set a pin number :
const int ledPin = 26; // the number of the LED pin
// Variables will change :
int ledState = LOW; // ledState used to set the LED
// Generally, you should use "unsigned long" for variables that hold time
// The value will quickly become too large for an int to store
unsigned long previousMillis = 0; // will store last time LED was updated
// constants won't change :
const long interval = 1000; // interval at which to blink (milliseconds)
void setup() {
// set the digital pin as output:
pinMode(ledPin, OUTPUT);
}
void loop() {
// here is where you'd put code that needs to be running all the time.
// check to see if it's time to blink the LED; that is, if the
// difference between the current time and last time you blinked
// the LED is bigger than the interval at which you want to
// blink the LED.
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= interval) {
// save the last time you blinked the LED
previousMillis = currentMillis;
// if the LED is off turn it on and vice-versa:
if (ledState == LOW) {
ledState = HIGH;
} else {
ledState = LOW;
}
// set the LED with the ledState of the variable:
digitalWrite(ledPin, ledState);
}
}
Afficher le code brut
Comment fonctionne le code
Regardons de plus près cette esquisse clignotante qui fonctionne sans fonction delay() (elle utilise à la place la fonction millis()).
Fondamentalement, ce code soustrait l’heure enregistrée précédente (previousMillis) de l’heure actuelle (currentMillis). Si le reste est supérieur à l’intervalle (dans ce cas, 1 000 millisecondes), le programme met à jour la variable previousMillis à l’heure actuelle et allume ou éteint la LED.
if (currentMillis - previousMillis >= interval) {
// save the last time you blinked the LED
previousMillis = currentMillis;
(...)
Étant donné que cet extrait n’est pas bloquant, tout code situé en dehors de cette première instruction if devrait fonctionner normalement.
Vous devriez maintenant pouvoir comprendre que vous pouvez ajouter d’autres tâches à votre fonction loop() et que votre code fera toujours clignoter la LED toutes les secondes.
Vous pouvez télécharger ce code sur votre ESP32 et assembler le schéma suivant pour le tester et modifier le nombre de millisecondes pour voir comment il fonctionne.

ESP32 avec capteur de mouvement PIR : détection de mouvement
Après avoir compris ces concepts : interruptions et minuteries, poursuivons le projet.
Nous allons créer un exemple simple qui allumera une LED lorsqu’un mouvement est détecté. Après avoir appris son fonctionnement, la même façon de penser peut être appliquée à des applications utiles, comme l’envoi d’un e-mail ou le déclenchement d’une alarme.

Voici comment fonctionne l’exemple :
- Le capteur détecte le mouvement.
- L’ESP32 détecte cet événement.
- Il imprime sur le moniteur série qu’un mouvement a été détecté.
- Il allume une LED pendant 20 secondes.
- Pendant ces 20 secondes, nous n’imprimons rien d’autre sur le moniteur série.
- Après ces 20 secondes et si aucun mouvement n’a été détecté, nous éteignons la LED et imprimons un message sur le moniteur série indiquant que le mouvement s’est arrêté.
Schéma de circuit
Pour cet exemple, vous devez connecter le capteur de mouvement PIR et une LED à votre carte.
La LED est connectée au GPIO 26.
Nous utiliserons le capteur de mouvement PIR Mini AM312 qui fonctionne à 3,3 V. Il sera connecté au GPIO 27. Vous pouvez suivre le schéma suivant.

Important : le capteur de mouvement PIR Mini AM312 utilisé dans ce projet fonctionne à 3,3 V. Cependant, si vous utilisez un autre capteur de mouvement PIR comme le HC-SR501, il fonctionne à 5 V. Vous pouvez soit le modifier pour fonctionner à 3,3 V, soit simplement l’alimenter à l’aide de la broche Vin.
Code – ESP32 avec un capteur de mouvement PIR : détecter le mouvement
Après avoir câblé le circuit comme indiqué dans le schéma, copiez le code fourni sur votre IDE Arduino.
Vous pouvez télécharger le code tel quel ou modifier le nombre de secondes pendant lesquelles la LED reste allumée après la détection d’un mouvement. Modifiez simplement la variable timeSeconds avec le nombre de secondes souhaité.
/*********
Rui Santos & Sara Santos - Raspberryme.com
Complete project details at https://Raspberryme.com/esp32-pir-motion-sensor-interrupts-timers/
*********/
#include
// Set GPIOs for LED and PIR Motion Sensor
const uint8_t led = 26;
const uint8_t motionSensor = 27;
// Timer: Auxiliary variables
unsigned long now;
volatile unsigned long lastTrigger = 0;
volatile bool startTimer = false;
bool printMotion = false;
const unsigned long timeSeconds = 20 * 1000UL; //20 seconds in milliseconds
void ARDUINO_ISR_ATTR motionISR() {
lastTrigger = millis();
startTimer = true;
}
void setup() {
Serial.begin(115200);
pinMode(motionSensor, INPUT_PULLUP);
attachInterrupt(motionSensor, motionISR, RISING);
// Set LED to LOW
pinMode(led, OUTPUT);
digitalWrite(led, LOW);
}
void loop() {
now = millis();
// Turn LED on immediately on new trigger
if (startTimer && !printMotion) {
digitalWrite(led, HIGH);
Serial.println("MOTION DETECTED!!!");
printMotion = true;
}
// Turn off the LED after timeout
if (startTimer && (now - lastTrigger > timeSeconds)) {
Serial.println("Motion stopped...");
digitalWrite(led, LOW);
startTimer = false;
printMotion = false;
}
}
Afficher le code brut
Remarque : si vous rencontrez des problèmes lors du téléchargement du code sur votre ESP32, consultez le guide de dépannage de l’ESP32.
Comment fonctionne le code ?
Jetons un coup d’œil rapide au code pour mieux comprendre son fonctionnement.
Définir des variables
Nous commençons par définir les broches du capteur de mouvement LED et PIR. Ajustez si vous utilisez des broches différentes :
const uint8_t led = 26;
const uint8_t motionSensor = 27;
Créez des variables pour suivre la durée de la LED à l’état allumé. La variable now enregistre l’heure actuelle (temps écoulé depuis le démarrage du programme), lastTrigger enregistre la dernière fois qu’un mouvement a été détecté et startTimer est une variable booléenne pour indiquer si la minuterie pour allumer la LED est actuellement en cours d’exécution ou non.
unsigned long now;
volatile unsigned long lastTrigger = 0;
volatile bool startTimer = false;
Nous avons également une autre variable pour savoir si le texte Motion Detected a déjà été imprimé sur le moniteur série.
bool printMotion = false;
La variable timeSeconds enregistre la durée pendant laquelle nous voulons que la LED reste allumée après la détection d’un mouvement. Vous pouvez ajuster selon vos préférences.
const unsigned long timeSeconds = 20 * 1000UL; //20 seconds in milliseconds
mouvementISR()
Le motionISR() s’exécutera lorsqu’un mouvement est détecté. Nous enregistrons l’heure actuelle sur la variable lastTrigger pour suivre le moment où un mouvement a été détecté, et nous définissons la variable startTimer sur true pour indiquer qu’il est temps de démarrer la minuterie pour allumer la LED.
void ARDUINO_ISR_ATTR motionISR() {
lastTrigger = millis();
startTimer = true;
}
Nous gérerons ensuite ces variables dans la boucle() pour effectuer les tâches souhaitées.
installation()
Dans setup(), définissez le capteur de mouvement comme interruption en mode RISING (lorsqu’un mouvement est détecté, le capteur règle sa broche de sortie sur HIGH).
pinMode(motionSensor, INPUT_PULLUP);
attachInterrupt(motionSensor, motionISR, RISING);
Et réglez la LED comme SORTIE et réglez-la sur FAIBLE.
// Set LED to LOW
pinMode(led, OUTPUT);
digitalWrite(led, LOW);
boucle()
Dans la boucle(), nous obtenons constamment l’heure actuelle et la sauvegardons dans la variable now.
now = millis();
Ensuite, nous vérifions si la minuterie LED a démarré et si le message de mouvement n’a pas déjà été imprimé. Si ces conditions sont remplies, nous allumons la LED, imprimons un message sur le moniteur série et définissons la variable printMotion sur true, car nous avons maintenant imprimé le message Motion Detected sur le moniteur série.
if (startTimer && !printMotion) {
digitalWrite(led, HIGH);
Serial.println("MOTION DETECTED!!!");
printMotion = true;
}
Démonstration
Téléchargez le code sur votre carte ESP32. Assurez-vous d’avoir sélectionné la bonne carte et le bon port COM.
Ouvrez le moniteur série à un débit en bauds de 115 200. Appuyez sur le bouton ESP32 RST pour qu’il commence à exécuter le code.
Déplacez votre main devant le capteur PIR.

La LED doit s’allumer et un message est imprimé sur le moniteur série indiquant « MOUVEMENT DÉTECTÉ !!! ».

Après 20 secondes, la LED devrait s’éteindre (si aucun mouvement n’a été détecté entre-temps).

Maintenant que vous comprenez comment utiliser les interruptions pour détecter un mouvement avec un capteur de mouvement PIR, vous pouvez facilement ajuster le code pour effectuer toutes les tâches utiles au lieu de contrôler une LED.
Vous pouvez, par exemple, envoyer des notifications sur votre email ou votre smartphone pour indiquer qu’un mouvement a été détecté. Nous avons un didacticiel présentant sept façons différentes d’envoyer des notifications avec l’ESP32 que vous pouvez explorer :
Regardez le didacticiel vidéo et la démo du projet
Ce tutoriel est également disponible au format vidéo (regardez ci-dessous). Notez que le format vidéo peut être obsolète.

Conclusion
Pour conclure, les interruptions sont utilisées pour détecter un changement dans l’état du GPIO sans qu’il soit nécessaire de lire constamment la valeur actuelle du GPIO. Avec les interruptions, lorsqu’un changement est détecté, une fonction est déclenchée. Vous avez également appris à définir une minuterie simple qui vous permet de vérifier si un nombre prédéfini de secondes s’est écoulé sans avoir à bloquer votre code.
Nous avons d’autres tutoriels liés à l’ESP32 qui pourraient également vous plaire :
Ceci est un extrait de notre cours : Apprenez l’ESP32 avec l’IDE Arduino. Si vous aimez ESP32 et souhaitez en savoir plus, nous vous recommandons de vous inscrire au cours Apprendre ESP32 avec Arduino IDE.
Merci d’avoir lu.
Cette vidéo vous emmène dans l’histoire de Raspberry Pi :

-
AZDelivery Kit de démarrage ESP32 Dev Kit C NodeMCU – HC-SR501 PIR Détecteur de Mouvement avec Mini Breadboard Compatible avec Arduino y Compris Un E-Book!
-
Greluma 2 Pièces Mini commutateur de capteur de Mouvement PIR, commutateur de capteur de présence DC 5-24V 2A pour Bande Lumineuse LED
