资讯动态

用FPGA和AD9288 DIY一台便携示波器:从硬件到逻辑的完整指南

发布时间:2026/9/29 23:53:19 来源:尧图企业网站定制
先聊点实在的。如果你玩过单片机、搞过一点数字电路大概率会被台式示波器那四位数起步的价格劝退过。要么狠心买一台入门级当吃灰装备要么蹭实验室、蹭同学、蹭公司每次都像在求人办事。这个项目就是冲着这个痛点去的——用一块FPGA加一颗AD9288自己攒一台真正的便携式示波器采样率能做到100MSPS这个级别应对日常调试单片机、查看PWM波形、抓取I2C/SPI时序完全够用。而且整机比手机大不了多少揣包里就能带走。我并不是说DIY一台示波器就能替代几千块的专业仪器但在学习FPGA高速数据采集、理解示波器内部架构这件事上自己动手做一台比看十篇教程都有用。整理这篇内容之前我翻了不少AD9288的数据手册笔记和FPGA工程的往事把从选型、硬件、逻辑到调试的完整链路重新捋了一遍你可以直接把它当成一份复现指南。1. 为什么是AD9288从功能需求反推ADC选型先说清楚一件事便携式示波器这个词看着挺酷但本质需求非常具体——能测模拟信号、能采样、能显示波形、能随身带。核心指标就两个采样率和带宽。采样率决定了你能看多快的信号带宽决定了信号进ADC之前能不能被完整保留下来。1.1 台式示波器太贵DIY才是正路市面上的成品示波器入门级也要一千多能上100M带宽的基本奔着三四千去了。对很多刚接触电子的人来说这笔钱花得确实肉疼。而一颗AD9288芯片的单价只要几十块配上主流FPGA开发板或者自己画一块核心板总成本能压在三百块以内。这还只是经济账更重要的是技术账——当你亲手把模拟信号变成数字量再在屏幕上把波形画出来你对“示波器”这个东西的理解会完全不一样。我开始做这个项目的时候手头正好有一块黑金出的FPGA开发板Cyclone IV系列的EP4CE15板上资源足够跑ADC接口逻辑和显示驱动。如果你手里有其他型号的板子只要逻辑资源在几千个LE以上、有PLL、有几块Block RAM这套方案都能移植过去。1.2 AD9288这颗ADC的关键参数解读AD9288是ADI公司的一颗双通道8位ADC后缀不一样最高采样率也不同常见的是AD9288-100双通道同时采样时每通道最高100MSPS。8位分辨率听起来不高但示波器显示波形最重要的是采样率和带宽垂直分辨率8位256级其实够用因为人眼分辨256个灰度级完全没问题而且8位数据在FPGA里处理起来特别方便——一个时钟周期刚好一个字节。这颗芯片还有个很有意思的特性内部带了一个时钟倍频器和两个ADC核可以通过寄存器配置成“单通道200MSPS交织采样”模式或者“双通道100MSPS各自采样”模式。做示波器的话我会建议先用双通道100MSPS逻辑简单很多等把这个模式调通了再研究交织。AD9288输出的是并行CMOS电平每通道8根数据线加一个DCO时钟输出接口非常“复古”但很好接。电源方面模拟和数字分开供电3.3V单电源就行功耗很低非常适合便携场景。1.3 和常见替代方案的对比为什么不是ADS1115或AD9226很多人在选ADC的时候会先想到ADS1115那是一颗16位、最高860SPS的芯片适合做温度采集或者称重传感器用来做示波器就是灾难——采样率差了十万八千里。也有人会考虑AD9226那是单通道12位65MSPS的好芯片但一颗就得百八十块而且12位数据线比8位宽一半对入门级FPGA的管脚压力更大。我列个对比表你看完就明白为什么选AD9288了芯片型号分辨率最高采样率通道数参考价格适合做什么ADS111516位860SPS2/4约10元低速采集、传感器AD92888位100MSPS2约50元便携示波器、中频采集AD922612位65MSPS1约100元高性能单通道采集AD760616位200KSPS8约200元多通道同步采集从性价比来看AD9288在“高速”和“成本”之间取得了很好的平衡。如果你预算高一点、想追求更好的垂直分辨率AD9226也可以但整个项目难度会高半档因为12位数据的处理、存储、显示都要跟着改。我先用8位把链路跑通这个决策在后期调试时证明是非常明智的——少了一堆麻烦事。2. 硬件设计模拟前端、采样时钟和电源的三座大山硬件部分是最容易让新手劝退的环节。很多人把FPGA开发板和AD9288模块用杜邦线一插就以为能出波形结果全是毛刺。示波器是一个“进去什么就出来什么”的系统信号链路每一环的噪声都会叠加到最后显示的波形上。2.1 模拟前端从探头到ADC输入的保护与调理不要把ADC直接怼到待测信号上这是新手最容易犯的错误。待测信号可能有很高的直流分量、可能有静电、可能有毛刺直接进ADC轻则波形削顶失真重则烧掉芯片。标准做法是加一级模拟前端包含三件事输入保护、阻抗变换、幅度调理。输入保护用二极管钳位电路推荐用两个BAV99把输入电压钳位在0V到3.3V之间配合一个100Ω的串联电阻限流能扛住大多数误操作。阻抗变换用运放搭一个电压跟随器让输入阻抗达到1MΩ级别这样探头不会加载被测电路。幅度调理这步最关键。AD9288的满量程输入是2Vpp但示波器要能测不同幅度的信号。我的做法是用一个机械波段开关切换几个分压电阻网络实现1V/div、0.5V/div、0.1V/div三档垂直灵敏度再加一个50kΩ电位器做微调。如果要更高级可以换数字电位器或者用运放做程控增益但入门阶段机械开关完全够用。2.2 采样时钟AD9288时钟倍频器的正确打开方式采样时钟的质量直接决定示波器的底噪水平。AD9288的采样时钟输入可以接外部有源晶振也可以从FPGA的PLL输出引过来。我推荐后者因为这样不用额外买晶振而且可以通过FPGA动态调整采样率做时基档位切换非常方便。但这里有个细节AD9288的数据手册上写了采样时钟的抖动直接影响信噪比建议时钟源抖动控制在几十皮秒以内。FPGA的PLL输出抖动一般能满足这个要求但要注意PLL的供电引脚一定要加足够的去耦电容。我实测过PLL供电脚少放一个0.1μF电容采样时钟的抖动会肉眼可见地增加屏幕上波形边缘明显变糊。时钟倍频器的控制是通过MODE引脚的电平配置的。要上拉使能倍频器实现200MSPS交织还是下拉禁用倍频器跑100MSPS双通道硬件上在上电前就要定好。做示波器我建议禁用倍频器先跑双通道100MSPS等后面想挑战交织了再改。2.3 电源设计为什么AMS1117在这里翻车FPGA开发板上的电源通常是AMS1117-3.3这芯片便宜大碗但用在ADC供电上会翻车。因为AMS1117的噪声和纹波抑制能力在高频段表现一般而ADC的模拟供电对噪声特别敏感电源上的高频纹波会直接耦合进采样结果变成波形上的带状噪声。我当时测试时发现一个有趣现象用FPGA板载3.3V给AD9288供电示波器屏幕上看到一个约1MHz的低幅正弦波怎么也消除不掉。后来用示波器探头量ADC电源引脚发现上面叠加了一个1MHz、几十毫伏的纹波——那正是FPGA板载DC-DC的开关频率。解决办法是单独用一颗低噪声LDO我用的LP5907给AD9288的模拟电源供电并在电源引脚就近加磁珠和10μF0.1μF1000pF三颗去耦电容组合。改完这个底噪立刻降了一个数量级。2.4 PCB布局和布线的一个核心原则如果要把这套方案画成独立PCB布局时记住一个原则模拟地和数字地在ADC芯片下方单点连接。也就是说整个板子分成模拟区和数字区两个区域的铺地不要大面积直接重合只在AD9288底部用一小段铜皮连起来。这样数字信号的回流电流不会穿过模拟区域高频噪声耦合能减少很多。另外AD9288的DCO输出和数据线尽量等长布线控制在±5mil以内避免时序歪斜。我第一次布板时没注意这一点结果20cm的等长差导致高端采样率下数据错位调试了很久才定位到是布线长度问题。3. FPGA内部逻辑数据采集、触发和存储的协同工作硬件搭好之后就是FPGA逻辑的主场了。整个逻辑分成三块和ADC对接的接口逻辑、负责抓波形的触发模块、以及负责搬运数据的存储与显示模块。这三块像工厂流水线一样协同工作任何一环卡住都会影响最终的波形质量。3.1 ADC接口时序数据对齐是第一道坎AD9288的数据输出有一个DCO时钟数据在DCO的上升沿或下降沿有效具体看配置。最稳妥的做法是FPGA用一个DDR寄存器同时采DCO的上升沿和下降沿然后用一个FIFO把数据同步到自己的系统时钟域。我第一次写这段逻辑时偷了个懒只用了DCO上升沿采样结果发现偶发性的数据错位——大概是每隔几十个采样点就出现一个明显错误值。后来翻手册才明白AD9288在100MSPS时数据建立时间只有大约5ns如果FPGA内部时钟和DCO的相位关系不好单沿采样很容易采到数据跳变中间。改成双沿采样再取平均后问题彻底消失。下面是个简化的Verilog接口代码参考// ADC数据采集接口双沿锁存 module adc_interface ( input clk_50m, // 系统时钟50MHz input adc_dco, // ADC数据时钟100MHz input [7:0] adc_data, // ADC数据总线 output reg [7:0] sample_data, output reg sample_valid ); reg [7:0] data_rise, data_fall; always (posedge adc_dco) begin data_rise adc_data; end always (negedge adc_dco) begin data_fall adc_data; end // 用系统时钟做同步和有效性判断 always (posedge clk_50m) begin if (data_rise data_fall) begin sample_data data_rise; sample_valid 1b1; end else begin sample_data data_rise; // 不一致时取上升沿数据并标记异常 sample_valid 1b0; end end endmodule这段代码的思路是DCO的上升沿和下降沿各采一次如果两次采到的值一致说明数据稳定如果不一致说明正好采到了数据跳变的中间这时候取其中一个值但标记无效。实际使用中数据跳变导致的无效采样很少遇到也不用慌显示的时候丢掉那一个点就行。3.2 触发模块的简易实现边沿检测与预触发存储示波器如果没有触发功能看到的波形就是乱跑的根本没法稳定观察。触发的本质是让采集系统在满足某个条件时才开始存储这样每次抓到的波形都从同一位置开始显示出来就是稳定的。最简单的触发是上升沿触发实现思路是把当前采样值和前一个采样值比较如果前一个值小于触发电平、当前值大于等于触发电平就认为发生了一次上升沿跳变。这需要至少两级移位寄存器缓存历史数据。我设计的触发模块流程设置一个8位触发电平寄存器通过按键调整每来一个采样值先进入一个深度为128的环形FIFO预触发缓冲区同时比较当前值和前一值检测是否满足触发条件触发发生后继续存256个点然后把预触发缓冲区和这256个点一起输出到显示模块预触发缓冲区的作用是让你能看到触发点之前的波形这对排查问题非常有用。比如你想看某个信号异常前的状态触发条件设成异常发生预触发就能把异常前那段时间的波形也显示出来。// 边沿触发检测 reg [7:0] prev_sample, curr_sample; reg trigger_flag; always (posedge clk) begin prev_sample curr_sample; curr_sample adc_data; if (prev_sample trig_level curr_sample trig_level) trigger_flag 1b1; // 上升沿触发 else if (prev_sample trig_level curr_sample trig_level) trigger_flag 1b1; // 下降沿触发 else trigger_flag 1b0; end有个细节要提醒比较器输出直接连到状态机可能会产生亚稳态因为采样数据是异步进来的。稳妥做法是先两级寄存器同步把trigger_flag同步到系统时钟域再用。我因为这个偷懒被坑过一次触发偶尔失灵现象就是按多少次复位波形都稳不住后来加了同步寄存器就好了。3.3 跨时钟域与FIFO让波形数据流畅搬运ADC输出的采样率是100MHz而显示模块的工作时钟可能只有25MHzVGA像素时钟这中间必须有FIFO做缓冲。我用了FPGA内部的Block RAM搭了一个深度1024字节的异步FIFO写时钟接ADC采样时钟域读时钟接显示时钟域。FIFO的读写协调要配合触发状态机一起工作未触发时FIFO持续写入写满后覆盖最旧的数据环形模式触发后继续写固定数量的点然后停止写入通知显示模块读取显示模块读完后重新进入等待触发状态这套流程看起来简单但状态机的边界情况不少比如触发信号来了但FIFO还没写满或者显示还没读完触发又来了。我画状态机的时候就老老实实列了六种状态和转移条件写代码时就不会乱。FPGA不像单片机可以随便打断状态机跳错一个分支整个采集就废了而且很难查。4. 显示与交互让波形真正出现在屏幕上采集到数据只是完成了上半场把波形画到屏幕上才算真正用了。显示方案的选择会直接影响项目的复杂度和最终效果。4.1 显示方案的选型VGA、TFT还是上位机有几种常见选择我分别说一下它们的适用场景显示方案优点缺点适用阶段VGA接口接显示器驱动逻辑简单、调试方便需要外接显示器不便携调试电路时首选TFT液晶屏RGB接口便携、显示效果好驱动复杂、成本高最终成品首选上位机串口/USB数据处理方便、能存数据实时性差、需要电脑配合功能验证和数据分析我自己的经验是先用VGA把波形显示调试好因为这个方案下你能直接在一台大显示器上看到波形细节发现问题一目了然。等VGA方案稳定了再切换到TFT屏逻辑基本可以复用只是把像素时钟和同步信号换成TFT的时序就行。我用的是640×48060Hz VGA时序像素时钟25MHz。水平方向640个像素点正好能显示512个采样点每点显示一列两侧留边距垂直方向480行用中间256行显示波形相当于垂直分辨率刚好和ADC的8位分辨率一一对应。这样最简单的映射就是采样值直接映射成纵坐标采样序号映射成横坐标。4.2 波形绘制算法为什么点阵显示会“断线”如果直接把每个采样点的值画成一个点你会发现波形是断断续续的尤其是斜率大的信号相邻两个采样点之间在屏幕上可能隔了好几个像素行看起来像虚线。为了解决这个问题需要在两个相邻采样点之间做线性插值简单说就是画一条直线连接它们。实现线性插值有两种思路。一种是在FPGA里用Bresenham直线算法逐点绘制这个算法只用到加法和比较非常适合硬件实现另一种更简单粗暴——在纵坐标相邻的差值超过1时把中间的行填充上也就是用“竖线补齐”。我做的是后者省资源效果也够用。// 波形绘制纵向补线 // 已知上一帧该列坐标为y_prev当前列为y_curr // 如果差值大于1则从y_prev到y_curr之间每个像素都点亮 reg [8:0] y_prev, y_curr; always (posedge vga_clk) begin if (pixel_x col_start col_index) begin if (pixel_y min_of_two pixel_y max_of_two) begin vga_rgb {3b111, 3b111, 2b11}; // 白色波形 end end end虽然串口通信是调试期的事但想把波形数据发给电脑分析串口也是个好选择。发送数据时要注意波特率匹配100MSPS的采样率显然没法全量实时传一个折中方案是每次触发后只传一帧比如1024个点波特率115200也只需要大约90ms看起来有“刷新感”但又不卡。4.3 简单的人机交互按键、编码器和参数设置一台示波器总不能没有按键。我设计了三个按键加一个旋转编码器功能划分如下按键1切换通道CH1/CH2按键2调节触发电平按键3切换时基档位5μs/div、20μs/div、100μs/div、1ms/div旋转编码器调节垂直增益和垂直偏移按键处理要注意消抖。FPGA里做消抖很简单用计数器连续采样几十个周期如果电平稳定不变才认为按键有效。千万不能直接拿按键信号做触发不然按一下可能跳好几个状态。旋转编码器也是一个经典场景。AB两相输出有相位差根据相位关系判断旋转方向。我用了一个四倍频解码逻辑旋转一圈能产生四倍个脉冲调节起来手感很细腻。// 旋转编码器方向判断 reg a_prev, b_prev; always (posedge clk) begin a_prev encoder_a; b_prev encoder_b; if ({a_prev, b_prev} ! {encoder_a, encoder_b}) begin // 有变化 if ({encoder_a, encoder_b} 2b10 {a_prev, b_prev} 2b00) dir 1b1; // 正转 else if ({encoder_a, encoder_b} 2b00 {a_prev, b_prev} 2b10) dir 1b0; // 反转 end end5. 调试验证我踩过的那些坑这章节是最想说但又最不想回忆的部分。整个项目花在调试上的时间大概是开发时间的三倍而且很多问题不实际遇到根本想象不到。5.1 波形毛刺与噪声电源环路和地弹的教训第一次完整跑通采集显示时屏幕上确实有波形但波形上密密麻麻全是毛刺就像一条粗毛线。我先后排查了ADC配置、采样时钟、输出数据线都没问题最后用万用表量了ADC供电引脚发现模拟电源和数字电源之间竟然有300mV的压差波动。原因是我偷懒直接用开发板上电而那块板子的模拟3.3V和数字3.3V是同一个网络没有做隔离。解决方案就是前面提到的LP5907独立供电再加磁珠隔离。改完后毛刺从±8个LSB降到了±2个LSB效果立竿见影。这个坑给个忠告做视频、射频、高速采集这类项目电源设计真的不能凑合。开发板上看起来所有3.3V都长一个样但实际上数字电路的开头噪声、地弹脉冲都会通过电源网络耦合到模拟链路。ADC数字地和模拟地引脚之间的走线回路面积决定了系统底噪的下限。5.2 触发抖动问题亚稳态不是玄学之前提到触发信号亚稳态的问题这里展开说下排查过程。当时现象是波形偶尔会左右跳动半个屏幕就像有人在不停拧水平位置旋钮。我一开始以为是VGA显示时序的问题查了好久直到用逻辑分析仪抓触发信号才发现触发信号的跳变沿和采样时钟的相位关系不固定导致状态机有时提前一拍进入存储模式有时延后一拍。解决方法是把触发检测信号用三级D触发器同步后再进状态机。第一级输出可能有亚稳态第二级会把它稳定下来第三级是保险。这样虽然会引入几个时钟周期的延迟但对触发功能来说完全可接受。// 三级同步器消除亚稳态 reg sync_1, sync_2, sync_3; always (posedge clk) begin sync_1 trigger_in; sync_2 sync_1; sync_3 sync_2; end // 使用sync_3作为安全触发信号5.3 用信号发生器做整机指标校验硬件和逻辑都调通以后要对自己的示波器性能心里有数。我用一台信号发生器做了几个测试结果如下测试项目输入信号实测结果说明直流精度1.000V直流显示1.008V误差小于1%主要来自ADC量化误差频率准确度10.000MHz正弦波显示10.03MHz因为采样时钟是PLL生成的测量精度取决于PLL精度幅度测量100mVpp正弦波显示96mVpp低频档的运放增益误差底噪输入短路约5mVpp56MHz带宽限制后的系统噪声带宽20MHz正弦波幅度衰减约10%模拟前端运放带宽不够看这个表你也能明白DIY示波器不用追求实验室级的绝对精度关键是心里清楚自己这台仪器的极限在哪。比如我的方案带宽最高大约20MHz那测25MHz的信号显示的幅度就明显偏小这不是坏了是硬件特性如此。5.4 幅度和偏置校准的具体步骤所有示波器都需要校准DIY的更不例外。AD9288是8位的理论上有256个量化等级输入范围2Vpp理论分辨率约7.8mV/LSB。但运放偏置、电阻误差会让实际映射关系偏离理想值所以需要做两个校准偏置校准输入接地记录1000个采样点的平均值这个值就是零点偏置。在显示前把每个采样值减去这个平均值。增益校准输入一个已知幅度的方波比如1Vpp测量显示的峰峰值算出实际增益系数。这个系数是一个小数FPGA里可以用定点数处理比如放大256倍后取整。校准系数存在FPGA的Flash里上电时自动加载。每次开机如果发现波形垂直方向明显偏移多半是周围温度变了导致运放偏置漂移重新做个偏置校准就行。我增加了“一键校准”功能按键按住3秒自动完成偏置和增益校准比开盖调电位器方便多了。6. 项目复盘哪些经验能复用到别的项目做完这个项目最大的感受是把一个看起来“只有大厂才能做”的设备自己攒出来并没有想象中那么难但也没有想象中那么简单。整个过程除了收获一台便携示波器之外还有几个挺重要的经验沉淀下来了。6.1 高速数据采集项目的通用设计套路这类项目的架构其实非常固定模拟前端调理信号、ADC完成数字化、FPGA做接口和存储、显示模块把数据转成可视波形。无论你是做软件无线电、高速数据记录仪还是摄像头采集套路完全一样。所以把这个示波器的链路吃透了后面做任何数据采集相关项目都等于有了一个模板。尤其是跨时钟域处理这个点几乎在所有项目中都会遇到。ADC采样时钟、FPGA处理时钟、显示像素时钟三者频率各不相同怎么让数据不掉、不错位、不重复全靠FIFO和握手协议。我建议你在调试过程中遇到时钟问题时先停下来画画时序图把每个时钟域的频率、相位、数据速率列出来问题定位会快很多。6.2 给想复刻这个项目的人的几个建议第一别贪多。先学AD9288数据手册哪怕看十遍也要看把每个引脚的时序图都吃透比盲调代码有用一万倍。第二调试工具准备好一台带存储功能的示波器会帮你大忙你用DIY示波器调DIY示波器属于玄学操作。第三尽量用模块化设计。我当时把硬件分成了独立的三块模拟前端板、ADC板、FPGA板每块单独测试通过后再联调。这样出问题能快速定位是哪个模块的锅而不是整个系统一起抓瞎。第四触发模块只要实现边沿触发就够了不要一上来就想做脉宽触发、逻辑触发把基本的跑通了才是王道。选型上如果不想焊板子可以先用现成的AD9288模块搭配开发板验证一遍我前面说的坑你大概率会踩一遍但别灰心——我踩过一遍之后第二轮自己画板的时候几乎一气呵成。如果你也想搞一台真正属于自己、能随时揣包里的示波器这个项目值得花几个周末试试。等你自己按下触发键、屏幕正中央稳定地显示出一个方波的上升沿时那种成就感是买一百台成品示波器都换不来的。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑