0

Sử dụng Interrupt GPIO ESP32 trên Arduino IDE

ESP32-Ngat-GPIO

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.

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 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.

ESP32-các chân ngắt

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 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.ESP32-ngắt-button

Code ví dụ

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.

ESP32-Ngắt-Serial-Monitor

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 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ự GPIO18, số lần nút nhấn0trạng thái nút nhấnfalse.

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 của mình nhanh chóng hơn.

Chúc các bạn thành công!

thanhbinh89

Trả lời

Email của bạn sẽ không được hiển thị công khai.