CEtut – Part 4 : External Interrupt

Trong bài này, mục tiêu chính của bài là tìm hiểu và triển khai một mẫu chương trình (sample) liên quan đến chủ đề Ngắt (INTERRUPT) trong hệ thống nhúng, cụ thể hơn là điều khiển đèn led RGB bằng nút nhấn sử dụng ngắt ngoài, với chức năng cơ bản làm đèn led đổi màu sau mỗi lần nhấn
Share

Trong bài này, mục tiêu chính của bài là tìm hiểu và triển khai một mẫu chương trình (sample) liên quan đến chủ đề Ngắt (INTERRUPT) trong hệ thống nhúng, cụ thể hơn là điều khiển đèn led RGB bằng nút nhấn sử dụng ngắt ngoài, với chức năng cơ bản làm đèn led đổi màu sau mỗi lần nhấn

1. Tổng quan về các cách lập trình

Chúng ta có rất nhiều các cách lập trình khác nhau, và mỗi cách lập trình lại có ưu và nhược điểm riêng. Tùy vào sample mà chúng ta thực hiện, chúng ta sẽ lựa chọn cách lập trình tương ứng để khai thác tối đa ưu điểm và hạn chế nhược điểm hết mức có thể
Vậy với sample “Điều kiển đèn led RGB” để biết chọn cách lập trình phù hợp, ta sẽ tiến hành phân tích sơ qua lợi ích và khuyết điểm của một số cách lập trình phổ biến dưới đây

Polling

Hệ thống phải đáp ứng các sự kiện một cách tuần tự thực hiện từ trên xuống dưới.

int main (void)
        {
         Sys_init();
         while (true)
        {
             if (even1)
                Service_event_1();
             if (even2)
                Service_event_2();
              ..............................
             if (even_n)
                Service_event_n();
        }
}

Hãy cùng phân tích đoạn code trên.

  • Trong đoạn code trên chương trình được bắt đầu bằng một vài cài đặt ban đầu cho hệ thống rồi truy cập vào trong một vòng lặp vô hạn. Trong đó, các sự kiện mà hệ thống có thể phản ứng lại được kiểm tra. Khi có một sự kiện diễn ra, hoạt động của câu lệnh phản ứng lại sự kiện đó được kích hoạt.
  • Giả sử rằng thời gian thực hiện event1 lâu, các sự kiện sau sẽ bị trì hoãn
  • Trong trường hợp khác, nếu như chúng ta có một đoạn code kiểm tra nút nhấn. Khi dự án càng phức tạp, số lượng dòng code ngày càng nhiều hơn, thời gian đợi của mỗi sự kiện cũng tăng lên, việc nút nhấn của hệ thống thực thi nhiệm vụ có thể sẽ gặp khó khăn khi lệnh if (nút nhấn) được chạy qua trước khi chúng ta nhấn nút. Giải pháp tạm thời khi đó, phải giữ nút liên tục và đợi hệ thống thực hiện hết tất cả sự kiện và quay lại vòng lặp while để xử lí nút nhấn. Ta có thể thấy hệ thống không thể thực hiện tức thì và có độ chính xác thấp.

Interrupt

Quá trình ngắt – có thể được đáp ứng được về mặt Realtime và cũng gây không ít khó khăn cho lập trình viên. Khi xảy ra sự kiện ngắt thì sẽ tạm dừng chương trình đang thực thi và chuyển sang thực hiện chương trình ngắt.

Câu hỏi: Nếu có nhiều chương trình ngắt lồng nhau thì sao để phân biệt được?

Chúng ta có thể phân biệt được dựa trên mức độ ưu tiên (Để biết mức độ ưu tiên chúng ta sẽ tìm hiểu kỹ hơn ở những phần sau).

Ai có quyền cao hơn thì được chen hàng, đáp ứng nhu cầu Realtime

Giới thiệu:

  • 16 mức ưu tiên có thể lập trình được.
  • Độ trễ thấp (Xảy ra ngắt cực kì nhanh).
  • Có quản lí năng lượng cho vector ngắt.
  • Có các thanh ghi điều kiển quá trình ngắt.

Ngắt ngoài nằm trong 1 phần của NVIC (có giải thích ở khái niệm 3). Mỗi EXTI – interrupt/event controller có thể được lập trình chọn sự kiện/ ngắt, chọn cạnh lên, cạnh xuống hoặc cả hai, sắp xếp mức ưu tiên ngắt.

Câu hỏi: Cạnh lên, cạnh xuống là gì? Xung Clock?

  • Xung Clock là tín hiệu điện tử có dạng sóng hình chữ nhật, có chu kì và tần số xác định.
  • Cạnh lên xung Clock: Quá trình xung Clock chuyển từ mức logic thấp sang mức logic cao
  • Cạnh xuống xung Clock: Là quá trình xung Clock chuyển từ mức logic cao sang mức logic thấp

2. Ngắt ngoài là gì?

Ngắt ngoài

Giả sử một chân của vi điều khiển được cấu hình ngắt ngoài, nếu như tín hiệu mà chân đó nhận được bị thay đổi trạng thái mức năng lượng (từ HIGH xuống LOW và ngược lại) thì ngắt sẽ được kích hoạt. Dựa vào sự chuyển đổi trạng thái chúng ta chia làm 3 loại sau:

  • Rising edge (sườn lên): Phát hiện ngắt khi tín hiệu từ mức LOW lên HIGH
  • Falling edge (sườn xuống): Phát hiện ngắt khi tín hiệu từ mức HIGH xuống LOW.
  • Rising/Falling edge (sườn lên và xuống): Phát hiện ngắt khi tín hiệu thay đổi mức năng lượng, từ HIGH xuống LOW và từ LOW lên HIGH.

Sơ đồ ngắt ngoài:

Chúng ta có thể thấy chip STM32F103C8 gồm có 16 line ngắt riêng biệt
  • Ví dụ:
    • Line0 sẽ chung cho tất cả chân Px0 ở tất cả các Port, với x là tên của Port A,B,…
    • Line0 nếu chúng ta đã chọn chân PA0 (Chân 0 ở port A) làm chân ngắt thì tất cả các chân 0 ở các Port khác không được làm khai báo chân ngắt ngoài nữa.

3. Thế nào là mức độ ưu tiên ngắt?

MỨC ĐỘ ƯU TIÊN NGẮT

Các bạn sẽ gặp từ khóa này khá nhiều NVIC, thế nó là gì?

NVIC (Nested Vector Interrupt Controller) là một đơn vị tiêu chuẩn bên trong lõi Cortex. Thế nên bất kì vi điều kiển nòa dựa trên lõi Cortex sẽ có cùng một cấu trúc ngắt, bất kể nhà sản xuất chip là ST, Atmel,…. và NIVC hỗ trợ quản lí các ngắt chồng chéo nhau dựa trên mức độ ưu tiên.

Vậy thì mức độ ưu tiên bao gồm những gì:

  • Ngắt có Preemption Priority cao hơn thì sẽ được ưu tiên thực hiện trước.
    • Nếu một ngắt Preemption Priority thấp đang trong quá trình được thực thi mà có ngắt có Preemption Priority cao hơn yêu cầu thì ngắt có Preemtion Priority thấp hơn sẽ tạm ngưng thực thi, đồng thời ngắt có Preemption Priority cao hơn sẽ chiếm dụng vi xử lý để thực thi.
  • Nếu một ngắt đang thực thi, một ngắt khác có cùng Preemption Priority nhưng có Sub Priority cao hơn yêu cầu thì cũng sẽ không chiếm dụng vi xử lý. Vi xử lý vẫn tiếp tục thực hiện ngắt có Sub Priority thấp hơn.
  • Nếu các ngắt có cùng Preemtion Priority đang ở trạng thái chờ thì ngắt nào có Sub Priority cao hơn thì sẽ được thực hiện trước.
  • Nếu các ngắt có cùng Preemtion PrioritySub Priority thì ngắt nào đến trước sẽ được phục vụ trước.

Bảng phân công mức độ ưu tiên:

4. Các Function

Hàm này sẽ sử dụng để xử lí tất cả các ngắt ngoài, mỗi khi xảy ra event ngắt

Void HAL_GPIO_EXTI_Callback(unit16_t GPIO_Pin)
Tham số:
GPIO_Pin: Chân cấu hình ngắt ngoài
Lưu ý: Bất cứ yêu cầu ngắt ngoài tại chân nào cũng nhảy vào hàm  này, vì thế nếu sử dụng nhiều chân ngắt ngoài thì cẩn kiểm tra  xem đó là chân nào.

Ví dụ:

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
 if (GPIO_Pin == GPIO_PIN_0)
 {
   // chương trình ngắt của chân 0
 }
 else if (GPIO_Pin == GPIO_PIN_1)
 {
   // chương trình ngắt của chân 1
 }
}

5. Thực hành

a. Linh kiện

b. Cấu hình

Bước 1: Khởi tạo project CubeIDE, sau đó chọn cổng nạp dữ liệu Serial Wire, setup các thông số như bài trước

Bước 2: Chọn nguồn sử dụng thạch anh ngoại

Bước 3: Chọn chân PB13, PB14 và PB15 là chân GPIO_Output (đã học từ bài GPIO).

Bước 4: Chuột phải chọn Enter user lable sửa tên nhãn

Bước 5: Chọn chân PA6 là chân GPIO_EXTI6

Bước 6: Click vào system core => GPIO. Lúc này sẽ hiện ra một bảng Pin Configuration. Click lần lượt các chân PA6 để cấu hình:

  • GPIO_Pullup/Pull-down: Pull-up (Thiết lập tín hiệu khi chưa nhấn nút là 1)
  • GPIO_Mode: External Interrupt Mode with Falling edge trigger detection ( kích hoạt ngắt cạnh xuống, khi tín hiệu từ 1 xuống 0)

Bước 7: Tiếp theo các bạn click vào NVIC, ở đây chúng ta có thể thấy:

  • Piority Group: 4 bits for pre-emtion piority 0 bit for subpiority, ở đây mặc định ban đầu CubeMX đã set nhóm ưu tiên ngắt là ở nhóm 4 gồm 2 trường preempiority, subpiority, với 16 giá trị preempiority và 0 giá trị preempiority.
  • Chúng ta tích chọn để bật ngắt cho EXTI5_9 (bật ngắt line 5 đến 9), mặc định ban đầu preempiority và subpiority của ngắt vector ngắt này đều bằng 0, nghĩa là có mức độ ưu tiên như nhau. Chúng ta có thể cài đặt lại mức độ ưu tiên của từng vector ngắt tùy theo mục đích sử dụng. Các vector ngắt nào có preempiority cao hơn thì mức độ ưu tiên thấp hơn và ngược lại các vector ngắt nào có subpiority cao hơn thì mức độ ưu tiên cao hơn.

Bước 8: Ctrl + S để save và Generate Code

c. Code

Bước 1: Tạo biến cục bộ mode = 0 với kiểu dữ liệu số nguyên không dấu 8 bit uint8_t

Bước 2: Lập trình hàm ngắt HAL_GPIO_EXTI_callback

Khi nhấn nút, biến mode sẽ tăng giá trị và vào lệnh Switch case, mỗi case sẽ là một màu led.
Ngoài 3 màu led cơ bản RGB, ta có thể tạo màu khác bằng cách “pha màu”, cho các màu cơ bản sáng đồng thời.

Bước 3: Nạp code như hướng dẫn những bài trước

d. Video demo

Thực hiện bài viết: Nguyễn Thiên Hoàn Phúc, Nguyễn Bạch Khánh Đan