打印
[嵌入式linux]

STM32 中断和事件

[复制链接]
1160|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
terryzhouhz|  楼主 | 2022-5-4 21:01 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
中断和事件(Interrupts and events)
嵌套向量中断控制器(Nested vectored interrupt controller -NVIC)
中断是相对CPU而言的,因此例如IIC、定时器这些芯片内产生的中断也被称为外部中断,不能狭隘的理解为由芯片外的信号触发

EXTI被称为外部中断/事件控制器(External interrupt/event controller)

什么是中断?什么是事件

EXTI的23个中断事件线与中断的关系? 在同一时刻每个中断线只能相应一个GPIO端口的中断,不能够同时相应所有端口的中断事件

优先级定义

在NVIC有一个专门的寄存器:中断优先级寄存器NVIC_IPRx用来配置外部中断的优先级,IPR宽度为8bit,原则上每个外部中断可配置的优先级为0~255,数值越小,优先级越高。在STM32F4中使用了高4位设置中断优先级,也就是有16个可编程优先级。
中断优先级被分组为抢占优先级和子优先级。如果有多个中断同时响应,抢占优先级高的就会抢占抢占优先级低的优先得到执行,如果抢占优先级相同,就比较子优先级。如果抢占优先级和子优先级都相同的话,就比较他们的硬件中断编号,编号越小,优先级越高。

寄存器介绍
上面说到 NVIC 控制着芯片的中断相关功能, 那么肯定有很多对应的寄存器,在固件库 core_cm3.h 文件内定义了一个 NVIC 结构体,里面定义了相关寄存器,如下:

typedef struct
{
    __IO uint32_t ISER[8]; //中断使能寄存器
    uint32_t RESERVED0[24];
    __IO uint32_t ICER[8]; //中断清除寄存器
    uint32_t RSERVED1[24];
    __IO uint32_t ISPR[8]; //中断使能悬起寄存器
    uint32_t RESERVED2[24];
    __IO uint32_t ICPR[8]; //中断清除悬起寄存器
    uint32_t RESERVED3[24];
    __IO uint32_t IABR[8]; //中断有效位寄存器
    uint32_t RESERVED4[56];
    __IO uint8_t IP[240]; //中断优先级寄存器
    uint32_t RESERVED5[644];
    __O uint32_t STIR; //软件触发中断寄存器
} NVIC_Type;
在配置中断时,我们通常使用的只有 ISER、 ICER 和 IP 这三个寄存器,ISER是中断使能寄存器,ICER是中断清除寄存器,IP 是中断优先级寄存器。在固件库 core_cm3.h文件后面,还提供了一些对 NVIC 操作的库函数,这些函数都是遵循 CMSIS 标准, 所以只要是基于 Cortex-M3 内核的芯片都可以用这些函数来操作 NVIC,只不过我们很少这样做,甚至不使用这些函数,因为在后面我们会有更简单的办法来配置中断。至于这些函数内容,大家如果有兴趣的话,可以打开我们库函数版本任意程序,找到 core_cm3.h 文件查看即可。

这里多提一点__IO的用法:

/* IO definitions (access restrictions to peripheral registers) */
#ifdef __cplusplus
  #define __I  volatile         /*!< defines 'read only' permissions                 */
#else
  #define __I  volatile const   /*!< defines 'read only' permissions                 */
#endif
#define   __O  volatile         /*!< defines 'write only' permissions                */
#define   __IO volatile         /*!< defines 'read / write' permissions              */
其实就是将volatile关键字进行了重定义,用来区分读写,仅仅是语法提醒层面,并不强制。

中断配置
前面讲解了那么多中断知识, 如果大家不理解也没有关系, 我们会应用即可,等到后面 STM32 熟练了,再回过头深入了解自然就会明白。要使用中断我们就需要先配置它,通常都需经过这几步:

(1)使能外设某个中断,这个具体是由外设相关中断使能位来控制,比如

定时器有溢出中断,这个可由定时器的控制寄存器中相应中断使能位来控制。

(2)设置中断优先级分组,初始化 NVIC_InitTypeDef 结构体,设置抢占

优先级和响应优先级,使能中断请求。

NVIC_InitTypeDef 结构体如下:

typedef struct
{
  uint8_t NVIC_IRQChannel; //中断源
  uint8_t NVIC_IRQChannelPreemptionPriority; //抢占优先级
  uint8_t NVIC_IRQChannelSubPriority; //响应优先级
  FunctionalState NVIC_IRQChannelCmd; //中断使能或失能
} NVIC_InitTypeDef;
下面我们对 NVIC_InitTypeDef 结构体成员进行一下简单介绍。

1.NVIC_IRQChannel:中断源的设置,不同的外设中断,中断源不一样,自

然名字也不一样,所以名字不能写错,否则不会进入中断。中断源放在stm32f10x.h 文件的 IRQn_Type结构体内,由于内容太多,这里就不复制所有中断源,只截取一部分,如下:


typedef enum IRQn
{
  //Cortex-M3 处理器异常编号
  NonMaskableInt_IRQn = -14,
  MemoryManagement_IRQn = -12,
  BusFault_IRQn = -11,
  UsageFault_IRQn = -10,
  SVCall_IRQn = -5,
  DebugMonitor_IRQn = -4,
  PendSV_IRQn = -2,
  SysTick_IRQn = -1,
  //STM32 外部中断编号
  WWDG_IRQn = 0,
  PVD_IRQn = 1,
  TAMP_STAMP_IRQn = 2,
  // 限于篇幅,中间部分代码省略,具体的可查看库文件 stm32f10x.h
  DMA2_Channel2_IRQn = 57,
  DMA2_Channel3_IRQn = 58,
  DMA2_Channel4_5_IRQn = 59
}IRQn_Type;
2.NVIC_IRQChannelPreemptionPriority:抢占优先级,具体的值要根据优先级分组来确定,可以参考前面中断优先级分组内容。

3.NVIC_IRQChannelSubPriority:响应优先级,具体的值要根据优先级分组

来确定,可以参考前面中断优先级分组内容。

4.NVIC_IRQChannelCmd:中断使能/失能设置,使能配置为 ENABLE,失能配置为 DISABLE。

使用特权

评论回复

相关帖子

发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

73

主题

104

帖子

1

粉丝