STM32 中断详解

中断,在单片机中占有非常重要的地位。代码默认地从上向下执行,遇到条件或者其他语句,会按照指定的地方跳转。而在单片机执行代码的过程中,难免会有一些突发的情况需要处理,这样就会打断当前的代码,待处理完突发情况之后,程序会回到被打断的地方继续执行。

1 EXTI控制器

外部中断/事件控制器(EXTI)管理了控制器的 23 个中断/事件线。每个中断/事件线都对应有一个边沿检测器,可以实现输入信号的上升沿检测和下降沿的检测。EXTI 可以实现对每个中断/事件线进行单独配置,可以单独配置为中断或者事件,以及触发事件的属性。

外部信号进入经过1的边沿检测电路,检测是否符合(有2和3的上升沿和下降沿选择寄存器决定),产生信号,然后和4软件中断事件寄存器或值,(在这里也就说可以写入软件中断事件寄存器模拟中断和事件),之后产生信号一分为二,看5中断屏蔽寄存器和7事件屏蔽寄存器,如果中断和事件都没有屏蔽,首先会产生事件,进入脉冲发生器。其次,会进入6挂起寄存器,然后进入NVIC。

注意:

1、上面说,我们可以使用寄存器4软件模拟中断事件寄存器模式符合条件的信号进入,为什么不能用6寄存器呢?因为

寄存器是可读可清除的寄存器,通过写1清除。写0无效。所以不能使用

2、关于挂起寄存器,挂起就是,证明有了中断,会在触发中断。但是不会硬件清除。

只能软件清除,或者修改边沿极性的时候清除。如下

先说EXTI吧, 

EXTI 控制器的主要特性:

  • 每个中断/事件线上都具有独立的触发和屏蔽
  • 每个中断线都具有专用的状态位
  • 支持多达23个软件事件/中断请求
  • 检测脉冲宽度低于APB2 时钟宽度的外部信号

下图是ST207的框架图

下图为翻译版

从图中看出和外部中断有关的寄存器有:上升沿触发选择、下降沿触发选择、软件中断事件寄存器、中断屏蔽寄存器、挂起请求寄存器、事件屏蔽寄存器和NVIC中断控制寄存器等。此外就是对输入线的理解了。

另外七根 EXTI 线连接方式如下

也就是说对于一个外部中断线可以和多个GPIO相连,当你要使用哪一个IO的时候只要对SYSCFG_EXTICR对应的位设置就好了,在中断屏蔽寄存器或事件屏蔽寄存器对应位可以设置使用哪一个中断线

注:ST的使用SYSCFG_EXTICR来配置,GD的采用AFIO寄存器(在GPIO寄存器中)

EXTI是外部中断吧,上面的主要是针对的这22条中断线的说明,我们还知道还是有很多中断的,比如定时器中断,串口中断等等,他们不属于这22条中断线。

我们可以在中断向量表中看到

其他的中断配置都在各个模块的寄存器中了

2 NVIC控制器

在上面的EXTI寄存器都设置好后就可以设置NVIC了,关于NVIC的芯片编程手册上描述较少,但是说了

所以我们就参考一下M3手册吧

找到AIRCR寄存器,其中8到10位为优先级分组

我们在代码中使用的库函数是

1void NVIC_PRIGroup_Enable(uint32_t NVIC_PRIGroup) 2{ 3 /*Set the priority grouping value */ 4 SCB->AIRCR =AIRCR_VECTKEY_MASK | NVIC_PRIGroup; 5}

其中我们查到

1、SCB->AIRCR在库函数的地址是0XE000ED0C,不懂的如何查询的,请自行百度

2、查到SCB的结构体定义

我们看到SCB是SystemControl Block的简写

下面我们说一下分组的取值

在misc.c中有

1* ========================================================================================================================== 2 * NVIC_PriorityGroup | NVIC_IRQChannelPreemptionPriority |NVIC_IRQChannelSubPriority | Description 3 * ========================================================================================================================== 4 * NVIC_PriorityGroup_0 | 0 | 0-15 | 0 bits for pre-emption priority 5 * | | | 4 bits for subpriority 6 * -------------------------------------------------------------------------------------------------------------------------- 7 * NVIC_PriorityGroup_1 | 0-1 | 0-7 | 1 bits for pre-emption priority 8 * | | | 3 bits for subpriority 9 * -------------------------------------------------------------------------------------------------------------------------- 10 * NVIC_PriorityGroup_2 | 0-3 | 0-3 | 2 bits for pre-emption priority 11 * | | | 2 bits for subpriority 12 * -------------------------------------------------------------------------------------------------------------------------- 13 * NVIC_PriorityGroup_3 | 0-7 | 0-1 | 3 bits for pre-emption priority 14 * | | | 1 bits for subpriority 15 * -------------------------------------------------------------------------------------------------------------------------- 16 * NVIC_PriorityGroup_4 | 0-15 | 0 | 4 bits for pre-emption priority 17 * | | | 0 bits for subpriority 18 * ==========================================================================================================================

抢占优先级& 响应优先级区别

  1. 高优先级的抢占优先级是可以打断正在进行的低抢占优先级中断的。
  2. 抢占优先级相同的中断,高响应优先级不可以打断低响应优先级的中断。
  3. 抢占优先级相同的中断,当两个中断同时发生的情况下,哪个响应优先级高,哪个先执行。
  4. 如果两个中断的抢占优先级和响应优先级都是一样的话,则看哪个中断先发生就先执行。

例子:

假定设置中断优先级组为2,然后设置

中断3(RTC中断)的抢占优先级为2,响应优先级为1。

中断6(外部中断0)的抢占优先级为3,响应优先级为0

中断7(外部中断1)的抢占优先级为2,响应优先级为0。

那么这3个中断的优先级顺序为:中断7>中断3>中断6

表现在代码中

1NVIC_InitPara NVIC_InitStructure; 2NVIC_InitStructure.NVIC_IRQ = IRQn; 3NVIC_InitStructure.NVIC_IRQPreemptPriority =pri; 4NVIC_InitStructure.NVIC_IRQSubPriority = pri1; 5NVIC_InitStructure.NVIC_IRQEnable = ENABLE; 6NVIC_Init(&NVIC_InitStructure);

分组0,那么pri的取值范围00,pri1的取值范围016

分组2,那么pri的取值范围04,pri1的取值范围04

分组4,那么pri的取值范围016,pri1的取值范围00

下面我们讲解一下NVIC寄存器

__IO uint8_t  IP[240]; //中断优先级控制的寄存器组

__IO uint32_t ISER[8]; //中断使能寄存器组

__IO uint32_t ICER[8]; //中断失能寄存器组

__IO uint32_t ISPR[8]; //中断挂起寄存器组

__IO uint32_t ICPR[8]; //中断解挂寄存器组

__IO uint32_t IABR[8]; //中断激活标志位寄存器组

中断优先级控制的寄存器组:IP[240]

全称是:InterruptPriority Registers

240个8位寄存器,每个中断使用一个寄存器来确定优先级。

比如:STM32F10x系列一共60个可屏蔽中断,使用IP[59]~IP[0]。

每个IP寄存器的高4位用来设置抢占和响应优先级(根据分组),低4位没有用到。

void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct);

中断使能寄存器组:ISER[8]

作用:用来使能中断

32位寄存器,每个位控制一个中断的使能。STM32F10x只有60个可屏蔽中断,所以只使用了其中的ISER[0]和ISER[1]。

ISER[0]的bit0bit31分别对应中断031。ISER[1]的bit027对应中断3259;

void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct);

中断失能寄存器组:ICER[8]

作用:用来失能中断

32位寄存器,每个位控制一个中断的失能。STM32F10x只有60个可屏蔽中断,所以只使用了其中的ICER[0]和ICER[1]。

ICER[0]的bit0bit31分别对应中断031。ICER[1]的bit027对应中断3259;

配置方法跟ISER一样。

void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct);

中断挂起控制寄存器组:ISPR[8]

作用:用来挂起中断

中断解挂控制寄存器组:ICPR[8]

作用:用来解挂中断

1static __INLINE void NVIC_SetPendingIRQ(IRQn_Type IRQn)2static __INLINE uint32_t NVIC_GetPendingIRQ(IRQn_Type IRQn)3static __INLINE void NVIC_ClearPendingIRQ(IRQn_Type IRQn);

中断激活标志位寄存器组:IABR[8]

作用:只读,通过它可以知道当前在执行的中断是哪一个

如果对应位为1,说明该中断正在执行。

static __INLINE uint32_t NVIC_GetActive(IRQn_Type IRQn)

3 code

一定要使能系统时钟

因为配置GPIO和中断线的映射关系需要SYSCFG

SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOE, EXTI_PinSource11);

只要用到外部中断,就一定要打开SYSCFG时钟

开源代码地址:

https://github.com/strongercjd/STM32F207VCT6/tree/master/09-EXTI

点击查看本文所在的专辑,STM32F207教

点赞
收藏

评论区

加载中...

相关推荐

MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1

文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s

Oracle 分组与拼接字符串同时使用

SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(

MySQL部分从库上面因为大量的临时表tmp_table造成慢查询

背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_

皕杰报表之UUID

​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为

手写Java HashMap源码

HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22

2020年前端实用代码段,为你的工作保驾护航

有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )