首页 > 其他分享 >stm32F0中断系列详解

stm32F0中断系列详解

时间:2023-03-15 18:55:42浏览次数:43  
标签:优先级 中断 NVIC 详解 寄存器 GPIO stm32F0 EXTI

1、中断的概念

 概念:

  程序执行过程中CPU会遇到一些特殊情况,是正在执行的程序被“中断”,cpu中止原来正在执行的程序,转到处理异常情况或特殊事件的程序去执行,结束后再返回到原被中止的程序处(断点)继续执行。

2、NVIC

NVIC 是嵌套向量中断控制器

特性:

  • 68个可屏蔽中断通道(不包含16个Cortex™-M3的中断线);
  • 16个可编程的优先等级(使用了4位中断优先级);
  • 低延迟的异常和中断处理;
  • 电源管理控制;
  • 系统控制寄存器的实现;

它控制着整个芯片中断相关的功能,它跟内核紧密耦合,是内核里面的一个外设,可以实现低延迟的中断处理和高效地处理晚到的中断,但是各个芯片厂商在设计芯片的时候会对Cortex-M3内核里面的NVIC进行裁剪,把不需要的部分去掉,所以说 STM32的 NVIC是 Cortex-M3 的 NVIC 的阉割版。

嵌套向量中断控制器管理着包括内核异常等中断。更多关于异常和NVIC编程的说明请参考 《STM32F10xxx Cortex-M3编程手册》

NVIC 结构体定义,来自固件库头文件:core_cm3.h

1 typedef struct {
2 __IO uint32_t ISER[8]; // 中断使能寄存器
3 uint32_t RESERVED0[24];
4 __IO uint32_t ICER[8]; // 中断清除寄存器
5 uint32_t RSERVED1[24];
6 __IO uint32_t ISPR[8]; // 中断使能悬起寄存器
7 uint32_t RESERVED2[24];
8 __IO uint32_t ICPR[8]; // 中断清除悬起寄存器
9 uint32_t RESERVED3[24];
10 __IO uint32_t IABR[8]; // 中断有效位寄存器
11 uint32_t RESERVED4[56];
12 __IO uint8_t IP[240]; // 中断优先级寄存器(8Bit wide)
13 uint32_t RESERVED5[644];
14 __O uint32_t STIR; // 软件触发中断寄存器
15 } NVIC_Type;

在配置中断的时候我们一般只用 ISER、ICERIP 这三个寄存器,ISER 用来使能(开中断)中断ICER 用来失能(清楚某个中断的使能)中断IP 用来设置中断优先级

固件库文件 core_cm3.h 的最后,还提供了 NVIC 的一些函数

void NVIC_EnableIRQ(IRQn_Type IRQn) // 使能中断
void NVIC_DisableIRQ(IRQn_Type IRQn) // 失能中断
void NVIC_SetPendingIRQ(IRQn_Type IRQn) // 设置中断悬起位
void NVIC_ClearPendingIRQ(IRQn_Type IRQn) // 清除中断悬起位
uint32_t NVIC_GetPendingIRQ(IRQn_Type IRQn) // 获取悬起中断编号
void NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority) // 设置中断优先级
uint32_t NVIC_GetPriority(IRQn_Type IRQn) // 获取中断优先级
void NVIC_SystemReset(void) // 系统复位

 

优先级的定义

在 NVIC 有一个专门的寄存器:中断优先级寄存器 NVIC_IPRx,用来配置外部中断的 优先级,IPR 宽度为 8bit,原则上每个外部中断可配置的优先级为 0~255,数值越小,优先级越高。但是绝大多数 CM3 芯片都会精简设计,以致实际上支持的优先级数减少,在 F103 中,只使用了高 4bit,如下所示:

 

用于表达优先级的这 4bit,又被分组成抢占优先级和子优先级。如果有多个中断同时 响应,抢占优先级高的就会 抢占 抢占优先级低的优先得到执行,如果抢占优先级相同,就 比较子优先级。如果抢占优先级和子优先级都相同的话,就比较他们的硬件中断编号,编号越小,优先级越高。

优先级分组

优先级的分组由内核外设 SCB 的应用程序中断及复位控制寄存器 AIRCR 的 PRIGROUP[10:8]位决定,F103 分为了 5 组,具体如下:主优先级=抢占优先级

 

 设置优先级分组可调用库函数 NVIC_PriorityGroupConfig()实现,有关 NVIC 中断相关 的库函数都在库文件 misc.c 和 misc.h 中

 1  /**
 2  * 配置中断优先级分组:抢占优先级和子优先级
 3  * 形参如下:
 4  * @arg NVIC_PriorityGroup_0: 0bit for 抢占优先级
 5  * 4 bits for 子优先级
 6  * @arg NVIC_PriorityGroup_1: 1 bit for 抢占优先级
 7  * 3 bits for 子优先级
 8  * @arg NVIC_PriorityGroup_2: 2 bit for 抢占优先级
 9  * 2 bits for 子优先级
10  * @arg NVIC_PriorityGroup_3: 3 bit for 抢占优先级
11  * 1 bits for 子优先级
12  * @arg NVIC_PriorityGroup_4: 4 bit for 抢占优先级
13  * 0 bits for 子优先级
14  * @注意 如果优先级分组为 0,则抢占优先级就不存在,优先级就全部由子优先级控制
15 */
16  void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup)
17  {
18  // 设置优先级分组
19  SCB->AIRCR = AIRCR_VECTKEY_MASK | NVIC_PriorityGroup;
20  }

 

中断编程

在配置每个中断的时候一般有 3 个编程要点:

1、使能外设某个中断,这个具体由每个外设的相关中断使能位控制。比如串口有发送 完成中断,接收完成中断,这两个中断都由串口控制寄存器的相关中断使能位控制。

2、初始化 NVIC_InitTypeDef 结构体,配置中断优先级分组,设置抢占优先级和子优 先级,使能中断请求。NVIC_InitTypeDef 结构体在固件库头文件 misc.h 中定义。

1 typedef struct {
2 uint8_t NVIC_IRQChannel; // 中断源
3 uint8_t NVIC_IRQChannelPreemptionPriority; // 抢占优先级
4 uint8_t NVIC_IRQChannelSubPriority; // 子优先级
5 FunctionalState NVIC_IRQChannelCmd; // 中断使能或者失能
6 } NVIC_InitTypeDef;

 

  • NVIC_IROChannel:用来设置中断源,不同的中断中断源不一样,且不可写错,即 使写错了程序也不会报错,只会导致不响应中断。具体的成员配置可参考 stm32f10x.h 头文 件里面的 IRQn_Type 结构体定义,这个结构体包含了所有的中断源。
  • NVIC_IRQChannelPreemptionPriority:抢占优先级,具体的值要根据优先级分组来 确定。
  • NVIC_IRQChannelSubPriority:子优先级,具体的值要根据优先级分组来确定。
  • NVIC_IRQChannelCmd:中断使能(ENABLE)或者失能(DISABLE)。操作的 是 NVIC_ISER 和 NVIC_ICER 这两个寄存器。

3、编写中断服务函数 在启动文件 startup_stm32f10x_hd.s 中我们预先为每个中断都写了一个中断服务函数, 只是这些中断函数都是为空,为的只是初始化中断向量表。实际的中断服务函数都需要我 们重新编写,为了方便管理我们把中断服务函数统一写在 stm32f10x_it.c 这个库文件中。 关于中断服务函数的函数名必须跟启动文件里面预先设置的一样,如果写错,系统就 在中断向量表中找不到中断服务函数的入口,直接跳转到启动文件里面预先写好的空函数, 并且在里面无限循环,实现不了中断。

3、EXTI

EXTI简介:

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

EXTI框图:

 

 

 输入线:EXTI 控制器有 20 个中断/事件输入线,这些输入线可以通过寄存器 设置为任意一个 GPIO

 

 

 通过这四个AFIO寄存器来选择具体使用哪一个GPIO的哪一个引脚作为输入线:

 

 

 通过AFIO_EXTICRx配置GPIO线上的外部中断/事件,必须先使能AFIO时钟。对于小容量、中容量和大容量 的产品,参见6.3.7 137/754 节;对于互联型产品,参见7.3.7节

 另外四个EXTI线的连接方式如下:

  • EXTI线16连接到PVD输出
  • EXTI线17连接到RTC闹钟事件
  • EXTI线18连接到USB唤醒事件 
  • EXTI线19连接到以太网唤醒事件(只适用于互联型产品)

边沿检测电路:它会根据上升沿触发选择寄存器(EXTI_RTSR)和下降沿 触发选择寄存器(EXTI_FTSR)对应位的设置来控制信号触发。EXTI_RTSR 和 EXTI_FTSR 两个寄存器可以控制器需要检测哪些类型的电平跳变过 程,可以是只有上升沿触发、只有下降沿触发或者上升沿和下降沿都触发。

或门电路:它一个输入来边沿检测电路,另外一个输入来自 软件中断事件寄存器(EXTI_SWIER)。EXTI_SWIER 允许我们通过程序控制就可以启动中断/事件线,这在某些地方非常有用。

与门电路:它一个输入是或门电路,另外一个输入来自中断屏蔽 寄存器(EXTI_IMR)。与门电路要求输入都为 1 才输出 1,导致的结果是如果 EXTI_IMR 设置为 0 时,那不管或门电路的输出信号是 1 还是 0,最终与门 电路输出的信号都为 0; 如果 EXTI_IMR 设置为 1 时,最终与门电路输出的信号才由或门 电路的输出信号决定, 这样我们可以简单的控制 EXTI_IMR 来实现是否产生中断的目的。与门电路输出的信号会被保存到挂起寄存器(EXTI_PR)内,如果确定与门 电路输出为 1 就会把 EXTI_PR 对应位置 1。

最后将 EXTI_PR 寄存器内容输出到 NVIC 内,从而实现系统中断事件控制。

EXTI初始化结构:

1 typedef struct {
2 uint32_t EXTI_Line; // 中断/事件线
3 EXTIMode_TypeDef EXTI_Mode; // EXTI 模式
4 EXTITrigger_TypeDef EXTI_Trigger; // 触发类型
5 FunctionalState EXTI_LineCmd; // EXTI 使能
6 } EXTI_InitTypeDef;

 

1) EXTI_Line:EXTI 中断/事件线选择,可选 EXTI0 至 EXTI19,通过前面的学习我们知道,输入线是通过AFIO来选择的,所以这里的中断/事件线是为了编程寄存器中哪一个,而不是选择哪一条线

2) EXTI_Mode:EXTI 模式选择,可选为产生中断(EXTI_Mode_Interrupt)或者产生事 件(EXTI_Mode_Event)。

3) EXTI_Trigger:EXTI 边沿触发事件,可选上升沿触发(EXTI_Trigger_Rising)、下 降沿触发 ( EXTI_Trigger_Falling) 或者上升沿和下降沿都触发 ( EXTI_Trigger_Rising_Falling)。

4) EXTI_LineCmd:控制是否使能 EXTI 线,可选使能 EXTI 线(ENABLE)或禁用 (DISABLE)。

4、示例代码

 PC8连接到EXTI用于产生中断,PC8 的电平变化通过按键来控制,产生一次中断,led反转一次。

 配置按键所用的GPIO引脚

//配置中断优先级,主要在NVIC内核中断中配置
void EXTI_NVIC_Config(void){
    NVIC_InitTypeDef NVIC_InitStruct;
    // 分组
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
    //配置优先级
    NVIC_InitStruct.NVIC_IRQChannel = EXTI9_5_IRQn;//这个要注意,参数在stm32f10x.h中找,且0-4,5-9,10-15对应的参数不同
    NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1;  //抢占优先级
    NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1; //子优先级
    NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStruct);
}

 

 key按键原理图。

 

 

 

void EXTI_Key_Config(void){
    GPIO_InitTypeDef GPIO_InitStruct;
    EXTI_InitTypeDef EXTI_InitStruct;
// 1、初始化GPIO
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
    GPIO_InitStruct.GPIO_Pin=GPIO_Pin_8;
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IPU;//上拉输入  GPIO_Init(GPIOC, &GPIO_InitStruct); // 配置优先级 EXTI_NVIC_Config(); // 2、中断配置 //AFIO时钟使能 RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); //选择输入线,因为输入线的选择是在AFIO_EXTICRX中进行,所以应当首先打开AFIO的时钟 GPIO_EXTILineConfig(GPIO_PortSourceGPIOC, GPIO_PinSource8); //初始化EXTI EXTI_InitStruct.EXTI_Line = EXTI_Line8;//中断屏蔽寄存器上面的位操作 EXTI_InitStruct.EXTI_Mode = EXTI_Mode_Interrupt;//中断模式 EXTI_InitStruct.EXTI_Trigger = EXTI_Trigger_Falling;//下降沿触发 EXTI_InitStruct.EXTI_LineCmd = ENABLE; //使能 EXTI_Init(&EXTI_InitStruct); }

 

 初始化Led所在的GPIO

void Led_GPIO_Config(void){
    GPIO_InitTypeDef GPIO_InitStruct;
    
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    
    GPIO_InitStruct.GPIO_Pin=GPIO_Pin_8;
    GPIO_InitStruct.GPIO_Mode=GPIO_Mode_Out_PP;
    GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStruct);
}

 

配置中断函数

void EXTI9_5_IRQHandler(void)// 在startup_stm32f10x_hd.s 中我们找提前写好的中断函数名。
{
  //确保是否产生了中断 
  if(EXTI_GetITStatus(EXTI_Line8) != RESET)
  {
    //需要的操作
    //别放置耗时间的操作   
  }
  //清除中断标志位 
  EXTI_ClearITPendingBit(EXTI_Line8);
}

 

参考b站野火stm32教程。

标签:优先级,中断,NVIC,详解,寄存器,GPIO,stm32F0,EXTI
From: https://www.cnblogs.com/wangkehui/p/17215907.html

相关文章

  • js 高频面试题详解
    一:js中的变量提升例1a=2;vara;console.log(a);答:2解析:它会将当前作用域的所有变量的声明提升到程序的顶部,上述代码等价为:vara;a=2console.log(a);//......
  • 百度2024届暑期实习后端算法题详解
    目录一Coding1题目描述解题思路详细代码二Coding2题目描述解题思路详细代码三Coding3题目描述解题思路详细代码这是百度2024届暑期实习后端岗位的第一轮笔试,总共有十五......
  • (转)go context详解
    原文:https://www.cnblogs.com/niuben/p/15110611.html前言平时在Go工程的开发中,几乎所有服务端的默认实现(例如:HTTPServer),都在处理请求时开启了新的 goroutine 进行......
  • LoadRunner——分析图详解(十四)
    《分析图详解》一、RunningVusers图X轴表示运行所用的时间,Y轴表示vuser数,显示在整个运行过程中随着时间的推移,虚拟用户数量是如何变化的,具体描述为:用户是如何增长的......
  • 【C】操作符详解
    1.操作符分类:算术操作符移位操作符位操作符赋值操作符单目操作符关系操作符逻辑操作符条件操作符逗号表达式下标引用、函数调用和结构成员2.算术操作符+-*......
  • (转)go语言执行系统命令 - 标准库os/exec详解
    原文:https://blog.csdn.net/weixin_49393427/article/details/116693536exec包对os.StartProcess的包装,方便重新映射标准输入输出,连接io到管道等。exec包不调用系统shell,......
  • 详解React的Transition工作原理原理
    Transition使用姿势Transition是react18引入的新概念,用来区分紧急和非紧急的更新。紧急的更新,指的是一些直接的用户交互,如输入、点击等;非紧急的更新,指的是UI界面......
  • linux 网络管理之tcpdump命令详解
    一、tcpdump的作用tcpdump是linux环境的网络数据采集分析工具,也就是所谓的抓包工具,与tcpdump只有命令行格式不同,Windows有个图形可视化工具Wireshark所谓的抓包工具就......
  • nginx之详解fastcgi指令
    location/{fastcgi_passlocalhost:9000;fastcgi_indexindex.php;fastcgi_paramSCRIPT_FILENAME/home/www/scripts/php$fastcgi_script_name;fastcgi_p......
  • IntelIJ IDEA配置Tomcat详解,遇到问题Error during artifact deployment. See server l
    查了一圈,最后发现自己在artifcat中加了太多了   将之前那些全部删掉,然后重新建一个项目,添加tomcat服务器,就可以正常运行了 ......