Chapter 16 STM32 中断应用概览

Chapter 16 STM32 中断应用概览

STM32 中断非常强大,每个外设都可以产生中断

文中所述 “异常就是中断,中断就是异常”

异常类型

  • 系统异常有8个,加上 Rest 和 HardFrault 也算上就是 10 个
  • 外部中断有 60 个
  • 除个别异常的优先级被固定外,其它异常的优先级都是可以编程的

系统异常和外部中断在标准库文件 stm32f10x.h 头文件中可查询。

IRQn_Tpye 结构体里包含了 F103 系列全部的异常声明

NVIC 简介

NVIC 控制整个芯片中断相关功能。它是内核里面的一个外设。

STM32 中的 NVIC 是 Cortex-M3 的 NVIC 的一个子集。

NVIC 寄存器简介

NVIC 结构体定义,在固件库头文件:core_m3.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/** @addtogroup CMSIS_CM3_NVIC CMSIS CM3 NVIC
memory mapped structure for Nested Vectored Interrupt Controller (NVIC)
@{
*/
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;
/*@}*/ /* end of group CMSIS_CM3_NVIC */

配置中断的时候我们一般只用:

  • ISER :使能中断
  • ICER :清除中断
  • IP :设置中断优先级

NVIC 中断配置固库

固件库文件 core_m3.h 的最最后,定了 NVIC 的一些函数。用得比较少,甚至不用,配置中断的时候会用更简洁的方法。

中断优先级

优先级定义

中断优先级寄存器 NVIC_IPRx

  • 配置外部中断优先级,8 位,只使用高 4 位
  • 这 4 位又被分成:抢占(主)优先级、子优先级
  • 多中断响应时按:“抢占优先级 > 子优先级 > 硬件中断编号” 顺序执行

优先级分组

  • 由内核外设 SCB->AIRCR(应用程序中断和复位控制寄存器) 的 PRIGROUP[10:8] 位决定。
  • 设置优先级分组:NVIC_PriorityGroupConifg()
  • 有关 NVIC 中断相关的库函数:misc.cmisc.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// NVIC 设置中断优先级分组函数
/**
* @brief Configures the priority grouping: pre-emption priority and subpriority.
* @param NVIC_PriorityGroup: specifies the priority grouping bits length.
* This parameter can be one of the following values:
* @arg NVIC_PriorityGroup_0: 0 bits for pre-emption priority
* 4 bits for subpriority
* @arg NVIC_PriorityGroup_1: 1 bits for pre-emption priority
* 3 bits for subpriority
* @arg NVIC_PriorityGroup_2: 2 bits for pre-emption priority
* 2 bits for subpriority
* @arg NVIC_PriorityGroup_3: 3 bits for pre-emption priority
* 1 bits for subpriority
* @arg NVIC_PriorityGroup_4: 4 bits for pre-emption priority
* 0 bits for subpriority
* @retval None
*/
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;
}

优先级分组真值表:

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

中断编程

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

1、使能外设某个中断

  • 具体由每个外设的相关中断全能位控制

2、初始化 NVIC_InitTypeDef 结构体

  • 配置中断优先级分组

  • 设置抢占优先级、子优先级

  • 使能中断请求

    1
    2
    3
    4
    5
    6
    7
    8
    // NVIC 初始化结构体
    typedef struct
    {
    uint8_t NVIC_IRQChannel; // 设置中断源:成员配置在 IRQn_Type 枚举型定义
    uint8_t NVIC_IRQChannelPreemptionPriority; // 抢占优先级,具体值要依据优先级分组来确定
    uint8_t NVIC_IRQChannelSubPriority; // 子优先级,具体值要依据优先级分组来确定
    FunctionalState NVIC_IRQChannelCmd; // 中断使能/除能。操作的是:ISER、ICER 两个寄存器
    } NVIC_InitTypeDef;

3、编写中断服务函数

  • 在启动文件中 stm32f10x_startup_md.s 中已预告为每个中断写了一个中断服务函数,内容为空,用于初始化中断向量表
  • 实际使用的中断服务函数是我们自己重新编写,写在 stm32f10x_it.c 文件中
  • 中断服务函数的函数名必须与启动文件里预先设置的一样,否则程序跳进启动文件里的空函数无限循环,实现不了中断

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!