写在前面:前面的学习中,我们接触了stm32的第一个外设gpio,这也是最常用的一个外设;而除了gpio外,中断也是一个十分重要且常用的外设;只有掌握了中断,再处理程序时才能掌握好解决实际问题的逻辑思路。此节我们学习stm32的中断;
在前面51的学习中,我们也介绍过中断的内容,但是相对于32来说,52的中断十分简单,只有5个中断源,中断的优先级,响应函数也是比较简单的,感兴趣的读者可以看一下下面的这篇博客。
csdnhttps://mp.csdn.net/mp_blog/creation/editor/133904885
目录
一、什么是中断
中断:打断cpu执行正常的程序,转而处理紧急程序,然后返回原暂停的程序继续运行;
举例:当你正在写作业时,做到一半又去吃饭,吃完饭后又回来接着原来的作业继续完成。
对于单片机来说,中断是指cpu正在处理某个事件a,发生了另一件事件b,请求cpu迅速去处理(中断发生);cpu暂时停止当前的工作(中断响应),转去处理事件b(中断服务);待cpu处理事件b完成后,再回到原来的事件a(断点)继续执行,这一过程称之为中断。
stm32 gpio外部中断简图:
下面将分别对上述过程中的各个部分进行详细的描述;
二、 nvic(中断管家)
2.1 nvic基本概念
nvic 即嵌套向量中断控制器,全称 nested vectored interrupt controller。属于是内核的器件,其作用是对stm32中的中断进行管理,因为m3内核中的中断数量很多,当同时出现多个中断时,优先处理哪个中断?以及那些中断不处理等,都要靠nvic 进行控制。m3 内核都是支持 256 个中断,其中包含了 16 个系统中断和 240 个外部中断,并且具有 256 级的可编程中断设置。
nvic支持:256个中断(16个内核+240个外部);支持256个优先级。
但是对于st公司来说,用不了m3内核中的所有中断以及中断优先级,进而对其进行了一定的裁剪。stm32中共有10个内核中断,60个外部中断,16个中断优先级;
在中断的使用中还有一个极其重要的一部分为中断服务函数(触发中断后,系统执行的部分,例如上文的吃饭过程)中断服务函数是中断的入口。
2.2 nvic相关寄存器
nvic相关的寄存器有很多,但是重要的有以下几个,也是需要进行掌握的:
名称 | 位数 | 个数 | 作用 |
中断使能寄存器(iser) | 32 | 8 | 每一位控制一个中断(打开) |
中断失能寄存器(icer) | 32 | 8 | 每一位控制一个中断(关闭) |
应用程序中断及复位控制寄存器(aircr) | 32 | 1 | 位[10:8]控制中断优先级分组 |
中断优先级寄存器ipr | 8 | 240 | 8个位对应一个中断,而stm32只使用高4位 |
2.3 nvic工作原理
工作原理图:
2.4 中断优先级
stm32中断优先级基本概念:
1、抢占优先级(pre):高抢占优先级可以打断正在执行的低抢占优先级中断;
2、响应优先级(sub):当抢占优先级相同时,响应优先级高的先执行,但是不能相互打断;
3、抢占优先级和响应优先级都相同的情况下,自然优先级越高的先执行;
4、自然优先级:中断向量表中的优先级;
5、数值越小,表示优先级越高;
stm32中断优先级分组:
在前面我们说过aircr寄存器,位10、9、8三位用于控制优先级的分组,但是只取其中的五组优先级分组;ipr寄存器,用于控制中断的优先级,包括抢占优先级与响应优先级,高4位控制,如下表所示:
优先级分组 | aircr[10:8] | ipr[7:4]分配 | 分配结果 |
0 | 111 | none:[7:4] | 抢占优先级(0位、0级) 响应优先级(4位、16级) |
1 | 110 | [7]:[6:4] | 抢占优先级(1位、2级) 响应优先级(3位、8级) |
2 | 101 | [7:6]:[6:4] | 抢占优先级(2位、4级) 响应优先级(2位、4级) |
3 | 100 | [7:5]:[4] | 抢占优先级(3位、8级) 响应优先级(1位、2级) |
4 | 011 | [7:4]:none | 抢占优先级(4位、16级) 响应优先级(0位、0级) |
假定设置中断优先级分组为 2,然后设置中断3的抢占优先级为 2,响应优先级为 1。中断6的抢占优先级为 3,响应优先级为0。 中断7的抢占优先级为 2,响应优先级为 0。那么这 3 个中断的优先级顺序为: 中断 7>中断 3>中断 6。 上面例子中的中断 3 和中断 7 都可以打断中断 6 的中断。而中断 7 和中断 3 却不可以相互打断!
在一个工程中,一般只设置一次中断优先级分组(aircr寄存器);
2.5 nvic使用(stm32)
1、hal_nvic_setprioritygrouping()
中断分组的设置在hal_init()函数中配置:
2、hal_nvic_setpriority()
函数说明:
用于设置中断的抢占优先级和响应优先级(子优先级)
函数形参:
形参 1 是中断号,可以选择范围:irqn_type 定义的枚举类型。
形参 2 是抢占优先级,可以选择范围:0 到 15。
形参 3 是响应优先级,可以选择范围:0 到 15。
3、hal_nvic_enableirq()
函数描述: 用于使能中断。
函数形参: 形参 irqn 是中断号,可以选择范围:irqn_type 定义的枚举类型
三、exit(外部中断控制)
3.1 exit基本概念
全称:外部中断事件控制器
包含20个产生事件/中断请求的边沿检测器,即20条exit线;
每个输入线可以独立地配置输入类型(脉冲或挂起)和对应的触发事件(上升沿或下降沿或者双边沿都触发)。每个输入线都可以独立地被屏蔽。挂起寄存器保持着状态线的中断请求
3.2 exit工作原理
工作原理图:
3.3 exit相关寄存器
在上述工作原理图中,所涉及的寄存器共有7个,但是对于外部中断来说,我们只需要掌握其中四个寄存器:上升沿触发选择寄存器(exti_rtsr)、下降沿触发选择寄存器(exti_ftsr)、挂起寄存器(exti_pr)与中断屏蔽寄存器(exti_imr)。
1、上升沿触发选择寄存器(exti_rtsr)
2、下降沿触发选择寄存器(exti_ftsr)
3、挂起寄存器(exti_pr)
4、中断屏蔽寄存器(exti_imr)
3.4 exit线与io映射关系
前面说过, exti 线 0~15:对应外部 io 口的输入中断。但是stm32f1 供给 io 口使用的中断线只有 16 个,但是 stm32f1 的 io 口 却远远不止 16 个,所以 stm32 把 gpio 管脚 gpiox.0~gpiox.15(x=a,b,c,d,e,f,g)分别对应中断线 0~15。这样子每个中断线对应了最多 9 个 io 口,以线 0 为例:它对应了gpioa.0、gpiob.0、 gpioc.0、gpiod.0、gpioe.0、gpiof.0 和 gpiog.0。而中断线每次只能连接到 1 个 io 口上, 这样就需要通过配置决定对应的中断线配置到哪个 gpio 上了。
gpio 和中断线映射关系是在寄存器 afio_exticr1 ~ afio_exticr4 中配置的
外部中断配置寄存器 1(afio_exticr1)
四、中断的使用
4.1中断的使用步骤
4.2exit的配置步骤
4.3通用外设驱动
这个内容在上一节gpio的使用中已经说明;详细内容请看下面这个博客;
stm32--gpio点亮led灯(手把手,超详细)-csdn博客
4.4中断回调机制(hal库)
五、硬件设计
5.1实现功能
利用stm32f1精英开发板的独立按键模块key0控制led0灯的亮灭;
5.2原理图
1、led设置
在该开发板上的led灯共有3个,本次我们点亮led0,即对pb5进行操作;我们看到led0右端接的是vcc3.3v,那么只需要控制左端的pb5输出即可;(输出0点亮,输出1熄灭);
我们还需要确定gpiob_5的工作模式;我们采用推挽输出,其特点为:输出引脚电平,高电平为vdd,低电平为vss;
2、key设置
在该开发板上的key共有三个按键,本次我们使用的是key0,即对pe4进行操作,当按键按下是,pe4输出低电平,当按键未按下时,pe4应为高电平;所以gpioe_4的工作模式为上拉输入。
六、程序设计
6.1程序设计流程图
6.2中断初始化函数
6.3中断服务函数
每开启一个中断,就必须编写其对应的中断服务函数,否则将会导致死机(cpu 将找不到 中断服务函数)。stm32f1 的 io 口外部中断函数只有 7 个上文已经说明。
中断线 0-4,每个中断线对应一个中断函数,中断线 5-9 共用中断函数exti9_5_irqhandler, 中断线 10-15 共用中断函数 exti15_10_irqhandler。一般情况下,我们可以把中断控制逻辑直 接编写在中断服务函数中,但是 hal 库把中断处理过程进行了简单封装。
6.4中断处理回调函数
hal 库为了用户使用方便,提供了一个中断通用入口函数 hal_gpio_exti_irqhandler, 在该函数内部直接调用回调函数 hal_gpio_exti_callback。
该函数实现的作用非常简单,通过入口参数 gpio_pin 判断中断来自哪个 io 口,然后清除 相应的中断标志位,最后调用回调函数 hal_gpio_exti_callback()实现控制逻辑。在所有的外 部中断服务函数中直接调用外部中断共用处理函数 hal_gpio_exti_irqhandler,然后在回调 函数 hal_gpio_exti_callback 中通过判断中断是来自哪个 io 口编写相应的中断服务控制逻 辑。
6.4源码
exti.c文件
#include "./bsp/exti/exti.h"
#include "./system/delay/delay.h"
void exti_init(void)
{
gpio_inittypedef gpio_init_struct;
__hal_rcc_gpioe_clk_enable();
gpio_init_struct.pin=gpio_pin_4;
gpio_init_struct.mode=gpio_mode_it_falling ;
gpio_init_struct.pull=gpio_pullup ;
hal_gpio_init(gpioe,&gpio_init_struct);
hal_nvic_setpriority(exti4_irqn,2,0);
hal_nvic_enableirq(exti4_irqn);
}
void exti4_irqhandler(void)
{
hal_gpio_exti_irqhandler(gpio_pin_4);
__hal_gpio_exti_clear_it(gpio_pin_4);
}
void hal_gpio_exti_callback(uint16_t gpio_pin)
{
delay_ms(20);
if( gpio_pin==gpio_pin_4)
{
if(hal_gpio_readpin(gpioe,gpio_pin_4)==0)
{
hal_gpio_togglepin(gpiob, gpio_pin_5);
}
}
}
6.5实验现象
32中断点灯
总结: 本文主要讲解了stm32单片机的中断使用,主要内容有:中断的概念、nvic、exit的介绍,以及中断使用的步骤。并且利用中断实现了按键控制led灯。大家一定要反复阅读,才能掌握其中的思路,也要对实验部分进行多次尝试。。
创作不易,还请大家多多点赞支持!!!
发表评论