问题引入:我们想通过 按键 控制灯亮 ,怎么做
一般做法:轮询
2b轮询例子:
2:吃了吗?B:没吃
2:吃了吗?B:没吃
2:吃了吗?B:吃了
2:吃了吗?B:…
2:吃了吗?B:滚!
具体做法
1 将GPIO口设为输入模式,
2 不断判断GPIO口的电平状态,从而得到是否按下按键
这样的 方式叫 “轮询”
轮询 有天生的 缺陷:
有人提出,能不能这样做,按下或弹起的时候,外设主动通知CPU,这就叫中断。
日常中的中断,有更紧急的事情出现要去处理。比如说看电视的时候,电话响了,暂停电视听电话。
处理器的中断:在处理器中,中断是一个过程。在处理器正常执行程序时,出现内部/外部紧急事件需要去处理,处理器暂停当前的程序,去处理紧急事件,处理完毕后,返回被打断的程序处继续往下执行。
中断可以提升CPU的处理效率,同时能堆突发事件做出实时的处理。实现程序的并行化,实现嵌入式系统进程之间的切换。
中断不是动不动就用的,在特定的应用场合应用。
中断
轮询
保护现场,寄存器的值压栈。
执行中断服务程序,通过中断向量去寻找中断服务程序。
恢复现场。
中断是什么?请简述单片机中断处理的过程
CPU在正常执行程序的过程中,由于内部/外部事件的触发或程序的预先安排引起CPU暂时中断当前正在运行的程序,而转去执行中断服务子程序,待中断服务子程序执行完毕后,CPU继续执行原来的程序,这一过程称为中断;
中断处理的过程:
第一步:保护现场,将当前位置的PC地址压栈;
第二步:跳转到中断服务程序,执行中断服务程序;
第三步:恢复现场,将栈顶的值回送给PC;
第四步:跳转到被中断的位置开始执行下一个指令;
相比于正常子函数,中断服务函数有什么特点和需要注意的地方?
1.相比正常的子函数,中断函数服务函数中不能有耗时的操作,最不能在中断服务函数中有延时函数。
2.不能有引起中断睡眠的函数。
3.不能递归调用自身。
4.在中断服务函数中不能出现可重入函数。比如printf。
5.中断服务函数中没有参数以及没有返回值。
每一个外设(分管部门):外设中的每一个外设都有一个自己的中断开关,内核中的系统定时器等也有自己中断开关。能够产生中断的设备通过中断请求线(IRQ line)连到NVIC上面,所有能够产生中断的设备必须要有一根中断请求线。
NVIC(主管家):NVIC专门管理中断的,每一个中断都要在NVIC中挂号(使NVIC监听器中断请求)。NVIC收到外设的中断请求,会将其中断请求发送给内核,内核收到NVIC的中断通知之后,就会去判断时哪个中断发生,然后查找FLASH中断向量表去获取相应的中断处理函数。
举例:
由简单GPIO电平引起的中断,由专门的部件管理中断,这个部件脚EXTI(外部中断管理控制器)。
某个GPIO需要产生中断,由EXTI使能之后,EXTI会把中断的请求,通知给NVIC,NVIC若对其使能,则NVIC把这个中断请求通知给CORTEX_M3,由CORTEX_M3处理中断。
stm32所有的I/O都可以配置中断。
Nested Vectored interrupt controller,NVIC属于M3内核的一个外设。这个NVIC是个重大的创举有着伟大的意义,就像秦朝设立丞相那样减轻的皇帝的负担。它的库函数在core_cm.3和misc.h
1、快。(男人就是要快!)
快速的运行的产品需要快,如高铁,飞机,导弹等产品。
2、标准化,同一化。
中断服务程序同一了,方便编程人员。
STM32f03支持60个课屏蔽中断,每个中断具备自己的中断优先级控制字节(8位,但是只使用高4位),用于表达优先级的高4位被分为抢占式优先级和响应优先级。
所以STM32(Cortex-M3)中有两个优先级的概念-抢占式优先级(主优先级)和响应优先级(从优先级)。每个中断源都需要被指定这两种优先级。
中断被响应先后顺序:
中断号保存在 IPSR
中断优先级控制的寄存器组:IP[240]
因为M3内核最多有 240个可屏蔽的中断,所以有240个确定 中断优先级的寄存器 ,
每个IP寄存器是8位的, 高4位用来设置抢占和响应优先级(根据分组),
低4位没有用到
Stm32f10x有60个中断 ,所以用到了 IP[0]~IP[59]
中断使能寄存器组:ISER[8]
32位寄存器,每个位控制一个中断的使能。
STM32F10x只有60个可屏蔽中断,所以只使用了其中的ISER[0]和ISER[1]。
ISER[0]的bit0~bit31分别对应中断0 ~ 31。ISER[1]的bit0 ~ 27对应中断32 ~59;
中断失能寄存器组:ICER[8]
32位寄存器,每个位控制一个中断的失能。
STM32F10x只有60个可屏蔽中断,所以只使用了其中的ICER[0]和ICER[1]。
ICER[0]的bit0 ~ bit31分别对应中断 0 ~31。ICER[1]的bit0 ~ bit27 对应中断32 ~ 59;
配置方法跟ISER一样。
中断挂起控制寄存器组:ISPR[8]
作用:用来挂起中断
中断解挂控制寄存器组:ICPR[8]
作用:用来解挂中断
思路:
系统运行后先设置中断优先级分组(4bits 空间 存储两个优先级)。
1.首先得对优先级进行分组。
调用函数:
void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup);
参数NVIC_PriorityGroup选择如下:
NVIC_PriorityGroup_0 //抢占优先级占0bits, 响应优先级占4bits
NVIC_PriorityGroup_1 //抢占优先级占1bits, 响应优先级占3bits
NVIC_PriorityGroup_2 //抢占优先级占2bits, 响应优先级占2bits
NVIC_PriorityGroup_3 //抢占优先级占3bits, 响应优先级占1bits
NVIC_PriorityGroup_4 //抢占优先级占4bits, 响应优先级占0bits
举例:在设置为NVIC_PriorityGroup_2 时,抢占优先级有2^2=4个,同理响应优先级也有4个。
2. 针对每个中断,设置对应的抢占优先级和响应优先级。
void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct);
typedef struct
{
uint8_t NVIC_IRQChannel; //指定要初始化的中断通道(中断号)
uint8_t NVIC_IRQChannelPreemptionPriority;//设置响应优先级,0~15数值越低,优先级越
uint8_t NVIC_IRQChannelSubPriority; //设置抢占优先级,0~15数值越低,优先级越高
FunctionalState NVIC_IRQChannelCmd; //ENABLE/DISABLE。禁止中断/使能中断
} NVIC_InitTypeDef;
注意:只能指定一个,不能使用 或运算符| 来初始化多个中断通道。
stm32有许多中断,用中断向量表对中断进行管理。中断向量表给每个中断分配一个地址。这个地址里面是一个跳转语句。可以看到每个向量占用4个字节。而这四个字节就可以存储一个跳转指令。
非阴影部分为外设的中断向量。4个字节
共60个外部中断。