再次把“手持示波器”这个项目捡起来的时候,距离第一版做出来已经隔了大半年。第一版其实也能亮,能测个音频波形,但每次想看看电源纹波或者单片机通信波形的时候,就暴露出一堆毛病:波形乱飘、触发电平调不了、刷新慢得像幻灯片。这次“再战”,我不想再做一个玩具,而是想认真做一台能带出门、能现场调试、看着也像那么回事的手持示波器。这篇文章就把这次从方案选型、电路设计、软件调试到实测翻车的全过程记录下来,给想自己做示波器或者想升级初代方案的兄弟们一个参考。
这次的目标也很简单:实时采样率做到 40MSPS 左右,模拟带宽做到 10MHz 上下,能测 0.1V 到 20V 的信号,屏幕刷新做到肉眼不难受,电池能用半天以上。下面我把每一步的思考和踩坑都摊开来讲。
1. 再战的原因:初代方案到底输在哪
1.1 初代手持示波器的三个硬伤
第一版我当时用了某款入门级 MCU 的内置 ADC,标称采样率 1MSPS,想着测测音频、看看电源波动足够了。但实际用起来才发现,内置 ADC 在连续采样时问题很大——多通道扫描和 DMA 调度的开销让实际吞吐量根本跑不满标称值。更难受的是,那款 MCU 的 ADC 输入引脚在采样瞬间会有一个明显的电荷注入,前端不加缓冲的话,测高阻信号时波形会跟着采样频率发生周期性塌陷。
第二是显示。我用的是 SPI 接口的屏幕,分辨率 320x240,底层刷一帧全屏大概要 80ms。加上波形绘制还要算坐标、描点,实际刷新率卡在 8fps 左右。测低频信号还没什么感觉,一旦测到几十 kHz 以上的信号,屏幕上就是一堆断断续续的线段,根本谈不上观察细节。
第三也是最要命的:触发做的是纯软件触发。MCU 在 DMA 搬运完一帧数据后,软件再去扫描数据找电平交叉点。因为采样数据和触发事件之间没有硬同步,波形的水平位置每次都不同,看起来就是波形在屏幕上左右乱跑。后来我虽然加了缓存对齐的算法,但效果只能说勉强能用,和正经示波器那种“波形钉在屏幕上”的感觉差远了。
1.2 这次重新立项的目标和原则
吸取初代教训之后,我把这次的需求拆成几条硬指标:
| 项目 | 目标参数 | 设计导向 |
|---|---|---|
| 实时采样率 | 40MSPS | 单通道连续采样,峰值得保留 |
| 模拟带宽 | DC~10MHz | 输入阻抗 1MΩ,带衰减网络 |
| 垂直灵敏度 | 10mV/div ~ 5V/div | 多档程控增益 |
| 水平时基 | 100ns/div ~ 1s/div | 支持手动和自动时基 |
| 触发方式 | 上升沿/下降沿,可调触发电平 | 硬件比较器+软件辅助 |
| 屏幕 | 4.3寸 800x480 TFT,RGB 接口 | 尽量提高刷新率 |
| 供电 | 3.7V 锂电池,Type-C 充电 | 续航目标 6 小时以上 |
设计原则我定了两条:第一,参数不追求极端,但每一项都要“稳定可用”;第二,所有模块尽量模块化,方便以后单独替换升级。方向上不再依赖内置 ADC,而是外挂高速独立 ADC,把采样时序交给定时器和硬件触发去管,MCU 只负责搬运数据和显示。
2. 整体方案选型:MCU、ADC和显示链路的取舍
2.1 三条技术路线的对比
做手持示波器,常见的方案无非三条:MCU 内置 ADC、MCU 外挂高速 ADC、FPGA/CPLD 加 ADC。第一条我已经踩过坑了,性能天花板太低;第三条性能最强,但开发复杂度和成本也最高,而且 FPGA 的电源设计和逻辑时序调试对业余项目来说是个不小的坑。最终我选了中间路线:MCU 外挂高速 ADC。
| 对比项 | MCU内置ADC | MCU外挂ADC | ADC+FPGA |
|---|---|---|---|
| 采样率上限 | 一般 ≤5MSPS | 可到 100MSPS+ | 可到 1GSPS+ |
| 难度 | 低 | 中 | 高 |
| 实时性 | 差 | 较好 | 最好 |
| 成本 | 最低 | 中 | 较高 |
| 灵活性 | 一般 | 中等 | 高 |
外挂 ADC 的好处在于采样速率和 MCU 主频解耦。MCU 只需要通过并行或者串行接口把数据读走,不需要在中断里面频繁喂 ADC 启动转换,触发和采样都由独立的硬件逻辑完成,实时性比纯软件靠谱得多。坏处是接口时序和 PCB 布局对新手不友好,搞不好就是满屏噪声或者数据错位。
2.2 核心器件怎么选才靠谱
MCU 的选择上,我优先考虑带高速并行接口、DMA 支持和足够定时器资源的 Cortex-M7 内核芯片。看中它主要是三点:主频高,运算能力强,浮点性能对波形插值算法有帮助;带并行摄像头接口或 FMC 接口,可以和 ADC 的数据输出直接对接;DMA 通道足够多,可以把 ADC 数据流直接送进内存,CPU 几乎零负担。
ADC 芯片则选了一颗双通道、并行输出、采样率最高 50MSPS 的 8 位芯片。可能有人会问,为什么不用 12 位的?手持示波器一般只有 8 到 10 位垂直分辨率,8 位在屏幕上用 256 级灰度表示波形已经够用,关键是采样率要够,分辨率太高反而会让数据量暴增,MCU 处理不过来。这颗 ADC 的输入范围是 0~2V,单端输入,配合前端模拟电路做电平偏移,正好匹配。
屏幕方面,我淘汰了 SPI 屏幕,改用 RGB 并口 TFT。因为 RGB 接口可以用 MCU 的 LCD 控制器直接驱动,刷新一帧 800x480 只需要软件往显存里写数据,速度比 SPI 快了一个数量级。实际用下来,满屏波形刷新能到 25fps 左右,虽然比不上商用示波器的丝滑,但肉眼看已经很舒服了。
这里给个选型建议:新手不要上来就追求 1GSPS 采样率,那个级别的 ADC 通常是 LVDS 差分输出,MCU 很难处理,必须用 FPGA。老老实实做 20~50MSPS 这个区间,既能覆盖绝大多数维修和教学场景,又不会把自己逼到绝境。
3. 模拟前端设计:带宽做不上去的罪魁祸首
3.1 输入阻抗、保护电路和衰减网络
示波器的输入前端和普通信号采集电路最大的区别在于:它要兼容 1MΩ 高阻抗输入和 ±20V 以上的大信号,还要承受用户带电误接的冲击。这次的输入级我采用了经典的“保护电阻+二极管钳位+JFET 缓冲”结构。
首先,输入端串一个 1kΩ 的电阻,再在信号路径上并联两个背对背的二极管到地。二极管用的是低结电容的高速开关管,保证正常测量时不影响带宽,出现异常高压时钳位到地,保护后端器件。这里有一个容易踩的坑:普通整流二极管的结电容高达几十皮法,串在信号路径上会把高频信号直接短路到地,测方波时会看到边沿明显变缓。一定要选结电容小于 5pF 的管子。
衰减网络是前端设计的重头戏。我用的是经典的“电阻分压+补偿电容”结构,一共有三档:1x、10x、100x。1x 档直通,10x 档用 9MΩ 串联 1MΩ 分压,100x 档用 9.9MΩ 串联 0.1MΩ 分压。这里的关键是和探头一样,要在并联电阻两端配一个补偿电容,否则高频时电容阻抗会改变分压比,导致方波形状出现畸变。
补偿电容的取值需要算:输入端等效并联电容大约 10~20pF(包括布线寄生和运放输入电容),要让 9MΩ 电阻和 1MΩ 电阻上的电容分压比等于电阻分压比,即 C1/C2 = R2/R1。所以 10x 档的补偿电容大约选 12pF 到 18pF,实际需要用小电容并联微调。这一环节没有捷径,只能靠信号发生器输出方波,看波形是否平顶来反复微调。
3.2 缓冲放大与增益切换
衰减之后,信号进入缓冲放大器。这里我要求输入阻抗极高、输出阻抗极低,带内相位偏移小。做第一版时我用的是通用运放,带宽只有 3MHz,测高频正弦波时幅度已经明显衰减,这次特意换成了增益带宽积在 200MHz 以上的 JFET 输入运放。由于是单位增益缓冲,压摆率只需要满足前端最大信号带宽即可,但这颗运放输入端的共模输入范围和输出摆幅要仔细看,避免信号削底。
增益切换放在缓冲级之后,通过模拟开关切换反馈电阻实现 1x、2x、5x、10x、20x、50x 六档增益。这里要注意模拟开关的导通电阻会随温度和电压变化,如果直接串在反馈环路上,会导致增益漂移。我在反馈电阻上并联了小电容来限制带宽,同时把模拟开关的导通电阻控制到 50Ω 以下,实测增益误差控制在 2% 以内。
3.3 ADC 驱动级和电平偏移
ADC 芯片需要 0~2V 的单端输入,而缓冲级输出的是以地为参考的双极性信号。所以我加了一级电平偏移电路:用一个低噪声基准源产生 1V 偏置电压,通过加法电路把信号整体抬升到 0~2V 区间。这个偏置电压的稳定性直接影响波形的垂直精度,基准源纹波一定要控制在 1mV 以内,否则你会看到波形基线在上下抖动,还以为是信号有问题。
ADC 驱动级还串了一个二阶低通滤波器,截止频率设置在 15MHz 左右,用来滤除采样时钟和数字电路耦合过来的高频噪声。需要注意的是,这个滤波器会引入额外相位延迟,在测方波时能看到过冲或者振铃,需要在软件里做相位补偿——更简单的方法是把截止频率往高调一点,留够余量。
4. 采样时序和触发逻辑:波形稳定显示的关键
4.1 让 ADC 和 MCU 协同工作
外挂 ADC 的数据输出是 8 位并行总线,采样时钟由 MCU 的定时器输出比较信号提供。我用了高级定时器的两个通道:一个通道产生方波作为 ADC 的采样时钟,另一个通道在采样完成时触发 DMA 搬运。这样做的核心目的是“一个时钟既采样又搬运”,ADC 的数据总线每一个采样周期出现一次有效数据,DMA 在同一个边沿把数据锁存进内存,不会丢点也不会重复。
DMA 我配了双缓冲模式,ADC 数据交替写入两个缓冲区。当第一个缓冲区填满时,DMA 自动切换到第二个缓冲区,同时产生中断通知 CPU 处理第一块数据。这样 CPU 在画波形的时候,ADC 还在持续采样,数据不中断,显示不卡顿。实际调下来,24 个采样点为一组,一组对应屏幕上一条垂直扫描线,一个屏幕总共 240 条扫描线,一帧数据 5760 个点,非常清晰。
4.2 触发模块:从软件触发升级到硬件触发
这次我铁了心要做硬件触发。方案是用一颗高速比较器比较输入信号和触发电平,比较器输出经过整波后,作为触发脉冲送到 MCU 的外部中断引脚。MCU 收到脉冲后,立即重置采样时序,保证 ADC 从同一个触发点开始采集数据。这样波形在屏幕上的水平位置每次一致,看起来就“钉住”了。
触发电平由 DAC 产生,我在 MCU 里做了个可调菜单,用户通过编码器调节。需要注意的是,比较器的输入要加一点迟滞,否则信号在触发电平附近抖动时,会产生大量误触发。迟滞量取 10~20mV 即可,太小没效果,太大又会影响触发精度。
这里有个小技巧:当被测信号频率低于 100Hz 时,硬件触发几乎等不到第二个边沿,屏幕上只有一条直线。我在软件里加了个超时检测,超过 200ms 没有触发脉冲就自动切换为内部自由扫描,避免用户以为机器坏了。这个逻辑虽然简单,但真是能救命的。
4.3 软件触发作为补充
硬件触发虽然稳,但只能做边沿触发。做串口波形调试时,我更希望能按波特率周期来观测。后来我在软件里又加了一档“脉宽触发”,原理是在 DMA 中断的间隙,软件检测数据流中大于某个阈值的持续宽度,当宽度落在设定范围内时,把当前帧标记为有效帧并显示。这种触发适合测调制信号、PWM 信号,但它的实时性比硬件触发差,只能作为辅助。
4.4 校准和自检:没有这一步,测得再准也是假的
示波器是需要校准的,尤其是直流偏置和增益。我在板上留了一个 2.5V 基准电压源和一个 1kHz 方波输出接口,校准流程是:先把探头接到方波输出,软件读出波形的幅度和偏置误差,更新存储在 flash 中的校准参数表。增益校准直接改变显示比例系数,偏置校准则调整 ADC 驱动级的偏置电压。
校准过程中我发现一个问题:不同档位衰减网络的实际电阻值有偏差,导致 10x 档和 100x 档的幅度误差比 1x 档大。后来我把每个档位单独校准,分别存了不同的校准系数,实测垂直精度可以达到 3% 以内,已经满足日常维修和教学用了。
5. 软件和显示:把数据处理成看得懂的波形
5.1 波形渲染的三种模式
拿到 ADC 原始数据后,直接画点是最简单的做法,但屏幕只有 480 行高,8 位 ADC 数据有 256 级,如果直接线性映射,波形会显得很“排骨”。我做了三种显示模式,可以随时切换:
第一种是经典线模式,把每个采样点连成线段。适合观察正弦波、三角波等连续信号的形状。
第二种是峰值模式,把每个显示像素列内所有采样点的最大值和最小值找出来,画一条竖线。这个模式特别适合观察噪声毛刺和信号包络,这也是我用 40MSPS 采样率带来的最大优势——可以在每个像素列里塞进几十个采样点,把偶发的毛刺都逮住。
第三种是余晖模式,把最近 N 帧的波形以不同透明度叠加显示。通过软件模拟的余晖效果可以直观看到信号抖动范围。这个功能听起来花哨,实现其实不复杂:为每个像素点维护一个计数器和衰减定时器,每帧把旧帧的 Alpha 值衰减一点,再把新数据叠上去。当然这只是精简版,但实际观察通信波形已经很有效了。
5.2 坐标网格和触发指示
显示波形之前,我先把静态网格画到显存里,再进行波形绘制。网格采用十字刻度线,X 轴每格代表 20 个像素,Y 轴每格也是 20 个像素。触发位置用一个倒三角标记画在网格上,触发电平用一条虚线加文字标注,用户调节时可以实时看到变化。
这里要提醒一下:RGB 屏的显存很大,如果每次都整屏重绘,即使有 DMA 也很吃总线带宽。我的做法是“部分刷新”,静态网格和菜单只在变化时重绘,波形区域单独用一个窗口区域更新。实测波形刷新率从整屏重绘的 15fps 提升到了 25fps,效果非常明显。
5.3 菜单交互和编码器的配合
按键和编码器配合的交互,我摸索出比较顺手的方案:编码器的旋转用于调节当前选中参数,单击确认键进入下一层菜单,长按切换通道或者模式。界面不要做过多的菊花链深菜单,最多两级就到头,否则现场调试时一只手拿探头、一只手操作,很容易崩溃。
菜单的核心功能就五个:时基、垂直增益、触发电平、触发方式、波形模式。我把它做成了屏幕右侧的一列图标栏,点击图标直接在下方弹出调节条。这个设计后来实测下来效率很高,基本盲操作也能调。
6. 实测结果和调试过程中的典型翻车
6.1 信号发生器实测数据
整机装起来后,我找了一台信号发生器和一台商用台式示波器做对照。下面列几组有代表性的测试数据:
| 测试信号 | 实测频率 | 实测幅度 | 波形形态 | 说明 |
|---|---|---|---|---|
| 1kHz 正弦波 | 1.001kHz | 准确 | 平滑正弦 | 低频段非常稳定 |
| 100kHz 正弦波 | 99.98kHz | 衰减 <2% | 平滑正弦 | 受限于运放带宽,开始有相位延迟 |
| 1MHz 方波 | 998kHHz | 幅度准确 | 边沿可见轻微过冲 | 带宽接近极限 |
| 5MHz 正弦波 | 5.02MHz | 衰减约15% | 幅度明显降低 | 超出设计带宽后不可作为定量测量 |
| 20Hz 方波 | 19.96Hz | 准确 | 上升沿无明显畸变 | 低频耦合正常 |
从数据看,在 2MHz 以内做定性分析和幅度测量都没问题,超过 5MHz 后衰减比较明显。这个结果基本符合标称 10MHz 带宽的设计——因为信号衰减到 70% 的转折点就在 10MHz 附近,而 5MHz 还在过渡带,这个表现已经够用。
6.2 翻车实录:三个让我折腾了好几天的坑
第一个坑是 ADC 数据错位。刚开始上电,屏幕上显示的波形像被“撕裂”了一样,每隔几个像素就跳一段。排查了很久,发现是 ADC 数据总线的时序裕量不够,DMA 在数据线稳定之前就开始采样了。解决办法是在 ADC 的并行总线数据脚和 DMA 时钟之间加了约 10ns 的延迟,说白了就是在 PCB 上走线长度差上做文章,后来干脆在软件里把采样时钟相位微调了半拍,问题才彻底解决。
第二个坑是触发电平的大范围偏移。我在 1x 档触发正常,切到 10x 档后,想在 100mV 处触发,可是屏幕上的触发标记显示在 400mV 处。查了一圈发现,衰减档位切换时,模拟开关的导通电阻引起前端偏置电流变化,导致输入端的直流工作点偏移。解决办法是在衰减电阻网络后面加了一级隔直电容,让衰减网络和缓冲级之间直流隔离,漏过来的低频分量再由软件做基线恢复。
第三个坑是电池供电时的地环路噪声。用锂电池供电时,波形上面叠加了 50mV 左右的工频干扰,插上充电器更严重。这不是屏蔽问题,而是充电器的负端与板子数字地之间存在共模电压。我把模拟地和数字地在 ADC 芯片下方做了单点连接,又在电源输入端加了共模电感,噪声才从 50mV 压到了 3mV 以内。
6.3 常见问题速查
| 故障现象 | 常见原因 | 排查/解决办法 |
|---|---|---|
| 波形显示断断续续 | DMA 配置错误或数据总线时序不对 | 调采样时钟相位,检查 DMA 请求源 |
| 波形基线漂移 | 模拟前端直流偏置不稳定 | 检查基准源纹波,检查模拟开关漏电流 |
| 高频方波有过冲 | 滤波器截止频率过低或补偿电容不匹配 | 提高滤波器截止频率,微调补偿电容 |
| 垂直灵敏度不准 | 增益校准数据丢失 | 重新执行自检校准流程 |
| 电池显示剩 20% 突然关机 | 电池保护板触发过流保护 | 检查开机瞬间电流,软件里做软启动 |
| 屏幕有残影、拖尾 | RGB 屏刷新率不够或显存读写冲突 | 部分刷新,避免全屏重绘 |
7. 再战之后的心得和建议
这次再造手持示波器,我最想说的是:不要把方案想得过于复杂。第一版失败根本不是因为器件太差,而是我没把“稳定的触发”和“干净的信号链”当回事。一个示波器,用户最关心的永远是“波形稳不稳”和“测出来准不准”,其他的比如界面炫酷、按键多少都是次要的。
给准备入坑的兄弟们三个建议。第一个,模拟前端一定要舍得花时间,这是示波器的灵魂,MCU 再强,前端噪声大、带宽窄,后面都是白搭。第二个,触发一定要优先考虑硬件触发,软件触发只能是辅助,靠软件对齐的波形永远做不到让人舒服。第三个,多做校准,每档位单独标定,别偷懒用一个全局系数,这决定了你测试结果的可信度。
后续我还在考虑把采样率再往上提一档,做到 80MSPS,同时也想着给机器加个蓝牙串口,把波形数据直接发到手机上分析。不过这些都是之后的计划了,先把这版用得滚瓜烂熟再说。