Bài 4: Lập trình Ngắt Ngoài STM32 EXTI

Ngắt ngoài STM32 EXTI

Bài này chúng ta sẽ nói về lập trình Ngắt ngoài STM32 (EXTI), Ngắt là gì, cách hoạt động của ngắt. Ngắt ngoài là gì, cách lập trình ngắt ngoài STM32

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

Ngắt (Interrupts) là gì?

Hãy tưởng tượng MCU chính là bạn, Sau khi khởi tạo các công việc hàng ngày như Thức dậy, ăn sáng, vệ sinh cá nhân …. Đó là các hàm được viết sau main().

Bạn đi đến công ty và làm việc các công việc trong while(1) cứ như vậy lặp đi lặp lại. Quá trình này trong lập trình gọi là Polling, việc nào đến trước làm trước, đến sau làm sau và không có sự ưu tiên việc nào làm trước.
Trong quá trình làm việc bỗng bạn nhận được nhiệm vụ từ xếp đó là “Đi gặp khách hàng”, công việc này phải ưu tiên hoàn thành trước, sau khi làm xong mới bắt đầu làm tiếp công việc thường này.

Sự kiện này trong lập trình gọi là Ngắt ( Interrupts)

Trong lập trình hiện nay, hiếm có chương trình nào ko sử dụng ngắt, vì có các dữ liệu phải được xử lý tức thì nếu không sẽ dẫn đến sai hoặc mất dữ liệu.

Các ngắt đều có 1 trị số priority ( Sự ưu tiên) cho phép người lập trình có thể ưu tiên xử lý ngắt nào trước nếu sảy ra ngắt chồng nhau.
Lấy ví dụ: Trong khi bạn đang gặp khách hàng lại được tin “ vợ đẻ “, nếu sự kiện “vợ đẻ” có priority cao hơn “Đi gặp khách hàng” thì chắc chắn bạn sẽ đi đón vợ đẻ trước, sau đó mới đi gặp khách hàng. Và chắc chắn việc gặp khách hàng sẽ chậm hơn 1 chút.

Trong STM32 việc quản lý các ngắt đó được điều khiển bằng bộ NVIC tạm dịch là bộ điều khiển ngắt lồng nhau.

Bộ điều khiển ngắt lồng nhau NVIC trong STM32

Thông số của NVIC như sau:

  • Bao gồm 68 ngắt ( chưa gồm 16 ngắt hệ thống)
  • Lập trình 16 mức ưu tiên ngắt (4 bit được sử dụng)
  • Độ trễ thấp
  • Quản lý năng lượng tiêu hao

Các vector ngắt được trình bày trong phần 10.1.2 reference manual

H1 1

Ngắt ngoài STM32 EXTI

EXTI (External Interupts) tạm dịch là ngắt ngoài hay ngắt sự kiện bên ngoài. Ngắt EXTI được kích hoạt khi có sự kiện từ bên ngoài tác động vào chân EXTI đó, tùy theo sự kiện đó có phù hợp với điều kiện ngắt không thì ngắt ngoài mới sảy ra.

Ngắt ngoài STM32 được mô tả như sau:

Các tham số (Main Features):

  • Kích hoạt độc lập trên mỗi dòng ngắt (Line Interrupts)
  • Truy cập đến từng Bit trong mỗi dòng ngắt
  • Tạo ra tối đa 20 sự kiện/ngắt
  • Tín hiệu phải có độ rộng xung thấp hơn chu kì xung nhịp của APB2 (vì APB2 cấp xung cho GPIO)

Các bạn tham khảo thêm 10.2.1 và 10.2.2 phần Block diagram

H2 2

Các Line ngắt ngoài được tổ chức như sau:

H3 1

Các chân PA0,PB0,…,PG0 sẽ chung là line EXTI0, Tiếp tục như vậy đến EXTI15 chúng ta có 16 ngắt.

4 ngắt ngoài đặc biệt đó là:

  • EXTI line 16: dùng cho PVD output
  • EXTI line 17: dùng cho sự kiện báo thức của bộ RTC
  • EXTI line 18: dùng cho sự kiện thức dậy của USB
  • EXTI line 19: dùng cho sự kiện thức dậy của ngoại vi Ethernet

Cấu hình Ngắt ngoài STM32 trên CubeMX

Trong bài này chúng ta sẽ cấu hình 3 nút nhấn gồm các chân PA0, PB3, PA1 sau đó phân biệt các sự kiện đó trong ngắt rồi điều khiển led.

PA0 Led sáng

PA1 Led tắt

PB3 Led nhấp nháy

Oke các bạn mở CubeMX lên chọn chip STM32f103c8 và tạo project

Nếu các bạn chưa biết tạo thì vui lòng đọc Bài 3 nhé

Trong SYS chọn Debug: Serial Wire , RCC giữ nguyên nhé.

Trong GPIO chọn các chân PA0,PA1,PB3 là GPIO_EXTI

H4

Trong mục Configuration có các lựa chọn sau:

GPIO mode:

  • External Interrupt Mode Rising edge: Ngắt ngoài chế độ phát hiện xung lên
  • External Interrupt Mode Falling edge: Ngắt ngoài chế độ phát hiện xung xuống
  • External Interrupt Mode Rising/Falling: Ngắt cả sườn lên và xuống
  • Exteral Event Mode Rising edge: Sự kiện ngoài phát hiện xung lên
  • Exteral Event Mode Falling edge: Sự kiện ngoài phát hiện xung xuống
  • External Event Mode Rising/Falling: Sự kiện cả sườn lên và xuống

Trong bài này chúng ta sẽ chọn chế độ ngắt phát hiện xung xuống.

External Interrupt Mode Falling edge

GPIO Pull: Có dùng trở kéo lên hoặc xuống không. Ta chọn trở kéo lên Pull UP

User Label ko cần sử dụng

H5 1

Trong Tab Nvic Tick vào các ô Enable để bật ngắt đó lên

H6 1

Chọn PC13 là Output. Sau đó chuyển Tab project manager đặt tên và Gen code

H7 2

Cấu hình Ngắt ngoài STM32 trên Keil C

Trong Keil C các bạn nhấn F7 để IDE Build chương trình mới tạo ra

Vào File Stm32F1xx_it.c sẽ thấy 3 chương trình phục vụ ngắt được sinh ra đó là:

EXT0_IRQHanler, EXT1_IRQHanler , EXT2_IRQHanler

Các bạn nhấn Chuột phải vào tên và Define tới nơi viết chương trình phục vụ ngắt đó.

H8 1

Trong hàm phục vụ ngắt sẽ có 1 câu lênh kiểm tra cờ ngắt tại tham số là GPIO_Pin truyền vào.

Nếu sảy ra ngắt sẽ xóa cờ ngắt để sẵn sàng cho ngắt tiếp theo xảy ra

Sau đó gọi tới hàm Callback

H9 1

Các bạn chuyên qua Tab Functions chọn file stm32f1xx_hal_gpio.c  Tìm đến hàm

HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)

Copy cả hàm đó và bỏ từ khóa  __weak

H10 1

Paste vào khu tiền xử lý trên hàm main() và code vào trong hàm này như sau

H11 1

Giải thích: Vì mọi ngắt ngoại tại các Line khác nhau đều gọi tới một hàm xử lý ngắt, chỉ khác tham số truyền vào là PIN nào vậy nên chúng ta so sánh PIN truyền vào với các PIN tương ứng với Line 0, 1, 3 để xác định ngắt xảy ra tại đâu.

Sau đó gọi hàm bật tắt led theo đúng yêu cầu bên trên .

Tiếp đó Build bằng F7 và Nạp code vào mạch bằng F8.

Kết nối nút nhấn vào 3 chân PA0, PA1, PA3, sau đó nhấn nút. Bạn sẽ thấy Led nháy tương ứng với ngắt tại chân đó

Lưu ý:

Mỗi Line chỉ sử dụng được 1 chân: Ví dụ Line 0 dùng chân PA0 thì PB0 sẽ ko thể sử dụng làm chân ngắt nữa

Kết

Ngắt ngoài STM32 được sử dụng rất rộng rãi, nhất là trong các ứng dụng Low power, khi đó MCU sẽ phải rơi vào trạng thái Sleep, khi có tác động từ bên ngoài, ngắt ngoài sẽ xảy ra và báo MCU hoạt động trở lại

 

5/5 - (5 bình chọn)

15 những suy nghĩ trên “Bài 4: Lập trình Ngắt Ngoài STM32 EXTI

  1. Đức nói:

    Em làm theo anh nhưng khi mô phỏng hàm Hal_Delay(100) trong ngắt gây ra lỗi treo chương trình. Nếu bỏ hàm delay thì chương trình chạy được. Em đang làm sai ở đâu phải không a?

  2. Đức nói:

    Em làm theo hướng dẫn ở trên, nhưng khi có ngắt line 3 thì chương trình nhảy vào ngắt và không thoát ra được. Khi bỏ hết hàm delay trong chương trình ngắt line 3 thì chương trình chạy bình thường a

  3. Thanh Hoàng nói:

    em làm đúng như anh hướng dẫn nhưng khi Buil thì báo lỗi “of undeclared identifier LED_GPIO_Port” là sao ạ???

    • Huy nói:

      Anh ơi cho em hỏi trong hàm xử lý ngắt ngoài khi hàm xử lý đấy chưa thực hiện xong chương trình ngắt của nó thì em nhấm thêm nút nhấn một lần nữa thì có hiện tượng gì xảy ra ạ.Cái event nhấn nút thứ 2 sẽ chuyển vào pending hay sẽ bị hủy ạ. Mong a giải đáp giúp em ạ

  4. Huy nói:

    Anh ơi cho em hỏi trong hàm xử lý ngắt ngoài khi hàm xử lý đấy chưa thực hiện xong chương trình ngắt của nó thì em nhấm thêm nút nhấn một lần nữa thì có hiện tượng gì xảy ra ạ.Cái event nhấn nút thứ 2 sẽ chuyển vào pending hay sẽ bị hủy ạ. Mong a giải đáp giúp em ạ

  5. nguyên nói:

    Sinh viên khai báo thêm 2 button sử dụng
    ngắt ngoài. Button 1 khi bấm sẽ thực hiện ngắt và đếm lên, button 2 khi bấm sẽ thực hiện
    đếm xuống. Giá trị hiển thị trên led từ 0-99..anh giải code giúp em với ạ!!!1

  6. Đức nói:

    Trong hàm ngắt ngoài chúng ta không nên sử dụng hàm hal_delay() vì khi đó chương trình sẽ bị treo trong vòng lặp vô hạn mn có thể tìm hiểu thêm tại:https://khuenguyencreator.com/hal_delay-voi-systick-va-delay-us-voi-timer-tren-stm32/
    để xử lý việc này chúng ta có thể có hai cách: 1 là xét mức độ ưu tiên cho ngắt ngoài(cách này không hiệu quả và khó quản lý ưu tiên ngắt) và 2 là có thể sử dụng một tín hiệu cho hàm ngắt sau đó lôi ra hàm while trong main để có thể tha hồ delay().
    uint8_t a = 0;
    void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
    {
     if(GPIO_Pin == GPIO_PIN_3)
    {
    a = 1;
    }
    }
    sang hàm while(1) trong main()
    while (1)
     {
      /* USER CODE END WHILE */

      /* USER CODE BEGIN 3 */
    if(a == 0)
    {
    HAL_GPIO_TogglePin(led1_GPIO_Port, led1_Pin);
    HAL_Delay(200);
    }else
    {
    a = 0;
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_4, GPIO_PIN_RESET);
    for(int i = 0; i <= 9 ; i++)
    {
    HAL_GPIO_TogglePin(led2_GPIO_Port,led2_Pin);
    HAL_Delay(1000);
    }
    HAL_GPIO_WritePin (GPIOB, GPIO_PIN_5,GPIO_PIN_RESET);
    }
    }
    trên đây là một vài chia sẻ của e một người mới hk được cho mn đi sau. cảm ơn mn nếu có cách hay hơn mn hay share nhé!!

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 *