一、实验背景与目的
上一节课中,我们已经学习了如何使用外部高速时钟 HSE(High Speed External)作为系统时钟源,并通过 MCO(Microcontroller Clock Output)输出信号来验证时钟配置是否正确。
本节我们将继续深入学习:
如何使用内部高速时钟 HSI(High Speed Internal)配置系统时钟,并通过 MCO 输出验证系统频率。
二、HSI 的原理回顾
HSI 是 STM32 内部自带的高速 RC 振荡器(通常为 8 MHz),不依赖外部晶振。它启动速度快,但精度略低,一般用于:
-
节省成本或无外部晶振时;
-
在调试、测试阶段使用;
-
或在低功耗快速启动应用中。
HSI 可直接作为系统时钟源,也可以经过 除 2 后作为 PLL 输入源,经倍频后生成更高频率。
例如:
HSI = 8 MHz
HSI / 2 = 4 MHz
若倍频因子 = 16 → 系统时钟 = 4 MHz × 16 = 64 MHz
三、代码分析与实现步骤
1. 头文件 bsp_rcclkconfig.h
#ifndef __BSP_RCCLKCONFIG_H
#define __BSP_RCCLKCONFIG_H
#include "stm32f10x.h"
void HSE_SetSysClk(uint32_t RCC_PLLMul_x);
void MCO_GPIO_Config(void);
void HSI_SetSysClk(uint32_t RCC_PLLMul_x);
#endif
这里声明了三个函数:
HSE_SetSysClk():上节课的外部晶振配置函数。
MCO_GPIO_Config():配置 PA8 为时钟输出引脚。
HSI_SetSysClk():本节新增的函数,用于用 HSI 配置系统时钟。
2. 主函数 main.c
int main(void)
{
HSI_SetSysClk(RCC_PLLMul_16); // 使用HSI × 16 = 64MHz
MCO_GPIO_Config(); // 配置MCO输出引脚
RCC_MCOConfig(RCC_MCO_SYSCLK); // 输出系统时钟到PA8
LED_GPIO_Config(); // 初始化LED
while(1)
{
LED_G(OFF);
Delay(0xFFFFF);
LED_G(ON);
Delay(0xFFFFF);
}
}
程序逻辑讲解:
-
HSI_SetSysClk()使用内部时钟 HSI 作为 PLL 输入,倍频后配置系统时钟为目标频率(例:64 MHz)。
-
MCO_GPIO_Config()配置 PA8 为复用推挽输出,用于输出时钟信号。
-
RCC_MCOConfig(RCC_MCO_SYSCLK)将系统时钟源(SYSCLK)输出到 MCO 引脚(PA8),以便用示波器测量。
-
LED_GPIO_Config()与循环闪灯通过 LED 闪烁的频率变化,粗略观察系统时钟的快慢。
3. bsp_rcclkconfig.c 的实现逻辑
void HSI_SetSysClk(uint32_t RCC_PLLMul_x)
{
__IO uint32_t HSIStatus;
RCC_DeInit(); // 复位RCC寄存器
RCC_HSICmd(ENABLE); // 使能HSI
HSIStatus = RCC->CR & RCC_CR_HSIRDY; // 判断HSI是否稳定
if(HSIStatus == RCC_CR_HSIRDY) // 若稳定则配置系统时钟
{
FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
FLASH_SetLatency(FLASH_Latency_2);
RCC_HCLKConfig(RCC_SYSCLK_Div1);
RCC_PCLK1Config(RCC_HCLK_Div2);
RCC_PCLK2Config(RCC_HCLK_Div1);
RCC_PLLConfig(RCC_PLLSource_HSI_Div2, RCC_PLLMul_x); // HSI/2 × 倍频
RCC_PLLCmd(ENABLE);
while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET); // 等待PLL稳定
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); // 切换系统时钟源
while(RCC_GetSYSCLKSource() != 0x08); // 等待切换完成
}
else
{
/* 如果HSI启动失败,可以在这里加入错误处理 */
}
}
代码逻辑拆解:
| 步骤 | 动作 | 说明 |
|---|---|---|
| ① | RCC_DeInit() |
将 RCC 寄存器恢复到复位状态,防止旧配置干扰。 |
| ② | RCC_HSICmd(ENABLE) |
开启内部 8 MHz RC 振荡器。 |
| ③ | RCC->CR & RCC_CR_HSIRDY |
检查 HSI 是否准备就绪。 |
| ④ | FLASH_SetLatency() |
调整 Flash 等待周期,适应高频访问速度。 |
| ⑤ | RCC_PLLConfig(RCC_PLLSource_HSI_Div2, RCC_PLLMul_x) |
设置 PLL 源为 HSI/2,并指定倍频因子。 |
| ⑥ | RCC_PLLCmd(ENABLE) |
启动 PLL 并等待其锁定(稳定)。 |
| ⑦ | RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK) |
将系统时钟切换到 PLL 输出。 |
| ⑧ | RCC_GetSYSCLKSource() |
验证切换成功。 |
四、使用 MCO 输出验证时钟
1. 配置 GPIO(PA8)
void MCO_GPIO_Config()
{
GPIO_InitTypeDef GPIO_InitStruct;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_8;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStruct);
}
PA8 是 MCO 引脚(可输出 SYSCLK、HSI、HSE、PLLCLK/2 等信号)。
这里配置为复用推挽输出模式,以驱动示波器或外部电路。
2. 输出时钟信号
RCC_MCOConfig(RCC_MCO_SYSCLK);
此函数将 系统时钟(SYSCLK) 输出到 PA8 引脚。
若想输出 HSI,可改为
RCC_MCOConfig(RCC_MCO_HSI);若想输出 PLLCLK/2,可改为
RCC_MCOConfig(RCC_MCO_PLLCLK_Div2)。
五、实验现象与验证
| 配置 | 理论频率 | 实际测量(示波器) | 现象 |
|---|---|---|---|
HSE_SetSysClk(RCC_PLLMul_9) |
72 MHz | ≈ 72 MHz | LED闪烁正常 |
HSI_SetSysClk(RCC_PLLMul_16) |
64 MHz | ≈ 64 MHz | LED闪烁略慢 |
HSI_SetSysClk(RCC_PLLMul_12) |
48 MHz | ≈ 48 MHz | LED闪烁更慢 |
若测得的频率与预期一致,则系统时钟配置成功。
示波器应接地良好,并断开蜂鸣器跳帽(PA8连接蜂鸣器会影响波形)。
六、实验总结
通过本节实验,我们学会了:
-
如何使用 HSI (内部时钟)通过 PLL 倍频配置系统时钟;
-
如何通过 MCO 输出验证系统时钟频率;
-
理解了固件库函数
RCC_HSICmd、RCC_PLLConfig、RCC_MCOConfig的配合使用; -
掌握了调试与验证时钟系统的基本方法。