Thông thường các dự án lập trình vi điều khiển phức tạp đều sử dụng Interrupt (Ngắt). Bài viết sẽ hướng dẫn các bạn sử dụng Interrupt GPIO ESP32.
- Cài đặt ESP32 trên Arduino IDE (Window, Linux, Mac OS X)
- Cách sử dụng ESP32 Dual Core trên Arduino IDE
Interrupts trên ESP32
ESP32 tích hợp 32 khe interrupt trên mỗi core, mỗi interrupt đều có cấu hình độ ưu tiên nhất định. Có thể chia làm 2 loại interrupt.
Hardware Interrupts – Được kích hoạt từ các sự kiện bên ngoài, ví dụ: GPIO, Touch
Software Interrupts – Được kích hoạt từ các sự kiện bên trong, ví dụ:Timer, Watchdog.
Interrupt GPIO ESP32 Pin
Trên ESP32, chúng ta có thể khai báo một hàm mà sẽ được gọi khi GPIO có sự thay đổi mức logic.
Tất cả các chân GPIO của ESP32 đều có thể được sử dụng làm chân interrupt ngõ vào.
Trên Arduino IDE, chúng ta sẽ dùng hàm attachInterrupt()
để cấu hình chân interrupt.
attachInterrupt(GPIOPin, ISR, Mode);
Hàm này có ba thông số:
GPIOPin – Là chân GPIO được chỉ định interrupt.
ISR – Là tên của hàm sẽ được gọi khi có interrupt
Mode – Khai báo chế độ interrupt được sử dụng.
LOW | Interrupt được kích hoạt khi chân ở mức LOW |
HIGH | Interrupt được kích hoạt khi chân ở mức HIGH |
CHANGE | Interrupt được kích hoạt khi chân thay đổi mức, từ HIGH sang LOW, hoặc LOW sang HIGH |
FALLING | Interrupt được kích hoạt khi chân thay đổi mức, từ HIGH sang LOW |
RISING | Interrupt được kích hoạt khi chân thay đổi mức, từ LOW sang HIGH |
Xóa Interrupt GPIO ESP32 Pin
Bạn có thể dùng hàm detachInterrupt()
để xóa chỉ định ngắt trên một chân GPIO.
detachInterrupt(GPIOPin);
ISR – Interrupt Service Routine
Hàm ISR được gọi khi có interrupt xảy ra.
void IRAM_ATTR ISR() { Statements; }
Những hàm ISR trên ESP32 là những hàm đặc biệt, nó có một số quy tắc sau:
- Thời gian thực hiện trong hàm ISR phải càng ngắn càng tốt, vì nó chặn các chương trình bình thường.
- Các hàm ISR phải có thêm thuộc tính
IRAM_ATTR
, theo tài liệu ESP32
IRAM_ATTR là gì?
Cờ thuộc tính IRAM_ATTR
khai báo cho trình biên dịch biết rằng hàm sẽ được biên dịch và đặt trong RAM (IRAM) của ESP32. Ngược lại hàm sẽ được đặt trong FLASH.
Một hàm khi được đặt trên FLASH sẽ phải chờ Load xong mới có thể thực hiện gây tốn thời gian, do đó hàm ISR không nên được đặt trên FLASH.
Kết nối phần cứng
Kết nối GPIO 18 (D18) trên board ESP32 với nút nhấn, bạn sẽ không cần điện trở kéo bên ngoài vì chúng ta sẽ sử dụng điện trở kéo bên trong chip.
Code ví dụ sử dụng ngắt trên esp32
struct Button { const uint8_t PIN; uint32_t numberKeyPresses; bool pressed; }; Button button1 = {18, 0, false}; void IRAM_ATTR isr() { button1.numberKeyPresses += 1; button1.pressed = true; } void setup() { Serial.begin(115200); pinMode(button1.PIN, INPUT_PULLUP); attachInterrupt(button1.PIN, isr, FALLING); } void loop() { if (button1.pressed) { Serial.printf("Button 1 has been pressed %u times\n", button1.numberKeyPresses); button1.pressed = false; } static uint32_t lastMillis = 0; if (millis() - lastMillis > 60000) { lastMillis = millis(); detachInterrupt(button1.PIN); Serial.println("Interrupt Detached!"); } }
Sau khi Upload sketch, mở Serial Mornitor (115200) để quan sát.
Giải thích code
Ban đầu, chúng ta khai báo một struct có tên Button. Struct này lưu các biến là thứ tự GPIO, số lần nút nhấn và trạng thái nút nhấn.
struct Button { const uint8_t PIN; uint32_t numberKeyPresses; bool pressed; };
Tiếp theo chúng ta khải báo một biến struct Button, thứ tự GPIO là 18, số lần nút nhấn là 0 và trạng thái nút nhấn là false.
Button button1 = {18, 0, false};
Chúng ta khai báo một hàm ISR với thuốc tính IRAM_ATTR
Trong hàm ISR, thực hiện tăng dần số lần nhấn và thay đổi trạng thái nút nhấn thành true
void IRAM_ATTR isr() { button1.numberKeyPresses += 1; button1.pressed = true; }
Trong hàm Setup(), chúng ta khởi tạo giao tiếp Serial và GPIO thứ 18 là ngõ vào có điện trở kéo lên.
Tiếp đó, ta báo cho ESP32 biết rằng khi có interrupt FALLING tại chân D18 hàm isr sẽ được gọi.
Serial.begin(115200); pinMode(button1.PIN, INPUT_PULLUP); attachInterrupt(button1.PIN, isr, FALLING);
Trong Loop(), chúng ta đơn giản chỉ kiểm tra trạng thái nút đã được nhấn và in ra số lần nút được nhấn.
if (button1.pressed) { Serial.printf("Button 1 has been pressed %u times\n", button1.numberKeyPresses); button1.pressed = false; }
Trong Loop(), chúng ta kiểm tra thời gian chương trình đã chạy millis()
, nếu thời gian này lớn hơn 1 phút thì chân D18 sẽ bị xóa interrupt detachInterrupt()
.
static uint32_t lastMillis = 0; if (millis() - lastMillis > 60000) { lastMillis = millis(); detachInterrupt(button1.PIN); Serial.println("Interrupt Detached!"); }
Kết luận
Interrupt là một tính năng không thể thiếu trên các vi điều khiển, tuy đơn giản nhưng cách sử dụng sẽ khác nhau đối với mỗi loại chip. Hy vọng bài viết cung cấp kiến thức bổ ích cho các bạn thực hiện dự án khi sử dụng Interrupt GPIO ESP32 của mình nhanh chóng hơn.
Chúc các bạn thành công!