基于铁头山羊(38, 39)、HAL库教程(16, 17)、江科大(13-2)三教程综合整理
时钟(Clock)是数字电路的心跳。芯片内部的每个寄存器、计数器、通信接口等所有数字逻辑都在时钟沿的驱动下工作。RCC(Reset and Clock Control)模块负责:
上图:STM32 系统架构(包含总线矩阵与各外设挂载关系)(来源:STM32入门教程 PPT 第9页)
上图:STM32F10x 时钟树结构示意图(来源:STM32入门教程 PPT 第62页)
STM32F10x 共有 5 个时钟源:
| 时钟源 | 名称 | 频率 | 精度 | 用途 |
|---|---|---|---|---|
| HSI | 内部高速振荡器 | 8 MHz | 较低(出厂校准) | 上电默认时钟源,可作为 PLL 输入 |
| HSE | 外部高速振荡器 | 4~16 MHz(常用 8 MHz) | 高(晶振决定) | 可作为 PLL 输入,系统时钟 |
| PLL | 锁相环 | 最高 72 MHz | 取决于输入源 | 倍频输出作为 SYSCLK |
| LSI | 内部低速振荡器 | 40 kHz | 较低 | 独立看门狗(IWDG)、RTC |
| LSE | 外部低速振荡器 | 32.768 kHz | 高(专门音叉晶振) | RTC 时钟 |
PLL 的输入可以选择:
HSI(8 MHz)
↓ 二分频 → 4 MHz → PLL ×2~×16 → 最高 72 MHz
HSE(8 MHz 外部晶振)
↓ 直通或二分频 → 8 MHz 或 4 MHz → PLL ×2~×16 → 最高 72 MHz
默认配置: HSE = 8 MHz → 不分频 → PLL ×9 = 72 MHz。
┌──────────────┐
│ HSI 8 MHz │
└──────┬───────┘
│
┌──────▼───────┐
│ HSE 8 MHz │
└──────┬───────┘
│
┌──────▼───────┐
│ PLL ×9 │ → 72 MHz
└──────┬───────┘
│
┌─────────▼──────────┐
│ SYSCLK 选择器 │ ← 可选择 HSI / HSE / PLL
└─────────┬──────────┘
│
┌──────▼───────┐
│ AHB 分频器 │ → HCLK(内核、存储器、DMA)
└──────┬───────┘
│
┌──────────────┼────────────────┐
│ │ │
┌──────▼──────┐ ┌────▼─────┐ ┌──────▼──────┐
│ APB1 分频器 │ │ APB2 分频器│ │ 其他外设 │
│ ≤36 MHz │ │ ≤72 MHz │ │ │
└──────┬──────┘ └────┬─────┘ └─────────────┘
│ │
┌─────▼─────┐ ┌───▼────┐
│ TIM 等 │ │GPIO、ADC│
│ APB1 外设 │ │USART1等 │
└───────────┘ └────────┘
| 总线 | 最高频率 | 挂载的典型外设 |
|---|---|---|
| AHB | 72 MHz | 内核、存储器、DMA |
| APB1 | 36 MHz | TIM2~TIM7、USART2~5、SPI2/3、I2C1/2 |
| APB2 | 72 MHz | GPIO、USART1、SPI1、ADC1/2、TIM1/TIM8 |
注意:APB1 上的定时器(TIM2~TIM7)时钟源实际等于 APB1 ×2(当 APB1 分频系数 ≠1 时),所以在 APB1=36MHz 时 TIM 仍可获得 72MHz 的计数时钟。
启动文件(startup_stm32f10x_xx.s)在跳转到 main 之前会调用 SystemInit()。
SystemInit() 的功能:
SetSysClock() 设置系统时钟SystemCoreClock 全局变量(记录当前 SYSCLK 频率)SetSysClock() 在 system_stm32f10x.c 中实现,根据宏定义选择目标频率:
// 在 system_stm32f10x.c 中可选择以下宏之一
// #define SYSCLK_FREQ_HSE HSE_VALUE // 直接使用 HSE
// #define SYSCLK_FREQ_24MHz 24000000
// #define SYSCLK_FREQ_36MHz 36000000
// #define SYSCLK_FREQ_48MHz 48000000
// #define SYSCLK_FREQ_56MHz 56000000
#define SYSCLK_FREQ_72MHz 72000000 // 默认启用
// #define SYSCLK_FREQ_24MHz 24000000
SYSCLK = 72 MHz 的配置步骤(典型):
以下代码来自 system_stm32f10x.c,当定义 SYSCLK_FREQ_72MHz 宏时被 SetSysClock() 调用:
static void SetSysClockTo72(void)
{
__IO uint32_t StartUpCounter = 0, HSEStatus = 0;
/* 使能 HSE */
RCC->CR |= ((uint32_t)RCC_CR_HSEON);
/* 等待 HSE 就绪,超时则退出 */
do
{
HSEStatus = RCC->CR & RCC_CR_HSERDY;
StartUpCounter++;
} while ((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
if ((RCC->CR & RCC_CR_HSERDY) != RESET)
HSEStatus = (uint32_t)0x01;
else
HSEStatus = (uint32_t)0x00;
if (HSEStatus == (uint32_t)0x01)
{
/* 使能预取缓冲 */
FLASH->ACR |= FLASH_ACR_PRFTBE;
/* Flash 2 个等待周期(72MHz 需要) */
FLASH->ACR &= (uint32_t)((uint32_t)~FLASH_ACR_LATENCY);
FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_2;
/* HCLK = SYSCLK(AHB 不分频) */
RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;
/* PCLK2 = HCLK(APB2 不分频) */
RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;
/* PCLK1 = HCLK / 2(APB1 二分频) */
RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2;
/* PLL 配置:PLLCLK = HSE × 9 = 72 MHz */
RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC |
RCC_CFGR_PLLXTPRE |
RCC_CFGR_PLLMULL));
RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLMULL9);
/* 使能 PLL */
RCC->CR |= RCC_CR_PLLON;
while ((RCC->CR & RCC_CR_PLLRDY) == 0) { }
/* 选择 PLL 作为系统时钟 */
RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL;
/* 等待 PLL 切换完成 */
while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x08) { }
}
else
{
/* HSE 起振失败 — 可在此添加错误处理代码 */
}
}
static void SetSysClockTo72(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
/* HSE 振荡器配置:使能 HSE,作为 PLL 输入 */
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9; /* HSE × 9 = 72 MHz */
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { }
/* 时钟树配置:SYSCLK = PLL72MHz,总线分频 */
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK |
RCC_CLOCKTYPE_SYSCLK |
RCC_CLOCKTYPE_PCLK1 |
RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; /* HCLK = 72 MHz */
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; /* PCLK2 = 72 MHz */
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2; /* PCLK1 = 36 MHz */
/* Flash 等待周期:72MHz 需要 2 个等待周期 */
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK) { }
}
static void SetSysClockToHSE(void)
{
__IO uint32_t StartUpCounter = 0, HSEStatus = 0;
RCC->CR |= ((uint32_t)RCC_CR_HSEON);
do
{
HSEStatus = RCC->CR & RCC_CR_HSERDY;
StartUpCounter++;
} while ((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
if ((RCC->CR & RCC_CR_HSERDY) != RESET)
HSEStatus = (uint32_t)0x01;
else
HSEStatus = (uint32_t)0x00;
if (HSEStatus == (uint32_t)0x01)
{
FLASH->ACR |= FLASH_ACR_PRFTBE;
FLASH->ACR &= (uint32_t)((uint32_t)~FLASH_ACR_LATENCY);
FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_0;
RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;
RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;
RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV1;
RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
RCC->CFGR |= (uint32_t)RCC_CFGR_SW_HSE;
while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x04) { }
}
}
/* --- HAL库等价 --- */
static void SetSysClockToHSE(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
HAL_RCC_OscConfig(&RCC_OscInitStruct);
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK |
RCC_CLOCKTYPE_SYSCLK |
RCC_CLOCKTYPE_PCLK1 |
RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSE;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0);
}
static void SetSysClockTo24(void)
{
__IO uint32_t StartUpCounter = 0, HSEStatus = 0;
RCC->CR |= ((uint32_t)RCC_CR_HSEON);
do
{
HSEStatus = RCC->CR & RCC_CR_HSERDY;
StartUpCounter++;
} while ((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
if ((RCC->CR & RCC_CR_HSERDY) != RESET)
HSEStatus = (uint32_t)0x01;
else
HSEStatus = (uint32_t)0x00;
if (HSEStatus == (uint32_t)0x01)
{
FLASH->ACR |= FLASH_ACR_PRFTBE;
FLASH->ACR &= (uint32_t)((uint32_t)~FLASH_ACR_LATENCY);
FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_0;
RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;
RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;
RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV1;
RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLMULL));
RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLXTPRE_HSE_Div2 | RCC_CFGR_PLLMULL6);
RCC->CR |= RCC_CR_PLLON;
while ((RCC->CR & RCC_CR_PLLRDY) == 0) { }
RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL;
while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x08) { }
}
}
/* --- HAL库等价 --- */
static void SetSysClockTo24(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL6;
HAL_RCC_OscConfig(&RCC_OscInitStruct);
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_ALL;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0);
}
static void SetSysClockTo36(void)
{
__IO uint32_t StartUpCounter = 0, HSEStatus = 0;
RCC->CR |= ((uint32_t)RCC_CR_HSEON);
do
{
HSEStatus = RCC->CR & RCC_CR_HSERDY;
StartUpCounter++;
} while ((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
if ((RCC->CR & RCC_CR_HSERDY) != RESET)
HSEStatus = (uint32_t)0x01;
else
HSEStatus = (uint32_t)0x00;
if (HSEStatus == (uint32_t)0x01)
{
FLASH->ACR |= FLASH_ACR_PRFTBE;
FLASH->ACR &= (uint32_t)((uint32_t)~FLASH_ACR_LATENCY);
FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_1;
RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;
RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;
RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV1;
RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLMULL));
RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLXTPRE_HSE_Div2 | RCC_CFGR_PLLMULL9);
RCC->CR |= RCC_CR_PLLON;
while ((RCC->CR & RCC_CR_PLLRDY) == 0) { }
RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL;
while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x08) { }
}
}
/* HAL库等价版 */
static void SetSysClockTo36(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
HAL_RCC_OscConfig(&RCC_OscInitStruct);
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_ALL;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1);
}
static void SetSysClockTo48(void)
{
__IO uint32_t StartUpCounter = 0, HSEStatus = 0;
RCC->CR |= ((uint32_t)RCC_CR_HSEON);
do
{
HSEStatus = RCC->CR & RCC_CR_HSERDY;
StartUpCounter++;
} while ((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
if ((RCC->CR & RCC_CR_HSERDY) != RESET)
HSEStatus = (uint32_t)0x01;
else
HSEStatus = (uint32_t)0x00;
if (HSEStatus == (uint32_t)0x01)
{
FLASH->ACR |= FLASH_ACR_PRFTBE;
FLASH->ACR &= (uint32_t)((uint32_t)~FLASH_ACR_LATENCY);
FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_1;
RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;
RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;
RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2;
RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLMULL));
RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLMULL6);
RCC->CR |= RCC_CR_PLLON;
while ((RCC->CR & RCC_CR_PLLRDY) == 0) { }
RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL;
while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x08) { }
}
}
/* HAL库等价版 */
static void SetSysClockTo48(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL6;
HAL_RCC_OscConfig(&RCC_OscInitStruct);
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_ALL;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1);
}
static void SetSysClockTo56(void)
{
__IO uint32_t StartUpCounter = 0, HSEStatus = 0;
RCC->CR |= ((uint32_t)RCC_CR_HSEON);
do
{
HSEStatus = RCC->CR & RCC_CR_HSERDY;
StartUpCounter++;
} while ((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
if ((RCC->CR & RCC_CR_HSERDY) != RESET)
HSEStatus = (uint32_t)0x01;
else
HSEStatus = (uint32_t)0x00;
if (HSEStatus == (uint32_t)0x01)
{
FLASH->ACR |= FLASH_ACR_PRFTBE;
FLASH->ACR &= (uint32_t)((uint32_t)~FLASH_ACR_LATENCY);
FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_2;
RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;
RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;
RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2;
RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLMULL));
RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLMULL7);
RCC->CR |= RCC_CR_PLLON;
while ((RCC->CR & RCC_CR_PLLRDY) == 0) { }
RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL;
while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x08) { }
}
}
/* HAL库等价版 */
static void SetSysClockTo56(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL7;
HAL_RCC_OscConfig(&RCC_OscInitStruct);
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_ALL;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2);
}
MCO(Microcontroller Clock Output)可将内部时钟从 PA8 引脚输出,供外部测量或作为其它芯片的时钟源。
/* 标准库版:PA8 输出 PLL/2 = 36 MHz */
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
RCC_MCOConfig(RCC_MCO_PLLCLK_DIV2); /* MCO = PLL / 2 */
/* 其他可选时钟源 */
// RCC_MCOConfig(RCC_MCO_HSI); /* MCO = HSI 8 MHz */
// RCC_MCOConfig(RCC_MCO_HSE); /* MCO = HSE 8 MHz */
// RCC_MCOConfig(RCC_MCO_SYSCLK); /* MCO = SYSCLK */
// RCC_MCOConfig(RCC_MCO_PLLCLK_DIV2);/* MCO = PLLCLK / 2 */
/* HAL库等价:PA8 输出 PLL/2 = 36 MHz */
GPIO_InitTypeDef GPIO_InitStruct = {0};
__HAL_RCC_GPIOA_CLK_ENABLE();
GPIO_InitStruct.Pin = GPIO_PIN_8;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
HAL_RCC_MCOConfig(RCC_MCO1SOURCE_PLLCLK, RCC_MCODIV_2);
// system_stm32f10x.c 中定义
uint32_t SystemCoreClock = 72000000;
// 用户代码可直接读取
OLED_ShowNum(1, 8, SystemCoreClock, 8); // 显示当前系统主频
如果程序运行中修改了时钟配置(比如降低主频进入低功耗),需要调用
SystemCoreClockUpdate()更新此变量。
RCC 通过三个寄存器组控制外设时钟的开关。使用时只需调用以下标准库函数:
| 总线 | 标准库函数 | HAL 宏 |
|---|---|---|
| APB2 | RCC_APB2PeriphClockCmd() |
__HAL_RCC_GPIOA_CLK_ENABLE() 等 |
| APB1 | RCC_APB1PeriphClockCmd() |
__HAL_RCC_TIM2_CLK_ENABLE() 等 |
| AHB | RCC_AHBPeriphClockCmd() |
__HAL_RCC_DMA1_CLK_ENABLE() 等 |
标准库示例:
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
HAL库示例:
__HAL_RCC_GPIOB_CLK_ENABLE(); /* APB2 — GPIOB 时钟使能 */
__HAL_RCC_TIM2_CLK_ENABLE(); /* APB1 — TIM2 时钟使能 */
__HAL_RCC_DMA1_CLK_ENABLE(); /* AHB — DMA1 时钟使能 */
__HAL_RCC_USART1_CLK_ENABLE(); /* APB2 — USART1 时钟使能 */
__HAL_RCC_ADC1_CLK_ENABLE(); /* APB2 — ADC1 时钟使能 */
__HAL_RCC_SPI1_CLK_ENABLE(); /* APB2 — SPI1 时钟使能 */
不能在初始化函数中关闭时钟后再开启,否则外设寄存器会丢失配置。
| APB1(36 MHz 最高) | APB2(72 MHz 最高) |
|---|---|
| TIM2, TIM3, TIM4, TIM5, TIM6, TIM7 | TIM1, TIM8 |
| USART2, USART3, USART4, USART5 | USART1 |
| SPI2, SPI3 | SPI1 |
| I2C1, I2C2 | GPIOA~GPIOC(部分) |
| PWR, BKP | AFIO, EXTI |
通过修改 system_stm32f10x.c 中的宏定义来改变 SYSCLK 频率,观察主循环运行快慢和 SystemCoreClock 的值。
int main(void)
{
OLED_Init();
OLED_ShowString(1, 1, "SYSCLK:");
OLED_ShowNum(1, 8, SystemCoreClock, 8);
while (1)
{
OLED_ShowString(2, 1, "Running");
Delay_ms(500);
OLED_ShowString(2, 1, " ");
Delay_ms(500);
}
}
OLED 上会显示当前的 SYSCLK 值(如 72000000)。注意修改主频后:
system_stm32f10x.c 中的 SetSysClock() 会自动处理)症状:某个外设(GPIO、定时器、USART 等)寄存器写不进去,功能异常。
排查:检查是否调用了对应的 RCC_xxxPeriphClockCmd() 开启了时钟。
原因:STM32 的外设默认时钟是关闭的(省电设计),开启前无法访问其寄存器。
运行 SystemCoreClock 不正确可能的原因:
system_stm32f10x.c 中的宏没有正确配置| APB1 分频 | APB1 时钟 | TIM 时钟源 |
|---|---|---|
| 1(不分频) | 72 MHz | 72 MHz |
| 2(分频) | 36 MHz | 72 MHz(×2 自动补偿) |
| 4 | 18 MHz | 36 MHz(×2) |
| 8 | 9 MHz | 18 MHz(×2) |
APB1 定时器(TIM2~TIM7)时钟 = APB1 ×2 仅当 APB1 分频系数 ≠ 1 时成立。调试定时器频率时要注意这一点。