持续关注阿杰在线更新保姆式笔记~~坚持日更
参考资料:《STM32中文参考手册V10》-第9章 中断和事件
目录
使用中断就得设置优先级
其实,内核中断也叫内核异常。
在中断向量表中从优先级7-66(中断号从0-59)代表着STM32F103的60个中断。优先级号越小,优先级越高。当表中的某处异常或中断被触发,程序计数器指针(PC)将跳转到该异常或中断的地址处执行,该地址处存放这一条跳转指令,跳转到该异常或中断的服务函数处执行相应的功能。因此,异常和中断向量表只能用汇编语言编写。
在MDK中,有标准的异常和中断向量表文件可以使用(startup_stm32f10x_hd.s),在其中标明了中断处理函数的名称,不能随意定义。而中断通道NVIC_IRQChannel(即IRQn_Type类型)是在stm32f10x.h文件中进行了宏定义。
什么是NVIC?即嵌套向量中断控制器(Nested Vectored Interrupt Controller)。CM3的中有一个强大而方便的NVIC,它是属于Cortex内核的器件,中断向量表中60个中断都由它来处理。NVIC是Cortex-M3核心的一部分,关于它的资料不在《STM32的技术参考手册》中,应查阅ARM公司的《Cortex-M3技术参考手册》。Cortex-M3的向量中断统一由NVIC管理。
NVIC的核心功能是中断优先级分组、中断优先级的配置、读中断请求标志、清除中断请求标志、使能中断、清除中断等,它控制着STM32中断向量表中中断号为0-59的60个中断!!外部中断信号从核外发出,信号最终要传递到NVIC(嵌套向量中断控制器)。NVIC跟内核紧密耦合,它控制着整个芯片中断的相关功能。
几十个中断,怎么管理?
首先,对STM32中断进行分组,STM32可以将中断分成5个组,分别为组0-4;同时,对每个中断设置一个抢占优先级和响应优先级。分组配置是由SCB->AIRCR寄存器的bit10-8来定义的。SCB->AIRCR是在哪里的呢?由于这是CM3内核定义的,在文档《Cortex-M3权威指南(中文)》中能查找到。
其中AIRCR寄存器来确定是用哪种分组,IP寄存器是相对应于那种分组抢占优先级和响应优先级的分配比例。例如组设置成3,那么此时所有的60个中断优先寄存器高4位中的最高3位是抢占优先级,低1位为响应优先级。CM3中定义了8个Bit用于设置中断源的优先级,而STM32只选用其中的4个Bit。
(抢占优先级的级别高于响应优先级,而数值越小所代表的的优先级越高。 )
除此之外有两点需要注意:
CM3核的优先级分组方式,使用的设置函数NVIC_SetPriorityGrouping()。
接下来介绍STM32的中断优先级分组函数NVIC_PriorityGroupConfig(),用来进行中断分组设置的,此函数是在固件库下misc.c文件中
void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup)
{
/* Check the parameters */
assert_param(IS_NVIC_PRIORITY_GROUP(NVIC_PriorityGroup));
/* Set the PRIGROUP[10:8] bits according to NVIC_PriorityGroup value */
SCB->AIRCR = AIRCR_VECTKEY_MASK | NVIC_PriorityGroup;
}
函数的参数的取值,是在同文件中进行宏定义的:
#define NVIC_PriorityGroup_0 ((uint32_t)0x700) /*!< 0 bits for pre-emption priority
4 bits for subpriority */
#define NVIC_PriorityGroup_1 ((uint32_t)0x600) /*!< 1 bits for pre-emption priority
3 bits for subpriority */
#define NVIC_PriorityGroup_2 ((uint32_t)0x500) /*!< 2 bits for pre-emption priority
2 bits for subpriority */
#define NVIC_PriorityGroup_3 ((uint32_t)0x400) /*!< 3 bits for pre-emption priority
1 bits for subpriority */
#define NVIC_PriorityGroup_4 ((uint32_t)0x300) /*!< 4 bits for pre-emption priority
0 bits for subpriority */
分组设置好了之后,怎么设置单个中断的抢占优先级和响应优先级?
MDK为与NVIC相关的寄存器定义了如下的结构体,控制着中断向量表中60个中断(由于与中断内核有关,定义在core_cm3.h文件中):
typedef struct
{
__IO uint32_t ISER[8]; /*!< Offset: 0x000 Interrupt Set Enable Register */
uint32_t RESERVED0[24];
__IO uint32_t ICER[8]; /*!< Offset: 0x080 Interrupt Clear Enable Register */
uint32_t RSERVED1[24];
__IO uint32_t ISPR[8]; /*!< Offset: 0x100 Interrupt Set Pending Register */
uint32_t RESERVED2[24];
__IO uint32_t ICPR[8]; /*!< Offset: 0x180 Interrupt Clear Pending Register */
uint32_t RESERVED3[24];
__IO uint32_t IABR[8]; /*!< Offset: 0x200 Interrupt Active bit Register */
uint32_t RESERVED4[56];
__IO uint8_t IP[240]; /*!< Offset: 0x300 Interrupt Priority Register (8Bit wide) */
uint32_t RESERVED5[644];
__O uint32_t STIR; /*!< Offset: 0xE00 Software Trigger Interrupt Register */
} NVIC_Type;
我们依次介绍一下这些寄存器:
先介绍几个寄存器组长度为8,这些寄存器是32位寄存器。由于STM32只有60个可屏蔽中断,8个32位寄存器中只需要2个就有64位了,每1位控制一个中断。
接下来介绍如何使用库函数实现中断优先级管理,这里使用NVIC_Init()函数来进行对每个中断优先级的设置(misc.c文件中):
void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct)
{
uint32_t tmppriority = 0x00, tmppre = 0x00, tmpsub = 0x0F;
/* Check the parameters */
assert_param(IS_FUNCTIONAL_STATE(NVIC_InitStruct->NVIC_IRQChannelCmd));
assert_param(IS_NVIC_PREEMPTION_PRIORITY(NVIC_InitStruct->NVIC_IRQChannelPreemptionPriority));
assert_param(IS_NVIC_SUB_PRIORITY(NVIC_InitStruct->NVIC_IRQChannelSubPriority));
if (NVIC_InitStruct->NVIC_IRQChannelCmd != DISABLE)
{
/* Compute the Corresponding IRQ Priority --------------------------------*/
tmppriority = (0x700 - ((SCB->AIRCR) & (uint32_t)0x700))>> 0x08;
tmppre = (0x4 - tmppriority);
tmpsub = tmpsub >> tmppriority;
tmppriority = (uint32_t)NVIC_InitStruct->NVIC_IRQChannelPreemptionPriority << tmppre;
tmppriority |= NVIC_InitStruct->NVIC_IRQChannelSubPriority & tmpsub;
tmppriority = tmppriority << 0x04;
NVIC->IP[NVIC_InitStruct->NVIC_IRQChannel] = tmppriority;
/* Enable the Selected IRQ Channels --------------------------------------*/
NVIC->ISER[NVIC_InitStruct->NVIC_IRQChannel >> 0x05] =
(uint32_t)0x01 << (NVIC_InitStruct->NVIC_IRQChannel & (uint8_t)0x1F);
}
else
{
/* Disable the Selected IRQ Channels -------------------------------------*/
NVIC->ICER[NVIC_InitStruct->NVIC_IRQChannel >> 0x05] =
(uint32_t)0x01 << (NVIC_InitStruct->NVIC_IRQChannel & (uint8_t)0x1F);
}
}
其中,NVIC_InitTypeDef为一个结构体,它的成员变量为:
typedef struct
{
uint8_t NVIC_IRQChannel; /*!< Specifies the IRQ channel to be enabled or disabled.
This parameter can be a value of @ref IRQn_Type
(For the complete STM32 Devices IRQ Channels list, please
refer to stm32f10x.h file) */
uint8_t NVIC_IRQChannelPreemptionPriority; /*!< Specifies the pre-emption priority for the IRQ channel
specified in NVIC_IRQChannel. This parameter can be a value
between 0 and 15 as described in the table @ref NVIC_Priority_Table */
uint8_t NVIC_IRQChannelSubPriority; /*!< Specifies the subpriority level for the IRQ channel specified
in NVIC_IRQChannel. This parameter can be a value
between 0 and 15 as described in the table @ref NVIC_Priority_Table */
FunctionalState NVIC_IRQChannelCmd; /*!< Specifies whether the IRQ channel defined in NVIC_IRQChannel
will be enabled or disabled.
This parameter can be set either to ENABLE or DISABLE */
} NVIC_InitTypeDef;
NVIC_InitTypeDef结构体有4个成员变量:
其实我们看NVIC_Init()函数内部使能中断,也是通过ISER寄存器配置的。这与我么之前的内容并不矛盾。函数内部使用NVIC->ISER,而NVIC是一个宏定义,
#define NVIC ((NVIC_Type *) NVIC_BASE) /*!< NVIC configuration struct */
也就是直接操作结构体来实现操作ISER寄存器。
比如,使能串口1中断,抢占优先级为1,响应优先级为2,初始化的方法为:
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;//串口1中断--》stm32f10x.h167 IRQn
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1 ;// 抢占优先级为1
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;// 子优先级位2
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//IRQ通道使能
NVIC_Init(&NVIC_InitStructure); //根据上面指定的参数初始化NVIC寄存器
最后总结一下中断优先级设置的步骤:
1、系统运行后先设置中断优先级分组。调用函数:
void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup);//misc.h
整个系统执行过程中,只设置一次中断分组;
2、针对每个中断,设置对应的抢占优先级和响应优先级:
void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct);//misc.h
3、如果需要挂起/解挂,查看中断当前激活状态,分别调用相关函数即可。
#include_int64 ans(_int64 a, _int64 b){ _int64 n = a*b; _int64 temp,r; if(a { temp = a; a = b; b = temp; } while(b!=0) { r = a%b; a = b; b = r; } return n/a;}
Oracle 19C 安装指引18C新功能1.简化的基于镜像的Oracle数据库安装从18C开始,Oracle可以作为镜像文件来下载和安装,必须解压缩镜像文件到ORACLE_HOME目录,然后执行runInstaller安装。有关更多信息,请参阅关于基于映像的Oracle数据库安装2.基于RPM的Oracle数据库安装rpm -ivh 命令安装,可以自动完成安装前检查,将提取的软件包分配给预分配的用户和组,完成其他所有操作。有关更多信息,请参阅使用RPM软件包安装Oracle数据库3.只读O
之前由于双目测距的工作,用MATLAB获取摄像头数据并实时处理。现将一些基本操作分享给大家。欢迎交流
背景:Mac上的百度云盘下载速度堪忧,本人用的Chrome浏览器。以下也是以Chrome为例。解决办法:1、安装arua2gui,下载Aria2GUI-vx.x.x.zip这个压缩包,并解压将Aria2GUI放到你想要的位置比如说应用程序里,此时只是安装了一个下载软件,如果需要网页网盘直接导出下载,需要安装以下两个软件2、YAAW-for-Chrome,如下图,点击Download ZIP下载YA...
我已经读过Mysql服务器创建了一个日志文件,它记录了所有活动 - 比如何时执行查询和执行什么查询 .谁能告诉我我的系统中存在哪些内容?我怎么读呢?基本上,我需要使用不同的输入备份数据库[两个日期之间的备份]所以我想我需要在这里使用日志文件,这就是我想要这样做的原因......我认为必须以某种方式保护此日志,因为可能会记录用户名和密码等敏感信息[如果有任何查询需要];它可能是安全的,不容易被看到?...
首先他报错,百度了好久,试了各种办法,都不行,最后花了2小时的时间,被我百度出来了。我也不容易啊,如果有帮助就关注一下pip install demjsonresponse = requests.get(url=url, headers=headers).textwhh=demjson.encode(response, encoding='utf-8')hh=json.loads(whh)print(hh)有帮助的话,记得三联。...
C++之编译预处理文章目录C++之编译预处理引言预处理指令1. #include 指令2. #define 指令和 #undef 指令3. 条件编译 指令预处理操作符defined 操作符例子总结引言想必学习C++的朋友们对这个是十分熟悉的了。一个 C++ 程序需要经过编译器编译成功后生成目标代码,再结合链接库,形成链接程序,最后经运行调试,才能得到正确的程序。这里讲得就是关于编译预处理...
题库来源:安全生产模拟考试一点通公众号小程序安全生产模拟考试一点通:西式面点师(中级)考试是安全生产模拟考试一点通总题库中生成的一套西式面点师(中级)考试题库,安全生产模拟考试一点通上西式面点师(中级)作业手机同步练习。2021年西式面点师(中级)考试及西式面点师(中级)考试题库1、【单选题】使用分步搅拌法调制蛋糕面糊,进炉烧烤时体积膨胀值大,在,而且组织松软细腻,但()。(C)A、损耗比较大B、成品风味不足C、搅拌较费事D、感官性质不良2、【单选题】冻禽在冷藏时被假...
Problem Description百年来,人活着是为了什么这个问题一直萦绕在人的脑海里,也一直困扰着人的思想。人活着就是活着了,为活着本身而活着,而不是为活着之外的任何事物而活着的。正因为活着,所以活着。对,是有点莫明其妙,但也是一句最受用的话。芳姐特别喜欢猪,所以,她特意养了n头猪,建了m个猪圈,顺便在m个猪圈间修了k条无向边,每条边有都有起点u,终点v,距离w。每头猪呆在一个特定的...
1 ROS tested with Melodicsudo apt-get install -y ros-melodic-navigationsudo apt-get install -y ros-melodic-robot-localizationsudo apt-get install -y ros-melodic-robot-state-publisher2 gtsam (Georgia Tech Smoothing and Mapping library)wget -O ~/Downlo
到官网下载最新版的KindEditor 4.11,解压文件后可得asp:与asp结合的示例代码asp.net:与asp.net结合的示例代码attached:上传文件的根目录,可在相关的代码中修改examples:功能演示的示例代码jsp:与jsp结合的示例代码lang:语言包php:与php结合的示例代码plugins:控件的功能代码的实现kindedit
1. 概念eFuse的概念最早来源于2004年IBM工程师的发现。该发现表明:与更旧的激光熔断技术相比,电子迁移(EM)特性可以用来生成小得多的熔丝结构。EM熔丝可以在芯片上编程,不论是在晶圆探测阶段还是在封装中。采用I/O电路的片上电压(通常为2.5V),一个持续200微秒的10毫安直流脉冲就足以编程单根熔丝。通过运用eFuse技术,允许计算机芯片的动态实时重新编程。抽象地说,计算机逻辑通常是“...