stm32入门篇(6)

启动文件的源码解读不是很难,我们来接着看stm32的时钟配置

关键就是这个图,这个图理解了基本对时钟模块就有了比较好的了解了。

序号 模块名称(概念) 主要功能 / 作用 关键输入 关键输出与范围 相关寄存器位(典型) 备注 / 常见用法
外部高速振荡器 HSE 及前分频 接入 4--16 MHz 外部晶振或时钟信号,并可先 /2 作为 PLL 输入 OSC_IN/OSC_OUT 外部晶振;或外部时钟 HSECLK(原始外部时钟);HSECLK/2(经 PLLXTPRE) RCC_CR.HSEONHSEBYP 使能/旁路;RCC_CFGR.PLLXTPRE 选择是否 /2 常见:外部 8 MHz 晶振,给 PLL 提供 8 MHz 或 4 MHz 输入
PLL 源选择开关 PLLSRC 在 HSI/2 与 HSE(或 HSE/2) 之间选择 PLL 的输入源 HSI/2(内部 8 MHz/2)、HSE 或 HSE/2(来自①) PLL 输入时钟 PLLCLK_IN RCC_CFGR.PLLSRC 一般为了精确频率,用 HSE;若不接晶振,可用 HSI/2
PLL 倍频器 PLLMUL 将 PLL 输入时钟做 ×2~×16 倍频,生成高频系统基准 PLLCLK_IN(来自②) PLLCLK_OUT = PLLCLK_IN × N;最大 72 MHz RCC_CFGR.PLLMULL[3:0] 典型:HSE=8 MHz,选择 ×9 → PLL 输出 72 MHz
系统时钟源选择 SW(SYSCLK 选择器) 在 HSI、HSE、PLLCLK 之间选择系统时钟 SYSCLK HSI、HSE、PLLCLK(来自③) SYSCLK(系统时钟,最大 72 MHz) RCC_CFGR.SW[1:0] 选择;SWS[1:0] 状态 复位默认 HSI;稳定后常切到 PLL 72 MHz 作为 SYSCLK
AHB 预分频器(HCLK 分频) 对 SYSCLK 做 /1、/2、...、/512 分频,得到 AHB 总线时钟 HCLK SYSCLK(来自④) HCLK = SYSCLK / (1,2,...,512) RCC_CFGR.HPRE[3:0] HCLK 给 CPU、DMA、AHB 外设;通常设为 /1,让 HCLK = 72 MHz
APB1 预分频器 将 HCLK 再分频,得到低速外设总线 APB1 的时钟 PCLK1(≤36 MHz) HCLK(来自⑤) PCLK1 = HCLK / (1,2,4,8,16),最大 36 MHz;若分频≠1,则某些定时器时钟再×2 RCC_CFGR.PPRE1[2:0] 典型:HCLK=72 MHz,PPRE1= /2 → PCLK1=36 MHz;TIM2--TIM7 定时器时钟会再 ×2 变回 72 MHz
APB2 预分频器 将 HCLK 分频,得到高速外设总线 APB2 的时钟 PCLK2(≤72 MHz) HCLK(来自⑤) PCLK2 = HCLK / (1,2,4,8,16),最大 72 MHz;分频≠1 时,对应定时器时钟再×2 RCC_CFGR.PPRE2[2:0] 常见:PPRE2 = /1,使 PCLK2 = 72 MHz,供 GPIO、ADC1/2 等高速外设使用

外部时钟源和内部时钟源:

图中黄色 ① 块(HSE OSC)对应的,就是外部高速时钟源

  • STM32 芯片上只提供振荡放大器 + 接口电路(在芯片里)。

  • 真正的"时钟产生器件"在芯片外面,典型有两种接法:

    1. 外部晶振 + 两个电容

      • 一颗 8 MHz 晶振焊在板子上,两端接到 STM32 的 OSC_IN / OSC_OUT

      • 晶振两端再各接一个小电容(10~30pF 左右)到地。

      • 这样由 STM32 内部的振荡放大器 + 板上的晶振 + 电容一起组成振荡器。

    2. 外部有源时钟模块

      • 比如一个"8 MHz 方波时钟模块",直接把输出接到 OSC_IN

      • 这时一般不再用 OSC_OUT,也不需要外接晶振。

不管哪种,产生基准频率的是板子上的器件,所以叫"外部时钟源"

  • HSI / LSI:在芯片"肚子里"的 RC,什么都不用接 → 内部时钟。

  • HSE / LSE:要在板子上焊"石英石头"(晶振)或有源模块 → 外部时钟。

  • 图上 HSE 块只是"接口 + 控制电路",真正的振荡元件在芯片外。

其他时钟源:

标号 模块名称(概念) 主要功能 / 作用 关键输入 关键输出与范围 相关寄存器位(典型) 备注 / 常见用法
A USB 时钟预分频器 给 USB 外设产生 48 MHz 的 USBCLK PLLCLK(来自 PLL 输出,一般 72 MHz) USBCLK = PLLCLK /1 或 /1.5(目标 48 MHz) RCC_CFGR.USBPRE 典型:PLL=72 MHz 时,USBPRE=0 → /1.5 得到 48 MHz;如果 PLL 配成 48 MHz,则可选 /1 直接送 USB
B Cortex 内核 / AHB 核心时钟域 以 HCLK 作为 Cortex-M3 内核、总线矩阵、存储器接口等的主时钟;并给 FCLK(内核运行时钟) HCLK(来自 AHB 预分频器⑤) FCLK(Cortex 核心时钟)、系统总线时钟(AHB) RCC_CFGR.HPREFLASH_ACR 等相关 一般把 HCLK 直接设为 72 MHz,这样 CPU、DMA、SRAM、Flash 等都以 72 MHz 跑;要注意 Flash 等待周期要配置正确
C ADC 时钟预分频器 将 APB2 总线时钟 PCLK2 再分频,给 ADC 产生合适的时钟 PCLK2(来自 APB2 预分频器⑦) ADCCLK = PCLK2 /2、/4、/6、/8,最大 14 MHz RCC_CFGR.ADCPRE[1:0] 典型:PCLK2=72 MHz 时,常选 /6 → 12 MHz,或 /8 → 9 MHz,保证 ≤14 MHz;ADCCLK 过高会影响转换精度/稳定性
D 低速时钟 / RTC / 独立看门狗时钟块 管理 LSE(外部 32.768kHz)、LSI(内部 40kHz)以及 HSE/128 等低速时钟,用于 RTC 和 IWDG LSE 晶振(板上 32.768 kHz)、LSI(40 kHz RC)、HSE 分频 RTCCLK(RTC 时钟)、IWDGCLK(独立看门狗时钟) RCC_BDCR.RTCSEL 选择 RTC 源;LSEON/LSERDYRCC_CSR.LSION 常见:RTC 用 LSE 外部 32.768k(时间更准,可掉电保持);如果板上没焊 LSE,就用 LSI 或 HSE/128;IWDG 一般固定用 LSI
E MCO(主时钟输出)模块 把某个内部时钟输出到 MCO 引脚(常是 PA8),方便测量或给外部芯片当时钟 可选源:HSI、HSE、SYSCLK、PLLCLK/2 等(不同系列略有差异) MCO 引脚上的时钟信号 RCC_CFGR.MCO[2:0] 调试时用得多:例如把 SYSCLK 输出到 MCO,用示波器测当前系统频率是否 72 MHz;也可用作给外部器件供时

容易混淆概念:

  • SYSCLK 是芯片系统总时钟;SysTick 是一个定时器,用 SYSCLK(或其分频)作为计时源,经常被 RTOS 用来当"系统滴答"。

  • RCC 是"时钟和复位管理模块";RTC 是"独立的日历/时间计时模块",通常用低速时钟、可掉电保持。

配置时钟实战:

cpp 复制代码
void HSE_SetSysClock(uint32_t pllmul)
2 {
3 __IO uint32_t StartUpCounter = 0, HSEStartUpStatus = 0;
4 
5 // 把 RCC 外设初始化成复位状态
6 RCC_DeInit();
7 
8 //使能 HSE,开启外部晶振,野火 STM32F103 系列开发板用的是 8M
9 RCC_HSEConfig(RCC_HSE_ON);
10 
11 // 等待 HSE 启动稳定
12 HSEStartUpStatus = RCC_WaitForHSEStartUp();
13 
14 // 只有 HSE 稳定之后则继续往下执行
15 if (HSEStartUpStatus == SUCCESS) {
16 //-----------------------------------------------------------------//
17 // 这两句是操作 FLASH 闪存用到的,如果不操作 FLASH,这两个注释掉也没影响
18 // 使能 FLASH 预存取缓冲区
19 FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
20 
21 // SYSCLK 周期与闪存访问时间的比例设置,这里统一设置成 2
22 // 设置成 2 的时候,SYSCLK 低于 48M 也可以工作,如果设置成 0 或者 1 的时候,
23 // 如果配置的 SYSCLK 超出了范围的话,则会进入硬件错误,程序就死了
24 // 0:0 < SYSCLK <= 24M
25 // 1:24< SYSCLK <= 48M
26 // 2:48< SYSCLK <= 72M
27 FLASH_SetLatency(FLASH_Latency_2);
28 //-----------------------------------------------------------------//
29 
30 // AHB 预分频因子设置为 1 分频,HCLK = SYSCLK
31 RCC_HCLKConfig(RCC_SYSCLK_Div1);
32 
33 // APB2 预分频因子设置为 1 分频,PCLK2 = HCLK
34 RCC_PCLK2Config(RCC_HCLK_Div1);
35 
36 // APB1 预分频因子设置为 1 分频,PCLK1 = HCLK/2
37 RCC_PCLK1Config(RCC_HCLK_Div2);
38 
39 //-----------------设置各种频率主要就是在这里设置-------------------//
40 // 设置 PLL 时钟来源为 HSE,设置 PLL 倍频因子
41 // PLLCLK = 8MHz * pllmul
42 RCC_PLLConfig(RCC_PLLSource_HSE_Div1, pllmul);
43 //-------------------------------------------------------------//
44 
45 // 开启 PLL
46 RCC_PLLCmd(ENABLE);
47 
48 // 等待 PLL 稳定
49 while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET) {
50 }
51 
52 // 当 PLL 稳定之后,把 PLL 时钟切换为系统时钟 SYSCLK
53 RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
54 
55 // 读取时钟切换状态位,确保 PLLCLK 被选为系统时钟
56 while (RCC_GetSYSCLKSource() != 0x08) {
57 }
58 } else {
59 // 如果 HSE 开启失败,那么程序就会来到这里,用户可在这里添加出错的代码处理
60 // 当 HSE 开启失败或者故障的时候,单片机会自动把 HSI 设置为系统时钟,
61 // HSI 是内部的高速时钟,8MHZ
62 while (1) {
63 }
64 }
65 }

代码里有关闪存的处理:

  • 这两行的意思是:打开 Flash 预取缓冲,并把 Flash 的访问等待周期设为 2,以配合 48--72MHz 的 SYSCLK,防止访问速度过快导致错误。

  • Flash 不像 GPIO 那样在 RCC 里有一个开关时钟位。

    它的"时钟"可以理解为紧跟系统总线时钟,一直在工作;你做的只是给它配置"访问时间参数"(Latency)和"预取功能"。

这里就得说一下smt32的内存分布了:

项目 FLASH SRAM
类型 非易失性存储器(断电不丢) 易失性存储器(断电全没)
在 MCU 里的作用 相当于"硬盘 / 固态盘":放程序、常量、出厂参数等 相当于"运行内存(RAM)":放变量、栈、运行时数据
典型地址(STM32F1) 0x0800 0000 开始 0x2000 0000 开始
上电后的用途 CPU 从 FLASH 里取指令执行(代码就在里面) 启动代码会把需要的全局/静态变量初始化到 SRAM,然后程序运行过程中读写这里
是否可写 可以,但要按"页擦除+写入",操作复杂且慢,次数有限 随时读写,字节/字对齐即可,速度快
读写速度 读比 SRAM 慢,需要设置 等待周期(Latency),频率越高 Latency 越多 读写都很快,和 CPU 主频接近
断电是否保存数据 ✅ 是,内容保存 ❌ 否,断电全部丢失
容量特点 容量通常比 SRAM 大(比如 64K、128K、256K...) 容量通常比 FLASH 小(比如 20K、32K...)
适合放什么 程序代码(.text)、只读常量(const)、初始化数据、少量配置参数 全局/局部变量、堆栈、运行时缓冲区(如串口缓存、数组、算法数据)
擦写寿命 有限(大约 1万~10万 次擦写级别) 理论上无限次读写(受电路寿命限制,但远大于 Flash)
写入代价 写/擦要走专门的 Flash 编程流程,期间可能会阻塞或不能从同一块执行代码 普通内存访问指令即可,无需特殊流程
典型用法类比 MCU 的"硬盘" MCU 的"内存条"

具体数据展示:

启动代码做的三件关键事:

  1. 设置主栈指针 MSP(指向 SRAM 顶部)

  2. 把 FLASH 里的 .data 初始值复制到 SRAM 的 .data

  3. .bss 区全部清零

相关推荐
q***064713 小时前
SocketTool、串口调试助手、MQTT中间件基础
单片机·嵌入式硬件·中间件
洋九八14 小时前
电路基础和 PCB 制作
单片机·嵌入式硬件·pcb工艺
qq_4017004115 小时前
RS485基本原理,电路、防雷、layout及设计要点
stm32·单片机
2401_8534482317 小时前
ESP8266蓝牙模块
stm32·蓝牙模块·esp8266
许商17 小时前
【stm32】【printf】
java·前端·stm32
LaoZhangGong12318 小时前
以太网HTTP数据包格式分析
c语言·stm32·网络协议·http·tcp·arp
云山工作室19 小时前
用于电动汽车的永磁同步电机调速系统建模与仿真(论文+)
stm32·单片机·嵌入式硬件·毕业设计·毕设
yuan1999719 小时前
AD7689 12位串行ADC驱动与应用
单片机·嵌入式硬件
磨十三20 小时前
MCU 时钟系统全解析:主时钟、PLL、分频与外设时钟门控
arm开发·单片机·嵌入式硬件
逐步前行20 小时前
Proteus 8.9(四)51单片机仿真
嵌入式硬件·51单片机·proteus