stm32中断嵌套实例分析

发布者:不染尘埃最新更新时间:2023-06-26 来源: elecfans关键字:stm32  中断嵌套 手机看文章 扫描二维码
随时随地手机看文章

  STM32中断嵌套方法

  STM32中断嵌套方法先说明: 所有中断要放在同一个组里, 因为只有组确定了, 4位描述占先式优先级和副优先级的位数才可以确定。


  NVIC——Nested Vectored Interrupt Controller(嵌套中断向量控制器


  STM32有43个channel的settable的中断源:AIRC(Application Interrupt and Reset Register)寄存器中有用于指定优先级的4bits。这4个bits用于分配pre-emption优先级和sub优先级,在STM32的固件库中定义如下:

  NVIC_PriorityGroup_0 ((u32)0x700) //0 bits for pre-emption priority 4 bits for subpriority#define

  NVIC_PriorityGroup_1 ((u32)0x600) //1 bits for pre-emption priority 3 bits for subpriority#define

  NVIC_PriorityGroup_2 ((u32)0x500) //2 bits for pre-emption priority 2 bits for subpriority#define

  NVIC_PriorityGroup_3 ((u32)0x400) // 3 bits for pre-emption priority 1 bits for subpriority#define

  NVIC_PriorityGroup_4 ((u32)0x300) //4 bits for pre-emption priority 0 bits for subpriority

  形象化的理解是:你是上帝,造了43个人,这么多人要分社会阶级和社会阶层了;因为“阶级”的词性比较重;“阶层”比较中性,所以pre-emption优先级-》阶级;每个阶级内部,有一些阶层,sub优先级-》阶层;

  如果按照NVIC_PriorityGroup_4这么分,就分为了16个阶级每个阶级有0个阶层;阶级高的人,可以打断阶级低的正在做事的人(嵌套),最多可以完成1个中断和15级嵌套。每个阶级你来指定这43人中,谁进入该阶级;

  一个人叫EXTI0_IRQChannel,你指定他进入“阶级8”,则

  NVIC_InitStructure.NVIC_IRQChannel= EXTI0_IRQChannel;NVIC_InitStructure.

  NVIC_IRQChannelPreemptionPriority= 8;//指定抢占式优先级别1,可取0-15

  stm32中断嵌套实例分析

  在同一阶级内部,一个人在做事的时候,另外一个人不能打断他;(pre-emption优先级别相同的中断源之间没有嵌套关系)。

  还有,如果他们两个同时想做事,因为没有阶层,那么就根据Vector table中的物理排序,让排名靠前的人去做。

  又有1个人SPI1_IRQChannel,设定如下

  NVIC_InitStructure.NVIC_IRQChannel=SPI1_IRQChannel;

  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority= 0//指定抢占式优先级别1,可取0-15

  SPI1_IRQChannel的阶级高,EXTI0_IRQChannel做事的时候可以打断(嵌套)。

  如果按照NVIC_PriorityGroup_3这么分,就分为了8个阶级(1个阶级是1个preemption优先级),每个阶级内有2个阶层(sub优先级);高阶级的人,可以打断低阶级的正在做事的人(嵌套),最多可以完成1个中断和7级嵌套。每个阶级(每个preemption优先级),你来指定这43人中,谁进入该阶级;

  一个人叫EXTI0_IRQChannel,你指定他进入“阶级3”,则:

  NVIC_InitStructure.NVIC_IRQChannel= EXTI0_IRQChannel;

  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority= 3; //指定抢占式优先级别1,可取0-7

  还需要指定他的阶层:

  NVIC_InitStructure.NVIC_IRQChannelSubPriority= 0; //指定响应优先级别0,可取0-1

  另有1个人叫EXTI9_5_IRQChannel,他的阶级和阶层设定如下

  NVIC_InitStructure.NVIC_IRQChannel= EXTI9_5_IRQChannel;

  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority= 3; //指定抢占式优先级别0,可取0-7

  NVIC_InitStructure.NVIC_IRQChannelSubPriority= 1; //指定响应优先级别1

  那么这两个人是同一阶级的兄弟,一个人在做事的时候,另外一个人不能打断他(preemption优先级别相同的中断源之间没有嵌套关系)。如果他们两个同时想做事,因为前者的阶层高,所以前者优先。

  还有一个人叫USART1_IRQChannel,他的阶级和阶层设定如下

  NVIC_InitStructure.NVIC_IRQChannel= USART1_IRQChannel;

  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority= 2; //指定抢占式优先级别0,可取0-7

  NVIC_InitStructure.NVIC_IRQChannelSubPriority= 1; //指定响应优先级别1

  USART1_IRQChannel的优先级最高,当前面两个人做事的时候,他都可以打断(嵌套)。

  依次类推:如果按照NVIC_PriorityGroup_0这么分,那么没有阶级,只有16个阶层了。需要给各个人指定阶层编号。sub优先级的范围0-15当一个人做事的时候,另外的人不能打断他(就没有嵌套了);当多人同时想做事的时候,按照阶层编号的排序,排名靠前的先做事。阶层编号一样的人同时想做事,那么按照Vector Table硬件排序,排名靠前的先做。


  stm32中断嵌套实例

  ARM公司的Cortex-m3 内核,支持256个中断,其中包含16个内核中断和240个外部中断,并且具有256级的可编程中断设置。在ST公司的STM32单片机中最多有84个中断,包括16个内核中断(这16个内部中断是任何半导体商也改不了的),和68个可屏蔽中断,具有16级可编程的中断优先级。但是在STM32F103系列中只有60个可屏蔽中断,(107系列有68个)。

  针对这60个可屏蔽中断,重点掌握它的一个中断优先级寄存器组IPR,全称Interrupt Priority Registers。这个寄存器组包含15个32位的寄存器,一个可屏蔽中断占用8bit,那么一个寄存器可以控制4个可屏蔽中断,一共15*4=60。然而在这占用的8bit中又只使用了高4bit,这高4bit的分配才是STM32F103系列单片机中断嵌套的设置所在。STM32F103系列的中断嵌套分为5个组,分别是0、1、2、3、4 这5个组,下面是5个组与中断嵌套的对应关系。

  stm32中断嵌套实例分析

  对于抢占优先级和响应优先级,只需记住两点,第一、抢占任何优先级比都比所有响应优先级优先级高。只有抢占优先级更高的具有中断嵌套功能。(即打断其他正在执行的中断)。第二、数字越小优先级越高 ,抢占优先级和响应优先级都一样时,首先响应中断通道对应中断向量地址低的那个中断。

  下面对0组和1组的情况做一个分析。

  0组对应是0位抢占优先级,4位响应优先级,那么无抢占优先级,响应优先级可设置为0到15级(2的4次方种)中的任意一种。

  1组对应是1位抢占优先级,3位响应优先级,那么抢占优先级只可设置为0级或者1级中的任意一种(2的1次方种),响应优先级可设置为0到7级(2的3次方种)中的任意一种。

  上电复位时,中断配置为4组,并且60个外部中断都是抢占优先级为0级,无响应优先级。

  总结一下:

  1、高优先级的抢占优先级是可以打断正在进行的低抢占优先级中断的。

  2、抢占优先级相同的中断,高响应优先级不可以打断低响应优先级的中断。

  3、抢占优先级相同的中断,当两个中断同时发生的情况下,哪个响应优先级高,哪个先执行。

  4、如果两个中断的抢占优先级和响应优先级都是一样的话,则看哪个中断先发生就先执行。

  所以可以看出判断两个中断的优先级时先看抢占优先级的高低,如果相同再看响应优先级的高低。如果全都相同最后看中断通道向量地址。

  一般来说在使用过程中,一个系统使用一个组别就完全可以满足需要。所以在使用一个组别后一般不要在系统中再改动组别,骨灰级玩家可以去试试(小心芯片烧了)。

  外部中断:

  STM32F103的外部中断EXTI支持19个外部中断/事件请求。每个中断/事件都有独立的触发和屏蔽设置。

  0到15线:对应外部I/O口输入中断

  线16:接到PVD输出

  线17:接到RCT闹钟事件

  线18:接到USB唤醒事件

  线16到线18我自己都没用过,主要对线0到15的I/O输入中断做一个总结,有个注意的地方是这0到15线的外部中断,其中0到4线,这5个外部中断都有自己单独的中断响应函数。5到9线公用一个中断服务函数,10到15线公用一个中断服务函数。

  外部中断配置寄存器组EXTICR包含4个32位的寄存器,分别是EXTICR0、EXTICR1、EXTICR2、EXTICR3、但每一个寄存器只用了低16位,每4位控制一个I/O口,一个寄存器控制4个I/O口,EXTICR寄存器组控制16个I/O口,刚好一个GPIO的I/O口数。下面以 EXTICR0为例,用一个表格表示:

  stm32中断嵌套实例分析

  比如配置GPIOA.0就是将EXTICR0的低4位配置成0000,若配置GPIOB.1就是配置EXTICR0的4到7位,为0001。

  这里有一个问题,如果要配置GPIOA.0和GPIOB.0,会引起冲突,不知道是不是分时配置解决的。我用的固体库的方式,不需要考虑这些,呵呵。注意使用固件库时中断复位函数是写在stm32f10x_it.c这个文件里的。

  下面结合外部中断附上固件库版本的程序:

  主函数里:

  void NVIC_Configuration(void)

  {

  NVIC_InitTypeDef NVIC_InitSructure;

  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置为优先级组2

  NVIC_InitSructure.NVIC_IRQChannel = EXTI15_10_IRQn; //定义外部中断线13中断通道

  NVIC_InitSructure.NVIC_IRQChannelPreemptionPriority = 0; //抢占优先级0

  NVIC_InitSructure.NVIC_IRQChannelSubPriority = 0; //响应优先级0

  NVIC_InitSructure.NVIC_IRQChannelCmd = ENABLE; //使能指定通道

  NVIC_Init(&NVIC_InitSructure);

  NVIC_InitSructure.NVIC_IRQChannel = EXTI15_10_IRQn; //定义外部中断线15中断通道

  NVIC_InitSructure.NVIC_IRQChannelPreemptionPriority = 1;

  NVIC_InitSructure.NVIC_IRQChannelSubPriority = 1;

  NVIC_InitSructure.NVIC_IRQChannelCmd = ENABLE; //使能指定通道

  NVIC_Init(&NVIC_InitSructure);

  NVIC_InitSructure.NVIC_IRQChannel = EXTI0_IRQn; //定义外部中断线0中断通道

  NVIC_InitSructure.NVIC_IRQChannelPreemptionPriority = 1;

  NVIC_InitSructure.NVIC_IRQChannelSubPriority = 1;

  NVIC_InitSructure.NVIC_IRQChannelCmd = ENABLE; //使能指定通道

  NVIC_Init(&NVIC_InitSructure);

  }

  void EXTI_Configuration(void)

  {

  EXTI_InitTypeDef EXTI_InitStructure; //初始化结构

  GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource13); //指明当前哪个引脚为外部中断触发引脚

  GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource15);

  EXTI_ClearITPendingBit(EXTI_Line13); //清除中断标志位 EXTI_Line13对应相应的中断线13

  EXTI_ClearITPendingBit(EXTI_Line15);

  EXTI_InitStructure.EXTI_Mode =EXTI_Mode_Interrupt; //选择中断模式请求

  EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; //下降沿触发

  EXTI_InitStructure.EXTI_Line = EXTI_Line13|EXTI_Line15; // 选择待使能的外部中断线

  EXTI_InitStructure.EXTI_LineCmd = ENABLE; // 定义选中线的新状态 使能

  EXTI_Init(&EXTI_InitStructure); //把EXIT_InitStructure中的每一个参数按缺省值填入

  GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource0); //指明当前哪个引脚为外部中断触发引脚

  EXTI_ClearITPendingBit(EXTI_Line0);

  EXTI_InitStructure.EXTI_Mode =EXTI_Mode_Interrupt; //选择中断模式请求

  EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising; //上升沿触发

  EXTI_InitStructure.EXTI_Line = EXTI_Line0; // 选择待使能的外部中断线

  EXTI_InitStructure.EXTI_LineCmd = ENABLE; // 定义选中线的新状态 使能

  EXTI_Init(&EXTI_InitStructure); //把EXIT_InitStructure中的每一个参数按缺省值填入

  }

  stm32f10x_it.c这个文件里

  void EXTI15_10_IRQHandler(void)

  {

  if(EXTI_GetITStatus(EXTI_Line13)!=RESET)

  { GPIO_WriteBit( GPIOA,GPIO_Pin_8,(BitAction)(1-GPIO_ReadOutputDataBit(GPIOA,GPIO_Pin_8))); //LED0翻转

  EXTI_ClearITPendingBit(EXTI_Line13);

  }

  if(EXTI_GetITStatus(EXTI_Line15)!=RESET)

  { GPIO_WriteBit( GPIOD,GPIO_Pin_2,(BitAction)(1-GPIO_ReadOutputDataBit(GPIOD,GPIO_Pin_2))); //LED0翻转

  EXTI_ClearITPendingBit(EXTI_Line15);

  }

  }

  void EXTI0_IRQHandler(void)

  {

  if(EXTI_GetITStatus(EXTI_Line0)!=RESET)

  { GPIO_WriteBit( GPIOA,GPIO_Pin_8,(BitAction)(1-GPIO_ReadOutputDataBit(GPIOA,GPIO_Pin_8))); //LED0翻转

  GPIO_WriteBit( GPIOD,GPIO_Pin_2,(BitAction)(1-GPIO_ReadOutputDataBit(GPIOD,GPIO_Pin_2))); //LED0翻转

  EXTI_ClearITPendingBit(EXTI_Line0);

  }

  }


关键字:stm32  中断嵌套 引用地址:stm32中断嵌套实例分析

上一篇:基于STM32步进电机多细分控制的设计
下一篇:stm32任务调度的简单说明

推荐阅读最新更新时间:2024-11-12 15:22

使用MDK创建stm32 库函数工程简单教程
一. 需要准备的资料及环境: 1.STM32固件库,我们使用的固件库为STM32F10x_StdPeriph_Lib_V3.5.0,可在st官方下载 2.MDK开发环境(我们使用的版本为MDK4.7A)。 二. 新建工程 1.打开MDK ,然后选择菜单 Project- Close Project,关掉已存在的工程!这样整个MDK就是一个空的了,接下来我们将建立工程。 2.在建立工程之前,建议用户在电脑的某个目录下面建立一个文件夹,后面所建立的工程都可以放在这个文件夹下面,这里我们建立一个文件夹为: STM32_IAP.在该文件夹下再创建CORE、OBJ、STM32F10x_FWLib、USER等文件夹,USER用
[单片机]
使用MDK创建<font color='red'>stm32</font> 库函数工程简单教程
用Eclipse开发stm32(GNU ARM Eclipse Plug-in)(编码+编译+下载+调试)
传统的IDE功能强大,特别是调试功能,但是如今,其它软件的发展,大家感觉到传统的IDE用户交互、编辑界面、编码效率不够友好;或者为了降低成本,需要使用开源工具 于是,有人选择使用IDE用来调试,用其它编辑器编码(比如source insight 、sublime text3、notepad++、atom、Eclipse等),来提高效率;或者使用其它的工具链来配合编辑器达到自制一个IDE的效果 当然还有一些改进得比较好的免费IDE和收费的IDE,比如coocox 这里是在Eclipse上编写 ARM 程序 在Eclipse上编写程序方法: 使用GCC、G++、makefile的方式进行手动编码,一切靠自己 使用Eclipse+插件
[单片机]
用Eclipse开发<font color='red'>stm32</font>(GNU ARM Eclipse Plug-in)(编码+编译+下载+调试)
STM32在线调试正常,上电运行不正常
贴了两块样板,烧写同样的固件。其中一块工作正常,但是另外一块出现了很奇怪的现象:在线调试正常;每次烧写完后工作正常;重新上电有时候工作正常,有时候工作不正常;工作不正常时,按下复位按键,恢复正常。 工作异常现象:main函数中的系统运行指示灯不闪烁,但是初始化过程中点的一个灯是亮的!说明程序运行一段时间后,不工作了。 由于在线调试模式,板子工作正常,无法通过在线调试的方式判断程序运行的异常状态。 分析可能的原因: 1、初始化过程中,程序陷入死循环。但程序初始化过程中,没有while(1)死循环的代码。 2、板子上电后不断复位,导致无法进入main函数中的while(1)循环。 问题查找: 硬件: 1、确认BOOT0管脚接10k
[单片机]
关于STM32_GPIO的BSRR和BRR寄存器
首先, typedef struct { vu32 CRL; vu32 CRH; vu32 IDR; vu32 ODR; vu32 BSRR; vu32 BRR; vu32 LCKR; } GPIO_TypeDef; BSRR和BRR寄存器是32位的。 比较: 1)置GPIOA- BSRR低16位的某位为'1',则对应的I/O端口管脚置'1'; 置GPIOA- BSRR低16位的某位为'0',则对应的I/O端口管脚保持不变。 2)置GPIOA- BSRR高16位的某位为'1',则对应的I/O端口管脚置'0'; 置GPIOA-
[单片机]
STM32 IIC难点易错点
先来点题外话~网上说STM32F103的IIC有瑕疵!就当是有些短板吧,个人觉得,用起来肯定没问题,只是不好用。因为ST公司考虑到专利问题,所以没按飞利浦的标准来。导致STM32的IIC使用起来非常繁杂。下面就讲讲用STM32 IO口模拟IIC的注意问题: IIC总线时序: 进入正题→_→博主就因为没理解好应答,吃了亏。讲一讲IIC的几个重要状态: 1、空闲状态:当IIC总线空闲时,SDA和SCL两条线均为高电平,由于连接到总线上的器件必须是漏级和集电极开路(至于威为什么请读者自己搜索),只要有一个器件任意时刻输出低电平,都将使总线上的信号变低,即各器件的SDA和SCL是线与的关系。由于各器件输出端是漏级开路,故必须通
[单片机]
<font color='red'>STM32</font> IIC难点易错点
STM32高级定时器、通用定时器 、 基本定时器区别
高级定时器TIM1和TIM8、通用定时器(TIM2,TIM3,TIM4,TIM5) 、 基本定时器(TIM6和TIM7) 区别? 我觉得总的来说应该没多大区别,似乎是高级定时器多了三相电机控制所需的功能,还请各位高人指点吧~~ TIM1和TIM8主要特性TIM1和TIM8定时器的功能包括: ● 16位向上、向下、向上/下自动装载计数器 ● 16位可编程(可以实时修改)预分频器,计数器时钟频率的分频系数为1~65535之间的任意数值 ● 多达4个独立通道: ─ 输入捕获 ─ 输出比较 ─ PWM生成(边缘或中间对齐模式) ─ 单脉冲模式输出 ● 死区时间可编程的互补输出 ● 使用外部信号控制定时器和定时
[单片机]
keil+stm32+JTAG利用swd方式进行printf输出
使用ITM机制实现调试stm32单片机,实现printf与scanf。 1. ITM简介 ITM机制是一种调试机制,是新一代调试方式,在这之前,有一种比较出名的调试方式,称为半主机(semihosting)方式。 在pc上编写过C语言的人都知道,printf可以向控制台输出,scanf可以从控制台获取输入,这里的printf/scanf都是标准库函数,利用操作系统的这些函数,我们可以很方便的调试程序。在嵌入式设备上(如stm32单片机平台上)开发工具(如MDK/IAR)也都提供了标准库函,自然也提供了printf/scanf函数,那么这些函数是否可以使用呢? 问题来了,printf向哪里输出呢?并且大部分情况下,也没有键盘,又如何
[单片机]
keil+stm32+JTAG利用swd方式进行printf输出
基于STM32单片机的数据记录装置设计
引言 本文针对电动汽车研究的实际需求,设计一款数据记录装置,该数据记录装置是搭建在电池能量管理系统基础上的,通过与能量管理系统通信,记录电动汽车实际运行时电池的外部状态(如:电池电压、电流、温度等),一方面为了研究电池的工作特性,另一方面为了对能量管理系统的工作情况做验证,为电动汽车动力电池的理论研究提供数据支持。 1 系统总体设计 本数据记录装置的设计包括硬件设计与软件设计两方面,软件设计主要包括数据接收的编程以及数据存储的编程,而硬件设计主要有几个方面:主控芯片的选择、复位功能的实现、电源模块、实时时钟、通信模块以及SD卡连接等。主控芯片是控制系统的核心,它内部所集成的模块越多,就能省去更多的外部电路,使得电路的设
[电源管理]
基于<font color='red'>STM32</font>单片机的数据记录装置设计
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved