十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

STM32 DIY示波器实测指南:从采样率到FFT的完整验证

STM32 DIY示波器实测指南:从采样率到FFT的完整验证 很多嵌入式开发者在调试串口、SPI、电机驱动这类低速信号时会发现自己缺一台能随时拿出来看的示波器。台式示波器要么太贵要么放在实验室不方便借串口调试助手只能看数据内容看不到电平细节逻辑分析仪擅长数字时序却看不出模拟波形失真。于是这两年“DIY示波器”成了热门的替代思路。先说判断DIY示波器不是玩具但也别指望它把几千块的台式机按在地上摩擦。它真正让人“超出想象”的地方是用一两百元的物料成本让嵌入式开发者在调串口、看PWM、抓单次脉冲、验证ADC采样这些日常场景里能拥有一台可以随身携带的调试工具。更重要的是组装和测试它的过程会让你把采样率、带宽、触发、存储深度这些平时只背概念的名词彻底变成自己的知识。如果你正在纠结“要不要自己做一台示波器”或者已经装好了板子但不太确定测试结果靠不靠谱这篇文章可以帮你把整个实测思路和判断方法理清楚。下面用一套常见的STM32入门级DIY示波器方案作为讨论对象从核心指标开始把手里的信号源校准、实测、读数和排查讲完整。1. 为什么要认真做一次DIY示波器实测很多人在选购或自制示波器的时候第一眼看的是“最高采样率”。好像采样率标得越高机器就越厉害。但DIY示波器的问题恰恰在于标称参数和实际能测到的参数往往不是一回事。举个例子同样是基于STM32的采集方案ADC理论上能跑几MSPS但受限于模拟前端带宽、运放驱动能力、采样保持时间、DMA传输带宽甚至屏幕刷新逻辑实际测量100kHz方波时上升沿可能已经被明显削平。如果不做一轮系统性实测你会误以为看到的就是真实信号这会直接影响调试结论。所以做性能实测不是闲得无聊而是为了弄清楚三个问题这台DIY示波器在什么频率范围内测得准在什么条件下会出现混叠、失真或假触发哪些调试场景可以放心交给它哪些场景必须换专业设备。下面把示波器的核心指标和DIY方案的关键瓶颈放在一起讲这样后面看测试步骤时不会觉得只是机械地拧旋钮。2. 示波器性能指标采样率、带宽、存储深度和触发2.1 采样率不是简单“越高越好”采样率表示示波器每秒采集多少个点单位是Sa/s或MSa/s。根据奈奎斯特采样定理要还原一个频率为 f 的信号采样率至少要大于 2f。但在实际测量中只满足2倍关系是非常危险的因为方波、PWM这类信号含有大量高次谐波2倍采样率远远不足以还原边沿。如果你只是用DIY示波器看1kHz方波是否存在8k或16k采样率就已经够用。但如果想较精确地测PWM的上升沿/下降沿时间采样率至少要比信号最高次谐波高一个数量级否则边沿会显示成一条斜线你测到的上升时间比真实值大这个问题在热词里也大量出现“示波器测上升时间比平时大了一倍”。不一定是硬件坏了多半是采样点太稀。2.2 带宽决定你“能不能看到这个信号”带宽指的是示波器前端能通过的信号频率范围通常以-3dB点为界。超过带宽频率的正弦波幅度会明显衰减。对于数字信号带宽不够的直接后果不是波形变小而是边沿变缓。所以用一台标称1MHz带宽的DIY示波器去测几百kHz的方波幅度看起来还在边沿却可能已经完全失真。这里有一个常用估算关系示波器系统上升时间约为 0.35 / 带宽。例如标称1MHz带宽系统自身上升时间大约是350ns。如果被测信号的上升时间只有100ns屏幕上看到的边沿几乎就是示波器自己的边沿不是信号的真实边沿。2.3 存储深度才是连续捕获的关键很多DIY方案只有几千字节的缓存采样数据只能存很短一段。调节时基到每格几百毫秒看起来是慢扫了但可能实际是用低采样率采长时窗波形细节已经丢失。存储深度不足还容易造成单次捕获时波形“前面没有、后面突然冒出来”的体验。2.4 触发波形能稳定显示的前提触发告诉示波器“从哪个时刻开始画波形”。没有触发的示波器每次扫描的起点都不一样看到的波形会像一条不断水平漂移的闪烁曲线。对于DIY示波器触发性能差是常见问题尤其是上升沿触发在信号幅度很小或不稳定时很容易出现“波形乱跳”的现象。顺便说一句很多人在Keil调试里打开逻辑分析仪窗口发现找不到信号原因通常有两个一是没有把变量或引脚添加到逻辑分析仪窗口二是采样周期设置得太长信号变化太快被漏掉。这个问题和DIY示波器“看着没波形实际信号是好的”很相似排查思路是检查触发条件、采样率和时基范围。3. 实测前的环境准备与仪器连接3.1 硬件环境要做示波器性能实测需要准备以下硬件设备作用一套STM32类的DIY示波器被测对象常见成品有DSO150/DSO138或自焊板信号发生器输出标准方波、正弦波、三角波作为测试信号源万用表校准直流电压精度时的参考探头或带屏蔽的测试线连接被测信号尽量使用短地线USB转串口模块部分DIY示波器没有屏幕需要把数据传给上位机如果手里没有信号发生器可以用一片STM32开发板临时做一个低频信号源通过DAC输出正弦波或者用定时器输出PWM方波。缺点是频率和幅度不如专业信号发生器稳定但在几百kHz范围内做课堂式验证完全够用。3.2 连接注意事项连接前先看共地问题。DIY示波器外壳经常是金属或者USB口和GND直连测试外部电路时要先确认两边电源没有压差否则容易出现打火或损坏前端。测量220V这类高压是一票否决项不是“加个衰减探头就能解决”的事。没有隔离通道和设备就不要尝试。接线顺序建议先接示波器地线再接信号拆线时顺序反过来先拆信号线再拆地线探头地线尽量短最好在被测点旁边就近接地测量前先把探头补偿校准做好否则高频信号幅度会严重偏小。3.3 软件环境准备如果DIY示波器本身不带屏幕通常需要通过串口把采集数据发给上位机显示。软件准备如下Python 3.x并安装 pyserial、numpy、matplotlib 三个库串口调试助手或Minicom用于查看原始数据一个能编译STM32工程的IDE本文示例用STM32CubeIDE或者Keil都能跑。安装依赖命令pip install pyserial numpy matplotlib这里不建议直接上来就把硬件焊好、一上电就看波形而是先确认固件里的采样率配置是多少再决定后面怎么设置信号源频率。很多DIY示波器“超频”使用真实采样率和屏幕右上角显示的不一致所有后续测量都会失去意义。4. DIY示波器核心实测步骤4.1 第一步直流电压精度校准把示波器输入接地观察零基线是否平直然后输入1V直流电压。调整垂直增益直到显示值与万用表读数接近。这一步的意义不是追求高精度而是确保后续测电压幅度时有基本可信度。通常DIY示波器会受到ADC参考电压误差影响显示值偏大或偏小10%都不奇怪。如果发现每个量程都偏同一个比例那多半是分压电阻的误差适合做软件校准或换更高精度电阻如果只有某个量程偏说明该档位的模拟开关或衰减网络有问题。4.2 第二步用方波看真实采样率和带宽把信号发生器输出设置为1kHz方波幅度1V占空比50%。先记录屏幕上的幅值、频率、上升沿和下降沿。然后把方波频率逐步提高到10kHz、50kHz、200kHz、500kHz每个频率下都观察一次显示频率是否和信号源设置一致波形边沿是否越来越平缓方波顶部和底部是否出现明显过冲或振铃波形是否会出现毫无规律的跳变或“摩尔纹”。这个方法比测正弦波更严苛因为方波边沿里包含高频分量。如果你发现50kHz方波看起来已经像三角波说明这台DIY示波器当前档位的有效带宽并不高后面再去测2.4G射频或者其他高速信号就没有意义。如果方波在低频段出现了阶梯状更像是采样点数不足而不是带宽不足。4.3 第三步测正弦波频率并观察混叠这一步用来判断采样率和信号频率的关系。设定一个干净的正弦波从10kHz开始逐步提高到采样率的1/2附近再往上一点。当你把信号频率提高到超过奈奎斯特频率时示波器屏幕上会出现比真实频率低很多的假波形这就是混叠。如果你的DIY示波器标称采样率是1MSPS理论上能测到500kHz以内的正弦波但实际因为你开了低通滤波或者模拟前端衰减超过一两百kHz后幅度可能已经不准。正确的测试方法是固定示波器水平时基不变信号源从低到高缓慢扫频每增加一个频点记录显示频率和幅度观察显示频率从什么时候开始与信号源设定值明显偏离。如果出现显示频率突然回落的现象例如输入700kHz信号屏幕上却显示300kHz请不要怀疑是信号发生器坏了这大概率是采样率不足导致的混叠。4.4 第四步触发稳定性和单次捕获测试把信号源设置为“脉冲串”模式发出一串几毫秒宽的脉冲然后停顿一段时间再重复。观察DIY示波器能否稳定地触发在脉冲的第一个上升沿。这里可以顺便测试热词里关于“上升沿和下降沿”功能的支持选择上升沿触发时波形左侧边应该是上升沿选择下降沿触发时波形左侧边应该是下降沿对于-1V到1V这样的双极性信号如果DIY示波器输入量程只能测正电压通常会触发不到需要加直流偏置或换通道。如果屏幕上波形横向乱跳说明触发判断有抖动或者触发阈值没有设置在信号上升沿范围内。解决方法是把触发电平调到信号幅度的约50%位置再打开触发释抑或锁定。4.5 第五步电源纹波测量最容易产生误判的场景很多人入手DIY示波器后第一件事是量电源纹波。这个场景需要认真提醒入门级DIY示波器通常不适合做mV级纹波测量。原因有三探头地线过长会引入噪声示波器自身ADC量化噪声在垂直档位放到很小时非常明显如果使用的是USB供电的DIY示波器USB电源本身可能就是纹波来源测出来的很可能是设备自身噪声。如果非要测低压电源纹波建议采用限制带宽做法同时用短线接地。但结论不要直接作为产品质量判定依据只能作为“有没有异常尖峰”的粗筛。真正的纹波达标测试还是需要专业示波器和合适的探头方案。5. 把数据导出来示例代码与验证方法如果只看屏幕很多DIY示波器的显示帧率很低人眼很难捕捉细节。更可靠的办法是把ADC采样数据通过串口导出到上位机再用Python做数值分析。下面给出一套最小可行的示例代码用于理解“采集-传输-分析”链路。5.1 STM32通过ADCDMA采集波形数据以STM32 HAL库为例初始化ADC并用DMA循环采集。这个示例只展示核心思路不是完整工程// 文件路径user/diy_scope_adc.c #include main.h ADC_HandleTypeDef hadc1; DMA_HandleTypeDef hdma_adc1; #define ADC_SAMPLES 2048 uint16_t adc_buf[ADC_SAMPLES]; void MX_ADC1_Init(void) { hadc1.Instance ADC1; hadc1.Init.ScanConvMode DISABLE; hadc1.Init.ContinuousConvMode ENABLE; hadc1.Init.DiscontinuousConvMode DISABLE; hadc1.Init.ExternalTrigConv ADC_SOFTWARE_START; hadc1.Init.DataAlign ADC_DATAALIGN_RIGHT; hadc1.Init.NbrOfConversion 1; HAL_ADC_Init(hadc1); } void MX_DMA_Init(void) { __HAL_RCC_DMA2_CLK_ENABLE(); HAL_NVIC_SetPriority(DMA2_Stream0_IRQn, 0, 0); HAL_NVIC_EnableIRQ(DMA2_Stream0_IRQn); } void ADC_Start_DMA_Sampling(void) { HAL_ADC_Start_DMA(hadc1, (uint32_t *)adc_buf, ADC_SAMPLES); } void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc) { if (hadc-Instance ADC1) { // 一轮采样完成可以启动串口发送 } }在这段代码里采样率由ADC时钟分频和采样周期共同决定。例如ADC时钟为12MHz采样周期配置为12个周期单次转换大约需要1us对应1MSPS左右。具体频率要以你的库文件和时钟树为准不要拿这段代码直接当精确计时依据。5.2 示例分段把ADC数据从串口发出去如果2048个点一次性通过串口发送波特率太低会耗时很长造成数据断档。最稳妥的做法是分成若干包发送调试阶段一个个包分析即可// 文件路径user/diy_scope_uart.c #include stdio.h #include main.h extern UART_HandleTypeDef huart1; extern uint16_t adc_buf[2048]; void Send_Adc_Samples(void) { uint8_t header[4] {0xAA, 0x55, 0x00, 0x10}; HAL_UART_Transmit(huart1, header, 4, 100); for (uint16_t i 0; i 2048; i) { uint8_t tmp[2]; tmp[0] adc_buf[i] 0xFF; tmp[1] (adc_buf[i] 8) 0xFF; HAL_UART_Transmit(huart1, tmp, 2, 10); } }串口发送的每一帧可以定义成“帧头长度数据校验”的格式。这个例子省略了校验在实际工程里建议加上CRC或者简单的累加和否则解析时错一个字节就可能整帧错位。5.3 Python解析采样数据并计算频谱下面是Python端脚本它读取串口数据、还原ADC值、按时间轴画出波形并计算基波频率。注意在读取前要先把DIY示波器的ADC采样率写进脚本的sample_rate变量例如sample_rate 1_000_000。# 文件路径tools/scope_fft.py import serial import numpy as np import matplotlib.pyplot as plt SERIAL_PORT COM10 # Linux下通常是 /dev/ttyUSB0 或 /dev/ttyACM0 BAUDRATE 921600 SAMPLE_RATE 1_000_000 # 这里必须改成你固件里实际的ADC采样率 BUFFER_SIZE 2048 ser serial.Serial(SERIAL_PORT, BAUDRATE, timeout3) def read_frame(): while True: head ser.read(1) if head b\xAA: second ser.read(1) if second b\x55: ser.read(2) # 长度字段本示例固定为0x0010的简化版 raw ser.read(BUFFER_SIZE * 2) return np.frombuffer(raw, dtypenp.uint16) data read_frame() ser.close() # 将 ADC 原始值转换为 0 ~ 3.3V 电压 voltage data.astype(np.float32) * 3.3 / 4095.0 t np.arange(BUFFER_SIZE) / SAMPLE_RATE fft_vals np.fft.rfft(voltage - voltage.mean()) freqs np.fft.rfftfreq(BUFFER_SIZE, 1.0 / SAMPLE_RATE) amplitude np.abs(fft_vals) * 2.0 / BUFFER_SIZE idx np.argmax(amplitude[1:]) 1 print(主峰频率: {:.2f} kHz.format(freqs[idx] / 1000.0)) print(主峰幅度: {:.3f} V.format(amplitude[idx])) fig, (ax1, ax2) plt.subplots(2, 1, figsize(10, 6)) ax1.plot(t * 1e3, voltage) ax1.set_title(DIY Scope Captured Waveform) ax1.set_xlabel(Time (ms)) ax1.set_ylabel(Voltage (V)) ax2.plot(freqs / 1000.0, amplitude) ax2.set_title(Spectrum) ax2.set_xlabel(Frequency (kHz)) ax2.set_ylabel(Amplitude (V)) plt.tight_layout() plt.show()运行方式是先接好串口再执行命令python tools/scope_fft.py如果脚本没有输出主峰频率说明串口读回来的数据错位了需要检查帧头匹配和波特率是否一致。如果频率显示为0大概率是SAMPLE_RATE与实际不符可以尝试改成500000或250000再看。5.4 用示例代码验证一份完整测试实际测试时建议这样操作用信号发生器给DIY示波器输入一个10kHz、1V的正弦波把Python脚本里SAMPLE_RATE设置为1MSPS执行脚本后先看时域波形幅度是否是1V左右再看频谱主峰是否在10kHz附近。如果这两个结果都对说明硬件链路没问题。之后再把频率逐步提高到100kHz、300kHz、500kHz分别记录主峰频率和幅度就可以画出一条频率响应曲线。这条曲线就是你这台DIY示波器真实的可用带宽比屏幕上那个“100MHz”之类的标称值更有说服力。6. 如何评估DIY示波器的实测表现6.1 超出想象的正面体验做完整套测试你会理解为什么很多人说“DIY示波器也可以超出想象”。首先是成本低但基础体验完整。一个带屏幕的入门套件通常只花百来元却能显示波形、调时基、切换触发方式。对低速数字电路调试来说完全能取代“没有示波器可用”的尴尬。其次是有问题的波形能逼你思考原理。当自己组装的示波器在500kHz方波上显示出一个完全不存在的振铃你才会主动去查探头补偿、地线寄生电感、采样率限制。这种理解深度是直接用昂贵台式示波器很难获得的。再者是DIY方案公开了所有代码和数据流。从ADC采样到DMA搬运再到串口协议和上位机绘图每一层都能自己改自己查。如果以后做USB示波器、LabVIEW虚拟示波器、WiFi数据传输示波器底子就是这套链路。6.2 不能让DIY示波器强行代班的场景需要理性认知的反面也很清楚场景DIY示波器建议原因串口/SPI/I2C逻辑和波形验证可用频率一般在几十MHz以下低速模式问题不大音频信号观察可用频率范围低带宽要求不高PWM检查、继电器动作时间可用主要看边沿和时间关系电源纹波精确测量不建议作为评判依据mV级噪声容易淹没真实纹波射频或百MHz以上信号不可用模拟前端和采样率都不够单次高速异常毛刺捕获较难存储深度和触发性能受限市电等高压信号严禁安全隔离不达标6.3 怎么判断采样数据是真实还是假象一个简单的现场判断法改变信号源频率观察DIY示波器显示频率是否同步连续变化。如果频率从200kHz调到300kHz屏幕上显示频率却从200kHz跳到100kHz说明已经混叠了。此时不要再相信波形的形状把频率调低缩小时基再用“真实”状态去观察。另一个判断法是看波形是否逐步变化。真实信号在扫频时波形边沿会平滑变化如果波形像随机产生的噪声多半是触发不稳或采样率不足。可以把采集到的数据导出来用上面Python脚本做FFT用“主峰频率是否等于输入频率”作为客观依据而不是仅凭屏幕目测。7. 常见问题与排查思路问题现象可能原因排查方式解决方案屏幕上完全没波形输入通道没开或量程选得过大/过小检查同轴接口、通道耦合方式使用GND档看基线切换到直流耦合将量程调为1V/div左右波形横向乱跳触发电平不在信号范围内打开测量菜单查看当前触发电平把触发电平设置为信号幅度的50%方波显示成三角波带宽不足或采样点太少逐步降低输入频率观察边沿是否恢复只测量当前真实带宽以内的信号显示频率比输入频率低采样率不够出现混叠对同一信号提高采样率档位缩小水平时基或换更高采样率方案幅度比实际值小很多探头10x衰减未切换或输入阻抗不匹配查看探头上的衰减开关将探头设为1x或在软件里设置10x补偿测上升时间偏大示波器自身带宽不够测量一个已知的快沿信号对比根据带宽估算上升时间不要用DIY实测高速边沿串口上位机收不到数据固件串口参数或USB转串口驱动问题用串口调试助手发一个测试字节检查波特率、数据位、停止位和驱动FFT主峰频率不对Python脚本里采样率设置错误对照固件实际ADC配置复查把SAMPLE_RATE改成真实值测量电源纹波噪声明显地线太长或示波器自身噪声叠加用短弹簧地线对比测试限制带宽测量或改用专业低噪前端Keil逻辑分析仪找不到信号变量未添加、周期配置过长检查Debug设置中的逻辑分析仪窗口添加要观察的IO或变量调整显示周期遇到问题时不要急着怀疑硬件损坏。绝大多数现象是触发方式、衰减系数、采样率、时基范围这四大项的设置问题。按“先接地GND看基线再输入低频校准信号最后逐步提高频率”的顺序排查效率会更高。8. 最佳实践把DIY示波器真正用于日常调试8.1 每次使用前做快速自检用示波器自带方波输出或信号发生器接一个1kHz方波看一眼幅度和上升沿是不是和上次一致。如果形状变了先查探头和端口避免把错误测量带入后续问题。8.2 保存波形截图和关键参数调试不是“看一眼波形就修好了”而是要沉淀结论。建议把屏幕截图或者Python导出的曲线图保存下来并标注以下信息被测点、信号频率、显示幅度、时基档位、触发模式、测量日期。一段时间后你会发现这些记录比记忆可靠得多。8.3 把DIY示波器和逻辑分析仪配合使用串口调试助手解决“协议数据对不对”的问题逻辑分析仪解决“时序边沿对不对”的问题DIY示波器解决“模拟波形有没有畸变”的问题。三者是互补关系。当逻辑分析仪抓不到信号时先用示波器看对应引脚上到底有没有电平跳变再回头检查电平阈值的设置。这种排查习惯能显著缩短定位时间。8.4 安全边界必须写清楚DIY示波器通常没有隔离设计外壳、串口GND、USB口GND都可能和被测电路共地。在给飞线比较多的板子供电或测量时建议先测量两路GND之间的电压差GND有电压差时必须先处理供电关系否则轻则信号损坏重则打火。测量高压或电源设备时请使用正规隔离示波器和专用差分探头。8.5 把它当学习平台而不是精密工具如果只想找一个最省事的测量工具直接买一台靠谱的成品示波器可能更省心。但如果你愿意花一个周末去调通采样、传输和显示链路DIY示波器给你的回报会远超这百来元成本。你会顺便掌握STM32的ADC多通道配置、DMA中断、串口帧格式设计、上位机绘图等一连串嵌入式基础技能。这些技能在后续所有嵌入式项目中都用得上这才是“超出想象”的核心所在。9. 总结回到一开始的问题DIY示波器到底靠不靠谱答案取决于你把它放在哪个测量区间里用。放在几十到几百kHz的低频信号调试中它能提供完整的示波器交互逻辑帮助你看清串口电平、PWM波形和单次脉冲放在高频或高精度测量场景里它的带宽、噪声、触发和存储深度都会暴露明显局限。这篇文章介绍了DIY示波器的核心指标、实测步骤、串口数据采集和FFT分析方法也明确了哪些场景不能用。如果你手里正好有一套DIY方案建议跟着第4节和第5节的流程先跑一遍用1kHz方波确认基本链路正常然后逐步提到500kHz以上把每一档的显示频率和幅度记录下来。等你亲眼看到混叠出现、边沿变缓、FFT主峰偏移的瞬间对采样率和带宽的理解会比读十篇理论文章都深。接下来可以再去研究更高端的FPGA采集方案、逻辑分析仪协议解码或者基于网络传输的远程示波器。
返回列表