系统级架构设计:万用表功能模块划分

好,咱们进入正题。上一章聊了需求分析,说白了就是搞清楚「我们要做什么」。这一章,我们来拆解「怎么做」——也就是系统级架构设计。

我个人习惯,拿到一个项目,先画大框框。万用表这种嵌入式设备,功能再多,也能归到四个核心模块里:测量、显示、通信、电源。你想想看,是不是这么回事?

一、四大功能模块的划分

1. 测量模块——万用表的心脏

测量模块负责把物理信号变成数字信号。我做过一个项目,客户要求测到10μV级别的直流电压,结果前端模拟电路噪声就吃掉了一半精度。嗯,这里要注意,测量模块的难点不在ADC选型,而在前端调理电路。

测量模块内部又分几个子模块:

  • 输入保护电路:防烧表,这是底线。我曾经因为省了一个PTC电阻,烧了三块样板,血的教训。
  • 信号调理:包括衰减器、放大器、滤波器。说白了就是把信号调到ADC喜欢的范围。
  • ADC转换:常用的是Σ-Δ型ADC,精度高,但速度慢。测电阻、电容还需要额外的激励源。
  • 量程切换:自动量程还是手动量程?我建议新手先做手动,自动量程的逻辑坑很多。

关键数据流:模拟信号 → 保护电路 → 调理电路 → ADC → 数字信号 → MCU

2. 显示模块——用户的眼睛

显示模块,大家最熟悉。但我要说,显示模块的功耗往往被低估。一个128×64的OLED屏,全亮时能吃掉20mA,比MCU本身还多。

显示模块的架构要点:

  • 显示驱动:要么用MCU自带LCD驱动,要么外挂驱动IC。我建议用外挂,比如SSD1306,MCU负担小很多。
  • 显示内容管理:数值、单位、量程、电池电量、功能符号。别小看这个,UI逻辑写不好,用户会骂娘的。
  • 刷新策略:静态显示还是动态刷新?低功耗模式下,我习惯用「变化才刷新」的策略,能省不少电。

我的小技巧:显示模块的缓冲区放在MCU内部RAM里,别用外部存储器。每次刷新只更新变化的部分,别全屏重绘。

3. 通信模块——万用表的触角

通信模块,现在基本是标配。蓝牙、USB、甚至Wi-Fi。但你要想清楚,通信模块是功耗大户。

常见的通信方案对比:

通信方式 峰值功耗 传输距离 适用场景
蓝牙BLE ~10mA 10m 手机连接、数据记录
USB ~100mA 有线 固件升级、高速传输
Wi-Fi ~200mA 100m 物联网、远程监控

我建议,低功耗万用表首选蓝牙BLE。为什么?因为它的待机功耗可以做到μA级,而且手机端生态成熟。我曾经做过一个USB通信的方案,用户反馈插拔USB时经常死机,后来发现是热插拔保护没做好。

4. 电源模块——系统的命脉

电源模块,我把它放在最后讲,因为它最重要。没有好的电源,前面三个模块都是白搭。

电源模块的设计要点:

  • 电池选择:干电池还是锂电池?干电池简单,但电压会下降。锂电池需要充电管理。我个人偏爱锂电池+升压方案。
  • 电压转换:万用表内部需要多个电压轨。模拟电路需要±5V或±3.3V,数字电路需要3.3V或1.8V。升压、降压、LDO,怎么组合?
  • 功耗管理:自动关机、待机模式、深度睡眠。我习惯用PMOS管做负载开关,彻底切断不用的模块。

注意:电源模块的纹波噪声会直接影响测量精度。尤其是ADC的参考电压,必须用低噪声LDO单独供电。我曾经因为共用了一个LDO,导致测量结果跳了3个字,查了两天才找到原因。

二、系统框图与数据流

好了,四个模块讲完了。现在把它们拼起来,看看数据是怎么流动的。

系统框图,我习惯用「自顶向下」的方式画。最顶层是MCU,它负责调度一切。下面是四个模块,各自通过总线与MCU通信。

+------------------+
|      MCU         |
|  (STM32/GD32)    |
+--------+---------+
         |
         +-------+--------+--------+--------+
         |       |        |        |        |
   测量模块  显示模块  通信模块  电源模块
         |       |        |        |
    ADC数据  显示缓存  蓝牙协议  电池管理
         |       |        |        |
         +-------+--------+--------+--------+
                  |
              用户交互

数据流是这样的:

  1. 测量数据流:模拟信号 → 测量模块 → ADC → SPI/I2C → MCU → 数据处理 → 显示缓存
  2. 显示数据流:MCU → 显示缓冲区 → SPI/I2C → 显示驱动 → 屏幕
  3. 通信数据流:MCU → UART/SPI → 蓝牙模块 → 手机APP
  4. 电源数据流:电池 → 升压/降压 → LDO → 各模块供电

你可能会问,这些数据流是并行的还是串行的?答案是:分时复用。MCU在一个时间片里只能做一件事。测量时,显示和通信可以暂停。显示刷新时,测量可以继续。这就是嵌入式系统的精髓——时间片调度。

核心思路:测量模块是最高优先级,因为它对实时性要求最高。显示和通信可以适当延迟。电源模块是后台任务,持续监控电池电压。

三、模块间的接口定义

模块划分好了,接口定义是关键。我见过太多项目,模块内部做得很好,但接口没定义清楚,最后联调时一团糟。

接口定义的原则:

  • 物理接口:SPI、I2C、UART、GPIO。选哪种?SPI速度快,但线多。I2C线少,但速度慢。UART简单,但需要波特率匹配。
  • 逻辑接口:数据格式、命令集、状态码。我建议用结构体封装,别用散乱的全局变量。
  • 时序接口:采样率、刷新率、通信速率。这些要提前约定好,不然后期改起来很痛苦。

举个例子,测量模块和MCU的接口:

// 测量模块数据结构
typedef struct {
    uint16_t adc_raw;       // ADC原始值
    float    voltage;       // 转换后的电压值
    uint8_t  range;         // 当前量程
    uint8_t  status;        // 状态:0=正常,1=超量程,2=欠量程
} MeasureData_t;

// MCU读取测量数据
MeasureData_t get_measurement(void) {
    MeasureData_t data;
    data.adc_raw = read_adc();
    data.voltage = adc_to_voltage(data.adc_raw);
    data.range   = get_current_range();
    data.status  = check_range(data.voltage);
    return data;
}

你看,接口定义清楚了,MCU只管调用get_measurement(),不用关心测量模块内部怎么实现的。这就是模块化的好处。

四、避坑指南

最后,分享几个我踩过的坑:

  • 电源模块的纹波:我曾经用示波器量过,一个便宜的升压芯片,纹波有50mV,直接导致ADC测量结果波动。后来换了低纹波的LDO,问题解决。
  • 显示模块的刷新率:别设太高,30Hz就够了。我试过60Hz,功耗翻倍,人眼还看不出区别。
  • 通信模块的协议栈:蓝牙协议栈很复杂,建议用现成的模组,别自己写。我见过一个团队自己写蓝牙协议,半年没搞定。
  • 测量模块的输入保护:一定要加!哪怕只是两个二极管和一个PTC。我烧过三块样板,都是因为用户误接了高压。

好了,这一章就到这里。系统级架构设计,说白了就是「分而治之」。把大问题拆成小问题,每个小问题用专门的模块去解决。下一章,我们会深入测量模块,聊聊ADC选型和前端电路设计。