本篇博客重点在于标准库函数的理解与使用,搭建一个框架便于快速开发
目录
EXTI简介
EXTI配置
使能AFIO的时钟
配置GPIO端口为外部中断
外部中断初始化
NVIC介绍与配置
NVIC中断优先级分组
NVIC初始化
NVIC框架
EXTI配置图
中断函数
中断函数配置
获取中断挂起位
清楚中断挂起标志位
中断函数框架
EXTI框架
EXTI简介
EXTI(Extern Interrupt),外部中断,也可配置事件,又可称事件控制器
EXTI可以监测指定GPIO口的电平信号,当其指定的GPIO口产生电平变化时,EXTI将立即向NVIC发出中断申请,经过NVIC裁决后即可中断CPU主程序,使CPU执行EXTI对应的中断程序
支持的触发方式:上升沿/下降沿/双边沿/软件触发
支持的GPIO口:所有GPIO口,但相同的Pin不能同时触发中断
中断通道数:16个GPIO_Pin,外加PVD输出、RTC闹钟、USB唤醒、以太网唤醒
后个主要用于低功耗的停止模式下使用外部中断唤醒
触发响应方式:中断响应/事件响应,中断由CPU响应,事件由外设响应
EXTI配置
使能AFIO的时钟
外部中断需要写事件控制寄存器(AFIO_EVCR),外部中断配置寄存器(AFIO_EXTICRX)
对寄存器AFIO_EVCR,AFIO_MAPR和AFIO_EXTICRX进行读写操作前,应当首先打开AFIO 的时钟。
事件控制寄存器(AFIO_EVCR)
故要开启AFIO的时钟,而AFIO在APB2外设总线上
再由RCC时钟树,需要使能APB2外设的AFIO时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
配置GPIO端口为外部中断
有关GPIO的详细配置请阅读这篇博客,这里不再赘述
【STM32】GPIO和AFIO标准库使用框架-CSDN博客
外部中断的GPIO_Mode为输入模式,设置为输入信号的默认电平对应的模式,更多见STM32F10xxx参考手册8.1.11 外设的GPIO配置
输入电平默认为高电平,上拉输入;输入电平默认为低电平,下拉输入。输入电平不确定选浮空输入
相同的Pin不能同时触发中断,比如GPIOX0只能有一个可以触发中断,GPIOA0映射到中断了,GPIOB0就不可以了
GPIO_PortSourceGPIOX ,X为A,B,C...
GPIO_PinSourcexX, X为0,1,2 ...
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource12);
GPIO_EXTILineConfig函数将指定端口配置到中断通道
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//输出速度,输入无用
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource12);
外部中断初始化
中断
要产生中断,必须先配置好并使能中断线。根据需要的边沿检测设置2个触发寄存器,同时在中断屏蔽寄存器的相应位写’1’允许中断请求。当外部中断线上发生了期待的边沿时,将产生一个 中断请求,对应的挂起位也随之被置’1’。在挂起寄存器的对应位写’1’,将清除该中断请求。
事件
如果需要产生事件,必须先配置好并使能事件线。根据需要的边沿检测通过设置2个触发寄存 器,同时在事件屏蔽寄存器的相应位写’1’允许事件请求。当事件线上发生了需要的边沿时,将产生一个事件请求脉冲,对应的挂起位不被置’1’。 通过在软件中断/事件寄存器写’1’,也可以通过软件产生中断/事件请求。
使能中断线
要产生中断,必须先配置好并使能中断线。
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
触发边沿选择
这个配置的是进入中断函数的电平变化边沿
上升沿 | EXTI_Trigger_Rising |
下降沿 | EXTI_Trigger_Falling |
双边沿 | EXTI_Trigger_Rising_Falling |
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
选择模式
中断模式 | EXTI_Mode_Interrupt |
事件模式 | EXTI_Mode_Event |
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
选择中断通道
对于互联型产品,外部中断/事件控制器由20个产生事件/中断请求的边沿检测器组成,对于STM32F10xxx其它产品(小容量、中容量和大容量),则有19个能产生事件/中断请求的边沿检测器
那我这个有19个能产生事件/中断请求的边沿检测器
EXTI_LineX, X为0到19
EXTI_InitStructure.EXTI_Line = EXTI_Line12;
EXTI初始化
EXTI_InitTypeDef EXTI_InitStructure;
EXTI_InitStructure.EXTI_Line = EXTI_Line12;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
EXTI_Init(&EXTI_InitStructure);
● EXTI线0~15连接到GPIO口
● EXTI线16连接到PVD输出
● EXTI线17连接到RTC闹钟事件
● EXTI线18连接到USB唤醒事件
● EXTI线19连接到以太网唤醒事件(只适用于互联型产品)
后四个主要用于低功耗的停止模式下使用外部中断唤醒
NVIC介绍与配置
NVIC是CPU的助手,管理中断,使中断有序执行
NVIC在内核里,不是外设,标准库函数声明在 misc.h 文件
NVIC特性
68个可屏蔽中断通道(不包含16个Cortex™-M3的中断线);
● 16个可编程的优先等级(使用了4位中断优先级);
● 低延迟的异常和中断处理;
● 电源管理控制;
● 系统控制寄存器的实现; 嵌套向量中断控制器(NVIC)和处理器核的接口紧密相连,可以实现低延迟的中断处理和高效地 处理晚到的中断。
嵌套向量中断控制器管理着包括内核异常等中断
NVIC中断优先级分组
NVIC的中断优先级由优先级寄存器的4位(0~15)决定,这4位可以进行切分,分为高n位的抢占优先级和低4-n位的响应优先级,抢占优先级高的可以中断嵌套,响应优先级高的可以优先排队,抢占优先级和响应优先级均相同的按中断号排队
具体中断号见参考手册中断向量表
中断个数比较少的话,就比较随意了,这个函数整个文件只需配置一次,多次配置会覆盖
示例代码为分组二
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC初始化
中断通道接入NVIC
NVIC_IRQChannel,参数在stm32f10x.h 文件
NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn;
使能NVIC通道
NVIC_IRQChannelCmd,指定NVIC_IRQChannel中定义的IRQ通道是启用还是禁用
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
抢占优先级
NVIC_IRQChannelPreemptionPriority
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
响应优先级
NVIC_IRQChannelSubPriority
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
NVIC初始化框架
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
NVIC_Init(&NVIC_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 = 2;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
NVIC_Init(&NVIC_InitStructure);
EXTI配置图
图片来源:STM32入门教程-2023版 细致讲解 中文字幕_哔哩哔哩_bilibili
中断函数
中断函数位置不固定
中断函数配置
中断函数名要与启动文件内中断向量名一样
中断函数快进快出,尽量不要加延时,不要在主函数和中断函数同时使用OLED等外设,易导致错误
中断函数不在主函数内使用,空闲时,不执行。检测到通道对应的边沿,立刻跳转,跳转后清除中断标志位,执行完中断函数,返回主函数里中断函数执行前的位置。
获取中断挂起位
FlagStatus EXTI_GetFlagStatus(uint32_t EXTI_Line);//main中调用
ITStatus EXTI_GetITStatus(uint32_t EXTI_Line);//中断函数中调用
清楚中断挂起标志位
void EXTI_ClearFlag(uint32_t EXTI_Line);//main中调用
void EXTI_ClearITPendingBit(uint32_t EXTI_Line);//中断函数中调用
中断函数框架
void EXTI15_10_IRQHandler(void)
{
if(EXTI_GetITStatus(EXTI_Line12) == SET)
{
EXTI_ClearITPendingBit(EXTI_Line12);
}
}
EXTI框架
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//输出速度,输入无用
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource12);
EXTI_InitTypeDef EXTI_InitStructure;
EXTI_InitStructure.EXTI_Line = EXTI_Line12;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
EXTI_Init(&EXTI_InitStructure);
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 = 2;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
NVIC_Init(&NVIC_InitStructure);
void EXTI15_10_IRQHandler(void)
{
if(EXTI_GetITStatus(EXTI_Line12) == SET)
{
EXTI_ClearITPendingBit(EXTI_Line12);
}
}