Bài 5: Lập trình ESP32 ngắt ngoài EXTI

lap trinh ESP32 ngat ngoai exti

Trong bài này chúng ta sẽ cùng học lập trình ESP32 ngắt ngoài hay EXTI (External Interrupts). Hiểu cách hoạt động của một ngắt trong chương trình nhúng, cách lập trình để tránh sự xung đột khi dùng ngắt.

Bài 5 trong Serie Học lập trình ESP32 từ A tới Z

Ngắt ngoài là gì?

Đầu tiên chúng ta phải hiểu về khái niệm ngắt và tuần tự trước đã.

  • Tuần tự: Một trương trình C,Cpp sẽ được xử lý tuần tự theo chiều từ trên xuống dưới và sẽ bị ảnh hưởng bởi các câu lệnh rẽ nhánh và loop
  • Ngắt: Chương trình sẽ bị thoát ra khỏi quá trình tuần tự, xử lý xong các lệnh trong ngắt, sau đó mới quay lại xử lý tiếp

Nói một cách đơn giản, Ngắt là một công việc được ưu tiên làm trước, khi xử lý xong mới được làm các việc khác. Các sự kiện ngắt có thể đến từ nhiều nguồn khác nhau như: ADC, IO, UART. TIMER…

interrupt processing
Ngắt là một sự kiện được ưu tiên xử lý trước

Ngắt ngoài EXTI chính là một sự kiện ngắt được sinh ra với nguồn từ các chân IO của ESP32.

Ngắt ngoài trong ESP32

Khác với các chip Arduino truyền thống, trên ESP32 mọi chân Input đều có thể được cài đặt để sử dụng với ngắt ngoài. Nó không bị giới hạn như Arduino Uno hoặc các loại tương đương là chỉ có 2 chân có thể được sử dụng làm ngắt ngoài

Ngắt ngoài có các kiểu ngắt khác nhau tương ứng cho tín hiệu xung trên chân GPIO đó, cụ thể:

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

ngat ngoai esp32

Để lập trình ngắt ngoài trên ESP32 chúng ta sử dụng 2 hàm chính đó là:

attachInterrupt(GPIOPin, ISR, Mode);

Đây là hàm chức năng được sử dụng để cài đặt ngắt ngoài cho 1 chân cụ thể.

Hàm này có ba đối số đầu vào:

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, các chê độ tương ứng với các kiểu ngắt bên trên đã nêu.

detachInterrupt(GPIOPin);

Đây là hàm chức năng để xóa các cấu hình ngắt trên chân đó đi. Đối số truyền vào là chân được chỉ định ngắt.

void IRAM_ATTR ISR() {
    Statements;
}
//example
void IRAM_ATTR NgatNgoai(){
  //do some things
}

Đây là hàm được gọi khi có một sự kiên ngắt sảy ra.

ISR: Interrupts Service Routine hay định tuyến dịch vụ, là tên hàm sẽ được gọi khi ngắt sảy ra

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

Lập trình ESP32 ngắt ngoài điều khiển led bằng nút nhấn

Với ví dụ này chúng ta sẽ điều khiển led bằng nút nhấn, nhưng không cần đọc giá trị nút nhấn như bài 1.

Chuẩn bị:

  • Breadboard
  • Kit ESP32 dev
  • Trở 200R
  • Led cắm
  • Nút nhấn

Sơ đồ nguyên lý

Chúng ta sử dụng sơ đồ nguyên lý như bài 1.

ESP32 led và nút nhấn
Sơ đồ nguyên lý ngắt ngoài esp32

Code và giải thích code

Full code

#include <Arduino.h>

const int led = 17;
const int button = 16;
bool ledstates = 0;
portMUX_TYPE mux = portMUX_INITIALIZER_UNLOCKED;

void IRAM_ATTR buttonPush() {
  portENTER_CRITICAL_ISR(&mux);//Phần quan trọng cần được bảo vệ khỏi mọi truy cập đồng thời để thay đổi nó
  Serial.println("Button Pushed!!!");
  digitalWrite(led, ~ledstates);
  portEXIT_CRITICAL_ISR(&mux);//Cho phép tiếp tục chạy các task khác
}
void setup() {
  pinMode(button, INPUT_PULLUP);
  // cài đặt ngắt vào chân button, kiểu ngắt là falling (xung xuống), hàm gọi khi có sự kiện ngắt là button push
  attachInterrupt(digitalPinToInterrupt(button), buttonPush, FALLING);
  // chọn led là đầu ra
  pinMode(led, OUTPUT);
  //ghi giá trị ban đầu
  digitalWrite(led, ledstates);
}
void loop() {
  // do nothing
}

Giải thích code:

Chúng ta khởi tạo các chân led và button, một biến để lưu trữ giá trị của Led

const int led = 17;
const int button = 16;
bool ledstates = 0;

portMUX_TYPE mux = portMUX_INITIALIZER_UNLOCKED;

Khai báo một biến mux với kiểu portMUX_TYPE biến này có tác dụng chống sự xung đột giữa các CPU và chương trình chính khi hoạt động.

Tiếp tới khơi tạo 1 hàm được gọi khi ngắt xảy ra:

void IRAM_ATTR buttonPush() {
  portENTER_CRITICAL_ISR(&mux);//Phần quan trọng cần được bảo vệ khỏi mọi truy cập đồng thời để thay đổi nó
  Serial.println("Button Pushed!!!");
  digitalWrite(led, ~ledstates);
  portEXIT_CRITICAL_ISR(&mux);//Cho phép tiếp tục chạy các task khác
}

Trong hàm này, chúng ta sẽ đảo trạng thái led, và in ra màn hình dòng chữ nút đã được bấm

Trong setup chúng ta khởi tạo Ngắt, chân Led và ghi giá trị ban đầu cho Led

Serial.begin(9600);
pinMode(button, INPUT_PULLUP);
// cài đặt ngắt vào chân button, kiểu ngắt là falling (xung xuống), hàm gọi khi có sự kiện ngắt là button push
attachInterrupt(digitalPinToInterrupt(button), buttonPush, FALLING);
// chọn led là đầu ra
pinMode(led, OUTPUT);
//ghi giá trị ban đầu
digitalWrite(led, ledstates);

Trong loop không cần làm gì cả.

Nạp code và kết quả

Nhấn nút upload trên thanh công cụ nạp, sau đó nhấn nút để thay đổi trạng thái led nhé

Kết

Lập trình ESP32 ngắt ngoài rất quan trọng trong quá trình code một dự án nhúng, ngắt rất tiện lợi cho việc bắt các sự kiện tức thời, không cần CPU phải gọi lệnh kiểm tra, thế nên rất được ưa chuộng

Nếu thấy hay hãy chia sẻ bài viết này tới bạn bè nhé. Đừng quên tham gia nhóm Nghiện lập trình để kết nối với những người cùng đam mê.

 

3 thoughts on “Bài 5: Lập trình ESP32 ngắt ngoài EXTI

Trả lời

Email của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *