编写者:LCKFB-YZH
版本:v1.0
日期:2026-09-18
更新记录:
- v1.0(2026-09-18):完成 STM32F407 时钟源、PLL、总线分频、CubeMX 配置、HAL/寄存器分析、MCO 测量与工程实践说明。
一 本章简介
单片机中的 CPU、存储器和外设都依赖时钟推进。时钟配置正确时,程序只是 正常运行 ;一旦配置错误,对时序不敏感的程序,比如闪灯也许还能正常工作,但现象却可能散落在整个系统中:串口波特率偏差、定时器周期不对、USB 无法枚举、SDIO 不稳定、HAL_Delay() 时间异常,甚至程序在切换系统时钟时直接停住。
STM32F407 的复位与时钟控制器(Reset and Clock Control,RCC)负责选择 HSI、HSE、LSI、LSE 等时钟源,配置锁相环(Phase-Locked Loop,PLL),再把时钟分配到内核、AHB、APB 和各个外设。本章既讲 CubeMX 怎么配,也会讲每一个时钟数字为什么成立、怎样独立验证。
1.1 学习目标
| 序号 | 学习目标 | 重要程度 |
|---|---|---|
| 1 | 能区分 HSI、HSE、LSI、LSE 和 PLL 的作用、精度与使用边界 | ⭐⭐⭐⭐⭐ |
| 2 | 能根据 HSE、PLLM、PLLN、PLLP、PLLQ 计算 SYSCLK 和 48 MHz 域 | ⭐⭐⭐⭐⭐ |
| 3 | 能从时钟树得到 HCLK、PCLK1、PCLK2 和 APB 定时器时钟 | ⭐⭐⭐⭐⭐ |
| 4 | 能在 CubeMX 中配置 168 MHz 与 84 MHz 两套合法时钟方案 | ⭐⭐⭐⭐⭐ |
| 5 | 能解释 Flash 等待周期、电压范围和最高 HCLK 之间的关系 | ⭐⭐⭐⭐⭐ |
| 6 | 能看懂 HAL_RCC_OscConfig()、HAL_RCC_ClockConfig() 及关键 RCC 寄存器 | ⭐⭐⭐⭐ |
| 7 | 能用软件读取、调试器、DWT 和 MCO/示波器完成分层验证 | ⭐⭐⭐⭐⭐ |
| 8 | 能说明动态切换、时钟故障和外设在途事务的工程风险 | ⭐⭐⭐⭐ |
1.2 阅读建议
- 初学者请先读第二节到第五节,完成 168 MHz 配置后,再按照本章的 7.1、7.2 节做软件验证。
- 已经会使用 CubeMX,可重点阅读第四章的 PLL/总线推导、第六章的安全切换和第八章的工程边界。
- 原理部分可以独立阅读;动手操作部分沿用【11】新建点灯工程【HAL 库版本】的 CubeMX + Keil MDK 工程,需要先能编译、下载并进入调试。
- 本章按“时钟源 → PLL 和总线 → CubeMX 配置 → Keil 读回 → 外部测量”推进。DWT、动态切频和 CSS 属于进阶内容,第一遍可以跳过。
1.3 本章采用的硬件条件
本章主示例采用天空星STM32F407核心板(高配版和青春版均支持):
- MCU:STM32F407VET6(青春版)、STM32F407VGT6(高配版)。
- 外部高速晶振:8 MHz。
- 供电:正常通过TYPE-C或者筑基学习板的电源入口来供电即可,也可以通过天空星的TYPE-C口旁边的2x5p排针接口接调试器来供电。
- 最高方案:SYSCLK/HCLK 168 MHz,PCLK1 42 MHz,PCLK2 84 MHz。
- 降频方案:SYSCLK/HCLK 84 MHz,PCLK1 42 MHz,PCLK2 84 MHz。
不同厂家的核心板可能使用不同频率的 HSE,如果你当前使用的不是我们的天空星STM32系列核心板的话,不能照抄下面的 PLL 数字。第一步永远是确认当前板卡原理图、BOM 与晶振丝印,并让 HSE_VALUE (晶振的实际值)与真实频率一致。
实验前复制一份第 11 章工程,保留可正常运行的原工程。本章用两份分别生成的工程比较 168 MHz 与 84 MHz,不在正在工作的外设上直接修改 PLL。软件分析以 STM32F4 HAL V1.8.4 为例;
1.4 第一遍只要回答四个问题
第一次读时钟树,不需要先背寄存器位。围绕当前方案回答下面四个问题,就能完成基本配置:
- 输入从哪里来:天空星板载 HSE 为 8 MHz,PLL 输入选择 HSE。
- PLL 怎样计算:
8 MHz ÷ 8 × 336 = 336 MHz,再经 PLLP/2得到 168 MHz,经 PLLQ/7得到 48 MHz。 - 系统始终和总线时钟各是多少:SYSCLK/HCLK 为 168 MHz,APB1
/4得到 42 MHz,APB2/2得到 84 MHz。 - 有没有越过约束:检查 PLL 输入/VCO 范围、AHB/APB 上限、48 MHz 域、供电条件和 Flash 等待周期,并确认 CubeMX 没有红色错误。
第一遍先完成 5.1 节的 168 MHz 配置,再用 7.1、7.2 节验证。PLLR 边界、动态切换、DWT 对比、CSS 和功耗策略可以第二遍再读,它们用于解释工程限制,不影响第一次建立正确时钟。
二 时钟到底在做什么
2.1 从节拍器理解同步数字电路
可以把时钟暂时理解成乐队的节拍器:组合逻辑在两个有效边沿之间完成计算,触发器在时钟边沿到来时锁存新状态。频率越高,单位时间内可推进的状态越多,但这不等于每条 C 语句固定占用相同周期。

这个比喻需要提前理解的知识是:Cortex-M4 有流水线和分支行为,STM32F407 的 Flash 接口还提供预取和缓存,访问存储器时可能遇到总线等待,外设也能并行工作。一条指令需要多少周期,要结合具体指令、存储器位置、总线竞争和编译结果分析。
2.2 频率、周期与误差
时钟频率 f 和周期 T 的关系是:
T = 1 / f例如 8 MHz 的理想周期为 125 ns,168 MHz 的理想周期约为 5.95 ns。这里的“周期”描述时钟边沿间隔,不是指一条程序语句执行时间。
晶振或振荡器误差常用 ppm(parts per million,百万分之一)表示。20 ppm 对应相对误差 20 × 10^-6,不过最终系统误差还受温度、老化、负载电容、PCB 寄生和器件规格影响。实际工作中上应使用晶体厂商和 MCU 数据手册给出的条件, 温度对普通晶振的影响很大,假如你的产品工作温度变化很大,又对时钟精度要求很高的话,可以考虑采用温补晶振。
2.3 为什么外设也需要时钟
CPU 时钟只负责内核执行,外设还需要自己的总线时钟和功能时钟:
- GPIO 寄存器接口挂在 AHB1;关闭 GPIOB 时钟后,访问该外设不再具有正常工作条件。
- USART 的波特率发生器根据外设时钟分频,PCLK 变化会影响波特率计算。
- 通用定时器要根据 APB 定时器时钟计数,不一定等于 PCLK。
- USB OTG FS、随机数发生器和 SDIO 使用 PLL 提供的专用时钟域,对频率有特殊要求和约束,比如USB就得48M。
- RTC 可从 LSE、LSI 或分频后的 HSE 获得时钟,选择不同就会影响精度、低功耗和故障策略。
所以, CPU 能跑 不能证明整个时钟系统配置正确,毕竟我们的单片机是MCU,CPU只是其中一部分。
三 STM32F407 的时钟源
3.1 四个基础时钟源
| 时钟源 | 含义 | 典型用途 | 主要说明 |
|---|---|---|---|
| HSI | High-Speed Internal,高速内部时钟 | 复位默认系统时钟、启动与故障回退 | 无需外部器件,但精度和温漂不如外部晶振 |
| HSE | High-Speed External,高速外部时钟 | 高性能系统时钟、精度要求更高的应用 | 需要晶体/谐振器或外部时钟,PCB 与负载设计会影响起振 |
| LSI | Low-Speed Internal,低速内部 RC | 独立看门狗、低成本低速时钟 | 频率离散和温漂较大,不适合高精度计时 |
| LSE | Low-Speed External,低速外部时钟 | RTC 长期计时 | 常用 32.768 kHz 晶体,起振和 PCB 泄漏更敏感 |
复位后 HSI 为系统提供可用时钟,让软件有机会配置其他源。外部晶振是否存在、频率是多少,需要你自己去看你自己板子上的原理图或者BOM表,天空星目前全系列所用的 High-Speed External,高速外部时钟 都是8Mhz的,有一些其他友商的开发板所采用的HSE晶振是25Mhz,在开始配置工程前,一定要提前确认这一点。
3.2 HSE:本章使用的 8 MHz 外部晶振
DS8626 Rev 12 给出 STM32F405/407 HSE 晶体/陶瓷谐振器范围为 4~26 MHz。下面的表格同时给出了起振和负载设计的条件;5~25 pF 是外部电容的典型讨论范围,不是可以脱离晶振规格直接照抄的固定值,我们天空星在实际时, YXC(扬兴晶振)帮我们做了匹配测试,我们最终实际选择的是20pF的负载电容。

图源:DS8626 Rev 12,HSE oscillator characteristics。晶体负载应按 AN2867 Rev 24 的 Pierce 振荡器设计方法,结合晶体标称负载电容、PCB 与引脚寄生计算。
天空星核心板实际板载晶振的原理图

天空星核心板外部晶振的实际位置

【序号为1的是 8M 的高速外部晶振(High-Speed External,高速外部时钟),序号为2的是 32.768Khz 的是低速外部晶振(Low-Speed External,低速外部时钟)】
CAUTION
不要用手触摸晶体、短接 OSC 引脚或随意拆焊元件来“模拟故障”。这些做法不可控,可能引入静电、过压或硬件损坏,也不能形成可复现的测试结果。
3.3 HSI:启动和回退的重要资源
HSI 是芯片内部 16 MHz RC 振荡器。它不依赖外部晶体,适合复位启动、成本敏感或时钟故障回退。其频率会随电压和温度变化,精度条件应查 DS8626 Rev 12 的 HSI 特性表;所以说其实核心板就算不贴晶振也是可以正常启动的,除非你的程序里面明确配置了使用外部高速晶振。
3.4 LSE 与 LSI
32.768 kHz 等于 2^15 Hz,二进制分频 15 次即可得到 1 Hz,因此常用于 RTC。LSE 外部晶体通常精度更高,LSI 不需要外部器件且可供独立看门狗使用,但频率误差更大。
天空星核心板介绍列出的青春版预留 LSE 焊盘但未贴装,高配版配有 32.768 kHz 晶体,配套筑基学习板的焊接排针版本也已贴装了低速晶振。实际使用仍应核对手中硬件版本和焊接情况,因为我们的天空星STM32F407青春版卖的数量非常多,很有可能你手里的天空星板子就是没有焊接低速晶振的;
本章的 HSE/PLL 实验不依赖 LSE。目前我们只有天空星高配版和天空星焊接排针版是出厂就贴了外部低速晶振的,随天空星·筑基学习板赠送的那个天空星默认是焊接了低速晶振的焊接排针版。
3.5 PLL:倍频与分频网络
PLL 不会凭空产生时间基准,它以 HSE 或 HSI 为输入,通过 M、N、P、Q 参数得到多个输出。下面假设 PLLP 输出已被选为 SYSCLK:
fPLL_IN = fSOURCE / PLLM
fVCO_OUT = fPLL_IN × PLLN
fSYSCLK = fVCO_OUT / PLLP
fPLL48 = fVCO_OUT / PLLQ2
3
4
DS8626 Rev 12 的主 PLL 特性给出了输入、VCO 和输出范围。下图中的最小值、最大值必须结合完整条件使用,实际工程中绝对不要超频使用。

图源:DS8626 Rev 12,Table 36,Main PLL characteristics。此图为节选,完整续表和脚注见手册第 106~107 页:PLLM 由主 PLL 与 PLLI2S 共用;
配置时还要同时满足 RM0090 Rev 21 的寄存器约束:PLLM 为 2~63,PLLN 为 50~432,PLLP 只能为 2、4、6、8,PLLQ 为 2~15;分频后的 PLL 输入按 1~2 MHz 配置,VCO 输出为 100~432 MHz。参数各自合法只是第一步,它们组合后的频率也必须合法。图中的 PLL48 输出能力不能直接当作 USB、RNG 或 SDIO 的允许频率,外设限制见 4.3 节。
本章 168 MHz 方案:
HSE = 8 MHz
PLLM = 8 → fPLL_IN = 1 MHz
PLLN = 336 → fVCO_OUT = 336 MHz
PLLP = 2 → fSYSCLK = 168 MHz
PLLQ = 7 → fPLL48 = 48 MHz2
3
4
5
四 读懂 STM32F407 时钟树
4.1 官方时钟树

图源:RM0090 Rev 21,Figure 21。读图时从左向右追踪 【时钟源 → PLL/选择器 → SYSCLK → AHB/APB → 外设】 ,不要试图一次背下整张图,也没必要背,后面我们用STM32CubeMX来配置的时候会有图形化的界面能直接轻松理解的。
这幅原图有容易误读的标注:左上方连接独立看门狗的内部 32 kHz RC 应理解为 LSI;外部 32.768 kHz 那一路是 LSE 晶体振荡器,并非内部 RC。图中还画出了不适用于 STM32F407 的 PLL 分支,具体可配置字段要结合 4.5 节的寄存器定义。下面的简化图只保留本章实际使用的路径。
4.2 主系统时钟路径
本章 168 MHz 路径是:
flowchart TD
A["HSE 8 MHz"] --> B["PLLM /8\n1 MHz"]
B --> C["PLLN ×336\nVCO 336 MHz"]
C --> D["PLLP /2\nSYSCLK 168 MHz"]
D --> E["AHB /1\nHCLK 168 MHz"]
E --> F["APB1 /4\nPCLK1 42 MHz"]
E --> G["APB2 /2\nPCLK2 84 MHz"]
C --> H["PLLQ /7\nPLL48 48 MHz"]
HCLK 供给 AHB 总线、内核、存储器和 DMA。PCLK1/PCLK2 是 APB 外设寄存器接口时钟。CPU 的 168 MHz 不代表所有外设都以 168 MHz 工作。
4.2.1 初学者读图卡
面对任何一张时钟树,都可以从最终要使用的时钟反向检查,再沿箭头正向计算:
| 步骤 | 要找的对象 | 本章 168 MHz 示例 | 检查结果 |
|---|---|---|---|
| 1 | 最左侧输入源 | HSE 8 MHz | 来源与板上所贴晶振一致 |
| 2 | 中间倍频、分频 | /8 → ×336 → /2,另一路 /7 | VCO 为 336 MHz,PLL48 为 48 MHz |
| 3 | 系统时钟选择器 | PLLP 输出被选为 SYSCLK | SYSCLK 为 168 MHz |
| 4 | AHB/APB 分频 | AHB /1、APB1 /4、APB2 /2 | HCLK/PCLK1/PCLK2 为 168/42/84 MHz |
| 5 | 最右侧使用者 | CPU、GPIO、UART、定时器、USB/SDIO 等 | 逐项检查总线上限和专用时钟要求 |
读图时要把【选择器】和【分频器】分开理解:选择器决定用哪一路,分频器决定这一路变成多少。只看最终数字而没有追踪路径,换时钟源后很容易沿用错误的计算。
比如我刚学 STM32 的时候,一直坚信自己用的是外部晶振,甚至还觉得板子上那颗晶振 功不可没 ,做出来的程序肯定时序非常准确。直到有一天,我手欠把外部晶振拆了下来——上电,下载,运行。板子:一切正常。我:??? 查了半天配置才发现,原来从始至终开发板上的 MCU 用的都是内部晶振。那颗外部晶振在板子上兢兢业业待了这么久,唯一的工作大概就是:给我提供情绪价值。
4.3 AHB、APB1 与 APB2
高级高性能总线(Advanced High-performance Bus,AHB)连接内核、存储器及高速外设;高级外设总线(Advanced Peripheral Bus,APB)则承载相应的外设寄存器接口。SYSCLK 是系统选择器的输出,经过 AHB 分频得到 HCLK,再经过 APB 分频得到 PCLK1/PCLK2。
| 时钟域 | 本章频率 | 常见资源 | STM32F407 约束重点 |
|---|---|---|---|
| HCLK/AHB | 168 MHz | Cortex-M4、存储器、DMA、GPIO 总线 | 最高 168 MHz |
| PCLK1/APB1 | 42 MHz | USART2/3、I2C、CAN、TIM2~7 等 | 最高 42 MHz |
| PCLK2/APB2 | 84 MHz | USART1/6、ADC、SPI1、TIM1/8、SDIO 寄存器接口等 | 最高 84 MHz |
| PLL48CLK | 48 MHz | USB OTG FS、RNG、SDIO 功能时钟路径 | USB FS 要求准确 48 MHz |
SDIO 的寄存器接口位于 APB2,同时其功能时钟来自 48 MHz 域。把 SDIO 简单归为 AHB,或只看到 APB2 就忽略 PLL48,都会漏掉一半约束。
“48 MHz 域”,不表示三个外设都必须始终使用精确的 48 MHz。按 RM0090 Rev 21 的 PLLQ 字段说明,USB OTG FS 需要符合精度要求的 48 MHz(所以用到USB功能的时候最好要用外部高速晶振),RNG 和 SDIO 则允许使用低于或等于 48 MHz 的 PLLQ 输出;本章统一保留 48 MHz,方便后续实验。还要分别检查:
- RNG 有独立的时钟错误检测;当
fRNG_CLK < fHCLK/16时会报告时钟错误,不能无限降低其输入频率。 - SDIO 到卡片的
SDIO_CK还受内部时钟分频控制;APB2 必须满足fPCLK2 ≥ 3/8 × fSDIO_CK,卡片初始化与传输阶段也有各自要求。 - ADC 虽位于 APB2,但还要经过 ADC 预分频。本章 PCLK2 为 84 MHz。
这些条件分别见 RM0090 Rev 21 的 RCC、RNG、SDIO 与 ADC 章节。CubeMX 会结合已启用的外设检查约束。
4.4 APB 定时器为什么可能比 PCLK 快一倍
对 STM32F407 的 APB 定时器:
- APB 预分频为 1 时,定时器时钟等于对应 PCLK。
- APB 预分频不为 1 时,定时器时钟等于对应 PCLK 的 2 倍。
因此在 168 MHz 方案中:
PCLK1 = 42 MHz,APB1 定时器时钟 = 84 MHz
PCLK2 = 84 MHz,APB2 定时器时钟 = 168 MHz2
HAL_RCC_GetPCLK1Freq() 返回的是 PCLK1,不会替你自动变成某个定时器的输入频率。配置 PWM、输入捕获和周期定时器时,要先确认它位于哪条 APB 总线及当前预分频值。
4.5 时钟树中的 /R 不是 STM32F407 的可配置 PLLR
官方时钟树的 PLL 方框中能看到 /R,但 STM32F407 的 RCC_PLLCFGR 位 21:18 在 RM0090 Rev 21 中明确为 Reserved。芯片可配置的主 PLL 字段是 PLLM、PLLN、PLLP、PLLQ,没有可用 PLLR 输出。


4.6 Flash 等待周期
CPU 提升到高频后,片上 Flash 无法在每个 HCLK 周期内直接完成读取,需要在 FLASH_ACR.LATENCY 中设置等待周期(Wait State,WS)。先根据 VDD 范围和 HCLK 查 Flash 等待周期,再检查内部电压调节等级允许的最高主频。

图源:RM0090 Rev 21,Table 11。在 2.7~3.6 V、HCLK 168 MHz 条件下需要 5 WS;HCLK 84 MHz 时对应 2 WS。
WARNING
升频前必须先把 Flash 等待周期提高到足够值;降频后才能降低等待周期。顺序错误可能在切换瞬间造成取指失败。
4.7 外设时钟门控
RCC 的 AHB1ENR、APB1ENR、APB2ENR 等寄存器控制大量外设接口时钟。关闭不用的外设时钟可以减少动态功耗,但并不会形成软件访问保护,也不等同于复位外设;重新使用前仍需要确认状态并完成必要初始化。
五 使用 CubeMX 配置两套时钟
5.1 168 MHz 性能方案
打开复制后的 .ioc 文件,按下面的顺序操作:
- 在 Pinout & Configuration → System Core → RCC 中,将 HSE 设为 Crystal/Ceramic Resonator。天空星使用无源晶体,不能选择面向外部有源时钟输入的 Bypass。

- 打开 Clock Configuration,把 HSE 输入设为
8 MHz,PLL Source 选择 HSE,系统时钟选择器选择 PLLCLK。
- 按下表设置 M/N/P/Q 和 AHB/APB 分频【Q可以先不填,没用到的话是无法配置的】。核对最终输出,不只看 SYSCLK 一格是否为 168 MHz。

- 在 Project Manager 中保持第 11 章的 MDK-ARM 工具链设置,保留用户代码后生成工程。用 Keil 打开生成的
.uvprojx,重新编译并下载。
先按表核对生成参数,第 7 节再给出代码放置位置和 Keil 调试方法。CubeMX 的无错误提示只说明它识别出的约束成立,不能代替硬件供电、晶振和实测检查。
配置参数:
| 项目 | 设置 |
|---|---|
| HSE | 8 MHz |
| PLLM / PLLN / PLLP / PLLQ | 8 / 336 / 2 / 7 |
| SYSCLK / HCLK | 168 / 168 MHz |
| APB1 / PCLK1 | /4 / 42 MHz |
| APB2 / PCLK2 | /2 / 84 MHz |
| Flash latency | 5 WS(2.7~3.6 V 条件) |
| Voltage scale | Scale 1 |
5.2 84 MHz 降频方案
为了保持 PLL48CLK 为 48 MHz,可以保留 VCO 336 MHz,只把 PLLP 从 2 改为 4:
| 项目 | 设置 |
|---|---|
| PLLM / PLLN / PLLP / PLLQ | 8 / 336 / 4 / 7 |
| SYSCLK / HCLK | 84 / 84 MHz |
| APB1 / PCLK1 | /2 / 42 MHz |
| APB2 / PCLK2 | /1 / 84 MHz |
| PLL48CLK | 48 MHz |
| Flash latency | 2 WS(2.7~3.6 V 条件) |
| Voltage scale | Scale 1(保持不变) |
再次复制已能运行的 168 MHz 工程,将 PLLP 改为 /4、APB1 改为 /2、APB2 改为 /1,再生成、编译和下载。生成代码应使用 RCC_PLLP_DIV4、RCC_HCLK_DIV2、RCC_HCLK_DIV1 和 FLASH_LATENCY_2;不要只在 main.c 中手改一个常量后又让 CubeMX 覆盖。
这套方案保持两个 PCLK 不变,但内核、AHB 和 APB2 定时器时钟会变化:APB1 定时器仍为 84 MHz,APB2 定时器从 168 MHz 变为 84 MHz。它适合比较 CPU/HCLK 对执行时间的影响,不代表所有外设都完全不受影响。

5.3 用错误配置学习约束
可以在复制的工程中,把 168 MHz 方案的 APB1 分频临时改为 /2,观察 PCLK1 达到 84 MHz 时的超限提示,然后恢复 /4。不要把错误配置下载到开发板,也不要为制造现象绕过工具校验。

5.4 168 MHz 的生成代码
CubeMX 生成的 SystemClock_Config() 位于 main.c,由 main() 在 HAL_Init() 之后、外设初始化之前调用。下面用于核对生成结果,不要在已有工程里再添加同名函数。
/**
* @brief System Clock Configuration
* @retval None
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
/** Configure the main internal regulator output voltage
*/
__HAL_RCC_PWR_CLK_ENABLE();
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
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.PLLM = 8;
RCC_OscInitStruct.PLL.PLLN = 336;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = 4;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB buses clocks
*/
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;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK)
{
Error_Handler();
}
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
SystemClock_Config() 及其中的 RCC 参数由 CubeMX 管理,修改入口是 .ioc。在 Keil 中还应确认 stm32f4xx_hal_conf.h 的有效配置为 HSE_VALUE = 8000000U;若编译选项定义了同名宏,还要核对覆盖关系。HSE_VALUE 用于软件计算,它不会改变板上的晶振频率,也不会让未起振的 HSE 恢复工作。
5.5 配置完成后的三分钟自检
生成代码前,按顺序核对下表。任意一项不一致,都先留在 CubeMX 中修正,不要带着红色错误生成或下载。
| 检查项 | 168 MHz 方案应为 | 常见误区 |
|---|---|---|
| HSE 模式与输入值 | Crystal/Ceramic Resonator,8 MHz | 有源时钟才使用 Bypass;不能只改数字而忽略板上器件 |
| PLL 参数 | M/N/P/Q = 8/336/2/7 | 把 PLLP 编码值当作实际除数,或漏查 PLLQ |
| SYSCLK/HCLK | 168/168 MHz | 只看 SYSCLK,忘记 AHB 仍可分频 |
| PCLK1/PCLK2 | 42/84 MHz | APB1 超过 42 MHz,或把两条 APB 混为一条 |
| 48 MHz 域 | 48 MHz | CPU 能运行不代表 USB、RNG、SDIO 的功能时钟正确,本节中可以不配置 |
| APB 定时器时钟 | 84/168 MHz | 直接把 PCLK 当作预分频不为 1 时的定时器时钟 |
六 HAL 与寄存器中的时钟配置
6.1 两个核心 HAL 函数
本节对应STM32F4 HAL 官方源码中的 stm32f4xx_hal_rcc.c。HAL V1.8.4 的两个入口为:
HAL_StatusTypeDef HAL_RCC_OscConfig(const RCC_OscInitTypeDef *RCC_OscInitStruct);
HAL_StatusTypeDef HAL_RCC_ClockConfig(const RCC_ClkInitTypeDef *RCC_ClkInitStruct,
uint32_t FLatency);2
3
两个函数都要求配置结构体中的字段有效;本章先调用 HAL_Init() 建立可用的 HAL 时间基准,再调用它们。返回 HAL_OK 表示本次接口操作完成,HAL_ERROR 表示状态或配置不允许,HAL_TIMEOUT 表示等待超时。HAL 不会替应用自动证明所有外设频率都合法。
HAL_RCC_OscConfig() 负责振荡器与 PLL:
- 打开或关闭 HSE、HSI、LSE、LSI。
- 等待对应 Ready 标志,并带超时处理。
- 在允许的状态下配置 PLLM/N/P/Q。
- 等待 PLL 锁定。
HAL_RCC_ClockConfig() 负责系统和总线:
- 配置 AHB、APB1、APB2 分频。
- 处理 Flash latency 的安全更新顺序。
- 选择 HSI、HSE 或 PLL 为 SYSCLK,并等待 SWS 确认。
- 更新
SystemCoreClock。 - 重新初始化 HAL Tick,使其继续保持配置的 Tick 周期。
| 配置字段或操作 | 对应寄存器 | 阅读时关注什么 |
|---|---|---|
HSEState、PLLState | RCC_CR | ON 位发起操作,RDY 位反映是否就绪 |
PLLM/N/P/Q、PLLSource | RCC_PLLCFGR | 只能在允许的停用状态下修改 |
SYSCLKSource | RCC_CFGR.SW/SWS | SW 是请求,SWS 才是实际切换结果 |
| AHB/APB 分频 | RCC_CFGR.HPRE/PPRE1/PPRE2 | 中间切换状态也不能超限 |
FLatency | FLASH_ACR.LATENCY | 升频前增加,降频后减少,并读回确认 |
V1.8.4 在同时配置 HCLK 和 APB 分频时,会先临时提高 APB 分频系数,再完成目标配置,避免切换途中过频;最后更新 SystemCoreClock 并调用 HAL_InitTick()。该版本没有把 HAL_InitTick() 的返回值继续传给调用者,所以还应实际检查 Tick,尤其是自行替换了 HAL 时间基准时。
因此,使用正确 HAL 接口从 168 MHz 改为 84 MHz 后,HAL_Delay(500) 仍应接近 500 ms,他不会因为我们配置的时钟而改变,其内部会自动计算。
6.2 关键寄存器
RCC 的基地址为 0x40023800,下表偏移均相对该地址:
| 寄存器 | RCC 偏移 | 复位值 | 访问属性与关注内容 |
|---|---|---|---|
RCC_CR | 0x00 | 0x00000083 | ON 等控制位可读写,RDY 状态位只读;还包含 CSS 控制 |
RCC_PLLCFGR | 0x04 | 0x24003010 | 配置字段可读写,但修改有 PLL 状态限制 |
RCC_CFGR | 0x08 | 0x00000000 | SW/分频/MCO 等字段可读写,SWS 只读 |
RCC_AHB1ENR | 0x30 | 0x00100000 | 已定义的时钟使能位可读写;GPIO、DMA 等 |
RCC_APB1ENR | 0x40 | 0x00000000 | 已定义的 APB1 时钟使能位可读写 |
RCC_APB2ENR | 0x44 | 0x00000000 | 已定义的 APB2 时钟使能位可读写 |
寄存器偏移、复位值和字段均应以 RM0090 Rev 21 当前修订为准。保留位必须保持复位值,不能照搬其他 STM32 型号的宏或位图。
手写代码时不能把整个寄存器当作任意可写变量。例如对 RCC_CFGR 做读—改—写(Read-Modify-Write,RMW)时,另一个中断或任务也改它就可能丢失更新;时钟配置应由同一条受控路径负责。初始化期间先完成时钟配置,再启动依赖它的中断、DMA 和任务。
6.3 安全切换时钟的顺序
PLL 正在作为 SYSCLK 时,不能直接关闭 PLL 或改写其配置。完整的动态切换至少要考虑:
flowchart TD
A["确认目标频率、电压、Flash latency 与所有外设约束"] --> B["打开备用时钟源并等待 Ready,设置超时"]
B --> C["让在途 DMA/通信进入可切换状态"]
C --> D["通过 HAL 切到备用源并确认成功"]
D --> E["确认 SystemCoreClock 与 Tick 已更新,再关闭待重配 PLL"]
E --> F["确认共享源约束后修改 M/N/P/Q"]
F --> G["重新打开 PLL 并等待锁定"]
G --> H["通过 HAL 切到目标 PLL,按本次 HCLK 变化处理 Flash 和总线"]
H --> I["确认 SWS、SystemCoreClock 与 Tick"]
I --> J["重配并恢复依赖时钟的外设"]
切到临时 HSI 也算一次完整的系统时钟变更,不能等切回 PLL 后才更新软件频率和 Tick。每次调用 HAL_RCC_ClockConfig() 都要传入该阶段适用的 Flash 等待周期和总线分频,检查结果;HAL 会在升频前增加等待周期、降频后减少等待周期。关闭 PLL 后确认 PLLRDY 已清零,才能继续改写参数。
升频与降频顺序不同:
- 升频:先保证电压等级和 Flash latency,再提高 HCLK。
- 降频:先降低 HCLK,再降低 Flash latency 或电压等级。
UART、I2C、SPI、定时器、USB、SDIO、DMA 和 RTOS Tick 可能都依赖当前时钟。产品中动态切换不能只验证 CPU 还在执行,还要暂停或重配相关外设,并定义失败回退路径。
主 PLL 与音频 PLLI2S 共用 PLL 输入源和 PLLM;修改这两个共享参数前,也要处理 PLLI2S 的使用者并按 RM0090 Rev 21 要求停用相关 PLL。每一步超时都需要有效的计时来源,不能在关中断后仍假设依赖 SysTick 中断的 HAL_GetTick() 会继续增长。
WARNING
本章不提供脱离具体外设状态的“一键动态切频函数”。复制一个只改 RCC 的函数到正在通信的工程,可能造成帧损坏、DMA 超时和不可恢复的协议状态。先用 CubeMX 的静态 168 MHz/84 MHz 两个工程验证,再为具体产品设计切换事务。
七 分层验证时钟
本节的 Keil 实机读回、MCO 波形和两档功耗测量尚未完成,频率表中的数字为计算预期值;
7.1 软件读取频率
我们先完成不需要串口和示波器的验证。把四个变量放到 main.c 的 USER CODE BEGIN PV 区,把函数放到 USER CODE BEGIN 0 区;后者位于 main() 前,因此无需另写函数声明。
volatile uint32_t sysclk_hz = 0U;
volatile uint32_t hclk_hz = 0U;
volatile uint32_t pclk1_hz = 0U;
volatile uint32_t pclk2_hz = 0U;
static void Clock_ReadBack(void)
{
sysclk_hz = HAL_RCC_GetSysClockFreq();
hclk_hz = HAL_RCC_GetHCLKFreq();
pclk1_hz = HAL_RCC_GetPCLK1Freq();
pclk2_hz = HAL_RCC_GetPCLK2Freq();
}2
3
4
5
6
7
8
9
10
11
12

在 USER CODE BEGIN 2 区调用一次 Clock_ReadBack();。此时 SystemClock_Config() 已完成,再按下面的顺序观察:

- 编译并下载当前工程,进入 Keil 调试会话。
- 在
Clock_ReadBack()调用后的下一条可执行语句处下断点,点击运行;不要停在时钟初始化之前。 - 打开 Watch,加入
sysclk_hz、hclk_hz、pclk1_hz、pclk2_hz和SystemCoreClock,选择十进制显示。 - 分别下载两套工程,记录下表结果。变量保持为 0 时,先确认调用已执行,再排查时钟。
| 变量 | 168 MHz 工程预期值(Hz) | 84 MHz 工程预期值(Hz) |
|---|---|---|
sysclk_hz | 168000000 | 84000000 |
hclk_hz / SystemCoreClock | 168000000 | 84000000 |
pclk1_hz | 42000000 | 42000000 |
pclk2_hz | 84000000 | 84000000 |

7.2 调试器核对寄存器
建议观察:
RCC_CR:HSERDY、PLLRDY。RCC_PLLCFGR:PLLM=8、PLLN=336、PLLP 编码对应/2、PLLQ=7、PLLSRC=HSE。RCC_CFGR:SWS=PLL、HPRE=/1、PPRE1=/4、PPRE2=/2。FLASH_ACR:LATENCY=5,及工程选择的预取/缓存状态。
若 Keil 已载入对应器件的 SVD,可在外设寄存器视图展开 RCC 和 FLASH;若该视图不可用,可在 Watch 中查看 RCC->CR、RCC->PLLCFGR、RCC->CFGR 和 FLASH->ACR,按 RM0090 Rev 21 解码字段。只读取观察,不要通过调试窗口随意改写。切到 84 MHz 工程后,PLLP 应为 /4,PPRE1 为 /2,PPRE2 为 /1,LATENCY 为 2。

7.3 HAL_Delay() 与固定周期实验
正确的 168 MHz 和 84 MHz 工程中,HAL_Delay(500) 都应保持约 500 ms。要观察内核降频带来的差异,应测量固定数量 CPU 周期,而不是依赖已自动重配的 HAL Tick。
先沿用第 11 章的 LED 翻转循环,在两次翻转之间执行 HAL_Delay(500):相邻翻转约隔 500 ms,完整亮灭一轮约为 1 s。肉眼只能判断是否明显异常;要核对时间,需要在相应 LED GPIO 上用示波器或逻辑分析仪测量相邻边沿。默认 1 ms Tick 还会带来量化和函数执行开销,因此不要求每次正好等于 500.000 ms。
要观察固定工作量消耗的 CPU 周期,可以使用 Cortex-M4 的数据观察点与跟踪单元(Data Watchpoint and Trace,DWT)周期计数器。将下面两个函数放在 main.c 的 USER CODE BEGIN 0 区:
static void DWT_CycleCounter_Init(void)
{
CoreDebug->DEMCR |= CoreDebug_DEMCR_TRCENA_Msk;
DWT->CYCCNT = 0U;
DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk;
__DSB();
__ISB();
}
static uint32_t Measure_WorkCycles(void)
{
const uint32_t iterations = 10000U;
const uint32_t start = DWT->CYCCNT;
for (volatile uint32_t i = 0U; i < iterations; ++i)
{
__NOP();
}
return DWT->CYCCNT - start;
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
在 USER CODE BEGIN PV 区增加 volatile uint32_t work_cycles = 0U;,再在 USER CODE BEGIN 2 区加入:
DWT_CycleCounter_Init();
work_cycles = Measure_WorkCycles();2
在这两行执行完成之后暂停,查看 work_cycles。测量区间内保持自由运行,不单步、不打断点;DWT 在调试暂停状态下停止计数。其寄存器行为见 Armv7-M 架构参考手册的 DWT 说明。
循环的精确周期数受编译优化、Flash 等待、预取/缓存和中断影响。比较两套工程时保持工具链、优化级别和被测函数一致,并核对反汇编;记录实际周期数,不预设两次一定相等。对已测得的周期数 C,执行时间可按 t = C / HCLK 估算;只有周期数相同时,84 MHz 下的时间才是 168 MHz 下的两倍。这个估算仍依赖 HCLK 的正确性,不能作为独立的频率测量。
DWT 为 32 位计数器,无符号减法能处理一次跨零,但总测量间隔必须小于 2^32 个周期;在 168 MHz 下约为 25.6 s。当前短循环远小于这个范围。外部墙上时间需要另用 GPIO 包围被测代码并由仪器测量,不能把 Watch 刷新速度当作计时器。

7.4 用 PA8/MCO1 输出 8 MHz HSE
微控制器时钟输出(Microcontroller Clock Output,MCO)可以把内部时钟送到引脚,供示波器直接测量。本章选择 HSE 8 MHz 而不是输出 168 MHz,降低探测和信号完整性难度。
确认 HSE 已启动后,把以下调用放在 main.c 的 USER CODE BEGIN 2 区,位于 MX_GPIO_Init() 等生成的 GPIO 初始化之后,避免随后被其他初始化覆盖:
HAL_RCC_MCOConfig(RCC_MCO1,
RCC_MCO1SOURCE_HSE,
RCC_MCODIV_1);2
3
HAL V1.8.4 的 HAL_RCC_MCOConfig() 会使能相应 GPIO 时钟,并将 PA8 配为 AF0、推挽输出、无上下拉、Very High speed,再设置 MCO 源和分频。这里的 speed 控制 GPIO 输出边沿能力,不是选择 MCO 频率。
筑基学习板 V1.0 的PIN_OUT 原理图说明 PA8 从底板外扩排针 P2 第 34 脚引出;同排针的第 37、39 脚为 GND。单总线接口原理图也说明了它还连接 ONE_WIRE_DATA,并通过 R130(10 kΩ)上拉至 3.3 V。这里的 P2 指底板外扩排针,不是核心板连接器位号混用。
操作条件:
- 断电后取下 PA8 上的 DS18B20、DHT11 或其他单总线模块(如果你已经安装了的话),停用会再次配置 PA8 的驱动代码,本章代码不存在这个问题。
- 示波器探头接底板 P2-34/PA8,地夹接 P2-37、P2-39 或已经确认的数字 GND;不要夹到隔离侧地或电源脚,我这里为了方便就直接使用虚拟示波器【ADALM2000】了。
- 使用短地弹簧或尽量短的地线。
- 上电后预期测得约 8 MHz 方波,实际幅度和边沿以你自己所用的仪器记录为准。


7.5 四层验证分别证明什么
下面四层证据回答的问题不同,重要项目应至少完成软件、寄存器和外部测量三层交叉验证。
| 验证层 | 能够证明 | 不能单独证明 |
|---|---|---|
| HAL 频率读取 | 软件根据寄存器、常量与 SystemCoreClock 得到的频率是否符合预期 | 晶体实际频率、抖动和引脚波形质量 |
| RCC/FLASH 寄存器 | PLL、系统时钟选择、总线分频和 Flash latency 的实际配置位 | 外部晶体是否精确为标称频率 |
HAL_Delay() 与 DWT | Tick 重配后的时间行为,以及固定工作量消耗的内核周期 | 48 MHz 域和各外设时钟是否全部正确 |
| MCO 与示波器 | 指定内部时钟在真实硬件上的频率、幅度和边沿情况 | 未输出到 MCO 的其他分支是否都配置正确 |
如果四层结果互相矛盾,先记录原始数值和测试条件,再沿“时钟源 → PLL → 系统选择 → 总线分频 → 外设”逐级缩小范围。但是在实际工程中,最常见的时钟配错了,一般是通过看串口乱码发现的。
八 工程师需要知道的边界
8.1 时钟精度预算
通信能否稳定,取决于发送端和接收端总误差、采样结构、帧长度和协议容限。不能只说“HSE 比 HSI 准”,还要把晶体初始误差、温漂、老化、PLL 抖动和对端误差放进预算。USB、以太网、音频和精密测量应分别查对应外设与协议规范。
8.2 时钟安全系统
时钟安全系统(Clock Security System,CSS)可监测 HSE 故障。按 RM0090 Rev 21 的 7.2.7 节,检测到故障后硬件关闭 HSE,并通过不可屏蔽中断(Non-Maskable Interrupt,NMI)通知软件,同时向 TIM1/TIM8 的刹车输入发送故障事件。只有当 HSE 直接用作 SYSCLK,或经主 PLL 用作 SYSCLK 时,才涉及自动切换系统时钟到 HSI;本章的 168 MHz/84 MHz 方案都属于后一种。
HAL V1.8.4 提供 HAL_RCC_EnableCSS()、HAL_RCC_NMI_IRQHandler() 和弱回调 HAL_RCC_CSSCallback()。启用前必须打通故障处理路径:NMI_Handler() 调用 HAL_RCC_NMI_IRQHandler(),后者检测 CSS 标志、调用用户回调,并在回调返回后清除 CSS 中断标志。不清标志可能反复进入 NMI;不要只调用 EnableCSS 而留下默认的死循环 NMI 处理函数。
回退到 HSI 只表示 CPU 获得了备用时钟,不表示通信波特率、定时器、USB 和外部接口仍满足要求。硬件切换也不会自动调用 HAL_RCC_ClockConfig(),因此 SystemCoreClock 和 HAL Tick 可能仍保留旧配置。产品应在 CSS 回调中完成必要的输出保护和简短故障记录,再由受控路径决定降级运行或复位;降级运行需重新核对系统频率、Tick 和外设配置,不是说退回备用时钟后还继续执行程序,重要的是要记录这个异常。
NMI 中不能依赖较低优先级的 SysTick 中断推进时间,不能调用 HAL_Delay() 或执行等待 Tick 超时的阻塞恢复。若使用标志通知主循环,应明确只有谁写、谁清除;
8.3 时钟变更后的外设清单
每次修改时钟配置,至少复查:
- SysTick/RTOS Tick 与超时基准。
- USART 波特率、I2C/SPI 时序。
- 定时器、PWM、输入捕获与编码器。
- ADC 时钟和采样时间。
- USB、RNG、SDIO 的 48 MHz 域。
- DMA 正在传输的数据和外设握手。
- MCO、RTC、看门狗和低功耗唤醒源。
九 常见问题
9.1 程序卡在 HAL_RCC_OscConfig()
现象:进入 Error_Handler(),调试器显示 HSE 等待超时。
可能原因:板上没有对应晶振、RCC 模式选错、晶体未起振,或供电/焊接异常。若等待循环始终不返回,还要检查 HAL Tick 是否继续增长。
检查与解决:确认原理图和硬件版本;观察 HSERDY,检查是否误选 BYPASS,并区分卡在 HSE 就绪还是 PLL 锁定等待。HSE_VALUE 错误会造成软件频率计算错误,但不会直接使晶体不起振或使 HSERDY 置位失败。只有 HSE 已就绪时才能期待从 MCO 看见它的输出。
9.2 SYSCLK 显示 168 MHz,但串口波特率不对
可能原因:串口所在 APB 时钟理解错误、外设初始化早于最终时钟、HSE_VALUE 错误,或动态切频后未重新初始化串口。
检查与解决:读取 PCLK1/PCLK2;确认 USART 所属总线;核对 BRR 和实际波形;不要只看 SystemCoreClock。
9.3 定时器频率正好差两倍
原因:忽略了 APB 预分频不为 1 时,定时器时钟等于 2×PCLK。
解决:确认定时器位于 APB1 还是 APB2,读取 PPRE 后再计算定时器输入时钟。
9.4 修改主频后 HAL_Delay() 变快或变慢
可能原因:绕过 HAL 直接改寄存器后没有更新 SystemCoreClock 和 HAL Tick,或 SysTick 时钟源/优先级异常。
解决:优先使用 HAL_RCC_ClockConfig();确认返回值;检查 SystemCoreClock、SysTick LOAD 和 uwTick。正确重配后 500 ms 延时不应因为主频减半而变成 1 s。
9.5 USB 或 SDIO 在 CPU 正常时仍失败
可能原因:SYSCLK 合法,但 USB 的输入不满足 48 MHz 及精度要求;或 SDIO 的功能时钟、APB2 关系、卡时钟分频、引脚与协议时序不满足要求。
检查与解决:单独计算 fVCO/PLLQ,按 4.3 节分别检查 USB 和 SDIO。不要把 SDIO 输入低于 48 MHz 本身当作故障原因;一般使用USB时需要使用外部晶振。
9.6 MCO 没有波形
可能原因:PA8 被其他复用功能占用、单总线模块仍连接、MCO 源未就绪、探头或地线错误。
检查与解决:读取 PA8 MODER/AFR 和 RCC_CFGR MCO 字段;断开 ONE_WIRE_DATA 外设;确认探头接 P2-34 与 GND;先输出 8 MHz HSE,不直接输出过高频率。
十 练习、总结与参考资料
10.1 动手练习
- 手算 168 MHz 与 84 MHz 两套配置,逐项在 CubeMX 中核对。
- 保持 VCO 336 MHz,比较 PLLP=2 和 PLLP=4 时哪些总线必须重新分频。
- 在 Watch 窗口记录四个 HAL 频率 API 的返回值,并与 RCC 寄存器反推结果对照。
- 用 PA8/MCO1 输出 HSE,完成一次带探头条件的 8 MHz 实测。
- 选择一个实际外设,列出从 168 MHz 切到 84 MHz 前后必须重算的所有参数。
10.2 本章小结
- 时钟配置是一棵依赖树,不是单独填写一个 CPU 主频。
- 8 MHz HSE 经 M=8、N=336、P=2、Q=7 可得到 168 MHz SYSCLK 和 48 MHz 专用域。
- APB 定时器时钟可能是 2×PCLK;SDIO 同时涉及 APB2 接口和 48 MHz 功能时钟。
- Flash latency 按 HCLK 与 VDD 查表,电压调节等级另行限制最高主频。
- 软件读回、寄存器、DWT 和 MCO 各自验证不同层面,不能互相完全替代。
- 动态切频必须处理外设在途事务、Tick、超时和故障回退,不能只改 PLL 参数。
10.3 官方资料
- DS8626 Rev 12:STM32F405xx/STM32F407xx 数据手册。
- RM0090 Rev 21:STM32F405/407 等系列参考手册。
- AN2867 Rev 24:STM32/STM8 振荡器设计指南。
- UM1718 Rev 50:STM32CubeMX 用户手册。
- UM1725 Rev 8:STM32F4 HAL 与 LL 驱动说明。
- STM32F4 HAL 官方源码:本章分析
stm32f4xx_hal_rcc.cV1.8.4 的时钟配置、读回、MCO 与 CSS 行为。 - Armv7-M 架构参考手册:DWT 周期计数器与调试暂停行为。
- 天空星核心板介绍与筑基学习板硬件介绍:板载时钟资源,以及底板 PIN_OUT、单总线接口原理图。