最近在使用STM32的HAL库尝试作1个极其简单的小实验:以引脚PC1作外部中断响应,去激励引脚PC0-LED翻转…………但就是这么一个简单的实验,让我卡住了好久。下面来分析下这个实验和出现的问题: 板子的硬件原理图: HAL库代码配置:

一、初始化LED_IO口,即void MX_GPIO_Init(void),记得要在头文件声明

/** Configure pins as

* Analog

* Input

* Output

* EVENT_OUT

* EXTI

*/

void MX_GPIO_Init(void)

{

GPIO_InitTypeDef GPIO_InitStruct = {0};

/* GPIO Ports Clock Enable */

__HAL_RCC_GPIOC_CLK_ENABLE();

__HAL_RCC_GPIOA_CLK_ENABLE();

/*Configure GPIO pin Output Level */

HAL_GPIO_WritePin(GPIOC, GPIO_PIN_0, GPIO_PIN_RESET);

/*Configure GPIO pin : PC0 */

GPIO_InitStruct.Pin = GPIO_PIN_0;

GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;

GPIO_InitStruct.Pull = GPIO_NOPULL;

GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_MEDIUM;

HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

}

二、初始化按键_IO口,即void key_Init(void),下降沿触发EXTI中断,记得要在头文件声明

void key_Init(void)

{

GPIO_InitTypeDef GPIO_InitStruct = {0};

/* GPIO Ports Clock Enable */

__HAL_RCC_GPIOC_CLK_ENABLE();

// __HAL_RCC_GPIOA_CLK_ENABLE();

// /*Configure GPIO pin : PC1 */

// GPIO_InitStruct.Pin = GPIO_PIN_1;

// GPIO_InitStruct.Mode = GPIO_MODE_INPUT;

// GPIO_InitStruct.Pull = GPIO_PULLUP;

// GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_MEDIUM;

// HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

/*Configure GPIO pin : PC1 */

GPIO_InitStruct.Pin = GPIO_PIN_1;

GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;

GPIO_InitStruct.Pull = GPIO_PULLUP;

GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_MEDIUM;

HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);

HAL_NVIC_SetPriority(EXTI1_IRQn, 0, 0);

HAL_NVIC_EnableIRQ(EXTI1_IRQn);

}

三、在main.c中调用上述2个初始化函数MX_GPIO_Init();和key_Init();,记得包含有这2个函数的头文件

int main(void)

{

/* MCU Configuration--------------------------------------------------------*/

/* Reset of all peripherals, Initializes the Flash interface and the Systick. */

HAL_Init();

/* USER CODE BEGIN Init */

/* USER CODE END Init */

/* Configure the system clock */

SystemClock_Config();

MX_GPIO_Init();

key_Init();

USART1_Init();

while (1)

{

}

}

while(1)里面不用写东西,后面我们直接在中断回调callback函数编写中断服务

四、查看stm32f1xx_hal_gpio.c文件中的库函数

void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin)的作用是获取中断标志位和清除中断标志位、调用中断服务回调函数;__weak void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)是弱函数,如果我们在其他的.c文件重新定义实现这个函数,则该位置函数无效。这2个函数我们无需理会,这里只是作个说明。

/**

* @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) != 0x00u)

{

__HAL_GPIO_EXTI_CLEAR_IT(GPIO_Pin);

HAL_GPIO_EXTI_Callback(GPIO_Pin);

}

}

/**

* @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

*/

}

五、在stm32f1xx_it.c文件的后面手动加上下述中断响应函数

/* USER CODE END 1 */

/**

* @brief This function handles EXTI line0 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 */

}

六、编写中断服务函数

我们在按键key.c文件中实现void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)中断回调函数,回调代码段:

/**

* @brief exit callback function

* @param[in] GPIO_Pin:gpio pin

* @retval none

*/

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)

{

//if (GPIO_Pin == GPIO_PIN_1)

//{

// HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_0);

//}

while (GPIO_Pin == GPIO_PIN_1)

{

HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_0);

}

// do

// {

// HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_0);

// } while (GPIO_Pin == GPIO_PIN_1);

}

在这里问题出现了,如下图所示,我一开始用的while (GPIO_Pin == GPIO_PIN_1)来判断中断响应引脚,把程序下到MCU中,发现按键怎么按下都没有翻转LED,代码检查了一遍又一遍,还是未检查出问题,后面改成if (GPIO_Pin == GPIO_PIN_1)之后,按键就能翻转LED了……啊这……按照我的理解,if和while不都是能判断条件的吗?于是我再改成do{ }while形式去判断,果然也不行,为啥只有if起作用呢,为啥? 知其然,不知其所以然。那能怎么办呢,去请教网上的大佬看看if和while的具体用法呗,搜索中…………出现答案。 哦,意思就是if不会等你,它只会过一遍,而while会一直在原地等你,直到你来…………原来while的使用会进入无限循环判断,如果不加break,就会一直卡在判断条件成立与否,那EXTI中断就不能跳出循环进行下一次的响应了,害……C语言基础不牢,果真地动山摇。既然如此,那就修改下void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)中断回调函数的实现,添加break跳出语句,如下:

/**

* @brief exit callback function

* @param[in] GPIO_Pin:gpio pin

* @retval none

*/

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)

{

// if (GPIO_Pin == GPIO_PIN_1)

// {

// HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_0);

// }

// while (GPIO_Pin == GPIO_PIN_1)

// {

// HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_0);

// break;

// }

do

{

HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_0);

break;

} while (GPIO_Pin == GPIO_PIN_1);

}

这样,就能够正常使用外部中断去判断下降沿/上升沿触发啦。

精彩链接

评论可见,请评论后查看内容,谢谢!!!评论后请刷新页面。

大家都在找:

stm32:stm32最小系统

vscode:vscode配置python开发环境

单片机:单片机开发和嵌入式开发的区别

大家都在看: