STM32学习笔记
第二章 1.建立一个简单的中断
提示:写完文章后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
前言
建立一个按键触发的中断
提示:以下是本篇文章正文内容,下面案例可供参考
一、stm32f1系列的中断简介
STM32F103 的中断控制器支持 19个外部中断/事件请求:
EXTI 线 0~15:对应外部 IO 口的输入中断。
EXTI 线 16:连接到 PVD 输出。
EXTI 线 17:连接到 RTC 闹钟事件。
EXTI 线 18:连接到 USB 唤醒事件。
EXTI 线 19:连接到以太网唤醒事件。
从上面可以看出,STM32F1 供 IO 口使用的中断线只有16 个,但是 STM32F1 的 IO 口却远远不止 16 个,于是就只能复用,EXTI0链接(GPA0~GPG0)的所有中断,而中断线每次只能连接到 1 个 IO 口上
二、建立一个按键中断
总结:初始化引脚xx触发->配置中断优先级->EXTI0_IRQHandler(void) EXTI0线接口清零标志位且调用下面函数
->HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_n) 判断具体引脚执行具体功能
1) 使能 IO 口时钟,初始化 IO 口为输入
//外部中断初始化
GPIO_InitTypeDef GPIO_Initure;
__HAL_RCC_GPIOA_CLK_ENABLE(); //开启 GPIOA 时钟
__HAL_RCC_GPIOE_CLK_ENABLE(); //开启 GPIOE 时钟
GPIO_Initure.Pin=GPIO_PIN_0; //PA0
GPIO_Initure.Mode=GPIO_MODE_IT_RISING; //上升沿触发
GPIO_Initure.Pull=GPIO_PULLDOWN;
HAL_GPIO_Init(GPIOA,&GPIO_Initure);
GPIO_Initure.Pin=GPIO_PIN_3|GPIO_PIN_4; //PE3,4
GPIO_Initure.Mode=GPIO_MODE_IT_FALLING; //下降沿触发
GPIO_Initure.Pull=GPIO_PULLUP;
HAL_GPIO_Init(GPIOE,&GPIO_Initure);
2) 配置中断优先级(NVIC),并使能中断
//配置三个中断线的优先级
//中断线 0-PA0
HAL_NVIC_SetPriority(EXTI0_IRQn,2,0); //抢占优先级为 2,子优先级为 0
HAL_NVIC_EnableIRQ(EXTI0_IRQn); //使能中断线 0
//中断线 3-PE3
HAL_NVIC_SetPriority(EXTI3_IRQn,2,2); //抢占优先级为 2,子优先级为 2
HAL_NVIC_EnableIRQ(EXTI3_IRQn); //使能中断线 2
//中断线 4-PE4
HAL_NVIC_SetPriority(EXTI4_IRQn,2,3); //抢占优先级为 2,子优先级为 3
HAL_NVIC_EnableIRQ(EXTI4_IRQn); //使能中断线 4
3) 在各个EXTI接口中调用外部中断共用入口函数
中断服务函数的名字是在 HAL 库中事先有定义的。这里需要说明一下,STM32F1 的IO 口外部中断函数只有 7个,分别为:
void EXTI0_IRQHandler();
void EXTI1_IRQHandler();
void EXTI2_IRQHandler();
void EXTI3_IRQHandler();
void EXTI4_IRQHandler();
void EXTI9_5_IRQHandler();
void EXTI15_10_IRQHandler();
这几个接口都调用外部中断共用入口函数 HAL_GPIO_EXTI_IRQHandler
//中断服务函数
void EXTI0_IRQHandler(void)
{
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_0); //调用中断处理公用函数
}
void EXTI3_IRQHandler(void)
{
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_3); //调用中断处理公用函数
}
void EXTI4_IRQHandler(void)
{
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_4); //调用中断处理公用函数
}
//这就是中断处理公用函数
void HAL_GPIO_EXTI_IRQHandler(uint16_t GPIO_Pin)
{
if(__HAL_GPIO_EXTI_GET_IT(GPIO_Pin) != 0x00u)
{
__HAL_GPIO_EXTI_CLEAR_IT(GPIO_Pin); //清理标志位
HAL_GPIO_EXTI_Callback(GPIO_Pin); //执行通用回调函数
}
}
4) 编写外部中断回调函数HAL_GPIO_EXTI_Callback
//中断服务程序中需要做的事情
//在 HAL 库中所有的外部中断服务函数都会调用此函数
//GPIO_Pin:中断引脚号
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
delay_ms(100); //消抖
switch(GPIO_Pin)
{
case GPIO_PIN_0:
if(WK_UP==1)
{
LED0=!LED0; //控制 LED0 反转
}
break;
case GPIO_PIN_3:
if(KEY1==0) //控制 LED1 反转
{
LED1=!LED1;
}
break;
case GPIO_PIN_4:
if(KEY0==0)
{
LED0=!LED0;
LED1=!LED1;
}
break;
default :
break;
}
三、思考
外部中断回调函数 HAL_GPIO_EXTI_Callback,该函数用来编写真正的外部中断控制逻辑。
该函数有一个入口参数就是 IO 口序号。所以我们在该函数内部,一般通过判断 IO 口序号值来确定中断是来自哪个 IO 口,也就是哪个中断线,然后编写相应的控制逻辑。
所以在该函数内部,我们通过 switch 语句判断 IO 口来源,例如是来自 GPIO_PIN_0,那么一定是来自PA0,因为中断线一次只能连接一个 IO 口,而四个 IO 口中序号为 0 的 IO 口只有 PA0,所以中断线 0 一定是连接 PA0,也就是外部中断由 PA0 触发。
思考:如果GPA0和GPB0都有外部中断需求,用switch判断就无法区分,该如何处理同一个EXTI线下的中断处理呢?
答案是:做不到,GPA0和GPB0用的都是中断线0,故只有最后那个配置的有效。画pcb时也要留意这个;
总结
欢迎指正