BÀI 4. LẬP TRÌNH STM32 – External Interrupt – Ngắt ngoài

Hôm nay chúng ta sẽ tìm hiểu một cơ chế vô cùng quan trọng trong lập trình nhúng vi điều khiển, đó là cơ chế “Interrupt – Ngắt”. Xét ví dụ: Bạn đang ngồi soạn bài, bất chợt chuông điện thoại reo, đây là cuộc gọi từ một người thân (bố, mẹ, anh chị em …). Bạn ngay lập tức cầm điện thoại lên và bắt đầu cuộc trò chuyện, cuộc trò chuyện kết thúc sau một khoảng thời gian và sau đó bạn quay lại để tiếp tục công việc soạn bài của mình.

Một ví dụ khác: Lộ trình của bạn là đi từ nhà tới trường học, trên đường đi có một ông cụ muốn hỏi đường đi đến bệnh viện. Tất nhiên rồi bạn sẽ dừng lại và chỉ đường cho ông cụ, sau khi ông cụ nắm được đường đi và nói lời cảm ơn bạn sẽ tiếp tục con đường tới trường.

Qua hai ví dụ trên chúng ta nhận thấy rằng, công việc chính của chúng ta sẽ tạm ghác lại một khoảng thời gian để nhường cho công việc khác có mức độ khẩn và ưu tiên hơn, sau khi các công việc này thực hiện xong, chúng ta quay trở lại để tiếp tục công việc chính còn dang dở. Và chúng ta sẽ tiếp tục công việc chính không phải là bắt đầu lại từ đầu mà là từ những gì mà chúng ta đã làm được, như ví dụ trên: bạn sẽ soạn tiếp phần còn lại của bài giảng hay là bước tiếp phần đường còn lại để tới trường.

Đây cũng chính là bản chất của cơ chế Ngắt trong lập trình vi điều khiển. Chương trình chúng ta sẽ có lộ trình các công việc được thực hiện theo một thứ tự được lập trình sẵn, nếu bất chợt có tín hiệu Ngắt thì chương trình phải tạm dừng để thực hiện một công việc khác được gắn với tín hiệu Ngắt. Sau khi thực hiện xong công việc gắn với tín hiệu Ngắt, chương trình sẽ tiếp tục tại chỗ mà nó đã tạm dừng.

Để minh họa cho cơ chế Ngắt, chúng xét ví dụ sau: Có 5 đèn Led sáng lần lượt theo thứ tự từ 1 đến 5 với khoảng thời gian cách nhau là 1s cho đến khi cả 5 đèn cùng sáng. Sau đó 1s cả 5 đèn đều tắt và bắt đầu lại một chy trình mới, chương trình cứ như thế lặp đi lặp lại. Nếu bây giờ chúng ta có một nút bấm kết nối với một chân của vi điều khiển để tạo tín hiệu Ngắt ngoài – nếu như bấm nút sẽ tạo tín hiệu Ngắt. Công việc gắn với Ngắt ngoài này, tôi tạm gọi là “công việc xử lý Ngắt”, nội dung “công việc xử lý Ngắt” –  là sẽ làm thay đổi trạng thái của một đèn Led thứ 6. Như vậy, nếu như mà ở lần ngắt đầu tiên Led 6 sáng thì ở lần tiếp theo Led 6 sẽ tắt, sau mỗi lần bấm nút thì Led 6 sẽ thay đổi trạng thái.

Giả sử chương trình đang chạy và đã sáng được 2 đèn Led, tại đây chúng ta bấm nút thì lập tức tín hiệu Ngắt sẽ kích hoạt “công việc xử lý Ngắt” làm cho Led 6 thay đổi trạng thái, sau đó chương trình lại tiếp tục theo thứ tự sáng Led3, Led4…..

Mong rằng đến đây các bạn đã hiểu được bản chất của cơ chế Ngắt trong lập trình vi điêu khiển. Có rất nhiều nguồn để sinh ra Ngắt: có thể là thay đổi trạng thái của tín hiệu bên ngoài từ LOW sang HIGH, hoặc là từ HIGH sang LOW; tín hiệu ngắt từ các loại cảm biến báo hiệu dữ liệu đã sẵn sàng; ngắt của các ngoại vi như I2C, SPI, UART hay là của Timer… mà chúng ta sẽ cùng nhau tìm hiểu ở các bài học tiếp theo.

Trong bài viết ngày hôm nay chúng ta sẽ tìm hiểu về ngắt ngoài – External interrupt, cụ thể là hiện thực hóa ví dụ 6 Led và nút bấm vừa để cập ở trên.

Bắt đầu với STM32CubeMX. Sau khi cấu hình Clock Configuration như các bài trước, các bạn thiết lập cấu hình như sau:

Đối với 6 đèn Led, thiết lập 6 chân từ PB3 đến PB8 ở chế độ GPIO_Output và đặt tên theo thứ tự LED1 – LED6.

Chân để xác định ngắt ngoài là PA2, các bạn chuột trái vào PA2 sau đó lựa chọn chức năng GPIO_EXTI2 – đây là chân sẽ phát hiện thay đổi tín hiệu ngoài lên chân vi điều khiển khi ta bấm nút bấm, đặt tên là Button.

Tiếp theo chúng ta đi tới mục GPIO -> chọn PA2. Trong mục GPIO mode có 6 lựa chọn gồm 3 External Interrupt Mode và 3 External Event Mode. Sự khác nhau giữa 2 chế độ này như sau:

  • External Interrupt Mode: Gây ra ngắt khi có sự thay đổi tín hiệu bên ngoài, giúp vi điều khiển dừng chương trình hiện tại để xử lý sự kiện “công việc xử lý Ngắt”.
  • External Event Mode: Không tạo ngắt mà chỉ ghi nhận tín hiệu ngoài và có thể tác động đến các module khác của STM32 mà không làm gián đoạn chương trình.

Như đã đề cập, trong ví dụ này sẽ sử dụng External Interrupt Mode.

External Interrupt Mode with Rising edge trigger detection – Ngắt ngoài với chế độ phát hiện sườn lên, nghĩa là tín hiệu ngoài vào chân vi điều khiển thay đổi từ mức logic 0 lên mức 1.

External Interrupt Mode with Falling edge trigger detection – Ngắt ngoài với chế độ phát hiện sườn xuống, nghĩa là tín hiệu ngoài vào chân vi điều khiển thay đổi từ mức logic 1 xuống mức 0.

External Interrupt Mode with Rising/Falling edge trigger detection – Ngắt ngoài với chế độ phát hiện sườn lên/xuống, nghĩa là khi có sự thay đổi về mức logic của tín hiệu ngoài vào chân vi điều khiển thì sẽ xuất hiện ngắt.

Trong ví dụ này chúng ta sẽ sử dụng ngắt ngoài với chế độ phát hiện sườn lên. Khi bấm nút thì tín hiệu vào chân PA2 sẽ thay đổi từ LOW(0) sang HIGH(1). Cách kết nối nút bấm như bài 3 https://viliti.blog/2025/04/05/bai-3-lap-trinh-stm32-gpio-input-nut-bam/.

Tiếp theo các bạn đi tới mục NVIC – Nested vectored interrupt controller là bộ điều khiển xử lý ngắt có trong tất cả các dòng vi điều khiển STM32. Ở dòng EXTI line2 interrupt chọn Enable

Tại sao lại EXTI line2 interrupt? Thực tế stm32f103c8t6 có 16line dành cho ngắt ngoài, được đề cập tại trang 210 của datasheet.

Từ PA0 đến PG0 sẽ có chung 1line, tương tự từ các 1, 2, 3 …15 đều có chung 1 line. Một điểm lưu ý là chỉ có thể chọn 1 chân trên 1 line để sử dụng cơ chế ngắt ngoài, không thể sử dụng chúng đồng thời. Ví dụ, nếu đã sử dụng PA2 làm chân để phát hiện ngắt ngoài thì chúng ta không thể sử dụng các chân PB2, PC2, PD2, PE2, PF2, PG2 với chế độ ngắt ngoài được nữa.

Do chúng ta sử dụng thư viện HAL để lập trình cho nên không cần thiết phải đào sâu vào cấu tạo của chip hoặc đi sâu để tìm hiểu các thanh ghi liên quan đến Ngắt ngoài. Nếu bạn nào có nhu cầu tìm hiểu sâu về cấu trúc của chip thì đây là một điều tuyệt vời, nó sẽ giúp cho các bạn nắm chắc kiến thức và có cái nhìn rõ ràng hơn về đối tượng mà ta đang sử dụng.

Sau khi các bạn đã chọn Enable cho EXTI line2 interrupt, bước tiếp theo chúng ta cần phải cho phép RCC global interrupt.

Đây là chế độ cho phép tất cả các loại Ngắt hoạt động, nếu như bạn không chọn Enable thì chúng ta sẽ không sử dụng được bất cứ loại ngắt nào.

Tiếp theo các bạn Generate code và tiến hành viết phần mềm cho ứng dụng của chúng ta.

Đoạn code chương trình như sau:

Đầu tiên chúng ta viết hàm nháy 5 đèn Led sáng lần lượt theo thứ tự blink5led(). Tiếp theo là hàm gọi ngắt ngoài void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) , đây là hàm có sẵn của thư viện HAL. Hàm này sẽ được gọi mỗi khi có ngắt ngoài xảy ra trên các chân của vi điều khiển, trường hợp của chúng ta là chân PA2, nên câu lệnh

if(GPIO_Pin == GPIO_PIN_2)

được hiểu là nếu như xảy ra ngắt ở line thứ 2 thì : HAL_GPIO_TogglePin(GPIOB, LED6_Pin);

sẽ thay đổi trạng thái Led 6 “công việc xử lý Ngắt”

Trong vòng lặp while() các bạn gọi hàm chính nháy 5 led của chương trình

Các bạn debug chương trình, nếu mọi thứ diễn ra bình thường thì chương trình sẽ không báo lỗi.

Bước tiếp theo chúng ta sẽ cùng nhau kết nối mạch led và stm32f103c8t6. Sơ đồ mạch như sau

Điện trở tôi sử dụng có giá trị là 220 Om, các bạn có thể sử dụng giá trị khác, để chính xác hơn cần phải tính toán dựa trên dòng điện đi qua Led. Trong bài viết này tôi không đề cập đến cách lựa chọn giá trị của điện trở phù hợp với Led, các bạn có thể tự tìm hiểu nhé.

Giữa nguồn 3.3V và nút bấm sử dụng điện trở để hạn dòng

Mạch kết nối thực tế như sau:

Sau khi kết nối xong mạch, các bạn cắm Stlink vào máy tính -> nạp code và xem kết quả. Video kết quả thu được như sau: https://www.youtube.com/watch?v=5LXAg88-jLI&list=PLQyFDaQjUCO1iWbhrnlrUihuuSHIzmhgi&index=3

Các bạn có thể thấy rằng, mỗi khi chúng ta bấm nút thì dãy đèn xanh sẽ dừng công việc nháy lại và nhường chỗ cho đèn led đỏ thay đổi trạng thái, sau khi đèn đỏ thay đổi trạng thái xong thì các đèn xanh lại tiếp tục công việc của mình.

Một lưu ý là trong những lần mà các bạn nhấn nút, do nút bấm không phải là linh kiện hoàn hảo cho nên mỗi lần bấm nút có thể có nhiều lần thay đổi trạng thái tính hiệu từ LOW sang HIGH, sự thay đổi này diễn ra rất nhanh chúng ta không thể cảm nhận được nhưng vi điều khiển sẽ xem đó là những lần xuất hiện ngắt ngoài và sẽ tự động thay đổi trạng thái Led6. Đây gọi là hiện tượng “SWITCH BOUNCE”, để khắc phục hiện tượng này có thể dùng phần cứng bắng cách mắc thêm tụ điện hoặc bằng phần mềm, phần này đề nghị các bạn tự tìm hiểu thêm.

Mong rằng ví dụ ngày hôm nay đã giúp các bạn hiểu rõ về cơ chế Ngắt trong lập trình vi điều khiển. Bài viết tiếp theo chúng ta sẽ cùng nhau nghiên cứu về Timer trong vi điều khiển STM32F103C8T6. Xin chào tạm biệt và hẹn gặp lại!


Subscribe to my newsletter

2 bình luận cho “BÀI 4. LẬP TRÌNH STM32 – External Interrupt – Ngắt ngoài”

  1. Ảnh đại diện colorfulsuperblyef5490c90a
    colorfulsuperblyef5490c90a

    quá tuyệt vời ạ! Thanks ad nhiều

    Đã thích bởi 1 người

  2. Ảnh đại diện Nga Nguyễn Thị Thúy
    Nga Nguyễn Thị Thúy

    Rất dễ hiểu ạ, cảm ơn ad

    Thích

Gửi phản hồi cho colorfulsuperblyef5490c90a Hủy trả lời