1–EXTI简介
-
EXTI (external interrupt / event controller)——外部中断/事件控制器,管理了控制器20个中断/事件线,每个事件/中断都有一个边沿检测器,可以实现输入信号的上升沿或者下降沿的检测,EXTI可以实现对每一个中断/事件进行单独配置,可以单独配置中断或者事件,以及触发事件的属性。
-
中断:在主程序运行过程中,出现了特定的中断触发条件(中断源),使得CPU暂停当前正在运行的程序,转而去处理中断程序,处理完成后又返回原来被暂停的位置继续运行
-
中断优先级:当有多个中断源同时申请中断时,CPU会根据中断源的轻重缓急进行裁决,优先响应更加紧急的中断源
-
中断嵌套:当一个中断程序正在运行时,又有新的更高优先级的中断源申请中断,CPU再次暂停当前中断程序,转而去处理新的中断程序,处理完成后依次进行返回
中断源(例如串口收到了数据)
2–STM32的中断
- 68个可屏蔽中断通道,包含EXTI、TIM、ADC、USART、SPI、I2C、RTC等多个外设(具体可以查手册儿)
- 使用NVIC统一管理中断,每个中断通道都拥有16个可编程的优先等级,可对优先级进行分组,进一步设置抢占优先级和响应优先级
灰色的是内核的中断 其他的就是中断触发信号(触发源)
最右边是中断的地址 因为我们程序中的中断函数 他的地址 是有编译器来分配的 是不固定的 但是我们的中断跳转 只能跳到对应的位置进行执行程序 所以就有了地址 这些固定的地址存放这一条长跳转指令 当发生中断 就会由这个长跳转指令找到我们对应的中断处理函数
-
NVIC(嵌套中断向量控制表)(Nested Vectored Interrupt Controller)
NVIC的中断优先级由优先级寄存器的4位(0~15)决定,这4位可以进行切分,分为高n位的抢占优先级和低4-n位的响应优先级
抢占优先级高的可以中断嵌套,响应优先级高的可以优先排队,抢占优先级和响应优先级均相同的按中断号排队
分组方式 抢占优先级 响应优先级 分组0 0位,取值为0 4位,取值为0~15 分组1 1位,取值为0~1 3位,取值为0~7 分组2 2位,取值为0~3 2位,取值为0~3 分组3 3位,取值为0~7 1位,取值为0~1 分组4 4位,取值为0~15 0位,取值为0 -
支持的GPIO口:所有GPIO口,但相同的Pin不能同时触发中断
AFIO主要有2个作用 中断引脚选择 复用功能引脚重映射
3–EXTI框图详解
- EXTI分为两大部分 一个是产生中断,另一个是产生事件,这两个功能从硬件上就有所不同
图中红色的部分 是一个产生中断1的线路 最终流行NVIC控制器内
编号1是输入线 EXTI控制器内有19个中断/事件输入线 这些输入线可以通过寄存器任意一个GPIO口 也可以是一些外设的事件
编号2是一个边沿检测电路它会根据上升沿触发选择寄存器 (EXTI_RTSR) 和下降沿触发选择寄存器 (EXTI_FTSR) 对应位的设置来控制信号触发 边沿检测电路以输入线作为信号输入端,如果检测到有边沿跳变就输出有效信号 1 给编号 3 电路,否则输出无效信号 0而EXTI_RTSR 和 EXTI_FTSR 两个寄存器可以控制器需要检测哪些类型的电平跳变过程,可以是只有上升沿触发、只有下降沿触发或者上升沿和下降沿都触发。
编号3电路实际就是一个或门电路,它一个输入来自编号 2 电路,另外一个输入来自软件中断事件寄存器 (EXTI_SWIER)。 EXTI_SWIER 允许我们通过程序控制就可以启动中断/事件线,这在某些地方非常有用。我们知道或门的作用就是有 1 就为 1,所以这两个输入随便一个有有效信号 1就可以输出 1 给编号 4 和编号 6 电路
编号4是一个电路是一个与门电路,它一个输入是编号 3 电路,另外一个输入来自中断屏蔽寄存器(EXTI_IMR)。与门电路要求输入都为 1 才输出 1,导致的结果是如果 EXTI_IMR 设置为 0 时,那不管编号 3 电路的输出信号是 1 还是 0,最终编号 4 电路输出的信号都为 0;如果 EXTI_IMR设置为 1 时,最终编号 4 电路输出的信号才由编号 3 电路的输出信号决定,这样我们可以简单的控制 EXTI_IMR 来实现是否产生中断的目的。编号 4 电路输出的信号会被保存到挂起寄存器(EXTI_PR) 内,如果确定编号 4 电路输出为 1 就会把 EXTI_PR 对应位置 1。
编号 5 是将 EXTI_PR 寄存器内容输出到 NVIC 内,从而实现系统中断事件控制。
下面绿色的部分 他是一个产生事件的的电路流程 最终输出一个脉冲信号
123部分都是共用的 一路到了编号6 编号6是一个与门 他有2个输入端 一个软件中断事件寄存器 还有一个事件屏蔽寄存器 (EXTI_EMR )如果这一位设置为0 那么不管3是不是1 都输出0 如果 EXTI_EMR 设置为 1 时,最终编号 6 电路输出的信号才由编号 3 电路的输出信号决定,这样我们可以简单的控制 EXTI_EMR 来实现是否产生事件的目的。
编号7是一个脉冲发生器电路,当它的输入端,即编号 6 电路的输出端,是一个有效信号 1 时就会产生一个脉冲;如果输入端是无效信号就不会输出脉冲
编号8 是一个脉冲信号,就是产生事件的线路最终的产物,这个脉冲信号可以给其他外设电路使用,比如定时器 TIM、模拟数字转换器 ADC 等等,这样的脉冲信号一般用来触发 TIM 或者 ADC开始转换
- 产生中断线路目的是把输入信号输入到 NVIC,进一步会运行中断服务函数,实现功能,这样是
软件级的。而产生事件线路目的就是传输一个脉冲信号给其他外设使用,并且是电路级别的信号
传输,属于硬件级的。
4–程序分析
void Exti_Init(void)
{
/*****开启时钟*************/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB , ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO , ENABLE);
/******配置GPIO口**********/
GPIO_InitTypeDef GPIO_InitStructuer;
GPIO_InitStructuer.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructuer.GPIO_Pin = GPIO_Pin_14;
GPIO_InitStructuer.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB , &GPIO_InitStructuer);
/*******配置AFIO 中断引脚选择********/
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB , GPIO_PinSource14);
/*****配置EXTI********/
EXTI_InitTypeDef EXTI_InitStructure;
EXTI_InitStructure.EXTI_Line = EXTI_Line14; //选择中断线
EXTI_InitStructure.EXTI_LineCmd = ENABLE; //使能
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; //中断模式
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; //选择下降沿触发
EXTI_Init(&EXTI_InitStructure);
/*****配置NVIC*****/
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置优先级
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn; 使能所在的外部中断通道
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; 使能外部中断通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; //抢占优先级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //响应优先级
NVIC_Init(&NVIC_InitStructure);
}
- 中断函数
void EXTI15_10_IRQHandler(void) //外部中断函数
{
if(EXTI_GetITStatus(EXTI_Line14) == SET) //判断是否通道14来的中断
{
if (GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_14) == 0) //如果14号脚为低电平
{
Count ++;
}
EXTI_ClearITPendingBit(EXTI_Line14); //清除中断请求
}
}
5–程序验证
- 首先将硬件电路搭建好 我这里采用的是STM32C8T6最小系统板 + 对射红外传感器 这里将对射红外传感器的DO口接到STM32核心板上的PB14口 当有物体遮挡对射光电传感器时 DO口会输出一个高电平 因为设置的外部中断时下降沿触发 PB14引脚会捕捉到一个高电平到低电平的跳变信号 就会触发中断
- 进入Keil的Debug模式 在中断函数处打断点 后点击全速运行
用卡片遮挡我们的对射红外传感器 如果黄色箭头出现在我们打断点处 说明我们成功啦!!!
6 – 总结
在中断中 讲究块进快出 所以最好不要在中断里使用 Delay函数