Hotdry.

Article

电压表时钟的 PWM 占空比精密驱动:免 DAC 的指针平滑控制

详解 AVR 单片机通过高频 PWM 同步计数器与软件占空比计算,实现三块模拟电压表连续平滑运动的工程参数。

2026-05-17systems

在嵌入式系统领域,驱动模拟指针式仪表通常被认为需要专用 DAC 芯片或复杂模拟电路。但 lcamtuf 的电压表时钟项目提供了另一种思路:利用数字脉冲序列的占空比控制,配合表头的机械惯性实现无 DAC 的精密指针定位。这一方案的核心在于 PWM 周期与时间基准的精确同步,以及在无任何反馈的情况下保证指针的线性运动。

1 驱动架构:为什么不需要 DAC

模拟电压表的指针偏转角度与施加电压成正比。如果直接输出 0–5 V 模拟电压,需要 DAC 或数字电位器。但这里采用的方案是:在数百 kHz 的高频下输出恒定幅度的矩形波(0 V 或 5 V),通过调节占空比使表头看到的等效平均电压恰好对应目标指针位置。由于机械惯性远低于 PWM 频率,表针对高频脉冲进行积分,平稳停在占空比决定的中间位置。

lcamtuf 选用了 AVR128DA28 作为主控芯片。这颗 MCU 具备丰富 Timer TCA 资源,且引脚 slew rate 可调,能在输出高质量 PWM 的同时降低 EMI。电路极为简洁:8 MHz 外部晶体(ECS-80-18-4X-CKM)提供精确时钟基准,PD6 和 PD7 两个按键用于时间校准,无需任何显示屏。所有信号通过 PC0、PC1、PC2 三根引脚直接驱动三块电压表。

2 PWM 同步计数器的实现细节

代码中的 PWM 实现采用 600 步同步计数器方案。在主循环中,duty_ctr 从 0 递增到 599,形成周期为 600 的 PWM 波形。三个电压表的占空比在 adj_secx10adj_minx10adj_hrx10 三个变量中维护,每当 duty_ctr 归零时重新计算。这意味着 PWM 频率约为 8 MHz / 600 ≈ 13.3 kHz,远高于表头的机械响应带宽(通常在 10–50 Hz)。

时间基准由 Timer TCA0 的溢出中断提供,中断频率精确设定为 10 Hz(每秒 10 次)。预分频器设为 /256,PER 寄存器设为 3125,计算得 8 MHz / 256 / 3125 = 10 Hz。每次中断中,cur_secx10 自增(范围 0–599),达到 600 时归零并进位到分钟和小时。这一机制确保了时间计数与 PWM 占空比更新始终保持同步关系。

3 占空比计算:连续运动的关键

为了让指针在任意时刻平滑移动而非跳跃,代码采用了一种巧妙的数学映射。分钟表有 61 格(00–60),占空比范围 0–600(每格 10 步)。计算公式为:adj_minx10 = cur_min * 10 + cur_secx10 / 60,即在两个整分刻度之间按秒数均匀插入中间位置。例如,30 分 36 秒时,cur_min = 30cur_secx10 = 360cur_secx10 / 60 = 6,结果为 306,对应指针精确指向 30 分 36 秒的位置。

小时表的设计更为精妙。刻度盘印有 13 格(0–12),小时进位时指针应平滑爬向下一个刻度。代码将小时分为 12 大格,每格 50 步:adj_hrx10 = cur_hr * 50 + adj_minx10 / 12。分钟每走 12 秒(约 2 格),小时指针才移动 1 格。在 11:59 时,小时占空比接近 12 小时的位置而不超出表盘范围,实现了流畅的连续运动而非机械跳针。

秒表则直接使用 cur_secx10 的原始值,范围 0–599,与 PWM 周期完美对齐。

4 精度保障:晶体校准与软件补偿

该设计的精度完全取决于晶体频率与软件定时器的准确度。8 MHz 外部晶体相比内部 RC 振荡器(精度 ±3% 或更差)大幅提升了稳定性。对于需要更高精度的场景,可以替换为 32.768 kHz 晶体(常用 RTC 晶振),代码逻辑无需改变,仅需调整预分频参数。

lcamtuf 在代码注释中提到可以在占空比计算中加入校准因子(fudge factors)以补偿电压表的非线性。不同批次的 65C5 表头在相同占空比下可能有微小指针偏差,通过查表或线性系数调整即可修正。这种校准在无反馈的开环系统中是必要的工程权衡。

5 按钮去抖与时间设置逻辑

时间设置通过两个按钮完成,均配置内部上拉电阻(PORTD.PIN6CTRL = 0b00001000)。代码在 PWM 周期归零时检测按键状态,仅在首次按下时触发动作,避免重复递增。Key 0(PD6)推进分钟同时清零秒,确保秒针归位;Key 1(PD7)单独推进小时,不影响其他指针。这一设计允许用户独立校准三个表盘而无需记忆复杂操作顺序。

按键去抖通过 10 Hz 中断与主循环的协同完成,而非依赖延时函数,确保时间计数不被阻塞。代码中使用 key_last 标志位实现边沿检测,忽略持续按压状态。

6 机械工程:定制表盘与无缝外壳

指针精度不仅取决于电子驱动,还依赖于表盘刻度的物理布局。lcamtuf 使用 3D 软件绘制表盘模板,打印到自粘纸后替换原厂刻度。小时表 13 格(0–12 加 12 之后紧接 0)确保连续运动时有足够刻度容纳指针;分钟和秒表 61 格覆盖完整 60 分钟或 60 秒循环。

外壳采用 CNC 铣削正面与背面,弯曲侧壁通过在木板上切割内部缺口实现无需蒸汽弯曲的柔化处理。胶合时使用纸板模板保证精确对齐,最终表面涂硝基漆获得一致的质感。

7 参数汇总与工程建议

实现该方案的关键参数如下:

参数 说明
MCU AVR128DA28 3 组 TCA,充足定时器资源
晶体 8 MHz 或 32.768 kHz 外部晶体,精度 ±50 ppm
PWM 频率 ~13.3 kHz 8 MHz / 600 步
PWM 分辨率 600 步 覆盖秒 / 分钟 / 小时全范围
时间更新频率 10 Hz Timer TCA0 溢出中断
驱动方式 数字脉冲占空比 无需 DAC 或运放
表头数量 3 小时 / 分钟 / 秒各一

该方案的核心价值在于:以极简硬件实现高精度控制,依赖晶体稳定性和软件算法的协同。对于需要更高分辨率的场景,可在占空比计算中引入分数插值或增加 PWM 步数(如 1200 步)。对于移动端或电池供电场景,AVR 的低功耗特性(Active 电流 < 1 mA)也提供了不错的能效比。


资料来源:A nicer voltmeter clock - lcamtuf's substack,代码与表盘模板托管于 lcamtuf.coredump.cx

systems

内容声明:本文无广告投放、无付费植入。

如有事实性问题,欢迎发送勘误至 i@hotdrydog.com