STM32初学---RCC / NVIC / EXTI

一、RCC_CFGR 寄存器(Reset and Clock Control - Clock Configuration Register)

1、概念

  • RCC (Reset and Clock Control):这是一个专门负责控制 复位时钟 的外设模块。
  • CFGR (Configuration Register): 这是一个配置寄存器

作用解释:RCC_CFGRRCC\_CFGRRCC_CFGR 寄存器就是用来配置和选择 STM32 中各个总线和外设的时钟源和分频系数的。它是时钟系统配置中最重要的寄存器之一。

  • 时钟源选择: 决定了系统时钟(SYSCLK)从哪里来(例如,是内部高速时钟 HSI、外部高速时钟 HSE 还是 PLL 锁相环)。
  • 分频设置: 决定了系统时钟如何分配给不同的总线(AHB、APB1、APB2)和内核(Cortex System Timer 等),以控制它们运行的速度。

2、 RCC_CFGRRCC\_CFGRRCC_CFGR 寄存器中的两个相关字段:

  • SWSWSW(System Clock Switch): 这是一个控制位,您写入这个字段来选择您希望使用哪个时钟源作为 SYSCLKSYSCLKSYSCLK。
  • SWSSWSSWS(System Clock Switch Status): 这是一个状态位,您读取这个字段来确认系统是否已经成功切换到 SWSWSW 所选择的时钟源。

SWSSWSSWS 用于指示系统时钟 (SYSCLKSYSCLKSYSCLK) 当前使用的是哪个时钟源。

SWS 值 含义(当前系统时钟源)
00 HSI (High-speed Internal Clock) - 内部高速时钟
01 HSE (High-speed External Clock) - 外部高速时钟
10 PLL (Phase-Locked Loop) - 锁相环输出时钟
11 预留/其他(依具体型号而定)

简单来说:

  • SWSWSW →\rightarrow→ 你告诉 MCU 用哪个时钟 (Write);
  • SWSSWSSWS →\rightarrow→ MCU 告诉你它正在用哪个时钟 (Read)。

在代码中进行时钟初始化时,通常会配置 SWSWSW 字段 ,然后等待(或检查) SWSSWSSWS 字段,直到它变为期望的值,这代表时钟切换成功。

3、RCC_ClocksTypeDef结构体

RCC_ClocksTypeDef结构体中定义:SYSCLK_Frequency、HCLK_Frequency、PCLK1_Frequency、PCLK2_Frequency。这四个成员变量,是 STM32 时钟树(Clock Tree)和速度分配的关键。它们定义了芯片内部几个最重要的时钟频率。

变量名 对应时钟 全称 作用/含义
SYSCLK_Frequency SYSCLK (System Clock) 系统时钟 MCU 的主时钟。 它驱动 CPU 内核(Cortex-M)和 AHB 总线。它的频率决定了 MCU 的基本运行速度。SYSCLK 的来源可以是 HSI、HSE 或 PLLCLK。
HCLK_Frequency HCLK (AHB Clock) AHB 总线时钟 高速外设和存储器的时钟。 它驱动 AHB (Advanced High-performance Bus) 总线、SRAM 存储器、Flash 存储器和所有连接到 AHB 总线上的高速外设(例如 DMA、GPIO 等)。HCLK 是由 SYSCLK 经过 AHB 预分频器 (AHB Prescaler) 分频后得到的。
PCLK1_Frequency PCLK1 (APB1 Clock) APB1 低速外设时钟 低速外设的时钟。 它驱动连接到 APB1 (Advanced Peripheral Bus 1) 总线上的外设。通常用于低速且对频率要求不高的外设(例如 Timer 2/3/4/5/6/7,USART 2/3/4/5,I2C 1/2/3 等)。PCLK1 是由 HCLK 经过 APB1 预分频器 分频后得到的。
PCLK2_Frequency PCLK2 (APB2 Clock) APB2 高速外设时钟 高速外设的时钟。 它驱动连接到 APB2 (Advanced Peripheral Bus 2) 总线上的外设。通常用于高速或对时序有严格要求的外设(例如 Timer 1/8,USART 1/6,SPI 1/4,ADC 等)。PCLK2 是由 HCLK 经过 APB2 预分频器 分频后得到的。

二、NvicConfig:外设中断配置函数

主要包含4类操作:

① 设置中断优先级分组(Priority Grouping)

说明:

决定抢占/子优先级结构:
先占优先级(preemption priority)
响应 / 子优先级(sub priority)

例如(STM32):

javascript 复制代码
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);

分组决定优先级的划分方式。

NVIC_PriorityGroup决定 优先级字段里多少位用于抢占优先级,多少位用于子优先级。

在 Cortex-M 内核中,NVIC 的中断优先级一般是 4 位(0~15)。

这些 4 位会被拆分成两部分:

Priority Group 抢占位数 子优先级位数
Group 0 0 位 4 位
Group 1 1 位 3 位
Group 2 2 位 2 位
Group 3 3 位 1 位
Group 4 4 位 0 位

📌 Group 数字越大 → 抢占优先级越多 → 子优先级越少

为什么很多工程默认用 NVIC_PriorityGroup_4?

因为简单!只需要关心一个优先级(抢占优先级),中断只按"谁优先级更高"来打断,没有子优先级这种细节,适合大部分 STM32 项目。

javascript 复制代码
NVIC_PriorityGroup_4
表示:
抢占优先级占 4 位
子优先级占 0 位(没有子优先级概念)
所以:
✔ 你可以设置抢占优先级 0 ~ 15
✔ 所有中断没有平级排序,全靠抢占优先级决定先后

深入理解:

假设优先级分组是 NVIC_PriorityGroup_2(2 位抢占,2 位子优先级):

中断 抢占优先级 子优先级
EXTI0 1 0
USART1 2 0
TIM3 1 1

结论:

javascript 复制代码
EXTI0(1,0) 和 TIM3(1,1)
→ 抢占一样
→ 子优先级 0 < 1
→ EXTI0 先执行

USART1(2,x) 抢占级低
→ 不能打断 EXTI0 或 TIM3
→ 永远排最后

② 为某个外设选择中断优先级

典型步骤:

javascript 复制代码
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);

设置内容:

中断线号(IRQ)

抢占优先级

响应/子优先级

打开 NVIC 中断通道

③ 使能(Enable)NVIC 中断通道

例如:

javascript 复制代码
NVIC_EnableIRQ(USART1_IRQn);

或者在初始化结构里 Cmd = ENABLE。

④ 可选:清除挂起中断(Pending Flag)

说明:防止进入旧中断

确保启动前中断状态是干净的:

javascript 复制代码
NVIC_ClearPendingIRQ(EXTI0_IRQn);

三、EXTI 和 NVIC

1、概念

EXTI 负责"外部事件/引脚 → 产生中断请求"

NVIC 负责"多个中断请求 → 排队、抢占、执行"

2、NVIC(Nested Vectored Interrupt Controller)

NVIC 是 Cortex-M 内核的一部分,作用是:管理所有中断(外设 / 内部 / 外部)

决定:

  • 谁先执行
  • 谁能打断谁
  • 谁在等

3、EXTI(External Interrupt / Event Controller)

EXTI 是 芯片外设模块,负责:把 GPIO 引脚或内部事件,转换成中断请求

常见用途:

  • 按键中断
  • 外部传感器触发
  • 外部同步信号

EXTI 本身不直接连 GPIO,

中间有个 EXTI Line(中断线):

javascript 复制代码
GPIO 引脚
   ↓
EXTI Line (0~15)
   ↓
NVIC (EXTI0_IRQn, EXTI9_5_IRQn...)

3.1 EXTI 配置代码

① GPIO 配置为输入
javascript 复制代码
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
GPIO_Init(GPIOA, &GPIO_InitStructure);
② GPIO → EXTI Line 映射
javascript 复制代码
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0);
③ EXTI 配置
javascript 复制代码
EXTI_InitTypeDef EXTI_InitStructure;
EXTI_InitStructure.EXTI_Line = EXTI_Line0;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);
④ NVIC 配置
javascript 复制代码
NVIC_InitStruct.NVIC_IRQChannel = EXTI0_IRQn;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStruct);
⑤ 中断服务函数(ISR)

void EXTI0_IRQHandler(void)

{

if (EXTI_GetITStatus(EXTI_Line0) != RESET)

{

// 用户处理代码

复制代码
    EXTI_ClearITPendingBit(EXTI_Line0);
}

}

⚠️ 必须清 pending 位,否则会一直进中断

3.2 NVIC 和 EXTI 的关系(重点)

模块 作用
GPIO 物理引脚
EXTI 把引脚变化变成中断请求
NVIC 决定是否执行、何时执行
ISR 真正执行代码的地方
相关推荐
芯联智造6 小时前
【stm32简单外设篇】- 高灵敏麦克风传感器模块 KY-037
c语言·stm32·单片机·嵌入式硬件
Dillon Dong8 小时前
STM32嵌入式开发:巧用位运算,打造高效参数ID管理方案
stm32·单片机·嵌入式硬件
亿道电子Emdoor8 小时前
【Arm】Arm DS如何导出Build log文件
stm32·单片机·嵌入式硬件
DIY机器人工房8 小时前
解决方法:关于上传经纬度绑定到onenet可视化平台地图上位置偏移的问题
stm32·单片机·嵌入式硬件·gps·定位·diy机器人工房
bai54593610 小时前
STM32 CubeIDE 按键控制LED
stm32·单片机·嵌入式硬件
光子物联单片机10 小时前
STM32单片机开发入门(十一)STM32CubeIDE下载安装及开发调试说明
c语言·stm32·单片机·嵌入式硬件·mcu
cat_milk10 小时前
【潘多拉 STM32L475 IOT开发指南】【基础】1.LED
stm32·单片机·物联网
TEC_INO10 小时前
Stm32_2:蜂鸣器、按键、继电器
stm32·单片机·嵌入式硬件
yugi98783810 小时前
实现STM32读取INA226电流值并通过串口发送给HMI串口屏显示
stm32·单片机·嵌入式硬件