{"id":68479,"date":"2018-08-03T08:54:50","date_gmt":"2018-08-03T08:54:50","guid":{"rendered":"http:\/\/randomnerdtutorials.com\/?p=68479"},"modified":"2024-08-02T15:10:17","modified_gmt":"2024-08-02T15:10:17","slug":"esp32-pir-motion-sensor-interrupts-timers","status":"publish","type":"post","link":"https:\/\/randomnerdtutorials.com\/esp32-pir-motion-sensor-interrupts-timers\/","title":{"rendered":"ESP32 with PIR Motion Sensor using Interrupts and Timers"},"content":{"rendered":"\n<p>This tutorial shows how to detect motion with the ESP32 using a PIR motion sensor. In this example, when motion is detected (an interrupt is triggered), the ESP32 starts a timer and turns an LED on for a predefined number of seconds. When the timer finishes counting down, the LED is automatically turned off.<\/p>\n\n\n\n<!--more-->\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><img data-recalc-dims=\"1\" fetchpriority=\"high\" decoding=\"async\" width=\"1200\" height=\"675\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2018\/07\/ESP32_PIR_featured.jpg?resize=1200%2C675&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"\" class=\"wp-image-68496\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2018\/07\/ESP32_PIR_featured.jpg?w=1280&amp;quality=100&amp;strip=all&amp;ssl=1 1280w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2018\/07\/ESP32_PIR_featured.jpg?resize=300%2C169&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2018\/07\/ESP32_PIR_featured.jpg?resize=768%2C432&amp;quality=100&amp;strip=all&amp;ssl=1 768w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2018\/07\/ESP32_PIR_featured.jpg?resize=1024%2C576&amp;quality=100&amp;strip=all&amp;ssl=1 1024w\" sizes=\"(max-width: 1200px) 100vw, 1200px\" \/><\/figure><\/div>\n\n\n<p>With this example we\u2019ll also explore two important concepts: interrupts and timers.<\/p>\n\n\n\n<p>Before proceeding with this tutorial you should have the ESP32 add-on installed in your Arduino IDE. Follow one of the following tutorials to install the ESP32 on the Arduino IDE, if you haven\u2019t already.<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/randomnerdtutorials.com\/installing-esp32-arduino-ide-2-0\/\" title=\"\">Installing ESP32 Board in Arduino IDE 2 (Windows, Mac OS X, Linux)<\/a><\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\">Watch the Video Tutorial and Project Demo<\/h2>\n\n\n\n<p><em>This tutorial is available in video format (watch below) and in written format (continue reading).<\/em><\/p>\n\n\n<p style=\"text-align:center\"><iframe width=\"720\" height=\"405\" src=\"https:\/\/www.youtube.com\/embed\/PcqiKy_rb24?rel=0\" frameborder=\"0\" allowfullscreen><\/iframe><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Parts Required<\/h2>\n\n\n\n<p>To follow this tutorial you need the following parts<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/makeradvisor.com\/tools\/esp32-dev-board-wi-fi-bluetooth\/\" target=\"_blank\" rel=\"noopener noreferrer\">ESP32 DOIT DEVKIT V1 Board<\/a>\u00a0&#8211;\u00a0<a href=\"https:\/\/makeradvisor.com\/esp32-development-boards-review-comparison\/\" target=\"_blank\" rel=\"noopener noreferrer\">read ESP32 Development Boards Review and Comparison<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/makeradvisor.com\/tools\/mini-hc-sr505-pir-motion-sensor\/\" target=\"_blank\" rel=\"noopener noreferrer\">Mini PIR motion sensor (AM312)<\/a>\u00a0or\u00a0<a href=\"https:\/\/makeradvisor.com\/tools\/pir-motion-sensor-hc-sr501\/\" target=\"_blank\" rel=\"noopener noreferrer\">PIR motion sensor (HC-SR501)<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/makeradvisor.com\/tools\/3mm-5mm-leds-kit-storage-box\/\" target=\"_blank\" rel=\"noopener noreferrer\">5mm LED<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/makeradvisor.com\/tools\/resistors-kits\/\" target=\"_blank\" rel=\"noopener noreferrer\">330 Ohm resistor<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/makeradvisor.com\/tools\/jumper-wires-kit-120-pieces\/\" target=\"_blank\" rel=\"noopener noreferrer\">Jumper wires<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/makeradvisor.com\/tools\/mb-102-solderless-breadboard-830-points\/\" target=\"_blank\" rel=\"noopener noreferrer\">Breadboard<\/a><\/li>\n<\/ul>\n\n\n<p>You can use the preceding links or go directly to <a href=\"https:\/\/makeradvisor.com\/tools\/?utm_source=rnt&utm_medium=post&utm_campaign=post\" target=\"_blank\">MakerAdvisor.com\/tools<\/a> to find all the parts for your projects at the best price!<\/p><p style=\"text-align:center;\"><a href=\"https:\/\/makeradvisor.com\/tools\/?utm_source=rnt&utm_medium=post&utm_campaign=post\" target=\"_blank\"><img data-recalc-dims=\"1\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2017\/10\/header-200.png?w=1200&#038;quality=100&#038;strip=all&#038;ssl=1\"><\/a><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Introducing Interrupts<\/h2>\n\n\n\n<p>To trigger an event with a PIR motion sensor, you use interrupts. Interrupts are useful for making things happen automatically in microcontroller programs, and can help solve timing problems.<\/p>\n\n\n\n<p>With interrupts you don\u2019t need to constantly check the current value of a pin. With interrupts, when a change is detected, an event is triggered (a function is called).<\/p>\n\n\n\n<p>To set an interrupt in the Arduino IDE, you use the <strong><span class=\"rnthl rntliteral\">attachInterrupt()<\/span><\/strong> function, that accepts as arguments: the GPIO pin, the name of the function to be executed, and mode:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>attachInterrupt(digitalPinToInterrupt(GPIO), function, mode);<\/code><\/pre>\n\n\n\n<p><strong>GPIO Interrupt<\/strong><\/p>\n\n\n\n<p>The first argument is a GPIO number. Normally, you should use <span class=\"rnthl rntliteral\">digitalPinToInterrupt(GPIO)<\/span> to set the actual GPIO as an interrupt pin. For example, if you want to use <span class=\"rnthl rntcyellow\">GPIO 27<\/span> as an interrupt, use:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>digitalPinToInterrupt(27)<\/code><\/pre>\n\n\n\n<p>With an ESP32 board, all the pins highlighted with a red rectangle in the following figure can be configured as interrupt pins. In this example we\u2019ll use <span class=\"rnthl rntcyellow\">GPIO 27<\/span> as an interrupt connected to the PIR Motion sensor.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><img data-recalc-dims=\"1\" decoding=\"async\" width=\"522\" height=\"676\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2018\/07\/pins_used_as_interrupts.png?resize=522%2C676&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"\" class=\"wp-image-68484\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2018\/07\/pins_used_as_interrupts.png?w=522&amp;quality=100&amp;strip=all&amp;ssl=1 522w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2018\/07\/pins_used_as_interrupts.png?resize=232%2C300&amp;quality=100&amp;strip=all&amp;ssl=1 232w\" sizes=\"(max-width: 522px) 100vw, 522px\" \/><\/figure><\/div>\n\n\n<p><\/p>\n\n\n\n<p><strong>Function to be triggered<\/strong><\/p>\n\n\n\n<p>The second argument of the <span class=\"rnthl rntliteral\">attachInterrupt()<\/span> function is the name of the function that will be called every time the interrupt is triggered.<\/p>\n\n\n\n<p><strong>Mode<\/strong><\/p>\n\n\n\n<p>The third argument is the mode. There are 5 different modes:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><span class=\"rnthl rntliteral\">LOW<\/span>: to trigger the interrupt whenever the pin is LOW;<\/li>\n\n\n\n<li><span class=\"rnthl rntliteral\">HIGH<\/span>: to trigger the interrupt whenever the pin is HIGH;<\/li>\n\n\n\n<li><span class=\"rnthl rntliteral\">CHANGE<\/span>: to trigger the interrupt whenever the pin changes value &#8211; for example from HIGH to LOW or LOW to HIGH;<\/li>\n\n\n\n<li><span class=\"rnthl rntliteral\">FALLING<\/span>: for when the pin goes from HIGH to LOW;<\/li>\n\n\n\n<li><span class=\"rnthl rntliteral\">RISING<\/span>: to trigger when the pin goes from LOW to HIGH.<\/li>\n<\/ul>\n\n\n\n<p>For this example will be using the RISING mode, because when the PIR motion sensor detects motion, the GPIO it is connected to goes from LOW to HIGH.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Introducing Timers<\/h2>\n\n\n\n<p>In this example we&#8217;ll also introduce timers. We want the LED to stay on for a predetermined number of seconds after motion is detected. Instead of using a <span class=\"rnthl rntliteral\">delay()<\/span> function that blocks your code and doesn\u2019t allow you to do anything else for a determined number of seconds, we should use a timer.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><img data-recalc-dims=\"1\" decoding=\"async\" width=\"150\" height=\"150\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2018\/07\/alarm-clock-1-150x150.png?resize=150%2C150&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"\" class=\"wp-image-68480\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2018\/07\/alarm-clock-1-150x150.png?resize=150%2C150&amp;quality=100&amp;strip=all&amp;ssl=1 150w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2018\/07\/alarm-clock-1-150x150.png?resize=80%2C80&amp;quality=100&amp;strip=all&amp;ssl=1 80w\" sizes=\"(max-width: 150px) 100vw, 150px\" \/><\/figure><\/div>\n\n\n<h3 class=\"wp-block-heading\">The delay() function<\/h3>\n\n\n\n<p>You should be familiar with the <span class=\"rnthl rntliteral\">delay()<\/span> function as it is widely used. This function is pretty straightforward to use. It accepts a single int number as an argument. This number represents the time in milliseconds the program has to wait until moving on to the next line of code.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>delay(time in milliseconds)<\/code><\/pre>\n\n\n\n<p>When you call <span class=\"rnthl rntliteral\">delay(1000)<\/span> your program stops on that line for 1 second.<\/p>\n\n\n\n<p><span class=\"rnthl rntliteral\">delay()<\/span> is a blocking function. Blocking functions prevent a program from doing anything else until that particular task is completed. If you need multiple tasks to occur at the same time, you cannot use <span class=\"rnthl rntliteral\">delay()<\/span>.<\/p>\n\n\n\n<p>For most projects, you should avoid using delays and use timers instead.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">The millis() function<\/h3>\n\n\n\n<p>Using a function called <span class=\"rnthl rntliteral\">millis()<\/span> you can return the number of milliseconds that have passed since the program first started.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>millis()<\/code><\/pre>\n\n\n\n<p>Why is that function useful? Because by using some math, you can easily check how much time has passed without blocking your code.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Blinking an LED with millis()<\/h3>\n\n\n\n<p>The following snippet of code shows how you can use the <span class=\"rnthl rntliteral\">millis()<\/span> function to create a blink LED project. It turns an LED on for 1000 milliseconds, and then turns it off.<\/p>\n\n\n<pre style=\"max-height: 40em; margin-bottom: 20px;\"><code class=\"language-c\">\/*********\n  Rui Santos\n  Complete project details at http:\/\/randomnerdtutorials.com  \n*********\/\n\n\/\/ constants won't change. Used here to set a pin number :\nconst int ledPin =  26;      \/\/ the number of the LED pin\n\n\/\/ Variables will change :\nint ledState = LOW;             \/\/ ledState used to set the LED\n\n\/\/ Generally, you should use &quot;unsigned long&quot; for variables that hold time\n\/\/ The value will quickly become too large for an int to store\nunsigned long previousMillis = 0;        \/\/ will store last time LED was updated\n\n\/\/ constants won't change :\nconst long interval = 1000;           \/\/ interval at which to blink (milliseconds)\n\nvoid setup() {\n  \/\/ set the digital pin as output:\n  pinMode(ledPin, OUTPUT);\n}\n\nvoid loop() {\n  \/\/ here is where you'd put code that needs to be running all the time.\n\n  \/\/ check to see if it's time to blink the LED; that is, if the\n  \/\/ difference between the current time and last time you blinked\n  \/\/ the LED is bigger than the interval at which you want to\n  \/\/ blink the LED.\n  unsigned long currentMillis = millis();\n\n  if (currentMillis - previousMillis &gt;= interval) {\n    \/\/ save the last time you blinked the LED\n    previousMillis = currentMillis;\n\n    \/\/ if the LED is off turn it on and vice-versa:\n    if (ledState == LOW) {\n      ledState = HIGH;\n    } else {\n      ledState = LOW;\n    }\n\n    \/\/ set the LED with the ledState of the variable:\n    digitalWrite(ledPin, ledState);\n  }\n}\n<\/code><\/pre>\n\t<p style=\"text-align:center\"><a class=\"rntwhite\" href=\"https:\/\/github.com\/RuiSantosdotme\/ESP32-Course\/raw\/master\/code\/Blink_Without_Delay\/Blink_Without_Delay.ino\" target=\"_blank\">View raw code<\/a><\/p>\n\n\n\n<h4 class=\"wp-block-heading\">How the code works<\/h4>\n\n\n\n<p>Let\u2019s take a closer look at this blink sketch that works without a <span class=\"rnthl rntliteral\">delay()<\/span> function (it uses the <span class=\"rnthl rntliteral\">millis()<\/span> function instead).<\/p>\n\n\n\n<p>Basically, this code subtracts the previous recorded time (<span class=\"rnthl rntliteral\">previousMillis<\/span>) from the current time (<span class=\"rnthl rntliteral\">currentMillis<\/span>). If the remainder is greater than the interval (in this case, 1000 milliseconds), the program updates the <span class=\"rnthl rntliteral\">previousMillis<\/span> variable to the current time, and either turns the LED on or off.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>if (currentMillis - previousMillis &gt;= interval) {\n&nbsp; \/\/ save the last time you blinked the LED\n&nbsp; previousMillis = currentMillis;\n  (...)<\/code><\/pre>\n\n\n\n<p>Because this snippet is non-blocking, any code that\u2019s located outside of that first <span class=\"rnthl rntliteral\">if<\/span> statement should work normally.<\/p>\n\n\n\n<p>You should now be able to understand that you can add other tasks to your <span class=\"rnthl rntliteral\">loop()<\/span> function and your code will still be blinking the LED every one second.<\/p>\n\n\n\n<p>You can upload this code to your ESP32 and assemble the following schematic diagram to test it and modify the number of milliseconds to see how it works.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><a href=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2018\/07\/blink_without_delay_bb.png?quality=100&#038;strip=all&#038;ssl=1\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"645\" height=\"631\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2018\/07\/blink_without_delay_bb.png?resize=645%2C631&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"\" class=\"wp-image-68481\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2018\/07\/blink_without_delay_bb.png?w=645&amp;quality=100&amp;strip=all&amp;ssl=1 645w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2018\/07\/blink_without_delay_bb.png?resize=300%2C293&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 645px) 100vw, 645px\" \/><\/a><\/figure><\/div>\n\n\n<p><\/p>\n\n\n\n<p><strong>Note<\/strong>: If you&#8217;ve experienced any issues uploading code to your ESP32, take a look at the <a href=\"https:\/\/randomnerdtutorials.com\/esp32-troubleshooting-guide\/\">ESP32 Troubleshooting Guide<\/a>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">ESP32 with PIR Motion Sensor<\/h2>\n\n\n\n<p>After understanding these concepts: interrupts and timers, let\u2019s continue with the project.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Schematic<\/h3>\n\n\n\n<p>The circuit we&#8217;ll build is easy to assemble, we\u2019ll be using an LED with a resistor. The LED is connected to <span class=\"rnthl rntcblue\">GPIO 26<\/span>. We\u2019ll be using the <a href=\"https:\/\/makeradvisor.com\/tools\/mini-hc-sr505-pir-motion-sensor\/\" target=\"_blank\" rel=\"noopener noreferrer\">Mini AM312 PIR Motion Sensor<\/a> that operates at 3.3V.&nbsp; It will be connected to <span class=\"rnthl rntcyellow\">GPIO 27<\/span>. Simply follow the next schematic diagram.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"1200\" height=\"665\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2018\/07\/pir_esp32_interrupts.jpg?resize=1200%2C665&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"\" class=\"wp-image-68486\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2018\/07\/pir_esp32_interrupts.jpg?w=1274&amp;quality=100&amp;strip=all&amp;ssl=1 1274w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2018\/07\/pir_esp32_interrupts.jpg?resize=300%2C166&amp;quality=100&amp;strip=all&amp;ssl=1 300w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2018\/07\/pir_esp32_interrupts.jpg?resize=768%2C426&amp;quality=100&amp;strip=all&amp;ssl=1 768w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2018\/07\/pir_esp32_interrupts.jpg?resize=1024%2C567&amp;quality=100&amp;strip=all&amp;ssl=1 1024w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2018\/07\/pir_esp32_interrupts.jpg?resize=750%2C415&amp;quality=100&amp;strip=all&amp;ssl=1 750w\" sizes=\"(max-width: 1200px) 100vw, 1200px\" \/><\/figure><\/div>\n\n\n<p><\/p>\n\n\n\n<p><span style=\"color: #ff0000;\"><strong>Important<\/strong>:<\/span> <strong>the <a href=\"https:\/\/makeradvisor.com\/tools\/mini-hc-sr505-pir-motion-sensor\/\" target=\"_blank\" rel=\"noopener noreferrer\">Mini AM312 PIR Motion Sensor<\/a>&nbsp;used in this project operates at 3.3V. However, if you&#8217;re using another PIR motion sensor like the&nbsp;<a href=\"https:\/\/makeradvisor.com\/tools\/pir-motion-sensor-hc-sr501\/\" target=\"_blank\" rel=\"noopener noreferrer\">HC-SR501<\/a>, it operates at 5V. You can either&nbsp;<a href=\"https:\/\/randomnerdtutorials.com\/modifying-cheap-pir-motion-sensor-to-work-at-3-3v\/\" target=\"_blank\" rel=\"noopener noreferrer\">modify it to operate at 3.3V<\/a>&nbsp;or simply power it using the Vin pin.<\/strong><\/p>\n\n\n\n<p>The following figure shows the AM312 PIR motion sensor pinout.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"750\" height=\"292\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2018\/08\/mini-pir-pinout.jpg?resize=750%2C292&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"AM312 mini pir pinout\" class=\"wp-image-85870\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2018\/08\/mini-pir-pinout.jpg?w=750&amp;quality=100&amp;strip=all&amp;ssl=1 750w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2018\/08\/mini-pir-pinout.jpg?resize=300%2C117&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 750px) 100vw, 750px\" \/><\/figure>\n\n\n\n<p><\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Uploading the Code<\/h3>\n\n\n\n<p>After wiring the circuit as shown in the schematic diagram, copy the code provided to your Arduino IDE.<\/p>\n\n\n\n<p>You can upload the code as it is, or you can modify the number of seconds the LED is lit after detecting motion. Simply change the <span class=\"rnthl rntliteral\">timeSeconds<\/span> variable with the number of seconds you want.<\/p>\n\n\n<pre style=\"max-height: 40em; margin-bottom: 20px;\"><code class=\"language-c\">\/*********\n  Rui Santos\n  Complete project details at https:\/\/randomnerdtutorials.com  \n*********\/\n\n#define timeSeconds 10\n\n\/\/ Set GPIOs for LED and PIR Motion Sensor\nconst int led = 26;\nconst int motionSensor = 27;\n\n\/\/ Timer: Auxiliary variables\nunsigned long now = millis();\nunsigned long lastTrigger = 0;\nboolean startTimer = false;\nboolean motion = false;\n\n\/\/ Checks if motion was detected, sets LED HIGH and starts a timer\nvoid IRAM_ATTR detectsMovement() {\n  digitalWrite(led, HIGH);\n  startTimer = true;\n  lastTrigger = millis();\n}\n\nvoid setup() {\n  \/\/ Serial port for debugging purposes\n  Serial.begin(115200);\n  \n  \/\/ PIR Motion Sensor mode INPUT_PULLUP\n  pinMode(motionSensor, INPUT_PULLUP);\n  \/\/ Set motionSensor pin as interrupt, assign interrupt function and set RISING mode\n  attachInterrupt(digitalPinToInterrupt(motionSensor), detectsMovement, RISING);\n\n  \/\/ Set LED to LOW\n  pinMode(led, OUTPUT);\n  digitalWrite(led, LOW);\n}\n\nvoid loop() {\n  \/\/ Current time\n  now = millis();\n  if((digitalRead(led) == HIGH) &amp;&amp; (motion == false)) {\n    Serial.println(&quot;MOTION DETECTED!!!&quot;);\n    motion = true;\n  }\n  \/\/ Turn off the LED after the number of seconds defined in the timeSeconds variable\n  if(startTimer &amp;&amp; (now - lastTrigger &gt; (timeSeconds*1000))) {\n    Serial.println(&quot;Motion stopped...&quot;);\n    digitalWrite(led, LOW);\n    startTimer = false;\n    motion = false;\n  }\n}\n<\/code><\/pre>\n\t<p style=\"text-align:center\"><a class=\"rntwhite\" href=\"https:\/\/github.com\/RuiSantosdotme\/ESP32-Course\/raw\/master\/code\/PIR_Interrupts_Timers\/PIR_Interrupts_Timers.ino\" target=\"_blank\">View raw code<\/a><\/p>\n\n\n\n<p><strong>Note: <\/strong>if you&#8217;ve experienced any issues uploading code to your ESP32, take a look at the <a href=\"https:\/\/randomnerdtutorials.com\/esp32-troubleshooting-guide\/\">ESP32 Troubleshooting Guide<\/a>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">How the Code Works<\/h3>\n\n\n\n<p>Let\u2019s take a look at the code. Start by assigning two GPIO pins to the <span class=\"rnthl rntliteral\">led<\/span> and <span class=\"rnthl rntliteral\">motionSensor<\/span> variables.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ Set GPIOs for LED and PIR Motion Sensor\nconst int led = 26;\nconst int motionSensor = 27;<\/code><\/pre>\n\n\n\n<p>Then, create variables that will allow you set a timer to turn the LED off after motion is detected.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>\/\/ Timer: Auxiliar variables\nlong now = millis();\nlong lastTrigger = 0;\nboolean startTimer = false;<\/code><\/pre>\n\n\n\n<p>The <span class=\"rnthl rntliteral\">now<\/span> variable holds the current time. The <span class=\"rnthl rntliteral\">lastTrigger<\/span> variable holds the time when the PIR sensor detects motion. The <span class=\"rnthl rntliteral\">startTimer<\/span> is a boolean variable that starts the timer when motion is detected.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">setup()<\/h4>\n\n\n\n<p>In the <span class=\"rnthl rntliteral\">setup()<\/span>, start by initializing the Serial port at 115200 baud rate.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>Serial.begin(115200);<\/code><\/pre>\n\n\n\n<p>Set the PIR Motion sensor as an INPUT PULLUP.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>pinMode(motionSensor, INPUT_PULLUP);<\/code><\/pre>\n\n\n\n<p>To set the PIR sensor pin as an interrupt, use the <span class=\"rnthl rntliteral\">attachInterrupt()<\/span> function as described earlier.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>attachInterrupt(digitalPinToInterrupt(motionSensor), detectsMovement, RISING);<\/code><\/pre>\n\n\n\n<p>The pin that will detect motion is <span class=\"rnthl rntcyellow\">GPIO 27<\/span> and it will call the function <span class=\"rnthl rntliteral\">detectsMovement()<\/span> on RISING mode.<\/p>\n\n\n\n<p>The LED is an OUTPUT whose state starts at LOW.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>pinMode(led, OUTPUT);\ndigitalWrite(led, LOW);<\/code><\/pre>\n\n\n\n<h4 class=\"wp-block-heading\">loop()<\/h4>\n\n\n\n<p>The <span class=\"rnthl rntliteral\">loop()<\/span> function is constantly running over and over again. In every loop, the <span class=\"rnthl rntliteral\">now<\/span> variable is updated with the current time.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>now = millis();<\/code><\/pre>\n\n\n\n<p>Nothing else is done in the <span class=\"rnthl rntliteral\">loop()<\/span>.<\/p>\n\n\n\n<p>But, when motion is detected, the <span class=\"rnthl rntliteral\">detectsMovement()<\/span> function is called because we\u2019ve set an interrupt previously on the <span class=\"rnthl rntliteral\">setup()<\/span>.<\/p>\n\n\n\n<p>The <span class=\"rnthl rntliteral\">detectsMovement()<\/span> function prints a message in the Serial Monitor, turns the LED on, sets the <span class=\"rnthl rntliteral\">startTimer<\/span> boolean variable to <span class=\"rnthl rntliteral\">true<\/span> and updates the <span class=\"rnthl rntliteral\">lastTrigger<\/span> variable with the current time.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>void IRAM_ATTR detectsMovement() {\n  Serial.println(\"MOTION DETECTED!!!\");\n  digitalWrite(led, HIGH);\n  startTimer = true;\n  lastTrigger = millis();\n}<\/code><\/pre>\n\n\n\n<p><strong>Note:<\/strong> <span class=\"rnthl rntliteral\">IRAM_ATTR<\/span> is used to run the interrupt code in RAM, otherwise code is stored in flash and it&#8217;s slower.<\/p>\n\n\n\n<p>After this step, the code goes back to the <span class=\"rnthl rntliteral\">loop()<\/span>.<\/p>\n\n\n\n<p>This time, the <span class=\"rnthl rntliteral\">startTimer<\/span> variable is true. So, when the time defined in seconds has passed (since motion was detected), the following <span class=\"rnthl rntliteral\">if<\/span> statement will be true.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>if(startTimer &amp;&amp; (now - lastTrigger &gt; (timeSeconds*1000))) {\n  Serial.println(\"Motion stopped...\");\n  digitalWrite(led, LOW);\n  startTimer = false;\n}<\/code><\/pre>\n\n\n\n<p>The &#8220;Motion stopped&#8230;&#8221; message will be printed in the Serial Monitor, the LED is turned off, and the startTimer variable is set to false.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Demonstration<\/h2>\n\n\n\n<p>Upload the code to your ESP32 board. Make sure you have the right board and COM port selected.<\/p>\n\n\n\n<p>Open the Serial Monitor at a baud rate of 115200.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"745\" height=\"109\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2018\/05\/serial-monitor.png?resize=745%2C109&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"\" class=\"wp-image-61341\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2018\/05\/serial-monitor.png?w=745&amp;quality=100&amp;strip=all&amp;ssl=1 745w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2018\/05\/serial-monitor.png?resize=300%2C44&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 745px) 100vw, 745px\" \/><\/figure><\/div>\n\n\n<p><\/p>\n\n\n\n<p>Move your hand in front of the PIR sensor. The LED should turn on, and a message is printed in the Serial Monitor saying &#8220;MOTION DETECTED!!!&#8221;. After 10 seconds the LED should turn off.<\/p>\n\n\n<div class=\"wp-block-image\">\n<figure class=\"aligncenter\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"750\" height=\"408\" src=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2018\/07\/pir_ESP32_demo.jpg?resize=750%2C408&#038;quality=100&#038;strip=all&#038;ssl=1\" alt=\"\" class=\"wp-image-68485\" srcset=\"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2018\/07\/pir_ESP32_demo.jpg?w=750&amp;quality=100&amp;strip=all&amp;ssl=1 750w, https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2018\/07\/pir_ESP32_demo.jpg?resize=300%2C163&amp;quality=100&amp;strip=all&amp;ssl=1 300w\" sizes=\"(max-width: 750px) 100vw, 750px\" \/><\/figure><\/div>\n\n\n<p><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Wrapping Up<\/h2>\n\n\n\n<p>To wrap up, interrupts are used to detect a change in the GPIO state without the need to constantly read the current GPIO value. With interrupts, when a change is detected, a function is triggered. You\u2019ve also learned how to set a simple timer that allows you to check if a predefined number of seconds have passed without having to block your code.<\/p>\n\n\n\n<p>We have other tutorials related with ESP32 that you may also like:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><a href=\"https:\/\/randomnerdtutorials.com\/esp32-web-server-arduino-ide\/\">ESP32 Web Server \u2013 Arduino IDE<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/randomnerdtutorials.com\/esp32-data-logging-temperature-to-microsd-card\/\">ESP32 Data Logging Temperature to MicroSD Card<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/randomnerdtutorials.com\/esp32-esp8266-i2c-lcd-arduino-ide\/\">How to Use I2C LCD with ESP32 on Arduino IDE<\/a><\/li>\n\n\n\n<li><a href=\"https:\/\/makeradvisor.com\/esp32-vs-esp8266\/\" target=\"_blank\" rel=\"noopener noreferrer\">ESP32 vs ESP8266 \u2013 Pros and Cons<\/a><\/li>\n<\/ul>\n\n\n\n<p><em>This is an excerpt from our course:&nbsp;<a href=\"https:\/\/randomnerdtutorials.com\/learn-esp32-with-arduino-ide\/\">Learn ESP32 with Arduino IDE<\/a>. If you like ESP32 and you want to learn more, we recommend enrolling in&nbsp;<a href=\"https:\/\/randomnerdtutorials.com\/learn-esp32-with-arduino-ide\/\">Learn ESP32 with Arduino IDE course<\/a>.<\/em><\/p>\n\n\n\n<p>Thanks for reading.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>This tutorial shows how to detect motion with the ESP32 using a PIR motion sensor. In this example, when motion is detected (an interrupt is triggered), the ESP32 starts a &#8230; <\/p>\n<p class=\"read-more-container\"><a title=\"ESP32 with PIR Motion Sensor using Interrupts and Timers\" class=\"read-more button\" href=\"https:\/\/randomnerdtutorials.com\/esp32-pir-motion-sensor-interrupts-timers\/#more-68479\" aria-label=\"Read more about ESP32 with PIR Motion Sensor using Interrupts and Timers\">CONTINUE READING \u00bb<\/a><\/p>\n","protected":false},"author":5,"featured_media":68496,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[281,276,277,299,264],"tags":[],"class_list":["post-68479","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-esp32-project","category-esp32","category-esp32-arduino-ide","category-0-esp32","category-project"],"aioseo_notices":[],"jetpack_featured_media_url":"https:\/\/i0.wp.com\/randomnerdtutorials.com\/wp-content\/uploads\/2018\/07\/ESP32_PIR_featured.jpg?fit=1280%2C720&quality=100&strip=all&ssl=1","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/posts\/68479","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/users\/5"}],"replies":[{"embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/comments?post=68479"}],"version-history":[{"count":2,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/posts\/68479\/revisions"}],"predecessor-version":[{"id":161302,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/posts\/68479\/revisions\/161302"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/media\/68496"}],"wp:attachment":[{"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/media?parent=68479"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/categories?post=68479"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/randomnerdtutorials.com\/wp-json\/wp\/v2\/tags?post=68479"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}