STM32 -中断
并发(Concurrency)
并发是指同时处理多个任务的能力,但并不意味着这些任务实际上是在同一时刻物理上同时运行的。在单处理器或多处理器系统中,并发通过时间片轮转(time-slicing)等技术实现,这些技术使得操作系统可以在多个任务之间快速切换,从而在宏观上给用户造成所有任务都在同时运行的错觉。简而言之,并发主要关注的是任务的交错执行,以提高程序的执行效率和响应性。
并行(Parallelism)
并行则是指同时有多个任务真正地在物理上并行执行。这通常需要多核处理器或者多台计算机(分布式计算)的支持。在并行计算中,不同的任务(或同一任务的不同部分)可以在不同的处理器核心上同时执行,从而实现真正的并行处理。这种方式可以显著提高程序的执行速度,因为多个处理器可以同时处理数据。
并发并行总结
-
并发强调的是任务的交错执行,使得多个任务看起来像是在同时运行,但实际上它们是在共享的资源(如CPU)上交替执行的。
-
并行则指的是任务真正地同时在多个处理器上执行,这样可以显著提高计算速度和效率。
中断:
在主程序运行过程中,出现了特定的中断触发条件(中断源),使得CPU暂停当前正在运行的程序,转而去处理中断程序处理完成后又返回原来被暂停的位置继续运行。 中断优先级:当有多个中断源同时申请中断时,CPU会根据中断源的轻重缓急进行裁决,优先响应更加紧急的中断源。 中断嵌套:当一个中断程序正在运行时,又有新的更高优先级的中断源申请中断,CPU再次暂停当前中断程序,转而去处理新的中断程序,处理完成后依次进行返回。
功能框图:
产生中断
-
①是一个边沿检测电路 : 上升沿触发选择寄存器和下降沿触发选择寄存器
-
以输入线作为信号输入端,如果检测到有边沿跳变就输出有效信号‘1’,就输出有效信号‘1’到标号② 部分电路,否则输出无效信号‘0’。
-
②是一个或门电路 : 软件中断事件寄存器和边沿检测电路的输入信号
-
或门电路只要输入端有信号‘1’,就会输出‘1’,所以就会输出‘1’到标号③电路和标号④电路。
-
③是一个与门电路 : 中断屏蔽寄存器和标号②电路输出信号
-
与门电路要求输入都为‘1’才输出‘1’,中断屏蔽寄存器(EXTI_IMR)设置为 1 时,最终标号③电路输出 的信号才由标号②电路输出信号决定
-
请求挂起寄存器(EXTI_PR)的内容就输出到 NVIC 内,实现系统中断事件的控制。
产生事件
-
产生事件线路是从标号 2 之后与中断线路有所不用,之前的线路都是共用的。
-
④是一个与门,与门电路要求输入都为‘1’才输出‘1’ , 如果 EXTI_EMR 寄存器设置为 1,最终标号④ 电路输出信号就由标号③电路输出的信号决定,这样子就可以简单的控制 EXTI_EMR 来实现是否产 生事件的目的。
-
配置 AFIO 相关寄存器前,还需要打开 AFIO 时钟。
可以看到这82个可屏蔽中断通道,包含EXTI、TIM、ADC、USART、SPI、I2C、RTC等多个外设,本章我们重点研究EXTI外部中断。
ps:灰色的是内核的中断 一般用不到
NVIC
一、NVIC是什么? NVIC是一种中断控制器,管理所有低优先级和高优先级中断。当一个中断正在处理时,另一个更高优先级的中断可以打断当前中断的执行,并立即得到处理。这种机制使得处理器在高速运行的同时,能够及时响应不同优先级的中断请求。
二、有哪些优先级?(只有抢占优先级才会发生中断嵌套!!) 抢占优先级: 抢占优先级是指中断的打断优先级,抢占优先级高的中断可以打断正在执行的抢占优先级低的中断。 响应优先级: 响应优先级是指中断的响应顺序,响应优先级只有在抢占优先级相同的情况下才有意义。当抢占优先级相同时,俩个中断同时发生,响应优先级高的中断先响应。 自然优先级: 按照自带的优先级编号(硬件固定)在抢占和响应优先级相同的情况下决定先执行哪个中断,数字越小级别越高。这个是由厂家设计好的。 每个中断源的抢占优先级和响应优先级由用户决定(软件设置),而自然优先级已经被硬件固定, 不可更改。优先级越高其对应的值越低。数字越小,优先级越高。
三、什么是中断嵌套? 答:通俗来讲就是停止当前正在进行的任务去执行抢占优先级更高的中断任务。 例如:A的抢占优先级为0,B的抢占优先级为1。则当两个中断请求同时发生时,先执行抢占优先级高的A。但是当CPU正处理B时发生了A的中断请求,则停止执行B,先去执行A的中断,当执行完A中断后再去执行剩下的B程序。这就是中断嵌套。
四、优先级的优先等级(序号越低,优先级越高) (1)优先级大小:抢占优先级>响应优先级>自然优先级。
(2)抢占优先级相同,响应优先级不同,则先处理响应优先级高的。但是响应优先级没有中断嵌套。 例:如果A的抢占优先级为0,B的抢占优先级也为0。A的响应优先级为0,B的响应优先级为1。则两个同时发生中断请求时,在抢占优先级相同时先处理响应优先级高的A。但是如果CPU正在处理B时发生了A的中断请求,则继续执行B,当B完成后再执行A。因为响应优先级不会发生中断嵌套。
(3)如果抢占优先级和响应优先级都相同,则比较它们的硬件中断编号(自然优先级),中断编号越小,优先级越高。(硬件中断编号从中断向量表中查看)
五、优先级分组 Core-M4内核最多支持256级的可编程优先级。用8位来表示优先级级别,,优先级级别分为8组,分别是组0~组7。但是ST公司设计STM32F407ZGT6时,为了精简设计,只用了16 个可编程优先级(使用了 高四位4 位来设置中断优先级,设置低四位的值是无效的)。所以不同的芯片优先级分组会有不同。
原文链接:STM32基础-NVIC中断控制器_抢占优先级和响应优先级-CSDN博客
中断处理路径:
过程
先比较正在执行的程序和中断的抢占优先级,若中断的抢占优先级高则可以直接中断嵌套。
若不高,就比较响应优先级,如果响应优先级高则可以优先排队。
若抢占优先级和响应优先级均相同则按中断号排队
软件设计 EXTI 外部中断配置步骤
-
使能对应 GPIO 口时钟
-
设置 GPIO 工作模式,触发条件,开启 AFIO 时钟,设置 IO 口与中断线的映射关系
-
配置中断优先级( NVIC),并使能中断。
-
编写中断服务函数。
EXTI功能
EXTI可以监测指定GPIO口的电平信号,当其指定的GPIO口产生电平变化时,
EXTI将立即向NVIC发出中断申请,经过NVIC裁决后即可中断CPU主程序,
使CPU执行EXTI对应的中断程序
中断支持的触发方式
上升沿(电平从低电平变到高电平的瞬间出发中断)
下降沿(电平从低电平变到高电平的瞬间出发中断)
双边沿(上升沿和下降沿都可以触发中断)
软件触发(程序执行一句代码触发中断)
支持的GPIO口
所有GPIO口都可以当作外部中断的引脚,
但每个EXTI线路只能连接到一个物理引脚,所以相同的Pin不能同时触发中断
(因为共用中断线(通常是16条(EXIT0~EXIT15)))
(eg: PA0和PB0,PA1和PB1和PC1)
通道数
16个GPIO_Pin(GPIO_Pin_0~GPIO_Pin_15),外加PVD输出、RTC闹钟、USB唤醒、以太网唤醒
触发响应方式
中断响应/事件响应
代码
//exti.h
#ifndef __EXIT_H
#define __EXIT_H
void Key0_EXTI_Init(void);
void Key1_EXTI_Init(void);
#endif
//exti.c
#include "exti.h"
#include "stm32f4xx.h"
/*
按键中断控制LED
代码思路:
1.查看原理图确定引脚 PE4
(确定中断优先级分组 NVIC_PriorityGroupConfig)
2.GPIO初始化
...
3.EXTI配置
a.结构体申明 EXTI_InitTypeDef
b.时钟使能 使能SYSCFG的时钟
c.中断线与GPIO连接 SYSCFG_EXTILineConfig
d.配置结构体
中断线、中断触发方式、中断/事件的选择、使能
c.初始化 EXTI_Init
4.配置NVIC中断管理
a.结构体申明 NVIC_InitTypeDef
b.配置结构体
哪一个中断、抢占优先级、响应优先级
c.初始化 NVIC_Init
5.中断服务函数重写
a.判断中断标志位
b.中断业务代码(进中断做什么事情)
c.清除中断标志
*/
void Key0_EXTI_Init(void)
{
EXTI_InitTypeDef EXTI_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE); //使能时钟
SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOE, EXTI_PinSource4); //与GPIO PE4相连
EXTI_InitStructure.EXTI_Line = EXTI_Line4; //外部中断线4
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; //中断
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; //下降沿触发,对应1->0 即按键按下的一瞬间
EXTI_InitStructure.EXTI_LineCmd = ENABLE; //使能
EXTI_Init(&EXTI_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = EXTI4_IRQn; //外部中断4 EXTI4
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x01;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x02;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
void Key1_EXTI_Init(void)
{
EXTI_InitTypeDef EXTI_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE); //使能时钟
SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOE, EXTI_PinSource3); //与GPIO PE3相连
EXTI_InitStructure.EXTI_Line = EXTI_Line3; //外部中断线3
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; //中断
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; //下降沿触发,对应1->0 即按键按下的一瞬间
EXTI_InitStructure.EXTI_LineCmd = ENABLE; //使能
EXTI_Init(&EXTI_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = EXTI3_IRQn; //外部中断4 EXTI4
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x02;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
//重写中断服务函数
void EXTI4_IRQHandler(void)
{
//判断中断标志是否被置位
if(EXTI_GetITStatus(EXTI_Line4) == SET)
{
GPIO_ToggleBits(GPIOF, GPIO_Pin_9);
yanshi3();
}
//清除中断标志
EXTI_ClearITPendingBit(EXTI_Line4);
}
void EXTI3_IRQHandler(void)
{
//判断中断标志是否被置位
if(EXTI_GetITStatus(EXTI_Line3) == SET)
{
// GPIO_ResetBits(GPIOF,GPIO_Pin_8);
// yanshi3();
GPIO_ToggleBits(GPIOF, GPIO_Pin_10);
yanshi3();
}
//清除中断标志
EXTI_ClearITPendingBit(EXTI_Line3);
}