问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

STM32时钟配置全攻略——从小白到高手

创作时间:
作者:
@小白创作中心

STM32时钟配置全攻略——从小白到高手

引用
CSDN
1.
https://blog.csdn.net/wwwmy1/article/details/145682994

STM32的时钟配置是开发过程中的关键环节,它直接影响到MCU的运行速度和外设的工作效率。本文将从时钟系统的概述开始,逐步深入讲解时钟源、PLL、系统时钟和总线时钟的概念,并详细解析RCC_OscConfig和RCC_ClockConfig两个关键函数的使用方法。通过本文的学习,你将能够掌握STM32时钟配置的核心要点,成为一名合格的嵌入式开发者。

STM32 时钟系统概述

STM32的时钟系统相当于一个庞大的交通网络,所有外设都需要从某个时钟源获取“动力”来运转。它主要包括:

时钟源(Oscillator)

STM32内部有多个时钟源,它们的特点如下:

时钟源
作用
频率
特点
HSE(外部高速晶振)
主时钟源
8MHz / 16MHz
精度高,需要外部晶振
HSI(内部高速振荡器)
备用时钟源
16MHz
自带校准,但精度一般
LSE(外部低速晶振)
RTC(实时时钟)
32.768kHz
精度高,适合低功耗
LSI(内部低速振荡器)
看门狗、RTC备用
32kHz
低功耗,精度较差

这些时钟源可以直接使用,也可以经过PLL进行放大!

PLL(相位锁环)

STM32内置的PLL(Phase Locked Loop)允许对时钟进行倍频或分频,比如:

  • HSE = 8MHz,可以用PLL放大到168MHz,作为CPU主频!
  • HSI = 16MHz,可以用PLL倍频到48MHz,用于USB通信!

所以,高主频STM32(72MHz、168MHz)基本都依赖PLL!

系统时钟(SYSCLK)与总线时钟

系统时钟(SYSCLK)决定了MCU的运行速度,而总线时钟决定了外设的速度。

SYSCLK → AHB (HCLK) → APB1 (PCLK1) → 低速外设 (UART2/3, I2C, SPI2/3)
                 ↓  
                 APB2 (PCLK2) → 高速外设 (UART1, SPI1, ADC)
时钟
作用
典型频率
SYSCLK
系统时钟
72MHz / 168MHz
HCLK
AHB总线时钟
SYSCLK
PCLK1
低速外设
HCLK / 2 或 HCLK / 4
PCLK2
高速外设
HCLK / 2

掌握这些时钟后,我们就可以进行配置了!

STM32 时钟配置的完整流程

STM32的时钟配置通常分为两大步骤:

  1. 配置时钟源(Oscillator)
  2. 配置时钟分配(Clock)

这两个函数至关重要,我们逐个解析!

结构体RCC_OscInitTypeDef和RCC_ClkInitTypeDef介绍

RCC_OscInitTypeDef 结构体

该结构体用于配置STM32的时钟源(Oscillator),即MCU运行所需的基础时钟。它主要包含HSE(外部高速晶振)、HSI(内部高速振荡器)、LSE(外部低速晶振)、LSI(内部低速振荡器)以及PLL(相位锁环)的相关参数。

typedef struct
{
  uint32_t OscillatorType;       // 选择要配置的振荡器(HSE、HSI、LSE、LSI)
  uint32_t HSEState;             // HSE(外部高速晶振)的状态(开启、关闭、旁路)
  uint32_t LSEState;             // LSE(外部低速晶振)的状态(开启、关闭、旁路)
  uint32_t HSIState;             // HSI(内部高速振荡器)的状态(开启、关闭)
  uint32_t HSICalibrationValue;  // HSI校准值(用于调整HSI的精度)
  uint32_t LSIState;             // LSI(内部低速振荡器)的状态(开启、关闭)
  RCC_PLLInitTypeDef PLL;        // PLL(相位锁环)相关配置
} RCC_OscInitTypeDef;

结构体成员解析

参数
说明
可能的取值
OscillatorType
选择要配置的时钟源
RCC_OSCILLATORTYPE_HSE、RCC_OSCILLATORTYPE_HSI、RCC_OSCILLATORTYPE_LSE、RCC_OSCILLATORTYPE_LSI
HSEState
控制HSE(外部高速晶振)的状态
RCC_HSE_OFF(关闭)、RCC_HSE_ON(开启)、RCC_HSE_BYPASS(旁路)
LSEState
控制LSE(外部低速晶振)的状态
RCC_LSE_OFF、RCC_LSE_ON、RCC_LSE_BYPASS
HSIState
控制HSI(内部高速振荡器)的状态
RCC_HSI_OFF、RCC_HSI_ON
HSICalibrationValue
设置HSI校准值(影响HSI的精度)
0~31(寄存器值)
LSIState
控制LSI(内部低速振荡器)的状态
RCC_LSI_OFF、RCC_LSI_ON
PLL
配置PLL倍频
见RCC_PLLInitTypeDef结构体

RCC_ClkInitTypeDef 结构体

该结构体用于配置系统时钟(System Clock)及其在不同总线上的分配方式。它决定了主时钟来源以及AHB和APB总线的时钟分频情况。

typedef struct
{
  uint32_t ClockType;      // 需要配置的时钟类型
  uint32_t SYSCLKSource;   // 选择系统时钟源
  uint32_t AHBCLKDivider;  // AHB总线时钟分频
  uint32_t APB1CLKDivider; // APB1总线时钟分频
  uint32_t APB2CLKDivider; // APB2总线时钟分频
} RCC_ClkInitTypeDef;

结构体成员解析

参数
说明
可能的取值
ClockType
需要配置的时钟
RCC_CLOCKTYPE_SYSCLK(系统时钟)、RCC_CLOCKTYPE_HCLK(AHB时钟)、RCC_CLOCKTYPE_PCLK1(APB1时钟)、RCC_CLOCKTYPE_PCLK2(APB2时钟)
SYSCLKSource
选择系统主时钟来源
RCC_SYSCLKSOURCE_HSI(HSI)、RCC_SYSCLKSOURCE_HSE(HSE)、RCC_SYSCLKSOURCE_PLLCLK(PLL)
AHBCLKDivider
AHB总线分频(影响CPU及高速外设)
RCC_SYSCLK_DIV1(不分频)、RCC_SYSCLK_DIV2、RCC_SYSCLK_DIV4、RCC_SYSCLK_DIV8、RCC_SYSCLK_DIV16
APB1CLKDivider
APB1总线分频(低速外设,如UART2、I2C1)
RCC_HCLK_DIV1、RCC_HCLK_DIV2、RCC_HCLK_DIV4、RCC_HCLK_DIV8、RCC_HCLK_DIV16
APB2CLKDivider
APB2总线分频(高速外设,如UART1、SPI1)
RCC_HCLK_DIV1、RCC_HCLK_DIV2、RCC_HCLK_DIV4、RCC_HCLK_DIV8、RCC_HCLK_DIV16

HAL_RCC_OscConfig() —— 选择时钟源

HAL_RCC_OscConfig()用于选择MCU运行的时钟源,并配置PLL。

下列结构体配置中的参数是基于上述时钟树图,具体数字大家可以反复比对一下,细细理解其中每个参数的含义,加深对配置过程的理解。

结构体RCC_OscInitTypeDef

RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE; // 选择HSE
RCC_OscInitStruct.HSEState = RCC_HSE_ON; // 开启HSE
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; // 开启PLL
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; // 让PLL使用HSE
RCC_OscInitStruct.PLL.PLLM = 8; // 8分频
RCC_OscInitStruct.PLL.PLLN = 336; // 336倍频
RCC_OscInitStruct.PLL.PLLP = 2; // 2分频,最终得到168MHz
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) {
    Error_Handler(); // 错误处理
}

理解关键参数:

  • PLL.PLLM = 8 → HSE 8MHz ÷ 8 = 1MHz
  • PLL.PLLN = 336 → 1MHz × 336 = 336MHz
  • PLL.PLLP = 2 → 336MHz ÷ 2 = 168MHz

这样,我们就成功将系统主频调整到了168MHz!

HAL_RCC_ClockConfig() —— 分配时钟

HAL_RCC_ClockConfig()用于将主时钟分配给AHB、APB总线。

结构体RCC_ClkInitTypeDef

RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK |
                              RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; // 选择PLL
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; // AHB不分频
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4; // APB1 4分频
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2; // APB2 2分频
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK) {
    Error_Handler();
}

理解关键参数:

  • AHBCLKDivider = RCC_SYSCLK_DIV1 → HCLK = 168MHz
  • APB1CLKDivider = RCC_HCLK_DIV4 → PCLK1 = 42MHz
  • APB2CLKDivider = RCC_HCLK_DIV2 → PCLK2 = 84MHz

这样,我们的STM32就能跑得飞快!

总结

  • HAL_RCC_OscConfig()选择HSE并开启PLL,设定168MHz时钟。
  • HAL_RCC_ClockConfig()设定AHB = 168MHz,APB1 = 42MHz,APB2 = 84MHz。
  • 所有外设正常运行,STM32高速运转!
© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号