STC32G电桥的DAC分频为什么不能随手填0
做一台 LCR 电桥,容易把注意力全放在运放、量程切换和校准上。激励信号那边只有一行分频配置,看起来像个顺手填完的小参数。
DAC2_SetClockDivider(0);
偏偏这个 0 值得停下来。对于 STC32G144K246 的 DAC2,它代表直接使用系统时钟。当前核验工程把系统时钟预置为 48MHz,而手册要求 DAC2 模块工作频率不得高于 2MHz。按这组配置计算,模块时钟是上限的 24 倍。
这篇文章把问题收在上板前的参数审计里。我们用真实工程核对时钟来源,写一个能运行的规划工具,并在固件副本里落下改动。读者可以复用这套方法,检查自己项目里的特殊分频值和边界条件。

图1 从真实 EDA 工程重新导出的主控页。整体图用于定位,关键网络在下一张局部图中展开。
先把三个频率分开
DAC 模块工作时钟、定时器触发频率、最终模拟波形频率,分别对应不同环节。把它们都简称为“DAC 频率”,排错很容易绕远路。
模块时钟由 DAC2_DIVH/DIVL 配置,决定 DAC2 内部工作时钟。TIMER17 在固件里被选作自动触发源,决定触发机会。最终波形还取决于数据推进、DMA 语义、缓冲区组织和模拟链路。
本次能确认的是第一项。改变模块分频后,是否每次触发都能完成转换、DMA 是否按预期搬运,以及输出频率和失真如何变化,仍需相应的时序分析和实测。

图2 主控页把 DDS 标到 P7.4,把 DDS_EF 标到 PB.6。这些是板级网名。手册第23章还说明内部 DAC 本身没有输出缓冲能力,不能仅凭网名推断它直接驱动外部管脚;输出路由应继续核对片上缓冲级与模拟电路。
核验源码时,不能只看 config.h 中的 SYSCLK 宏。实际初始化先执行 HIRC_48M(),再选择 HIRC、旁路 MCLK2,最后把 SYSCLK 分频设为 1。头文件中的 HIRC_48M() 会读入 48MHz 的芯片校准值。SYS_Init() 又先调用 CLK_Init(),后调用 DAC2_Init()。这些证据共同支持“程序预置为标称 48MHz”的判断;真实振荡频率没有在本次测量。
0 为什么和 1 差这么多
手册 23.3.5 给出的规则有两条,必须分开处理。设系统时钟为 F,10 位分频寄存器值为 d:
d = 0 模块时钟 = F
1 ≤ d ≤ 1023 模块时钟 = F / (4 × d)
这里不能把 0 当成“最小分频”“自动选择”,也不能套用其他外设常见的 d+1 规则。原工程头文件的设置宏直接将参数高低字节写入 DAC2_DIVH/DIVL,没有替我们换算。

图3 依据手册重绘的计算示意。0 值旁路固定的除4环节与可编程分频;图中数字属于参数计算,未作为实测波形。
代入标称 48MHz,几个值的区别就很直观:
| d | DAC2 模块时钟 | 与 2MHz 上限的关系 |
|---|---|---|
| 0 | 48MHz | 超出 |
| 1 | 12MHz | 超出 |
| 5 | 2.4MHz | 超出 |
| 6 | 2MHz | 恰好到边界 |
| 7 | 约1.714MHz | 低于边界 |
因此,按标称值满足硬件限值的最小非零分频是 6。但“恰好到边界”不等于已经考虑了振荡器容差、温度和后续时钟改动。
本例另选 1.8MHz 作为设计预算,对手册上限留出 10% 的时钟预算空间。这个数是主动选定的软件约束,不能解释成芯片厂家保证的容差。预算下需要向上取整,分频值为 ceil(48000000 / (4 × 1800000)) = 7。
预算也不宜一味压低。模块时钟降低后,转换是否能在下一次触发前完成,需要继续检查。先把超限配置消掉,再验证转换与触发的配合,两个步骤缺一不可。
把边界写进工具
一次算出 7 很容易,困难在于下次换了系统时钟,还记不记得重新算。这里把规则写成 Python 工具,返回精确分数,再用整数边界规划分频。
下面两个函数与附件中的实现一致;输入检查函数和完整命令行入口在附件里。
def dac_clock(sysclk_hz, divider):
positive_int(sysclk_hz, "sysclk_hz")
validate_divider(divider)
if divider == 0:
return Fraction(sysclk_hz, 1)
return Fraction(sysclk_hz, 4 * divider)
def plan_divider(sysclk_hz, budget_hz=HARD_LIMIT_HZ):
positive_int(sysclk_hz, "sysclk_hz")
positive_int(budget_hz, "budget_hz")
if budget_hz > HARD_LIMIT_HZ:
raise ValueError("budget cannot exceed the DAC2 hard limit")
if sysclk_hz <= budget_hz:
return 0
denominator = 4 * budget_hz
divider = (sysclk_hz + denominator - 1) // denominator
if divider > DIVIDER_MAX:
raise ValueError("no representable divider meets this budget")
return divider
Fraction 从 Python 标准库导入,HARD_LIMIT_HZ 为 2,000,000,DIVIDER_MAX 为 1023。程序拒绝负数、浮点输入、布尔值、超出10位范围的分频,以及高于硬件上限的预算。
向上取整是这里最容易漏掉的细节。系统时钟为 8,000,000Hz、预算为 2MHz 时,d=1 正好合法。只增加到 8,000,001Hz,就需要 d=2。先把结果转成整数或只比较屏幕上显示的“两位小数”,可能把这一个赫兹吞掉。
工具还区分标称时钟与调用者确定的时钟上界。默认只按标称值计算;如果已经根据器件规格和环境条件确定最大 SYSCLK,可以传入 --sysclk-max,规划时采用这个上界,而报告仍分别列出标称值与上界值。它不会替你编造 HIRC 的容差。
解压附件,在代码目录运行,Python 3.10 或更高版本即可,依赖均来自标准库:
python dac_clock_audit.py --sysclk 48000000 --divider 0 --budget 1800000 --report result.json --header dac2_clock_guard.h
python -m unittest -v test_clock_audit

图4 真实运行报告的排版摘要。原配置超出上限;1.8MHz 预算规划得到 d=7,对应 DIVH=0、DIVL=7。测试覆盖7组测试、52,224组时钟/预算/寄存器组合,以及6,132个整数边界断言。
测试没有停在48MHz这个例子上。它枚举全部1024个寄存器值,用独立的整数不等式核对合法性,还验证每个向上取整边界、分频范围末端,以及无可表示解时必须报错。预算放宽到2MHz或改成1MHz时,也执行同样的检查。
改到副本里,再回到板上验证
工具生成 dac2_clock_guard.h,本例固定记下48MHz输入、1.8MHz预算和分频值7。头文件会检查 SYSCLK 是否变更、分频是否越界,并用商和余数检查频率边界,避免整数截断漏判。
在 dac.c 包含 config.h 后包含这个头文件,再将初始化改成:
#include "dac2_clock_guard.h"
/* 放在 DAC2_Init 的原时钟设置位置 */
DAC2_SetClockDivider(DAC2_CLOCK_DIVIDER);
以上改动已经应用到本地固件副本,原附件保持原样。若改变系统时钟或设计预算,应重新生成头文件,而不是手动改一个数字让检查通过。

图5 同一个真实 EDA 工程的 PCB1 顶、底层导出。两图保留编辑器俯视坐标,底层没有做物理翻板镜像;原丝印保留。此次修改属于固件参数,图中板子用于定位工程,不能据此宣称整机已验证。
真正接回硬件后,可以先读回 DAC2_DIVH/DIVL,确认程序写入的有效10位值;然后核对实际 SYSCLK、触发源和转换完成条件,再观察模拟输出与电桥标定结果。若波形还有问题,DMA 次数与字节组织、片上缓冲路由、运放带宽、开关及滤波网络都应分别检查。不要把“一行分频改对了”直接等同于“电桥测得准了”。
本次完成了主机工具运行、参数边界测试和本地固件副本修改。原工程使用 MCS-251/C251 工具链,当前环境没有可用的 C251 编译器,未进行目标编译、烧录或实体测量。因此可复用的结果是明确的分频语义、参数规划方法和验证工具;转换时序、波形及整机精度仍保留待验证范围。
来源、许可与代码获取
取材项目为《基于STC32G144K246的lcr电桥》,原作者 qq82871836。项目完整网址为 https://oshwhub.com/qq82871836/stc32g144k246-based-bridge 。核验的是2026-01-26更新页面下、2026-10-12下载的 BLINK.rar 附件和2026-01-25更新的真实 EDA 工程,源码以下载文件哈希固定版本。
项目及 EDA 标注 GPL 3.0。图1、图2、图5及封面中的PCB来自实际编辑器高清导出,做了局部裁剪、保真缩放与排版,必要丝印保留;这些复用图沿用原许可。本文新增文字、图3与图4按 CC BY 开放;第三方 EDA 图仍沿用 GPL 3.0,独立参数代码采用 MIT,各自权利分别适用。
参考资料为官方《STC32G144K246系列技术手册》2026-07-07修改版,重点是23.3.5,印刷页723、PDF第757页。完整资料地址为 https://stcmicro.com/datasheet/STC32G144K246-cn.pdf 。
本文独立参数工具采用 MIT,完整最小工程含脚本、测试、生成头文件、运行报告、接入说明及许可证,下载完整参数工具,也可使用本文附件。原固件源码位于上述项目页的 BLINK.rar,与独立工具分开获取。附件不含整套厂商库、旧版参考工程或可直接烧录的电桥固件。本文图3属于计算示意,图4来自工具运行结果,均不是硬件波形截图。
技术交流,欢迎关注微信公众号:美男子玩编程。




