Skip to content

Công nghệ 9 giây

“Website hướng dẫn, thử nghiệm và giải thích công nghệ theo cách dễ hiểu cho mọi người.”

Menu
  • Home
  • Công nghệ
  • STM32
  • ESP32
  • Altium Desinger
  • Kiến thức điện máy
Menu

BÀI 33 – EXTI: GPIO INTERRUPT TRÊN STM32F103

Posted on August 23, 2026August 23, 2026 by congnghe9s

BÀI 33 – EXTI: GPIO INTERRUPT TRÊN STM32F103

Sau Bài 32 – GPIO Input + Pull-up/Pull-down, bài tiếp theo rất quan trọng là EXTI (External Interrupt).

Đây chính là bước chuyển từ:

CPU liên tục hỏi nút nhấn → CPU được báo ngay khi nút nhấn xảy ra sự kiện.


1. Trước hết: GPIO Input hoạt động như thế nào?

Ở bài 32, chúng ta có thể đọc chân GPIO:

if (GPIOA->IDR & (1 << 0))
{
    // PA0 = HIGH
}
else
{
    // PA0 = LOW
}

CPU phải liên tục chạy:

while (1)
{
    if (button_pressed())
    {
        // xử lý
    }
}

Đây gọi là Polling.

Polling

CPU:

Đọc nút
  ↓
Chưa nhấn?
  ↓
Đọc lại
  ↓
Đọc lại
  ↓
Đọc lại
  ↓
Đọc lại
  ↓
...

Điều này có một nhược điểm lớn:

CPU phải liên tục kiểm tra.


2. Interrupt là gì?

Interrupt có thể hiểu rất đơn giản:

CPU đang làm việc khác, khi một sự kiện xảy ra thì phần cứng “gọi” CPU.

Ví dụ:

CPU đang chạy chương trình chính
          │
          │
          ▼
       EXTI
          ▲
          │
       PA0 thay đổi
          │
          ▼
    CPU bị ngắt
          │
          ▼
   Chạy hàm xử lý
          │
          ▼
   Quay lại chương trình

Ví dụ nút nhấn nối vào PA0.

Khi nhấn nút:

PA0: HIGH → LOW
          │
          ▼
       EXTI
          │
          ▼
        NVIC
          │
          ▼
       CPU IRQ
          │
          ▼
   EXTI0_IRQHandler()

Đây là ý tưởng cốt lõi của EXTI.


3. EXTI là viết tắt của gì?

EXTI = External Interrupt/Event Controller

Trên STM32F103, EXTI quản lý các tín hiệu sự kiện bên ngoài.

Các đường EXTI chính:

EXTI0
EXTI1
EXTI2
...
EXTI15

Tức là có 16 line EXTI:

LINE 0
LINE 1
LINE 2
...
LINE 15

Nhưng có một điểm cực kỳ quan trọng:

EXTI0 không có nghĩa là chỉ PA0.

EXTI0 có thể kết nối với:

PA0
PB0
PC0
PD0
PE0
...

Tùy cấu hình AFIO.


4. Đây là kiến trúc rất quan trọng

Ví dụ bạn muốn sử dụng:

PB5

làm nút nhấn.

Bạn có:

PB5
 │
 ▼
GPIOB
 │
 ▼
AFIO
 │
 ▼
EXTI5
 │
 ▼
NVIC
 │
 ▼
CPU

Có thể hình dung:

GPIO
  │
  ▼
AFIO
  │
  ▼
EXTI
  │
  ▼
NVIC
  │
  ▼
CPU

Có 4 khối cần nhớ:

  1. GPIO
  2. AFIO
  3. EXTI
  4. NVIC

5. EXTI line và GPIO port

Đây là phần rất dễ nhầm.

Ví dụ:

PA0 → EXTI0
PB0 → EXTI0
PC0 → EXTI0

Không thể đồng thời:

PA0 → EXTI0
PB0 → EXTI0
PC0 → EXTI0

theo kiểu tất cả cùng hoạt động độc lập.

Vì:

Mỗi EXTI line tương ứng với một số pin, còn port được chọn thông qua AFIO.

Ví dụ:

EXTI0 ← PA0 hoặc PB0 hoặc PC0...
EXTI1 ← PA1 hoặc PB1 hoặc PC1...
EXTI2 ← PA2 hoặc PB2 hoặc PC2...

Nhưng EXTI0 chỉ có một nguồn GPIO được chọn tại một thời điểm.


6. AFIO làm nhiệm vụ gì?

Trên STM32F103, AFIO chứa các thanh ghi cho phép chọn nguồn GPIO cho EXTI.

Ví dụ:

EXTI5

có thể lấy tín hiệu từ:

PA5
PB5
PC5
PD5
...

Ta dùng AFIO để nói:

“EXTI5, hãy lấy tín hiệu từ PB5.”

Đây là lý do khi học STM32F103 bạn sẽ gặp:

AFIO->EXTICR[]

7. EXTI có thể kích hoạt theo cạnh nào?

Đây là phần rất quan trọng.

EXTI có thể phát hiện:

Rising Edge

LOW → HIGH

Ví dụ:

0
 │
 │
 └──────────┐
            │
            1

Đây gọi là:

cạnh lên – Rising Edge


Falling Edge

HIGH → LOW

Ví dụ:

1
 │
 └──────────┐
            │
            0

Đây gọi là:

cạnh xuống – Falling Edge


Cả hai cạnh

Có thể phát hiện:

LOW → HIGH

và:

HIGH → LOW

8. Thanh ghi điều khiển cạnh

STM32F103 có:

EXTI->RTSR

RTSR:

Rising Trigger Selection Register

Dùng để bật phát hiện cạnh lên.

Và:

EXTI->FTSR

FTSR:

Falling Trigger Selection Register

Dùng để bật phát hiện cạnh xuống.

Ví dụ EXTI0:

EXTI->RTSR |= (1 << 0);

cho phép:

LOW → HIGH

Còn:

EXTI->FTSR |= (1 << 0);

cho phép:

HIGH → LOW

9. Ví dụ nút nhấn Pull-up

Đây là cấu hình rất phổ biến.

Mạch:

3.3V
 │
[Pull-up]
 │
 ├──── PA0
 │
[BUTTON]
 │
 GND

Khi chưa nhấn:

PA0 = HIGH

Khi nhấn:

PA0 = LOW

Vậy sự kiện nhấn nút là:

HIGH → LOW

Do đó ta sử dụng:

Falling Edge

tức:

EXTI->FTSR

10. Ví dụ thực tế

Giả sử:

PA0 = Button
PC13 = LED

Mục tiêu:

Mỗi lần nhấn nút PA0, LED PC13 đổi trạng thái.

Ban đầu:

LED OFF

Nhấn nút:

LED ON

Nhấn lần nữa:

LED OFF

Nhấn lần nữa:

LED ON

11. Các bước cấu hình EXTI

Đây là thứ bạn nên học thuộc theo trình tự.

Bước 1 – Bật clock GPIO

Ví dụ PA0:

RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;

Bước 2 – Cấu hình PA0 Input

Ví dụ Input Pull-up:

GPIOA->CRL &= ~(0xF << 0);
GPIOA->CRL |=  (0x8 << 0);

Sau đó:

GPIOA->ODR |= (1 << 0);

Bước 3 – Bật clock AFIO

RCC->APB2ENR |= RCC_APB2ENR_AFIOEN;

Đây là bước nhiều người mới học thường quên.


12. Chọn PA0 cho EXTI0

Với PA0, cấu hình AFIO tương ứng là mặc định.

Vì:

PA0 → EXTI0

nên không cần chuyển sang port khác.

Nhưng nếu sử dụng:

PB0

thì phải cấu hình:

PB0 → EXTI0

thông qua:

AFIO->EXTICR[0]

13. Bật EXTI0

Thanh ghi:

EXTI->IMR

là:

Interrupt Mask Register

Muốn EXTI0 được phép tạo interrupt:

EXTI->IMR |= (1 << 0);

Hiểu đơn giản:

IMR bit 0 = 1
        ↓
Cho phép EXTI0

14. Chọn Falling Edge

Vì nút Pull-up:

HIGH → LOW

nên:

EXTI->FTSR |= (1 << 0);

Không cần Rising:

EXTI->RTSR &= ~(1 << 0);

15. Bật NVIC

Đây là tầng cuối.

EXTI tạo interrupt nhưng CPU còn phải được NVIC cho phép.

Với EXTI0:

NVIC_EnableIRQ(EXTI0_IRQn);

Trong STM32F103, các interrupt EXTI được ánh xạ vào NVIC.

Một số nhóm:

EXTI0
EXTI1
EXTI2
EXTI3
EXTI4

EXTI9_5

EXTI15_10

16. Tại sao EXTI5 đến EXTI9 dùng chung IRQ?

Ví dụ:

PA5
PA6
PA7
PA8
PA9

đều có thể tạo:

EXTI5
EXTI6
EXTI7
EXTI8
EXTI9

nhưng chúng dùng chung:

EXTI9_5_IRQn

Tương tự:

EXTI10
EXTI11
EXTI12
EXTI13
EXTI14
EXTI15

dùng chung:

EXTI15_10_IRQn

Đây là kiến trúc phần cứng của STM32F103.


17. ISR là gì?

Khi interrupt xảy ra, CPU sẽ chạy một hàm đặc biệt.

Ví dụ EXTI0:

void EXTI0_IRQHandler(void)
{
    // xử lý interrupt
}

ISR:

Interrupt Service Routine

Có thể hiểu:

“Hàm phục vụ ngắt.”


18. Nhưng có một vấn đề cực kỳ quan trọng

Khi interrupt xảy ra:

EXTI
 ↓
CPU
 ↓
EXTI0_IRQHandler()

Trong EXTI còn có thanh ghi:

EXTI->PR

Pending Register.

Nó cho biết:

EXTI nào đang chờ được xử lý.


19. Phải xóa cờ Pending

Ví dụ EXTI0:

EXTI->PR = (1 << 0);

Sau khi xử lý interrupt, phải xóa cờ.

Nếu không:

Interrupt
   ↓
PR vẫn còn
   ↓
CPU tiếp tục vào ISR
   ↓
ISR tiếp tục chạy
   ↓
...

Đây là lỗi rất quan trọng.


20. Chương trình hoàn chỉnh tối giản

Ví dụ:

#include "stm32f10x.h"

void GPIO_Init(void)
{
    /* Enable GPIOA + GPIOC + AFIO */
    RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;
    RCC->APB2ENR |= RCC_APB2ENR_IOPCEN;
    RCC->APB2ENR |= RCC_APB2ENR_AFIOEN;

    /* PA0 = Input Pull-up */
    GPIOA->CRL &= ~(0xF << 0);
    GPIOA->CRL |=  (0x8 << 0);

    GPIOA->ODR |= (1 << 0);

    /* PC13 = Output Push-Pull 2 MHz */
    GPIOC->CRH &= ~(0xF << 20);
    GPIOC->CRH |=  (0x2 << 20);
}

void EXTI_Init(void)
{
    /* PA0 -> EXTI0 */

    /* Unmask EXTI0 */
    EXTI->IMR |= (1 << 0);

    /* Falling edge */
    EXTI->FTSR |= (1 << 0);

    /* Enable EXTI0 interrupt */
    NVIC_EnableIRQ(EXTI0_IRQn);
}

void EXTI0_IRQHandler(void)
{
    if (EXTI->PR & (1 << 0))
    {
        GPIOC->ODR ^= (1 << 13);

        EXTI->PR = (1 << 0);
    }
}

int main(void)
{
    GPIO_Init();
    EXTI_Init();

    while (1)
    {
    }
}

Điểm thú vị là:

while (1)
{
}

không làm gì cả.

CPU không cần liên tục hỏi:

"Nút nhấn chưa?"
"Nút nhấn chưa?"
"Nút nhấn chưa?"

Khi nhấn nút:

PA0
 ↓
EXTI0
 ↓
NVIC
 ↓
CPU
 ↓
EXTI0_IRQHandler()
 ↓
LED đảo trạng thái

Sau đó CPU quay lại:

while(1)
{
}

21. So sánh Polling và Interrupt

Polling Interrupt
CPU liên tục đọc GPIO GPIO báo CPU khi có sự kiện
Tốn thời gian CPU Hiệu quả hơn
Dễ học Khó hơn
Chương trình đơn giản Cần NVIC + EXTI
Có thể bỏ lỡ sự kiện nhanh Phù hợp sự kiện bất ngờ
Tốt cho bài đơn giản Tốt cho hệ thống thực tế

22. Một điều cực kỳ quan trọng: chống dội phím

Bạn có thể nghĩ:

“Vậy cứ nhấn nút → interrupt → đổi LED là xong.”

Chưa chắc.

Nút cơ khí bị:

bounce – dội phím.

Khi nhấn một lần, tín hiệu thực tế có thể:

HIGH
   ↓
LOW
   ↑
LOW
   ↑
LOW
   ↑
LOW
   ↓
LOW ổn định

Thay vì:

HIGH → LOW

nó có thể tạo nhiều cạnh.

Khi đó:

1 lần nhấn
     ↓
3 interrupt
     ↓
5 interrupt
     ↓
LED ON
     ↓
LED OFF
     ↓
LED ON

Bạn sẽ thấy LED hoạt động “điên loạn”.

Đây chính là lý do debounce sẽ là một phần rất quan trọng khi học EXTI thực tế.


23. Một nguyên tắc rất quan trọng khi viết ISR

Trong:

void EXTI0_IRQHandler(void)
{
}

không nên làm những việc quá nặng.

Ví dụ không nên:

delay_ms(1000);

hoặc:

while(...)
{
}

hoặc thực hiện một thuật toán cực kỳ dài.

ISR nên:

Nhanh
↓
Xử lý sự kiện
↓
Đặt cờ
↓
Thoát

Ví dụ tốt hơn:

volatile uint8_t button_event = 0;

void EXTI0_IRQHandler(void)
{
    if (EXTI->PR & (1 << 0))
    {
        button_event = 1;

        EXTI->PR = (1 << 0);
    }
}

Sau đó main() xử lý:

while (1)
{
    if (button_event)
    {
        button_event = 0;

        // xử lý việc chính
    }
}

Đây là một tư duy lập trình STM32 rất quan trọng.


24. Tại sao biến phải là volatile?

Ví dụ:

volatile uint8_t button_event;

Biến này được thay đổi trong:

EXTI0_IRQHandler()

nhưng được đọc trong:

main()

Compiler cần biết rằng:

Giá trị biến này có thể thay đổi bất ngờ bởi phần cứng/interrupt.

Vì vậy dùng:

volatile

Đây là một trong những trường hợp quan trọng nhất để hiểu volatile trong lập trình vi điều khiển.


25. Hãy nhớ sơ đồ này

Đây là sơ đồ bạn nên ghi nhớ sau Bài 33:

             GPIO INPUT
                 │
                 ▼
              GPIO pin
                 │
                 ▼
                AFIO
                 │
                 ▼
               EXTI
        ┌────────┴────────┐
        │                 │
    Rising Edge       Falling Edge
        │                 │
        └────────┬────────┘
                 ▼
                NVIC
                 │
                 ▼
                CPU
                 │
                 ▼
        EXTIx_IRQHandler()
                 │
                 ▼
          Xóa Pending Flag
                 │
                 ▼
          Quay lại main()

Nếu bạn hiểu được sơ đồ này thì bạn đã thực sự bắt đầu bước vào lập trình sự kiện trên STM32, chứ không chỉ đơn thuần điều khiển GPIO.


26. Bài thực hành cho bạn

Với Blue Pill STM32F103C8T6, hãy làm mạch:

PA0 ─── BUTTON ─── GND
 │
 └── Internal Pull-up

PC13 ─── LED onboard

Yêu cầu:

Bài tập 1

Nhấn nút PA0:

PC13 đảo trạng thái

Bài tập 2

Không sử dụng polling:

while(1)
{
}

Bài tập 3

Sử dụng:

EXTI0_IRQHandler()

Bài tập 4

Thử thay đổi:

EXTI->FTSR

thành:

EXTI->RTSR

và quan sát sự khác nhau.

Bài tập 5 – quan trọng

Thay vì đảo LED trực tiếp trong ISR:

GPIOC->ODR ^= (1 << 13);

hãy tạo:

volatile uint8_t button_event;

ISR chỉ đặt:

button_event = 1;

và main() xử lý LED.


Sau Bài 33, chúng ta sẽ học gì?

Tôi đề xuất đi theo chuỗi này:

Bài 32
GPIO Input + Pull-up/Pull-down
        ↓
Bài 33
EXTI – GPIO Interrupt
        ↓
Bài 34
NVIC – Nested Vectored Interrupt Controller
        ↓
Bài 35
Debounce nút nhấn bằng Timer
        ↓
Bài 36
EXTI + nhiều nút nhấn
        ↓
Bài 37
Interrupt + Timer
        ↓
Bài 38
Interrupt + UART
        ↓
Bài 39
Thiết kế driver GPIO/EXTI hoàn chỉnh

Đặc biệt, Bài 34 về NVIC rất đáng học kỹ, vì lúc đó bạn sẽ hiểu rõ đường đi:

GPIO
 → EXTI
 → Pending
 → NVIC
 → Vector Table
 → ISR
 → CPU

và bắt đầu hiểu bên trong STM32 thực sự xử lý một interrupt như thế nào.

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

Recent Posts

  • Bạn có thể hướng dẫn tôi quy trình sửa chữa một mainboard laptop cũng như mainboard của máy tính để bàn không?
  • Có những mức nguồn DC nào trên một bo mạch mainboard laptop?Kỹ thuật đốt dòng để kiểm tra nguồn laptop được thực hiện như thế nào?
  • bài tiếp theo hợp lý là: BÀI 63 – SENSOR FUSION THỰC CHIẾN: ENCODER + IMU MPU6050 + EKF + ODOMETRY X,Y,θ TRÊN STM32F103
  • BÀI 62 – EKF (EXTENDED KALMAN FILTER) CHO ROBOT 2 BÁNH: FUSION ENCODER + IMU + ƯỚC LƯỢNG X, Y, θ, V, ω
  • BÀI 61 – KALMAN FILTER CHO ENCODER + IMU: ƯỚC LƯỢNG TỐC ĐỘ, GÓC θ VÀ SENSOR FUSION

Recent Comments

No comments to show.

Archives

  • September 2026
  • August 2026
  • July 2026
  • June 2026
  • May 2026
  • February 2026

Categories

  • Altium Desinger
  • Công nghệ
  • ESP32
  • Khác
  • Kiến thức điện máy
  • STM32
Live 3D Globes Visitor
©2026 Công nghệ 9 giây | Design: Newspaperly WordPress Theme