NVIC – Nested vectored interrupt controller là bộ điều khiển xử lý ngắt có trong MCU STM32F103C8T6. Việc lập trình sử dụng ngắt là một kĩ năng quan trọng khi các bạn lập trìnhh vi điều khiển, nếu không có ngắt thì chương trình sẽ thực hiện theo một trình tự từ trên xuống dưới, ngắt giúp chương trình xử lý theo sự việc, đáp ứng được các sự kiện như sự thay đổi mức logic từ 1 chân vi điều khiển (ngắt ngoài), nhận một kí tự (ngắt nhận UART)…. Trong bài viết này, mình sẽ trình bày về ngắt ngoài (external interrupt) của vi điều khiển STM3232F103C8T6.
[HỌC ONLINE: LẬP TRÌNH VI ĐIỀU KHIỂN STM32, VI XỬ LÝ ARM CORTEX – M]
Một số thông số tính năng chính của NVIC:
- 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 khiển quá trình ngắt.
- 68 vector ngắt
Ngắt ngoài nằm trong 1 phần của NVIC. Mỗi EXTI – interrupt/event controller có thể được lập trình chọn loại sự kiện/ ngắt, chọn cạnh lên, cạnh xuống hoặc cả 2, sắp xếp mức ưu tiên ngắt.
Một số tính năng chính của ngắt ngoài:
- Kích hoạt độc lập và mask cho mỗi line sự kiện/ngắt.
- Có bit trạng thái (status) riêng cho mỗi line ngắt.
- Có thể có tối đa 20 sự kiện/ ngắt, tham khảo thêm trong reference manual.
- Kiểm tra tín hiệu ngoài có độ rộng xung nhỏ hơn clock trên APB2.
Sơ đồ khối của các khối điều khiển ngắt ngoài:
Cấu hình với thư viện chuẩn của ST. Có 2 loại ngắt ngoài chính đó là ngắt ngoài trên các chân điều khiển ở dạng thông thường và ngắt ngoài trên các ứng dụng như : PVD, RTC, USB, Ethernet.
Ngắt ngoài của chip STM32F103 bao gồm có 16 line:
Ở đây 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 khai báo làm chân ngắt ngoài nữa
- Line1 nếu chúng ta chọn chân PB1 là chân ngắt thì tất cả chân 1 ở các Port khác không được khai báo làm chân ngắt nữa.
Tiếp theo các Line ngắt sẽ được phân vào các Vector ngắt tương ứng. Các Line ngắt của chip STM32F103 được phân bố vào các vector ngắt như sau:
Các Line0, Line1, Line2, Line3, Line4 sẽ được phân vào các vector ngắt riêng biệt EXTI0, EXTI1, EXTI2, EXTI3, EXTI4, còn từ Line5->Line9 sẽ được phân vào vector ngắt EXTI9_5, Line10->Line15 được phân vào vecotr EXTI15_10.
Một số thanh ghi quan trọng:
1.EXTI_IMR – Interrupt mask register: Thanh ghi này cài đặt cho phép có yêu cầu ngắt trên Line tương ứng. (cho phép ngắt)
Bảng mức độ ưu tiên ngắt NVIC:
THỰC HÀNH:
Tiếp theo chúng ta sẽ thực hành project ngắt ngoài trên chip STM32F103C8T6 với CubeMX. Ở ví dụ này, chúng ta sẽ sử dụng chân PA0 tương ứng với Line0 – vector EXTI0 và PA6 tương ứng Line6 – vector EXTI5_9 để thực hành. Khai báo thêm chân Led PC13, khi ngắt ngoài ở chân PA0 thì chúng ta sẽ tắt Led, khi ngắt ngoài ở chân PA6 thì chúng ta sẽ bật Led
Bước 1:
Khởi tạo project CubeMX, sau đó chọn cổng nạp dữ liệu Serial Wire
Bước 2:
Chọn chân PC13 là chân GPIO_Output
Bước 3:
Chọn chân PA0 là chân GPIO_EXTI0, chúng ta cũng làm tương tự đối với chân PA6 là chân GPIO_EXTI6
Bước 4:
Tiếp theo, click vào System Core sau đó click vào GPIO. Lúc này sẽ hiện ra một bảng Pin Configuration. Click vào lần lượt các chân PA0 và PA6 để cấu hình:
GPIO_Mode: External Interrupt Mode with Falling edge trigger detection
GPIO_Pullup/Pull-down: Pull-up
Bước 5:
Tiếp theo các bạn click vào NVIC, ở đây chúng ta có thể thấy:
Piority Group: 4bits 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ít chọn để bật ngắt cho EXTI0 và EXTI5_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 6:
Cấu hình project và sinh code.
Bước 7:
Các bạn click vào Function, mở rộng main.c ở đây chúng ta có thể xem tất cả các hàm hiện có trong file main.
Click vào MX_GPIO_Init(void) ở đây chúng ta thấy rằng đã khởi tạo chân PA0,PA6, ngắt khi có cạnh xuống, chân này ban đầu được kéo lên nguồn.
Bật ngắt trên 2 vector EXTI0, EXTI5_9
Bước 8:
Ở hàm HAL_NVIC_Setpriority(), chúng có thể thấy thông số đầu tiên là vector, thông số thứ 2 là mức độ ưu tiên của preemprioity, thứ 3 là mức độ ưu tiên của subpriority. Mặc định ban đầu 2 thông số này của 2 vector ngắt set bằng 0 tương ứng với mức độ ưu tiên của 2 vector ngắt EXTI0, EXTI5_9 bằng nhau.
Bước 9:
Tiếp theo chúng ta khởi tạo hàm void HAL_GPIO_EXTI_Callback(){}
Bước 10:
Ở trong hàm này, mình sẽ có 2 lệnh điều kiện if() để phân luồng ngắt kiểm tra rằng ngắt hiện tại đang sinh ra ở chân nào.
If(GPIO_Pin == GPIO_PIN_0)
If(GPIO_Pin == GPIO_PIN_6)
Bước 11:
Sau khi đã phân luồng ngắt được rồi, tiếp theo ở trong hàm kiểm tra chân nào đang ngắt:
+ PA0 mình sẽ cho tắt Led PC13
+ PA6 mình sẽ cho bật Led PC13
Tiếp theo các bạn biên dịch và nạp code vào chip STM32F103C8T6.
Chúc các bạn thành công!
Xem thêm: Tổng hợp các bài hướng dẫn Lập trình vi điều khiển STM32 tại đây.
Nhóm Tapit ARM R&D