目录
EXTI理论部分
EXTI(External interrupt/event controller)— 外部中断/事件控制器,管理了控制器的 20 个中断/事件线。每个中断/事件线都对应有一个边沿检测器,可以实现输入信号的上升沿 检测和下降沿的检测。EXTI 可以实现对每个中断/事件线进行单独配置,可以单独配置为 中断或者事件,以及触发事件的属性。
上面讲到EXTI有20个中断/事件线,其中16个是GPIO,剩下分别是PVD、RTC、USB这些外设的
介绍EXTI初始化结构体
typedef struct
{
uint32_t EXTI_Line;
EXTIMode_TypeDef EXTI_Mode;
EXTITrigger_TypeDef EXTI_Trigger;
FunctionalState EXTI_LineCmd;
} EXTI_InitTypeDef;
1、uint32_t EXTI_Line, 用设置中断屏蔽寄存器相对应位,可以在 stm32f10x_exti.h文件中找到相对应的初始化值,如下图2,联想到EXTI结构框图,便知道此处的作用(开放请求)


2、EXTIMode_TypeDef EXTI_Mode, 用于设置相应中断/事件线到底是发出中断还是事件,对应值如下图
3、EXTITrigger_TypeDef EXTI_Trigger, 在EXTI结构框图中第二步可以看到,边沿检测电路是需要相应寄存器来设置的,可以设置为上升沿触发、下降沿触发以及同时触发产生两个中断。
4、FunctionalState EXTI_LineCmd,配置是否使能EXTI线,参数有:ENABLE、DISABLE
介绍NVIC初始化结构体
typedef struct
{
uint8_t NVIC_IRQChannel;
uint8_t NVIC_IRQChannelPreemptionPriority;
uint8_t NVIC_IRQChannelSubPriority;
FunctionalState NVIC_IRQChannelCmd;
} NVIC_InitTypeDef;
1、 NVIC_IRQChannel、选择中断源
2、NVIC_IRQChannelPreemptionPriority, 配置抢占优先级(也叫主优先级)
3、NVIC_IRQChannelSubPriority, 配置子优先级
4、NVIC_IRQChannelCmd, 使能外设
实践部分
本实践以stm32f103位基础,编写key1产生中断
编程思路
- 初始化要连接到EXTI的GPIO
- 初始化EXTI用于产生中断/事件
- 初始化NVIC,用于处理中断
- 编写中断服务函数
- 编写main函数
1、初始化GPIO
// 初始化GPIO
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd( KEY1_GPIO_CLK, ENABLE);
GPIO_InitStructure.GPIO_Pin = KEY1_GPIO_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(KEY1_GPIO_PORT, &GPIO_InitStructure);
2、初始化EXTI
2.1 初始化EXTI中断/事件线
GPIO_EXTILineConfig( GPIO_PortSourceGPIOA, GPIO_PinSource0);
在这里曾产生过一个疑问,这里的实参GPIO_PortSourceGPIOA,是否就是GPIOA,后来发现GPIO_PortSourceGPIOA这个参数和GPIOA不一样,因为这个函数是操作AFIO_EXTICRx(x=1...4),GPIO_PortSourceGPIOA是用来配置这个寄存器的,而GPIOA则是一个变量,这样子就说的清了,同理 GPIO_PinSource0 也是用来配置AFIO_EXTICR这类寄存器相应位的
2.2 初始化EXTI结构体
// 初始化EXTI结构体
EXTI_InitStructure.EXTI_Line = EXTI_Line0;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
2.3 调用EXTI初始化函数
// 在函数开始有定义声明 EXTI_InitTypeDef EXTI_InitStructure;
EXTI_Init( &EXTI_InitStructure );
3、初始化NVIC
以注释的方式写在代码段里了。
void NVIC_IQRPriority_Config(void)
{
//创建NVIC初始化结构体
NVIC_InitTypeDef NVIC_InitStructure;
//配置中断优先级分组
NVIC_PriorityGroupConfig( NVIC_PriorityGroup_1);
选择哪个中断/事件线
NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;
//打开NVIC外设
//NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
//分别配置主、子中断优先级为1、7
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 7;
//调用初始化函数,注意要的参数是地址
NVIC_Init( &NVIC_InitStructure );
}
4、编写中断服务函数
需要注意一点,中断服务函数的名字是固定的,在启动文件里的向量表中有各个中断服务函数的地址,可以在启动文件中找到相应的函数名,这里使用EXTI0_IQRhandler。
//这里实现让LED灯翻转的操作
void EXTI0_IRQHandler( )
{
//在中断打开的情况下操作
if ( EXTI_GetITStatus(EXTI_Line0 != RESET ) ) {
LED_G_TOGGLE;
}
//清除中断位,不然一直中断
EXTI_ClearITPendingBit( EXTI_Line0 );
}
5、在main函数中编写
最终实现的效果就是按下开关灭,再按就亮
文章中涉及的部分专业词汇
上升沿:指电信号从低电平(0)转到高电平(1)的一个过程。
下降沿:指电信号从高电平(1)转到低电平(0)的一个过程。
中断:中断是需要CPU参与的,需要软件的中断服务函数才能完成中断后产生的结果;
事件:是靠脉冲发生器产生一个脉冲,进而由硬件自动完成这个事件产生的结果
区别:事件是不需要CPU参与,降低了CPU的负荷
参考:
STM32之中断与事件---中断与事件的区别_flydream0的博客-CSDN博客_嵌入式中断和事件的区别
BSP(板级支持包),介于硬件和操作系统之间的为上层驱动程序提供访问硬件寄存器的函数包