misc

STM32F10x MISC 标准库函数参考文档

数据类型定义

NVIC_InitTypeDef - NVIC初始化结构体

typedef struct
{
  uint8_t NVIC_IRQChannel;                    /* 指定要使能或失能的IRQ通道 */
  uint8_t NVIC_IRQChannelPreemptionPriority;  /* 指定IRQ通道的抢占优先级 */
  uint8_t NVIC_IRQChannelSubPriority;         /* 指定IRQ通道的子优先级 */
  FunctionalState NVIC_IRQChannelCmd;         /* 指定IRQ通道的使能状态 */
} NVIC_InitTypeDef;

成员说明:

  • NVIC_IRQChannel:指定要配置的IRQ通道号,可以是IRQn_Type类型的任意值(完整的IRQ通道列表请参考stm32f10x.h文件)
  • NVIC_IRQChannelPreemptionPriority:指定IRQ通道的抢占优先级,取值范围0-15,具体取值范围取决于优先级分组配置
  • NVIC_IRQChannelSubPriority:指定IRQ通道的子优先级,取值范围0-15,具体取值范围取决于优先级分组配置
  • NVIC_IRQChannelCmd:指定IRQ通道的使能状态,可设置为ENABLE或DISABLE

常量定义

向量表基地址定义

#define NVIC_VectTab_RAM             ((uint32_t)0x20000000)  /* RAM中的向量表基地址 */
#define NVIC_VectTab_FLASH           ((uint32_t)0x08000000)  /* FLASH中的向量表基地址 */

系统低功耗模式定义

#define NVIC_LP_SEVONPEND            ((uint8_t)0x10)  /* 挂起事件唤醒 */
#define NVIC_LP_SLEEPDEEP            ((uint8_t)0x04)  /* 深度睡眠模式 */
#define NVIC_LP_SLEEPONEXIT          ((uint8_t)0x02)  /* 退出时睡眠 */

抢占优先级分组定义

#define NVIC_PriorityGroup_0         ((uint32_t)0x700)  /* 0位抢占优先级,4位子优先级 */
#define NVIC_PriorityGroup_1         ((uint32_t)0x600)  /* 1位抢占优先级,3位子优先级 */
#define NVIC_PriorityGroup_2         ((uint32_t)0x500)  /* 2位抢占优先级,2位子优先级 */
#define NVIC_PriorityGroup_3         ((uint32_t)0x400)  /* 3位抢占优先级,1位子优先级 */
#define NVIC_PriorityGroup_4         ((uint32_t)0x300)  /* 4位抢占优先级,0位子优先级 */

SysTick时钟源定义

#define SysTick_CLKSource_HCLK_Div8  ((uint32_t)0xFFFFFFFB)  /* HCLK/8作为SysTick时钟源 */
#define SysTick_CLKSource_HCLK       ((uint32_t)0x00000004)  /* HCLK作为SysTick时钟源 */

优先级分组表

根据NVIC_PriorityGroupConfig函数配置的优先级分组,抢占优先级和子优先级的允许值如下:

优先级分组抢占优先级范围子优先级范围说明
NVIC_PriorityGroup_000-150位抢占优先级,4位子优先级
NVIC_PriorityGroup_10-10-71位抢占优先级,3位子优先级
NVIC_PriorityGroup_20-30-32位抢占优先级,2位子优先级
NVIC_PriorityGroup_30-70-13位抢占优先级,1位子优先级
NVIC_PriorityGroup_40-1504位抢占优先级,0位子优先级

标准库函数详解

1. NVIC_PriorityGroupConfig

/**
 * @brief  划分 NVIC 抢占/子优先级位数,决定中断嵌套与同级排序规则,系统初始化时全局配置一次
 * @param  NVIC_PriorityGroup: 指定优先级分组,可以是以下值之一:
 *         - NVIC_PriorityGroup_0: 0位抢占优先级,4位子优先级
 *         - NVIC_PriorityGroup_1: 1位抢占优先级,3位子优先级
 *         - NVIC_PriorityGroup_2: 2位抢占优先级,2位子优先级
 *         - NVIC_PriorityGroup_3: 3位抢占优先级,1位子优先级
 *         - NVIC_PriorityGroup_4: 4位抢占优先级,0位子优先级
 * @retval
 * @example
 *     NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
 */
void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup);

功能说明:

  • 全工程通常只调用一次,更改分组会使已配优先级含义变化
  • Group_2 等分抢占与子优先级,适合多数裸机/RTOS 混合场景
  • 分组决定 NVIC_Init 中两字段的合法取值范围

2. NVIC_Init

/**
 * @brief  为指定 IRQ 通道设置抢占/子优先级并使能中断,是外设中断可用的关键一步
 * @param  NVIC_InitStruct: 指向NVIC_InitTypeDef结构体的指针,包含NVIC的配置信息
 * @retval
 * @example
 *     NVIC_InitTypeDef NVIC_InitStructure;
 *     NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
 *     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
 *     NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
 *     NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
 *     NVIC_Init(&NVIC_InitStructure);
 */
void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct);

功能说明:

  • 须在外设 xxx_ITConfig 与全局 __enable_irq 之前或之后按项目习惯配置
  • 抢占数值越小优先级越高,可打断低抢占优先级 ISR
  • 同一通道重复 Init 会覆盖旧优先级配置

3. NVIC_SetVectorTable

/**
 * @brief  重定位中断向量表基址,用于 Bootloader 跳转、IAP 或在 RAM 中调试向量表
 * @param  NVIC_VectTab: 指定向量表是在RAM还是FLASH中,可以是以下值之一:
 *         - NVIC_VectTab_RAM: 向量表位于RAM中
 *         - NVIC_VectTab_FLASH: 向量表位于FLASH中
 * @param  Offset: 向量表基地址的偏移量,必须是200的倍数
 * @retval
 * @example
 *     NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);
 */
void NVIC_SetVectorTable(uint32_t NVIC_VectTab, uint32_t Offset);

功能说明:

  • 偏移须为 512 字节(0x200)对齐,否则行为未定义
  • App 从非 0x08000000 启动时须与链接脚本起始地址一致
  • RAM 向量表适合调试时快速修补单条 ISR 入口

4. NVIC_SystemLPConfig

/**
 * @brief  配置 Cortex-M 低功耗相关行为,如中断返回后自动睡眠或深度睡眠配合 STOP 模式
 * @param  LowPowerMode: 指定要配置的低功耗模式,可以是以下值之一:
 *         - NVIC_LP_SEVONPEND: 挂起事件唤醒
 *         - NVIC_LP_SLEEPDEEP: 深度睡眠模式
 *         - NVIC_LP_SLEEPONEXIT: 退出时睡眠
 * @param  NewState: 指定低功耗模式的新状态,可以是ENABLE或DISABLE
 * @retval
 * @example
 *     NVIC_SystemLPConfig(NVIC_LP_SLEEPONEXIT, ENABLE);
 */
void NVIC_SystemLPConfig(uint8_t LowPowerMode, FunctionalState NewState);

功能说明:

  • SLEEPONEXIT 适合 ISR 处理完即睡,主循环用 WFI 唤醒
  • SLEEPDEEP 与 PWR 模块 STOP/STANDBY 配合使用
  • 各 LowPowerMode 可独立 ENABLE/DISABLE

5. SysTick_CLKSourceConfig

/**
 * @brief  选择 SysTick 计数时钟为 HCLK 或 HCLK/8,影响 tick 周期与延时/RTOS 时基计算
 * @param  SysTick_CLKSource: 指定SysTick时钟源,可以是以下值之一:
 *         - SysTick_CLKSource_HCLK_Div8: HCLK/8作为SysTick时钟源
 *         - SysTick_CLKSource_HCLK: HCLK作为SysTick时钟源
 * @retval
 * @example
 *     SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);
 */
void SysTick_CLKSourceConfig(uint32_t SysTick_CLKSource);

功能说明:

  • 须在 SysTick_Config 或写 LOAD 寄存器前配置
  • HCLK 精度更高;Div8 在 72MHz 下便于整除得到 1ms
  • 更改时钟源后须重算重装载值

使用示例

NVIC中断配置示例

#include "misc.h"

void NVIC_Configuration(void)
{
    NVIC_InitTypeDef NVIC_InitStructure;
    
    /* 设置NVIC优先级分组为Group2: 2位抢占优先级,2位子优先级 */
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
    
    /* 配置USART1中断 */
    NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
    
    /* 配置定时器2中断 */
    NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
}

SysTick配置示例

void SysTick_Configuration(void)
{
    /* 配置SysTick时钟源为HCLK/8 */
    SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);
    
    /* 配置SysTick为1ms中断一次,假设HCLK为72MHz */
    SysTick_Config(9000);  /* 72MHz/8/9000 = 1000Hz = 1ms */
}

低功耗模式配置示例

void LowPower_Configuration(void)
{
    /* 使能退出时睡眠功能 */
    NVIC_SystemLPConfig(NVIC_LP_SLEEPONEXIT, ENABLE);
    
    /* 配置深度睡眠模式 */
    NVIC_SystemLPConfig(NVIC_LP_SLEEPDEEP, ENABLE);
}

注意事项

  1. 优先级分组配置:NVIC_PriorityGroupConfig函数在整个应用程序中应该只调用一次,建议在系统初始化阶段配置,之后不要再更改。

  2. 优先级值范围:抢占优先级和子优先级的有效范围取决于优先级分组的配置,超出范围的值将被忽略。

  3. 向量表重定位:使用NVIC_SetVectorTable时,偏移量必须是512字节(0x200)的倍数,否则可能导致系统不稳定。

  4. SysTick时钟源:选择不同的SysTick时钟源会影响定时精度,需要根据实际的HCLK频率来计算合适的重装载值。

  5. 低功耗模式:配置低功耗模式时要注意系统的唤醒条件,确保系统能够正常从低功耗模式中唤醒。

  6. 中断优先级:抢占优先级高的中断可以打断抢占优先级低的中断,而子优先级只在抢占优先级相同时起作用,用于决定同时挂起的中断的执行顺序。

总结

MISC模块是STM32F10x标准库中的重要组成部分,提供了NVIC中断控制器和SysTick系统定时器的配置功能。通过合理配置中断优先级分组和各个中断的优先级,可以实现复杂的中断管理策略。SysTick定时器为系统提供了精确的时基,是实时操作系统和延时功能的基础。掌握MISC模块的使用对于开发高性能、低功耗的嵌入式应用至关重要。