中断
某些事件可能需要CPU暂停目前的程序优先处理
实现CPU暂停当前的程序并优先处理某一事件的机制称作中断
处理这一事件的程序叫做中断服务程序(Interrupt Handler)
中断的硬件实现
内部或外部信号产生中断
—>程序跳转到某一特定地址(中断向量)
//不同的中断可能会对应同一地址,此后在程序中需要进行判定
—>程序从中断向量跳转到对应的中断服务程序
//此时会将原来正在使用的重要数据压入堆栈(某一特定的内存空间)
—>执行完毕后返回原来被打断的位置
//堆栈中的数据被还原,保证原来的程序正常执行
stm32的外部中断
- 外部中断可由GPIO输入上升沿(0->1跳变)和/或下降沿(1->0跳变)触发
- 最多16个外部中断
- 每组GPIO相同编号的pin共享一个外部中断
- 每个GPIO都可以被配置为外部中断
HAL库的中断实现
首先Cube会生成一个stm32xx_it.c(即中断服务程序入口,中断向量处跳转指向的地址)
HAL库会预先处理中断,判断中断类型
//在中断服务程序入口处,HAL库会调用自己的一个函数
//在判定完中断类型后会调用对应的回调函数(即Callback)
//Callback用_week定义,可以被用户改写
外部中断的回调函数
void HAL_GPIO_EXTI_Callback (uint16_t GPIO_Pin)
可以在任意程序文件中重新定义这个函数
外部中断产生时,HAL库处理完中断会调用这个函数
//传入参数是具体产生中断的引脚,需要使用GPIO_Pin宏定义判定
//若需判定中断由上升沿还是下降沿产生,可以读取当前GPIO电平
使用外部中断检测按键(示例)
设置Cube外设
打开Cube,把基本外设以及时钟树设置完后
把PA0设置为GPIO_EXTI0,因为这是 A组GPIO 的第 0 号引脚所以其所属的中断向量为 EXTI0
在旁边外设设置中的NVIC中的EXTI line0 interrupt勾上,这样才会产生中断
在GPIO选项中PA0引脚被激活后可以在GPIO mode中选择上升沿触发还是下降沿触发
这次改成由上升沿和下降沿触发
中断的代码理解
用keil5打开代码后打开stm32f4xx_it.c文件,
里面有Cube自动生成的void xxFault_Handler(void)函数,
这些函数代表芯片出错后会进入这些中断,
这些函数里面都有一个while(1)循环,这样在出错后可以直接把程序卡死停止执行
在文件最下面有 EXTI0_IRQHandler
void EXTI0_IRQHandler(void)
{
/* USER CODE BEGIN EXTI0_IRQn 0 */
/* USER CODE END EXTI0_IRQn 0 */
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0);
/* USER CODE BEGIN EXTI0_IRQn 1 */
/* USER CODE END EXTI0_IRQn 1 */
}
在产生外部中断后,程序就会跳转到这个地方
其中有一个hal库函数
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0);
在stm32f4xx_hal_gpio.c中可以找到这个函数
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);
}
}
这个函数就代表如果它读到低电平,即按键按下后产生中断
__HAL_GPIO_EXTI_CLEAR_IT(GPIO_Pin);
这个函数会把中断的标志物清除
HAL_GPIO_EXTI_Callback(GPIO_Pin);
接着就会调用回调函数
在后面会有一个__weak函数
__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
*/
}
即该回调函数可以被再次声明,即会覆盖掉自动生成的函数
在中断回调函数中编写在此次中断中需要执行的功能即可。
代码编写
在main.c
在/* USER CODE BEGIN 4 */
/* USER CODE END 4 */中写入我们重定义的函数
即我们可以在这里添加我们的中断回调函数
/* USER CODE BEGIN 4 */
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
if(GPIO_Pin==GPIO_PIN_0)//判断是否为外部中断0的回调
{
if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0)==GPIO_PIN_SET)
{
HAL_GPIO_WritePin(GPIOH,GPIO_PIN_12,GPIO_PIN_RESET);
}
else if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0)==GPIO_PIN_RESET)
{
HAL_GPIO_WritePin(GPIOH,GPIO_PIN_12,GPIO_PIN_SET);
} //移植的电灯代码
}
};
/* USER CODE END 4 */
然后就可以进行编译烧录。文章来源:https://www.toymoban.com/news/detail-423984.html
参考资料
CH1.3 GPIO 第3讲 中断与EXTI【南工骁鹰嵌入式软件培训】文章来源地址https://www.toymoban.com/news/detail-423984.html
到了这里,关于stm32中断的基础知识的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!