Kết nối ESP32 với cảm biến chuyển động PIR dùng ngắt ngoài và millis()
Trong hướng dẫn này, các bạn sẽ kết nối ESP32 với cảm biến chuyển động PIR. Trong đó, khi cảm biến phát hiển chuyển động, tín hiệu sẽ kích lên mức CAO, ESP32 nhận ngắt ngoài và bắt đầu Timer. Sau đó, bật đèn LED trong một thời gian được xác định trước. Khi bộ hẹn giờ kết thúc, đèn LED sẽ tự động tắt.

Trong ví dụ này, chúng ta sẽ tìm hiểu hai khái niệm quan trọng: ngắt ngoài và Timer.
Trước khi thực hành hướng dẫn này, bạn nên cài đặt ESP32 cho Arduino IDE. Điều này đã được hướng dẫn trong bài viết
ESP32 cho Arduino IDE 2 (Windows, Mac OS X, Linux) – Embedded System Blog (machdien.net)
Các dụng cụ cần thiết trước khi bắt đầu
Để làm theo hướng dẫn này, bạn cần các phần sau
- ESP32 DOIT Devkit v1 Board
- Cảm biến chuyển động PIR thường dùng loại HC-SR501
- Đèn LED 5 mm
- Điện trở 330 ohm
- Dây nối đực đực 20cm
- Breadboard
Giới thiệu về ngắt ngoài trên ESP32
Để theo dõi cảm biến chuyển động PIR mà không cần phải đọc giá trị digitalRead liên tục, bạn sử dụng ngắt ngoài. Các ngắt ngoài là cách rất hữu ích để làm cho mọi thứ tự động xảy ra trong chương trình mà bạn code mà không làm ảnh hưởng đến hiệu xuất của những tác vụ khác.
Để thiết lặp một ngắt ngoài trong Arduino IDE, bạn sử dụng hàm attachInterrupt(), Trong đó bao gồm: số thứ tự chân GPIO, tên của hàm sẽ được thực thi khi điều kiện ngắt được thỏa mãn và chế độ ngắt ngoài:
attachInterrupt(digitalPinToInterrupt(GPIO), function, mode);Những chân GPIO có thể sử dụng để ngắt ngoài
Thành phần đầu tiên trong hàm attachInterrupt() là số thứ tự chân GPIO trên ESP32. Thông thường, bạn nên sử dụng hàm DigitalPintointerrupt (GPIO) để cài đặt GPIO làm chân nhận ngắt ngoài. Ví dụ: nếu bạn muốn sử dụng GPIO 27 làm ngắt ngoài:
DigitalPintointerrupt (27)Đối với board ESP32, tất cả các chân được đánh dấu màu đỏ dưới đây có thể được sử dụng để làm chân ngắt ngoài.

Hàm được gọi khi ngắt ngoài được kích hoạt
Thành phần thứ 2 trong hàm attachInterrupt() là tên hàm sẽ được gọi khi ngắt ngoài được kích hoạt. Ngay khi điều kiện ngắt ngoài được thỏa mãn theo mode, hàm này sẽ được thực thi ngay lặp tức.
Mode
Thành phần thứ 3 trong hàm attachInterrupt() là Mode .Có 5 Mode khác nhau:
- LOW: Ngắt ngoài sẽ được kích hoạt khi nào mức điện áp pin ở mức THẤP;
- HIGH: Ngắt ngoài sẽ được kích hoạt khi nào mức điện áp pin ở mức CAO;
- CHANGE: Ngắt ngoài sẽ được kích hoạt khi nào mức điện áp pin ở mức THẤP chuyển lên mức CAO hoặc mức CAO chuyển xuống mức THẤP;
- FALLING: Ngắt ngoài sẽ được kích hoạt khi nào mức điện áp pin chuyển từ mức CAO xuống mức THẤP;
- RISING: Ngắt ngoài sẽ được kích hoạt khi nào mức điện áp pin chuyển từ mức THẤP lên mức CAO;
Trong ví dụ chúng ta sẽ sử dụng RISING, bởi vì khi cảm biến chuyển động PIR phát hiện chuyển động, mức điện áp trên GPIO sẽ được kéo từ mức THẤP lên mức CAO.
Về Timer trong ESP32
Khi dụng hàm delay(), trong quá trình delay chúng ta không thể thực hiện bất kỳ tác vụ nào khác. Vậy nên chúng ta nên sử dụng bộ đếm thời gian – Timer trên ESP32.

Hiểu thêm về hàm delay()
Có lẽ bạn đã quá quen thuộc với hàm delay(). Nó được sử dụng rộng rãi trong đa số các chương trình sẵn có. Trong hàm delay() ta sử dụng một số int để làm thời gian delay được tính bằng mili giây. Trong thời gian này, chương trình phải đợi cho đến hết số mili giấy trên trước khi chuyển chương trình sang dòng code tiếp theo.
Delay(thời gian tính bằng mili giây)Khi chương trình thực thi hàm delay(1000). Toàn bộ chương trình của bạn sẽ dừng trên dòng đó trong 1 giây.
delay() trên thực tế là một hàm thực hiện chức năng chặn .Chặn đứng các dòng lệnh khác trong chương trình cho đến khi hết thời gian delay. Nếu bạn cần xử lý nhiều tác vụ khác, bạn không thể sử dụng delay.
Do đó, ta cần bộ hẹn giờ thay thế.
Hàm millis ()
Chúng ta sử dụng chức năng millis () để thay thế hàm delay. Khi sử dụng hàm này, bạn sẽ nhận được giá trị mili giây được đếm kể từ khi chương trình bắt đầu.
millis ()Chương trình mẫu: Nhấp nháy một đèn LED bằng millis ()
Đoạn mã sau đây sẽ minh họa cho việc sử dụng hàm millis () để chớp tắt đèn LED trong 1000 mili giây.
/*********
Rui Santos
Complete project details at https://randomnerdtutorials.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);
}
}
Kết nối ESP32 với cảm biến chuyển động PIR
Sơ đồ
Bạn kết nối cảm biến chuyển động và đèn LED với ESP32 theo sơ đồ dưới đây.

Lưu ý: Trong ví dụ này sử dụng Mini AM312 PIR hoạt động ở mức điện áp 3.3V. Tuy nhiên, nếu bạn sử dụng cảm biến chuyển động HC-SR501, nó hoạt động ở mức điện áp 5V. Bạn nên sử dụng điện trở chia áp trước khi cấp vào ESp32
Hình dưới đây cho thấy các chân của cảm biến chuyển động AM312 PIR.

Code mẫu
Sau khi nối dây mạch như trong sơ đồ, hãy sao chép mã được cung cấp cho Arduino IDE của bạn.
Bạn có thể tải lên mã như vậy hoặc bạn có thể sửa đổi số giây đèn LED được thắp sáng sau khi phát hiện chuyển động.Đơn giản chỉ cần thay đổithời gian thứ haibiến với số giây bạn muốn.
/*********
Rui Santos
Complete project details at https://randomnerdtutorials.com
*********/
#define timeSeconds 10
// Set GPIOs for LED and PIR Motion Sensor
const int led = 26;
const int motionSensor = 27;
// Timer: Auxiliary variables
unsigned long now = millis();
unsigned long lastTrigger = 0;
boolean startTimer = false;
boolean motion = false;
// Checks if motion was detected, sets LED HIGH and starts a timer
void IRAM_ATTR detectsMovement() {
digitalWrite(led, HIGH);
startTimer = true;
lastTrigger = millis();
}
void setup() {
// Serial port for debugging purposes
Serial.begin(115200);
// PIR Motion Sensor mode INPUT_PULLUP
pinMode(motionSensor, INPUT_PULLUP);
// Set motionSensor pin as interrupt, assign interrupt function and set RISING mode
attachInterrupt(digitalPinToInterrupt(motionSensor), detectsMovement, RISING);
// Set LED to LOW
pinMode(led, OUTPUT);
digitalWrite(led, LOW);
}
void loop() {
// Current time
now = millis();
if((digitalRead(led) == HIGH) && (motion == false)) {
Serial.println("MOTION DETECTED!!!");
motion = true;
}
// Turn off the LED after the number of seconds defined in the timeSeconds variable
if(startTimer && (now - lastTrigger > (timeSeconds*1000))) {
Serial.println("Motion stopped...");
digitalWrite(led, LOW);
startTimer = false;
motion = false;
}
}Hoạt động
Upload đoạn code trên vào ESP32 của bạn và mở cổng Serial với Baudrate là 115200.

Di chuyển trước cảm biến chuyển động PIR. Đèn LED sẽ bật, và một thông báo được hiển thị trong Serial Monitor !!!Sau 10 giây, đèn LED nên tắt.

Lời kết
Qua bài viết này, bạn đã tìm hiểu được ngắt ngoài trên ESP32 để thực hiện tác vụ mà không cần phải đọc liên tục các chân GPIO. Đồng thời sử dụng hàm millis() để bật tắt đèn LED mà không cần phải sử dụng hàm delay() làm trì hoãn việc thực hiện các tác vụ khác trong chương trình.
Link tham khảo: Random Nerd Tutorial
Tham khảo thêm các bài viết về ESP32 trên Lưu trữ ESP32 – Embedded System Blog (machdien.net)








