了解外部中断(EXTI)功能
监测指定的GPIO口,当电平产生变化时,EXTI向NVIC发出中断申请,NVIC裁决后中断CPU的程序。
AFIO(数据选择器)选择PAx,PBx,PCx….中的一个引脚接入EXIT的通道x上,所以相同的pin口不能同时触发中断
配置步骤
- 配置RCC,把涉及到的始终外设打开,让时钟可以工作
- 配置GPIO,让端口设置为输入模式
- 配置AFIO,选择使用的GPIO,连接到EXTI
- 配置EXTI,选择边沿触发方式(上升沿低变高、下降沿高变低、双边沿、软件手动),选择触发响应方式(中断响 应、事件响应)
- 配置NVIC,给中断一个合适的优先级,通过NVIC中断就可进入到 CPU,CPU收到信号,跳转到对应的中断函数执行中断程序
配置RCC
/*开启时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //开启GPIOB的时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); //开启AFIO的时钟,外部中断必须开启AFIO的时钟
配置GPIO
EXTI 推荐使用浮空、上拉、下拉输入
/*GPIO初始化*/
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
//将PB14引脚初始化为上拉输入
配置AFIO
GPIO_EXTILineConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource);
配置AFIO的数据选择器,来选择想要的中断引脚 (选择用作EXTI线的GPIO引脚。)
( GPIO_PortSourceGPIOX,GPIO_PinSourceX )
( 哪个GPIO上的中断源, 第几个引脚中断 )
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource14); //将外部中断的14号线映射到GPIOB,即选择PB14为外部中断引脚
AFIO的第14个数据选择器被定义:输入端为GPIOB的PB14引脚
输出端为EXTI的第14个中断线路(下面EXTI来选)
配置EXTI
EXTI_DeInit(void);
把EXTI的配置清除,恢复成上电默认的状态
EXTI_Init(EXTI_InitTypeDef* EXTI_InitStruct);
初始化EXTI外设(自己定义的结构体的地址)
EXTI_InitTypeDef EXTI_InitStructure; //定义结构体变量的名字 EXTI_InitStructure.EXTI_Line = EXTI_Line14; //选择配置外部中断的14号线 EXTI_InitStructure.EXTI_LineCmd = ENABLE; //指定外部中断线使能 中断线的新状态 EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; //指定外部中断线为中断模式 也可以是事件模式_Event EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; //指定外部中断线为下降沿触发 也可是上升沿触发_Rising
EXTI_Init(&EXTI_InitStructure); //将结构体变量的地址交给EXTI_Init,配置EXTI外设
EXTI_StructInit(EXTI_InitTypeDef* EXTI_InitStruct);
可以把参数中的结构体变量赋值成一个默认值(结构体)
EXTI_GenerateSWInterrupt(uint32_t EXTI_Line);
直接 手动 软件触发外部中断(中断线)
FlagStatus EXTI_GetFlagStatus(uint32_t EXTI_Line);
获得指定的标志位是否被置1 (中断线)
EXTI_ClearFlag(uint32_t EXTI_Line);
对置1的标志位进行清除(中断线)
EXTI_ClearITPendingBit(EXTI_Line14); //清除外部中断14号线的中断标志位
EXTI_GetITStatus(uint32_t EXTI_Line);
获取中断标志位是否被置1 (中断线)
EXTI_GetITStatus(EXTI_Line14) == SET //返回SET或者RESET
EXTI_ClearITPendingBit(uint32_t EXTI_Line);
清除中断挂起标志位 (中断线)
EXTI_ClearITPendingBit(EXTI_Line14);
配置NVIC
NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup);
中断分组(抢占优先级和响应优先级) (NVIC_PriortyGroup_X)
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //配置NVIC为分组2 //即抢占优先级范围:0~3,响应优先级范围:0~3 //此分组配置在整个工程中仅需调用一次 //若有多个中断,可以把此代码放在main函数内,while循环之前 //若调用多次配置分组的代码,则后执行的配置会覆盖先执行的配置
NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct);
根据结构体里面的值初始化NVIC
NVIC_InitTypeDef NVIC_InitStructure; //定义结构体变量 名字 NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn; //选择配置NVIC的EXTI15_10线 10-15都在这里 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //指定NVIC线路使能 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; //指定NVIC线路的抢占优先级为1 0-15 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //指定NVIC线路的响应优先级为1 0-15
NVIC_Init(&NVIC_InitStructure); //将结构体变量地址交给NVIC_Init,配置NVIC外设
void NVIC_SetVectorTable(uint32_t NVIC_VectTab, uint32_t Offset);
设置中断向量表
void NVIC_SystemLPConfig(uint8_t LowPowerMode, FunctionalState NewState);
系统低功耗配置
void SysTick_CLKSourceConfig(uint32_t SysTick_CLKSource);
定义中断函数
EXTI15_10_IRQHandler();
此函数为中断函数,无需调用,中断触发后自动执行
* 函数名为预留的指定名称,可以从启动文件复制
* 请确保函数名正确,不能有任何差异,否则中断函数将不能进入void EXTI15_10_IRQHandler(void) { //因为10-15号中断线都可触发 if (EXTI_GetITStatus(EXTI_Line14) == SET) //判断是否是外部中断14号线触发的中断 { /*如果出现数据乱跳的现象,可再次判断引脚电平,以避免抖动*/ if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_14) == 0) { 这是要执行的函数!!! } EXTI_ClearITPendingBit(EXTI_Line14); //清除外部中断14号线的中断标志位 //中断标志位必须清除 //否则中断将连续不断地触发,导致主程序卡死 } }
作者:氵羊——