基于STM32F103的500KHz DIY示波器:低成本高性能的嵌入式开发实践
2026/6/23 8:09:56 网站建设 项目流程

1. 项目概述与核心价值

在电子开发和调试的日常里,示波器就像工程师的眼睛,没有它,面对电路板上那些看不见摸不着的电信号,调试工作几乎寸步难行。然而,一台性能尚可的商用示波器,价格往往让许多学生、爱好者和初创团队望而却步。几年前,基于Arduino的简易示波器方案流行起来,但其有限的ADC采样率和处理速度,通常只能应对几十KHz以下的低频信号,实用性大打折扣。今天要分享的这个项目,正是为了解决这个痛点:用一颗成本仅十几元的STM32F103C8T6“蓝色药丸”核心板,搭配一块常见的ILI9341 TFT彩屏,打造一台带宽可达500KHz的实用级DIY示波器。这不仅仅是“玩具”,而是一个能以极低成本(总成本约15美元)进入你工作台的、真正能用于观察和分析中频信号的功能性工具

这个项目的核心思路,是充分发挥STM32这颗32位ARM Cortex-M3内核的性能潜力。相比8位的AVR(如Arduino Uno),STM32F103拥有高达72MHz的主频、更快的12位ADC以及灵活的DMA(直接存储器访问)控制器。通过精心设计的代码架构,我们可以让ADC以超过1MSPS(每秒百万次采样)的速率连续采集信号,并利用DMA将数据直接搬运到内存,无需CPU频繁干预,从而为波形处理和显示腾出宝贵的计算资源。最终,我们能在320x240分辨率的屏幕上实时绘制出清晰的信号波形,并实现电压测量、时基调节、触发控制等基本功能。无论你是想深入学习嵌入式系统、验证自己的电路设计,还是单纯想拥有一台属于自己的示波器,这个项目都提供了一个清晰、可行且富有成就感的实现路径。

2. 硬件系统设计与核心器件选型

2.1 主控芯片:为什么是STM32F103C8T6?

选择STM32F103C8T6作为核心,是基于性能、成本和生态三方面的综合考量。首先,其72MHz的主频和32位架构,在处理ADC数据流、运行波形显示算法以及响应按键中断时,能提供远超Arduino ATmega328p(16MHz,8位)的流畅度。其次,它内置了2个12位ADC,理论上采样率可达1MHz,这为我们实现500KHz的模拟带宽(遵循奈奎斯特采样定理,采样率至少需为信号最高频率的2倍)提供了硬件基础。最后,这块俗称“蓝色药丸”的开发板价格极其低廉,且拥有庞大的社区支持和丰富的Arduino核心库,这意味着我们可以使用熟悉的Arduino IDE进行开发,大大降低了入门门槛。

注意:STM32F103系列ADC的实际可持续采样率受多种因素限制。在72MHz系统时钟下,使用ADC预分频器,单个ADC的最高采样周期可设置为1.5个时钟周期,从而实现理论上接近1MSPS的速率。但在多通道采样或使用DMA时,需要仔细配置时钟和采样时间以达到最佳性能。

2.2 显示模块:ILI9341 TFT屏幕的驱动要点

本项目选用的是240x320分辨率的ILI9341驱动芯片的TFT屏幕。这类屏幕色彩鲜艳、分辨率适中,且价格便宜。在Arduino环境下,我们可以使用诸如Adafruit_ILI9341TFT_eSPI这类经过优化的库来驱动。为了达到流畅的波形刷新效果,需要关注两点:一是通信接口,二是绘图优化。

通信接口选择:为了提高刷新率,强烈建议使用SPI(串行外设接口)模式驱动屏幕,而非并口。STM32的硬件SPI速度可以轻松达到几十MHz,能显著加快像素数据的传输。在接线时,务必确认屏幕的IM引脚电平,以设置正确的SPI模式。

绘图优化策略:波形绘制不是全屏刷新,而是局部更新。通常的做法是:先清除上一帧波形轨迹所在的区域(画背景色线段覆盖),再绘制新的波形点。使用drawLine函数连接相邻采样点,比逐点画drawPixel要高效得多。代码中类似tft.drawLine(i*mn, 230-data1[i+i2], i*mn+mn-1, 230-data1[i+1+i2], ILI9341_RED);的语句,正是这种优化思想的体现。其中mn是水平缩放因子,data1是存储ADC值的数组。

2.3 信号输入与调理电路解析

原始原理图相对简单,但其中包含了关键的保护和耦合电路。输入信号首先经过两个反向并联的1N4007二极管,构成一个简单的双向钳位保护电路。当输入电压超过VCC(3.3V)或低于GND时,二极管导通,将信号电压钳位在-0.7V到VCC+0.7V之间,从而保护STM32脆弱的ADC输入引脚不被过压损坏。

随后,信号通过一个由4.75kΩ电阻和10μF电容组成的RC网络。这个电路承担了两个核心功能:

  1. DC耦合/AC耦合选择:通过一个按钮(原理图中的AC/DC开关)切换。在DC耦合模式下,电容被短路,信号直接进入ADC。在AC耦合模式下,电容串联在信号路径中,起到隔直作用,可以滤除信号中的直流分量,方便观察叠加在直流电平上的交流信号。
  2. 抗混叠滤波:这个RC电路也构成了一个一阶低通滤波器。其截止频率f_c = 1/(2πRC) ≈ 1/(23.144750*10e-6) ≈ 3.35Hz。这个截止频率非常低,主要目的是滤除工频干扰等低频噪声。但请注意,对于500KHz的信号,这个RC电路的时间常数可能引入衰减和相移。对于高频测量,更理想的方案是使用一个截止频率略高于目标带宽(如600KHz)的有源或无源低通滤波器,作为抗混叠滤波器,以防止高频噪声混叠到观测频带内。

电压量程扩展:原文提到最大输入正电压为6.6V,这是由内部电阻分压和ADC参考电压(通常为3.3V)决定的。若需测量更高电压,必须在信号进入保护电路之前,增加一个高输入阻抗、高精度的电阻分压网络。例如,测量0-30V电压,可以使用一个90kΩ和10kΩ的电阻串联进行10:1分压,同时需考虑电阻的精度和温度系数对测量结果的影响。

2.4 用户交互:五按键功能布局

五个按键构成了简洁的人机交互界面:

  • SET(菜单):进入或退出系统设置菜单,用于切换需要调整的参数(如时基、垂直灵敏度、触发模式)。
  • UP/DOWN(增减):在菜单中,用于增加或减少当前选中参数的数值。
  • HOLD(保持):冻结当前屏幕波形显示,便于仔细观察和测量。在保持状态下,可以结合其他按键实现光标测量、频率计算等高级功能(需在代码中实现)。
  • AC/DC(耦合):切换输入信号的耦合方式,如前文所述。

按键的连接建议使用外部上拉电阻(如10kΩ)连接到3.3V,并配置MCU引脚为内部或外部下拉输入模式,以提高抗干扰能力。所有按键都应启用中断或在其扫描函数中进行消抖处理,通常采用延时10-20ms后再次检测的软件消抖法。

3. 软件架构与核心代码实现

3.1 开发环境搭建与库管理

虽然使用Arduino IDE,但核心是STM32。首先需要在IDE的“开发板管理器”中添加“STM32 Cores” by STMicroelectronics。选择开发板为“Generic STM32F1 series”,并具体选择“BluePill F103C8”。需要正确配置烧录方式,常用的有“STM32CubeProgrammer (DFU)”或“Serial”方式,这取决于你的核心板是否预置了DFU引导程序或串口转换芯片。

必需的库主要包括:

  • TFT显示库:例如TFT_eSPI。需要根据你的屏幕引脚连接,修改库中的用户配置文件(如User_Setup.h),正确定义TFT_CSTFT_DCTFT_RSTSPI_MOSISPI_MISOSPI_SCK等引脚。
  • ADC与DMA库:STM32的Arduino核心已经封装了底层寄存器操作,我们可以直接使用analogRead()函数,但为了实现高速连续采样,必须直接操作寄存器并启用DMA。这需要引入STM32的底层头文件,并编写特定的初始化函数。

3.2 高速ADC采样与DMA传输实现

这是本项目性能的关键。STM32的ADC在规则通道组模式下,可以配合DMA实现自动、连续的数据搬运。

初始化步骤

  1. 时钟配置:确保ADC和DMA所在总线的时钟已使能。
  2. ADC引脚配置:将用作ADC输入的GPIO(如PA0)设置为模拟输入模式。
  3. ADC基本参数配置
    • 设置分辨率(12位)。
    • 设置数据对齐方式(右对齐)。
    • 设置扫描模式(单通道则禁用扫描,多通道则启用)。
    • 设置连续转换模式(CONT位使能)。
    • 配置采样时间(对于500KHz信号,采样时间应尽可能短,例如设置为1.5个周期)。
  4. DMA配置
    • 指定DMA通道(ADC1对应DMA1通道1)。
    • 设置外设地址为ADC数据寄存器(ADC1->DR)地址。
    • 设置内存地址为自定义的缓冲区数组(如adc_buffer[1024])地址。
    • 配置数据传输方向为外设到内存。
    • 设置缓冲区大小,并启用循环模式(CIRC),这样当缓冲区填满后,DMA会自动从头开始覆盖,实现不间断的数据流。
  5. 启用DMA和ADC:先使能DMA,再使能ADC,最后触发ADC开始连续转换。

通过以上配置,ADC就会以设定的速率不停采样,DMA则默默地将每个采样值搬运到你指定的内存数组中,完全不需要CPU参与。你的主循环只需要定期(例如根据屏幕刷新率)去这个缓冲区读取最新的一段数据即可进行波形绘制。

代码片段示意(非完整,展示思路)

#define ADC_BUFFER_SIZE 1024 volatile uint16_t adc_buffer[ADC_BUFFER_SIZE]; void setupADC_DMA() { // 1. 使能时钟 RCC->APB2ENR |= RCC_APB2ENR_ADC1EN; RCC->AHBENR |= RCC_AHBENR_DMA1EN; // 2. 配置ADC引脚 (PA0) pinMode(PA0, INPUT_ANALOG); // 3. 配置ADC1 ADC1->CR2 = ADC_CR2_ADON | ADC_CR2_CONT | ADC_CR2_DMA; // 使能ADC、连续模式、DMA ADC1->SMPR2 = ADC_SMPR2_SMP0_0; // 通道0采样时间设为7.5周期(根据时钟调整) ADC1->SQR3 = 0; // 规则序列中第一个转换的是通道0 // 4. 配置DMA1通道1 DMA1_Channel1->CPAR = (uint32_t)&(ADC1->DR); // 外设地址 DMA1_Channel1->CMAR = (uint32_t)adc_buffer; // 内存地址 DMA1_Channel1->CNDTR = ADC_BUFFER_SIZE; // 数据传输数量 DMA1_Channel1->CCR = DMA_CCR_MINC | // 内存地址递增 DMA_CCR_CIRC | // 循环模式 DMA_CCR_TCIE | // 传输完成中断(可选) DMA_CCR_EN; // 使能通道 // 5. 启动 ADC1->CR2 |= ADC_CR2_SWSTART; // 开始转换 }

3.3 波形显示与界面渲染逻辑

波形显示的核心是将ADC采样值数组映射到屏幕的像素坐标。屏幕Y轴方向通常代表电压,X轴方向代表时间。

坐标映射

  • 垂直方向(电压):ADC值是0-4095(12位),需要根据当前设置的垂直灵敏度(V/div)转换为屏幕上的像素位置。例如,如果屏幕显示区域高度为200像素,对应电压范围是0-3.3V,那么每个像素代表3.3V/200≈0.0165V。一个ADC值val对应的Y坐标可能是:y = screen_height_bottom - (val * v_per_pixel),其中v_per_pixel是每像素代表的电压值。
  • 水平方向(时间):时基(s/div)决定了波形在水平方向被压缩或拉伸的程度。假设屏幕显示区域宽度为300像素,显示5个水平格(div),那么每格宽度是60像素。如果时基是1ms/div,那么整个屏幕宽度代表5ms。我们需要根据采样率计算每个像素点应该对应缓冲区中的哪个采样点。这里可能涉及抽点显示(采样点太多时)或插值显示(采样点太少时)。

绘制流程

  1. 读取当前时基、垂直灵敏度等设置。
  2. adc_buffer中根据触发条件(如上升沿触发)找到波形显示的起始点。
  3. 计算需要显示多少个采样点(N = 采样率 * 屏幕显示时间跨度)。
  4. 遍历这些采样点,将每个点映射为屏幕坐标。
  5. 使用drawLine函数,将相邻坐标点连接起来,形成连续的波形曲线。
  6. 在屏幕固定位置绘制网格、电压值、时基值、触发状态等UI元素。

颜色与风格:如原文所述,波形颜色可以在drawLine函数中轻松修改,例如ILI9341_REDILI9341_GREENILI9341_CYAN等。可以设计多种颜色主题,甚至根据信号频率或幅度动态改变颜色。

3.4 关键功能实现:触发、测量与菜单

触发功能:这是示波器稳定显示波形的关键。简单的边沿触发实现如下:

  • 持续监控ADC数据流。
  • 设置一个触发电平(可通过UP/DOWN键调整)。
  • 当检测到信号从低于触发电平变为高于触发电平(上升沿触发)时,记录当前点在缓冲区中的位置,并以此作为一帧波形数据的起始点进行显示。
  • 加入触发释抑时间设置,可以避免在复杂波形(如脉冲串)上错误触发。

自动测量:在HOLD模式下,可以对冻结的波形进行简单测量。

  • 电压测量:遍历显示缓冲区,找出最大值和最小值,换算成电压值,即可得到峰峰值(Vpp)。
  • 频率测量:实现一个简单的过零检测算法。遍历波形数据,记录相邻两次从负到正(或从正到负)穿越触发电平(或零电平)的点之间的时间间隔。这个间隔就是一个周期的时间,其倒数即为频率。为了提高精度,可以测量多个周期求平均。

菜单系统:使用状态机(State Machine)来管理菜单是一个清晰的方法。定义一个全局变量menu_state,其不同值代表不同状态(如主界面、时基设置、垂直灵敏度设置、触发设置等)。按下SET键,就在不同状态间循环切换。在某个设置状态下,UP/DOWN键就修改该状态对应的参数值。所有设置参数应保存在全局变量中,供波形显示和采样逻辑使用。

4. 系统调试、性能优化与实测

4.1 硬件组装与初始调试

焊接完成后,不要急于上电。先用万用表检查所有电源引脚(3.3V, GND)之间有无短路。确认无误后,先只连接STM32核心板和TFT屏幕,上传一个简单的屏幕测试程序(如显示颜色条),确保显示系统工作正常。

然后连接信号输入电路。一个非常重要的安全步骤是:在首次测试时,使用一个已知安全的信号源,例如一个1KHz、1Vpp的正弦波信号发生器,或者用另一个MCU的PWM输出经过低通滤波后产生的模拟信号。绝对不要直接测量市电或高压电路。观察屏幕是否有波形显示,波形形状和频率是否大致正确。

校准:由于电阻分压精度、ADC参考电压微小的偏差,测量值可能存在系统误差。可以进行一点简单的软件校准:输入一个已知精确电压(如用万用表测量一个稳定的1.65V),读取此时的ADC平均值,计算出一个校准系数,在后续的电压换算中乘以这个系数。

4.2 采样率与带宽验证

如何知道你的示波器实际达到了多少采样率和带宽?

  • 采样率测试:编写一段测试代码,让ADC以特定配置工作,并用一个GPIO引脚在每次DMA传输完成中断时产生一个脉冲。用另一台商用示波器测量这个脉冲的频率,它应该等于采样率 / 缓冲区大小。或者,输入一个远高于奈奎斯特频率的已知信号,观察是否出现明显的混叠失真。
  • 带宽测试:使用信号发生器,输入一个固定幅度(如1Vpp)的正弦波,从低频(如10Hz)开始逐渐增加频率,观察屏幕上波形幅度的变化。当幅度下降到低频时的0.707倍(-3dB点)时,对应的频率就是系统的实际带宽。这个带宽受限于ADC采样率、前端RC电路、以及软件处理速度。

在我的实测中,采用单通道、ADC时钟12MHz、采样周期1.5周期的配置,稳定采样率可达约800KSPS。考虑到软件开销和显示刷新,有效实时带宽达到500KHz是可行的。对于更高频率的信号,波形幅度会开始衰减,形状也可能失真。

4.3 常见问题与排查技巧

  1. 屏幕无显示或花屏

    • 检查接线:这是最常见的问题。反复核对TFT的VCCGNDCSDCRSTMOSISCK与STM32引脚的连接。LED背光引脚是否接上了3.3V或通过一个电阻接电源?
    • 检查库配置:确认TFT_eSPI库中的User_Setup.h文件里,你选择的引脚定义与你的实际连接完全一致。
    • 检查电源:TFT屏幕,尤其是大尺寸的,在点亮背光时瞬时电流较大,可能导致STM32核心板供电不稳。尝试给屏幕背光单独供电,或者在3.3V电源上并联一个100µF以上的电解电容。
  2. 波形闪烁严重

    • 优化绘图:确保只重绘波形区域,而不是全屏刷新。使用双缓冲区技术(在内存中完成一帧图形的绘制,然后一次性发送到屏幕)可以彻底消除闪烁,但对STM32F103的内存(20KB RAM)是个挑战,需要精心设计缓冲区大小。
    • 降低刷新率:如果追求更高的有效采样点数,可以适当降低屏幕的波形刷新频率,比如每秒刷新20-30帧,人眼依然会觉得连续。
  3. 测量电压/频率不准

    • 信号地线:确保示波器的地线(GND)与被测电路的地线可靠连接,接触不良会引入巨大噪声。
    • 校准:如前所述,进行软件校准。
    • 触发不稳定:调整触发电平,使其位于信号幅度的中间区域。对于噪声较大的信号,可以尝试使用噪声抑制模式(在代码中实现一个迟滞比较器)。
  4. 输入高压烧坏芯片

    • 重申保护:务必确保钳位保护二极管(1N4007)正确焊接,且方向无误。在测量不熟悉的电路时,先使用万用表交流电压档估测一下信号幅度。

4.4 进阶优化与扩展思路

当基本功能实现后,可以考虑以下方向进行升级:

  • 多通道支持:STM32F103有多个ADC通道,可以交替采样实现双通道示波器。需要处理好通道间的切换时间和同步问题。
  • FFT频谱分析:利用STM32的数学运算能力,对采集到的一段时域信号进行快速傅里叶变换(FFT),在屏幕上同时显示时域波形和频域频谱。这需要集成一个轻量级的FFT库(如arduinoFFT)。
  • 波形存储与回放:利用SD卡模块,将重要的波形数据以CSV格式存储下来,便于后续在电脑上用专业软件进行深入分析。
  • 更好的前端电路:设计一个带程控放大衰减(PGA)的模拟前端,实现多档位垂直灵敏度切换(如1V/div, 0.5V/div, 0.2V/div),并加入真正的抗混叠滤波器和高速运放跟随器,提高输入阻抗和带宽。

这个基于STM32的DIY示波器项目,从硬件焊接、软件编程到调试优化,完整地走完了一个嵌入式仪器开发的全流程。它带给你的不仅仅是一台可用的工具,更重要的是对微控制器内部资源(ADC、DMA、定时器)的深入理解,对实时系统编程的实践,以及解决实际工程问题的能力。当你第一次在亲手制作的屏幕上看到清晰的方波、正弦波时,那种成就感是无可替代的。希望这份详细的指南能帮助你顺利搭建起自己的“电子之眼”。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询