Làm sao để biết yêu cầu ngắt được tạo ra từ chân GPIO nào khi chương trình của bạn sử dụng nhiều chân External Interrupt? Trong bài viết này, mình sẽ giúp các bạn giải quyết được vấn đề trên với các ví dụ cụ thể. Mình sử dụng vi điều khiển STM32F103C8T6, cấu hình bằng STM32CubeMX sau đó code bằng Keil C IDE, sử dụng thư viện HAL.
[HỌC ONLINE: LẬP TRÌNH VI ĐIỀU KHIỂN STM32, VI XỬ LÝ ARM CORTEX – M]
Ví dụ mình có 02 nút bấm ở chân PA1 và PA2 khai báo External Interrupt, sử dụng trở kéo lên để định mức logic khi không nhấn nút, sử dụng sườn xuống để kích hoạt ngắt. Mình cấu hình thêm chân PC13 là GPIO OUTPUT để điều khiển LED.
Khi sinh code ra thì sẽ có các hàm liên quan đến ngắt ngoài trong thư viện HAL như sau:
Trong file stm32f1xx_hal_gpio.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
/** * @brief EXTI line detection callbacks. * @param GPIO_Pin: Specifies the pins connected EXTI line * @retval None */ __weak void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) { /* Prevent unused argument(s) compilation warning */ UNUSED(GPIO_Pin); /* NOTE: This function Should not be modified, when the callback is needed, the HAL_GPIO_EXTI_Callback could be implemented in the user file */ } /** * @brief This function handles EXTI interrupt request. * @param GPIO_Pin: Specifies the pins connected EXTI line * @retval None */ void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin) { /* EXTI line interrupt detected */ if (__HAL_GPIO_EXTI_GET_IT(GPIO_Pin) != RESET) { __HAL_GPIO_EXTI_CLEAR_IT(GPIO_Pin); HAL_GPIO_EXTI_Callback(GPIO_Pin); } } |
Trong file stm32f1xx_it.c:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
/** * @brief This function handles EXTI line1 interrupt. */ void EXTI1_IRQHandler(void) { /* USER CODE BEGIN EXTI1_IRQn 0 */ /* USER CODE END EXTI1_IRQn 0 */ HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_1); /* USER CODE BEGIN EXTI1_IRQn 1 */ /* USER CODE END EXTI1_IRQn 1 */ } /** * @brief This function handles EXTI line2 interrupt. */ void EXTI2_IRQHandler(void) { /* USER CODE BEGIN EXTI2_IRQn 0 */ /* USER CODE END EXTI2_IRQn 0 */ HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_2); /* USER CODE BEGIN EXTI2_IRQn 1 */ /* USER CODE END EXTI2_IRQn 1 */ } |
Bình thường, với 1 chương trình đơn giản, các bạn vào file stm32f1xx_hal_gpio.c copy cả phần định nghĩa hàm Callback ra file main.c, bỏ đi từ khóa weak và viết chương trình phục vụ ngắt vào đấy là xong. Ví dụ khi phát hiện nhấn nút (có sườn xuống tại bất 1 trong 2 chân đã khai báo) thì đảo trạng thái của LED.
1 2 3 4 5 6 7 8 |
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) { HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13); /* When the callback is needed, the HAL_GPIO_EXTI_Callback could be implemented in the user file */ } |
Nếu bài toán không phải là đảo LED khi nhấn bất kì 1 trong 2 nút bấm mà là nhấn nút PA1 thì bật LED còn nhấn nút PA2 thì tắt LED thì các bạn phải trả lời được câu hỏi:Làm sao để có thể phân biệt được chân nào đang sinh ra ngắt?
Có 2 cách:
Cách 1: Sử dụng hàm Callback như trên, tuy nhiên trong hàm Callback các bạn kiểm tra xem chân nào đang được truyền vào hàm thì chính là ngắt tại chân đó. Ví dụ:
1 2 3 4 5 6 7 8 9 10 11 |
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) { if(GPIO_Pin == GPIO_PIN_1) //PA1 - Turn on LED { HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, 1); } if(GPIO_Pin == GPIO_PIN_2) //PA1 - Turn on LED { HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, 0); } } |
Cách 2: Viết nội dung ngắt riêng cho từng line ngay tại các hàm phục vụ ngắt theo line trong file thư viện file stm32f1xx_it.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
//PA1 - Turn on LED void EXTI1_IRQHandler(void) { /* USER CODE BEGIN EXTI1_IRQn 0 */ HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, 1); /* USER CODE END EXTI1_IRQn 0 */ HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_1); /* USER CODE BEGIN EXTI1_IRQn 1 */ /* USER CODE END EXTI1_IRQn 1 */ } //PA2 - Turn off LED void EXTI2_IRQHandler(void) { /* USER CODE BEGIN EXTI2_IRQn 0 */ HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, 1); /* USER CODE END EXTI2_IRQn 0 */ HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_2); /* USER CODE BEGIN EXTI2_IRQn 1 */ /* USER CODE END EXTI2_IRQn 1 */ } |
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. Nếu có bất kì thắc mắc gì, hãy để lại bình luận.
Chúc các bạn thành công!
Nhóm TAPIT ARM R&D