提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
前言
扩展中断和事件控制器(EXTI)通过可配置和直接的事件输入来管理各个CPU和系统的唤醒。它向电源控制提供唤醒请求,并向CPU NVIC产生中断请求,向CPU事件输入产生事件。
提示:以下是本篇文章正文内容,下面案例可供参考
一、外部中断特点
EXTI的主要特点如下:
- 支持47个输入事件。
- 大多数事件输入允许系统被唤醒。
- 有些事件只能用于产生CPU唤醒事件。
- 在外设中没有相关唤醒标志的事件,在EXTI中有一个标志,并从EXTI产生一个中断给CPU。
异步事件输入被分为以下两组: - 可配置的事件(来自I/O或外设的信号能够产生一个脉冲),其特点如下:
- 可选择的主动触发边缘
- 中断等待状态寄存器位
- 单独的中断和事件生成掩码,用于调节CPU的唤醒、中断和事件生成
- SW触发的可能性
- 直接事件(来自外设的中断和唤醒源,有一个相关的标志在外设中被清除),具有以下特点:
- 固定上升沿主动触发
- EXTI中没有中断等待状态寄存器位(中断等待状态标志由产生事件的外设提供)。
- 单独的中断和事件生成掩码,用于调节CPU的唤醒和事件生成
- 没有软件触发的可能性
二、外围设备和CPU之间的EXTI连接
当系统处于停止模式时,能够产生唤醒或中断事件的外设被连接到EXTI。
产生脉冲的外设唤醒信号或外设中没有中断状态位的外设,被连接到EXTI可配置的事件输入。对于这些事件,EXTI提供了一个需要被清除的状态等待位。正是与该状态位相关的EXTI中断对CPU进行了中断。
外设中断和唤醒信号在外设中具有一个状态位,需要在外设中被清除,被连接到EXTI直接事件输入。EXTI内没有状态等待位。中断或唤醒是由外设中的CPU清除的。是外设的中断直接中断了CPU。
EXTI可配置的事件中断与CPU的NVIC相连。
专用的EXTI/EVG CPU事件被连接到CPU的rxev输入。
EXTI CPU唤醒信号连接到PWR块,用于唤醒系统和CPU子系统总线时钟
三、功能和相关寄存器
要产生中断,必须先配置好并使能中断线。根据需要的边沿检测设置 2 个触发寄存器,同时在 中断屏蔽寄存器的相应位写“1”使能中断请求。当外部中断线上出现选定信号沿时,便会产生中断请求,对应的挂起位也会置 1。在挂起寄存器的对应位写“1”,将清除该中断请求。
要产生事件,必须先配置好并使能事件线。根据需要的边沿检测设置 2 个触发寄存器,同时 在事件屏蔽寄存器的相应位写“1”允许事件请求。当事件线上出现选定信号沿时,便会产生事件脉冲,对应的挂起位不会置 1。
通过在软件中对软件中断/事件寄存器写“1”,也可以产生中断/事件请求。
具体细节参考
四、STM32CubeMX工程创建
1、芯片选择,根据需求选择响应芯片
2、引脚设置
这里将PA0配置位外部中断模式,通过按键控制电平变化,触发外部中断
3、GPIO配置
在这里插入图片描述
外部中断模式 上升沿触发检测的(这里我们选择上升沿触发)
外部中断模式,下降沿触发检测、
外部中断模式,上升/下降沿触发检测
外部事件模式,上升沿触发检测
外部事件模式,下降沿触发检测
外部事件模式,上升/下降沿触发检测!
开启外部中断
4、时钟配置
这里我用的msi作为时钟源
5、配置路径,选择IDE,创建工程
五、keil代码部分
在编写外部中端服务函数是发现,嵌套调用了下
这是个弱定义,我们重新编写
在main中加入
uint8_t flag=0;
GPIO_PinState PinState;
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin){
if(GPIO_Pin==BUT_Pin){
//HAL_Delay(20);中断函数为了高效,不能加入延时函数
GPIO_PinState PinState=HAL_GPIO_ReadPin(GPIOA,BUT_Pin);
if(PinState==GPIO_PIN_SET){//按键按下一次
/* if(flag==0){flag=1;HAL_GPIO_TogglePin(GPIOB,LED1_Pin);}
else if(flag==1){flag=2;HAL_GPIO_TogglePin(GPIOB,LED2_Pin);}
else if(flag==2){flag=3;HAL_GPIO_TogglePin(GPIOB,LED3_Pin);}
else if(flag==3){
flag=0;
HAL_GPIO_WritePin(GPIOB,LED1_Pin, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOB,LED2_Pin, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOB,LED3_Pin, GPIO_PIN_RESET);
}*/
switch(flag){
case 0:
// HAL_GPIO_WritePin(GPIOB,LED1_Pin, GPIO_PIN_SET);
flag=1;
HAL_GPIO_TogglePin(GPIOB,LED1_Pin); //点亮LED1
break;
case 1:
// HAL_GPIO_WritePin(GPIOB,LED2_Pin, GPIO_PIN_SET);
flag=2;
HAL_GPIO_TogglePin(GPIOB,LED2_Pin);//点亮LED2
break;
case 2:
//HAL_GPIO_WritePin(GPIOB,LED3_Pin, GPIO_PIN_SET);
flag=3;
HAL_GPIO_TogglePin(GPIOB,LED3_Pin);//点亮LED3
break;
case 3://熄灭所有灯
flag=0;
HAL_GPIO_WritePin(GPIOB,LED1_Pin, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOB,LED2_Pin, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOB,LED3_Pin, GPIO_PIN_RESET);
break;
default:break;
}
}
}
}
//发现按下去触发中断时可能会产生两次任务(预期是按下去就触发一次任务)。因为按键时会有抖动的,导致进入了两次中断
这里有个小BUG,正在解决,未完待续。。。。
总结
一个外部中断通道可以被多个pin使用,但同一时间只能有一个进行使用,通过多路复用器可以完成此操作