STM32外部中断学习
1)外部中断概述
1.外部中断描述
在日常生活中,例如早上在睡觉被闹钟吵醒,你去关闭闹钟就属于中断事件。
在主函数里的代码是由CPU运行的,CPU在执行过程中突然发生了异常事件(中断),CPU必须暂停当前的工作(设下断点),然后跑去处理这个异常事件的函数(中断服务函数),处理完这个异常事件后(执行完中断服务函数),CPU就会回到刚才的断点,继续执行其它代码。所以主函数和中断服务函数属于同级,互相不能被调用。
中断发生的时间不可知、一旦发生就需要立马去执行
发生的条件:由外部输入数据决定,例如按键输入0/1执行中断服务函数
中断分类:外部中断 软件中断 系统中断
中断示意图
2)设置中断好处
1.提高硬件的利用率;2.可完善代码的逻辑
举例说明
如寄存器的查询机制
void Usart1_Echo(void)
{
u8 data;
while(!(USART1->SR & (1<<5)));
data=USART1->DR;
while(!(USART1->SR & (1<<7)));
USART1->DR=data;
}
主函数调用了这个函数一直在循环判断标志位,若DR里没有数据到来,一直卡在输入输出的状态位上,不会执行main函数内的剩下的代码。
如果加入中断服务函数,主函数可一直执行其它代码,把串口数据接收配置为中断,
串口有数据过来 触发断点执行对应的中断服务函数
中断方式就会大大提升硬件的利用率和完善代码逻辑
3)中断入口及与主函数关系
子函数与主函数
1.主函数可以调用子函数;
2.子函数可以调用子函数 (递归函数)
3.子函数不能调用主函数
中断服务函数与主函数:
中断服务函数与主函数之间不存在调用关系(平级),发生了断点中断服务函数抢占CPU执行中断服务函数、执行完后把CPU还给主函数
执行中断服务函数过程中也有可能触发新的断点
中断嵌套关系图
如果抢占优先级比当前执行的中断服务函数的优先级更高,可以进行多层嵌套。如果抢占优先级同级,不能进行嵌套。
4)中断优先级说明
中断体系中: 数字越小优先级越高
优先级别分为:抢占优先级 响应优先级 自然优先级
先比较抢占优先级 抢占一样时才比较响应优先级
在ARM结构下的优先级
ARM体系下的优先级:技术手册第五章(5.3)
ST公司的ARM体系下进一步封装
ST在ARM体系下中断优先级分组(内核编程手册213页)
一定要注意:选择优先级时一定要先选分组号 再写抢占优先级和响应优先级。
一个工程内只能有一个优先级分组!!!否则后续的再次分组会替换掉前面的优先级分组。
5)设置优先级分组函数
函数原型: void __NVIC_SetPriorityGrouping(uint32_t PriorityGroup)
函数功能:设置优先级分组
形参: PriorityGroup 这个函数的组号按照下图的组号分配
NVIC_SetPriorityGrouping(1);//1位抢占 3位响应,可以理解为传入的形参就是多少位抢占优先级
6)设置中断优先级函数
函数原型:
void __NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority)
函数功能:设置优先级
形参:
IRQn----中断号
Priority----优先级
例如:
NVIC_SetPriorityGrouping(2);//2位抢占 2位响应
NVIC_SetPriority(USART1_IRQn,6);//串口1的中断设置成抢占优先级为1,响应优先级为2(0110)
NVIC_SetPriorityGrouping(1);//1位抢占 3位响应
NVIC_SetPriority(USART2_IRQn,7);//串口2的中断设置成抢占优先级为0,响应优先级为7(0111)
8)中断使能函数
void __NVIC_EnableIRQ(IRQn_Type IRQn)
传参是中断号
9)3Stm32F4XX中断向量表(参考中文手册或者启动文件stm32f40_41.s)
STM32F4系列有82个中断向量都封装在库函数内,具体可以按CTRL+F搜索IRQn查询需要用到的中断号
10)外部中断使用
GPIO发生电平变化产生的中断(外部中断)
23个中断源(16个EXTI线+7根另外的中断线)—其中16根是IO口触发的
82个IO口 —不可能每个IO口配置中断
相同引脚的IO口公用一个中断—EXTI线
这种公共入口的中断 进入中断服务函数内还需要判断具体哪个中断触发的
IO口的中断都是由引脚n映射到EXTIn(外部中断线n)上,5-9位共用一个映射,10-15共用一个映射,公用的映射都共用同一个中断服务函数
所以一个程序内最多只能容纳7+7=14个外部中断服务函数
例如配置PF4引脚的外部中断
首先打开PF时钟和EXTI时钟(SYSCFG时钟)
在数据手册中找到EXTI时钟线对应的SYSCFG时钟
GPIOF对应的时钟线是AHB1,EXIT(SYSCFG)对应的时钟线是APB2。这里图中标注的EXI时钟线,在参考手册对应是SYSCFG时钟。
所以我们应该置1该寄存器的第14位
需要配置SYSCFG的寄存器如下
SYSCFG->EXTICR[1] |=(5<<0);//PF是0101
这样可以将PF4映射到EXTI4线上
外部中断框图
从外部中断框图可知,数据通过IO口进来,先经过边沿检测电路(上升沿或下降沿触发),再和中断屏蔽寄存器(置1,开放第EXTIn中断线)进行逻辑与门后,通过挂起寄存器判断第n位数据到来,就可以执行中断服务函数的代码。
值得注意是:当发生中断请求,例如PF4中断请求时,
EXTI->PR的第四位会置1,当进入中断服务函数时,对第4位写1可以将标志位清除。
void system_Config()
{
RCC->APB2ENR |= (1<<14);//打开外部中断时钟
RCC->AHB1ENR |= (1<<6);//打开F端口时钟源
SYSCFG->EXTICR[1] |= (4<<0); //将PE4引脚映射到EXTI4上
EXTI->RTSR |= (1<<4);//设置为上升沿触发
EXTI->IMR |= (1<<4);//中断屏蔽寄存器设置
NVIC_SetPriorityGrouping(2);//设置优先级分组号,2位抢占,2位响应
NVIC_SetPriority(EXTI4_IRQn, 9);//EXTI0设置抢占2,响应1(1001)
NVIC_EnableIRQ(EXTI4_IRQn);//使能EXTI4
}
11)同理编写按键中断思路
1.代码中按键能正常工作
2.打开时钟(SYSCFG)
3.配置SYSCFG_EXTICR
4.配置边沿选择寄存器(上升沿 下降沿)
5.使能中断屏蔽寄存器
6.优先级(根据优先级分组,设置n位抢占,4-n位响应,使能中断号)
7.中断服务函数
进服务函数先将标志位写1清零!!
12)中断服务函数的注意事项(重点!)
1.中断服务函数名尽量用复制,不要自己写,因为只要你写错一个字母,这个函数就变成普通函数了。
2.(如果中断服务函数是公共入口)进入到中断服务函数后先要查询是哪种中断
3.先清中断标志,然后再做中断处理,不要把清中断标志放在函数的最后。(如果把清除中断标志放在中断服务函数的最后,会出现当发出清中断标志指令后,硬件还没有把相关标志清除掉,程序就已经跳出了中断服务函数,这个时候NVIC又会识别到标志是1,出现重复中断)。—可以清除中断标志命令发出后,等待清除成功再往下执行。
4.中断服务函数应该尽量简短,一般是做一些标识,不要在中断中做延时之类的占用CPU很长时间的工作。要做到快进快出
5.中断服务函数不会被任何一个函数调用,当中断条件满足后,NVIC控制把CPU拉到中断服务函数中执行。