工具柜里常年放着好几台测试仪器的人,大概率都经历过同一个尴尬时刻:测音频电路想扫个频响,手边只有固定输出的电源;调数字板卡需要逻辑脉冲,翻出来的函数发生器又只能出正弦;好不容易找到一台能调波形的,调个幅度还得拧三四个旋钮。这种“测试工具不少,但能干完整活儿的不多”的痛点,正是我做这台多功能信号发生器的起点。这个项目不是什么了不起的大发明,就是把信号发生器这个电子工程师的常备工具,做成一台参数可调、波形可选、能扫频能调制的实用设备,适合实验室调试、传感器标定、音频电路测试,也适合给刚入门的朋友当进阶练手项目。
下面把这台设备从方案选型、核心原理、硬件设计、固件实现到实测调校的全过程拆开讲,有原理的补原理解释,有计算的附计算过程,踩过的坑也一并记录,希望能帮到想做同类工具的人。
1. 项目概述与整体设计思路
1.1 一台信号发生器到底解决了什么问题
信号发生器在电路调试里的地位,有点像家电维修师傅手里的万用表——不是天天用,但用到的时候没有就很麻烦。它的核心职责就是按需产生特定波形、特定频率、特定幅度的电信号,去“喂”被测电路。比如调试一个功率放大器的频响曲线,需要从20Hz到20kHz连续扫频,看输出幅度有没有波动;再比如标定一个温度传感器的调理电路,需要一个已知频率和幅度的正弦信号作为参考激励;又比如验证一块数字逻辑板的时序,需要干净的方波脉冲去触发寄存器。
这个“按需”二字,就是多功能和固定输出的本质区别。一台合格的通用信号发生器,至少要能覆盖三个维度:波形类型可切换,正弦、方波、三角、锯齿是基本盘;频率在宽范围内连续可调,最好能按键输入而不只是旋钮盲调;幅度可调并且带衰减档位,因为驱动耳机和驱动功放前级需要的电平完全不同。把这些需求列出来,整个项目的功能边界就清晰了,后续所有硬件和软件的设计都在围绕这三个维度展开。
我在设计之初还加了一个很重要的前提:操作要直观。很多自制仪器项目功能做得花哨,但面板是一堆跳线和杜邦线,用起来非常劝退。所以这台设备从第一版起就保留了物理按键加LCD显示的人机接口,步进频率、切换波形、设置幅度都有明确反馈。如果是嵌入式工程师,可能会觉得加按键和屏幕是“浪费性能”,但对于真正要长期使用的工具来说,操作顺手远比省几颗芯片重要。
1.2 方案选型:DDS芯片、MCU加DAC、模拟振荡器,我为什么选DDS
做信号发生器最常见的有三条技术路线:纯模拟振荡器、微控制器直接驱动DAC、专用DDS芯片。选型时我把这几种方案从频率稳定度、波形纯度、可编程性、硬件复杂度和成本五个维度做了对比,这笔账算清楚之后选型就没什么悬念了。
| 方案 | 频率稳定度 | 波形纯度 | 可编程性 | 硬件复杂度 | 成本 |
|---|---|---|---|---|---|
| 模拟振荡器(ICL8038等) | 一般,受温度影响明显 | 中低,失真随频率升高变差 | 弱,模拟电位器控制 | 低 | 低 |
| MCU + DAC | 好,取决于晶振和定时器 | 中,受DAC位数和刷新率限制 | 强,完全软件可控 | 中 | 中 |
| DDS芯片(AD9833/AD9850等) | 极好,锁定时钟决定 | 高,相位连续切换,杂散可控 | 强,数字接口控制 | 低 | 中低 |
第一波排除的是纯模拟方案。ICL8038这类经典函数发生器芯片确实能让硬件电路非常“发烧”,两个电位器就能调出正弦、方波、三角波,但它的频率由电容充电电流决定,温漂很明显。我实测过,室温从20度升到35度,最高频率点能漂出去好几个百分点,这对于测量类应用是无法接受的。而且模拟方案的频率切换全靠旋钮盲扫,想要精确设置到10.000kHz全靠缘分,更别提做扫频和调幅这种“数字化操作”了。
第二波纠结发生在MCU加DAC和专用DDS之间。MCU加DAC的方案听起来自由度更高,因为波形完全由软件合成,理论上可以烧录任意波形数据。但这里有个坑:要合成一个干净的10MHz正弦波,每个周期至少采样几十个点,这意味着DAC的更新率需要跑到几百MSPS,这不是普通MCU能承受的。如果把工作频率限制在音频几百kHz以内,MCU加DAC确实可行,可一旦想要扩展到MHz级别,专用DDS芯片的优势就非常明显了。最终我选择了DDS芯片作为核心,因为它的相位累加器是纯数字逻辑在跑,只要时钟够快,频率就能做得高,而且输出频率的精度和稳定性完全由晶振决定,这点正好戳中了信号发生器最核心的痛点。
1.3 项目目标的量化:频率范围、波形种类与幅度指标
定下方案之后,我把项目目标量化成了可验收的指标表,这样后续每一步设计都有一个明确对标。参考常见的入门级商业信号发生器,我给自己定的指标是:正弦波和方波最高输出2MHz,三角波和锯齿波最高500kHz,频率设置精度达到1Hz步进;幅度在空载条件下0到10Vpp可调,带50欧负载时能提供至少5Vpp;支持正弦、方波、三角、锯齿四种基本波形,以及简易的扫频和AM调制功能。
这些数字不是拍脑袋定的,它们直接影响后面的器件选型和电路设计。举个例子,最高2MHz的正弦波,按每个周期16个点的最小采样密度来估算,DDS的等效采样时钟需要至少32MHz,选用125MHz系统时钟的AD9850是绰绰有余的,甚至还有余量可以做波形插值。幅度0到10Vpp的要求则意味着输出级需要至少5Vpeak的摆幅,加上运放的饱和压降,供电电压最少要正负7V以上,这也是后来电源部分用正负12V轨的原因。
2. 直接数字合成原理:从相位累加器到干净的正弦波
2.1 相位累加器与频率控制字的数学关系
既然核心是DDS芯片,那就必须把DDS的工作原理吃透。DDS的全称是直接数字合成,它的思想用一个生活化类比来解释:想象你手里有一个圆心在原点、半径为1的圆,要把一个点从0度开始沿圆周匀速运动,任意时刻点的纵坐标就是正弦值。DDS就是干这件事的,只不过它不用真实物理旋转,而是在数字域里用一个寄存器模拟角度不断累加。
这个寄存器就是相位累加器,它的位宽记为N,比较常见的AD9833是28位,AD9850是32位。每当一个时钟脉冲到来,累加器就加上一个频率控制字FTW。累加器溢出到高位后自动回卷,这个回卷周期就对应模拟转完一整圈,即产生一个完整的正弦周期。输出频率、系统时钟和频率控制字三者的关系是教科书级别的公式:
f_out = (FTW × f_clk) / 2^N
这个公式直接决定了设备的频率下限和频率精度。用AD9850的32位累加器配合125MHz时钟来计算:频率分辨率是125MHz除以2^32,约等于0.029Hz。这意味着在1Hz以上的频段,频率设置精度可以做到几乎无级可调,远超“1Hz步进”的项目指标。AD9833虽然只有28位累加器,但配25MHz时钟就有0.093Hz的分辨率,同样够用。所以选哪颗芯片,很大程度上取决于你想覆盖的最高频率和系统时钟方案,而不必被累加器位宽吓住。
实际写配置时要注意的是频率控制字要用整数送给芯片,不能直接把十进制频率丢进去。比如想让AD9850出10.000kHz,需要先算出FTW = f_out × 2^N / f_clk,也就是10000 × 2^32 / 125000000,约等于343597。在固件里最好用64位整型做这个乘法,否则会溢出产生误差。这个计算过程是DDS初始化的核心,很多新手都在这里栽过跟头,输出频率跟预设对不上,十有八九是控制字算错了。
2.2 查找表、DAC位数与输出纯净度
相位累加器算出来的是相位,要变成模拟电压还需要两个环节:查表把相位映射成幅度数字量,再通过DAC变成模拟电压。DDS芯片内部固化了一个正弦波查找表,常见的大小是1024点,也就是把0到360度的正弦函数量化成1024个数字幅度值。这里存在一个基本的精度取舍:查找表越大,相位量化误差越小,但芯片面积和功耗随之上升,1024点是性价比很高的折中。
DAC的位数则是另一个影响输出纯净度的关键参数。AD9833内置10位DAC,AD9850内置10位DAC,而更高端的DDS芯片如AD9910则是14位。位数越高,幅度量化的台阶越细,理论杂散底就越低。实务里要注意一个概念——无杂散动态范围,通常简写为SFDR,它衡量的是输出频谱中最大杂散分量相对主信号的比值。10位DAC在理想情况下能达到约60dBc的SFDR,AD9850实测在几百kHz频段通常能做到55到60dBc之间,应付大多数测试需求是够的。
提升输出纯净度还有一个常用技巧:展开查找表,把正弦表扩充到完整周期。有些DDS芯片内部默认只有四分之一周期正弦表,通过象限对称重构整个波形,这会引入象限切换点的幅度误差。如果你的芯片允许自定义波形表,建议直接存一整周期的正弦值,虽然占的存储多了一点,但换来的是更低的谐波分量。这个技巧在MCU加DAC方案里尤其好用,因为我可以在内存里先算好完整4096点表,输出时直接查表,避免频繁的对称计算。
2.3 扫频与相位连续的关键:为什么DDS适合做扫频
扫频信号发生器的本质是让输出频率随时间按一定规律变化,比如从20Hz线性扫到20kHz。如果是传统模拟振荡器,变频率就要改变RC时间常数,扫频过程往往不连续,频率跳变时波形会产生明显毛刺。而DDS的频率切换是瞬间改写频率控制字,相位累加器不会清零,相位始终连续,输出波形在切换点上不会出现跳跃断裂,这就是“相位连续”的含义。
这一点在做音频频响测试时特别重要。我用这台设备扫频驱动一个功放板,再在输出端采集幅度做对数坐标绘图,扫出来曲线是平滑的;如果相位不连续,扫频过某个频点时会听到“嗒”一声爆音,那就是波形跳变引起的瞬态冲击。所以DDS扫频真的是这项功能最优雅的实现方案,纯粹的软件操作,没有任何机械或模拟元件参与。
3. 硬件架构与关键电路设计
3.1 核心器件选型:从DDS芯片到MCU再到运放
DDS芯片我选了AD9850,原因并不复杂:125MHz系统时钟能覆盖项目指标的2MHz输出,50MHz甚至超过了这个需求;内置比较器可以直接输出方波,省了一路后级整形电路;10位DAC的SFDR达标;最关键的是它通过并口或串口编程,用单片机SPI就能控制,而且市面上模块很多,硬件调试门槛低。
MCU选了STM32F103系列的入门款。选它不是因为性能有多强,而是因为SPI外设、定时器、GPIO中断齐全,价格低,资料多,做这种人机交互加协议转换的工作非常合适。STM32用一个硬件SPI去写AD9850的频率控制字,同时用另一个定时器去做扫频的步进节拍,占用的资源非常少,剩下的CPU时间去处理按键扫描和LCD刷新绰绰有余。
输出级运放我用了ADA4891,轨到轨输出、单电源供电、带宽够大。DDS芯片的DAC输出通常是电流型或者小信号电压型,带载能力很弱,不能直接驱动后级负载,必须在后面加一级运放做缓冲和放大。ADA4891在单5V电源下都能摆动到接近轨道的幅度,配合正负电源供电后,输出10Vpp完全没压力。
3.2 输出级设计:低通重建滤波器与幅度调节
DDS的DAC输出是“阶梯状”的量化波形,频谱上除了主频,还在时钟频率的整数倍处有一堆镜像分量。如果不加滤波直接输出,在示波器上看到的波形边缘会有细密的台阶毛刺,这就是“重建不干净”的典型表现。所以DDS后面必须接一个低通滤波器,叫做重建滤波器,把高于奈奎斯特频率的镜像成分压掉。
滤波器阶数和截止频率的选择有个经验公式:对于AD9850,常用7阶椭圆低通,截止频率设为最高输出频率的1.5到3倍。比如我要覆盖到2MHz,就把截止频率设在6MHz左右,这样既不影响2MHz以下的信号,又能把5MHz以上的杂散压制到比较低的水平。椭圆滤波器特点是过渡带窄,但通带内有少量纹波,对于测试用途这是完全可以接受的。如果是初学者,可以用更简单的二阶LC低通先试通,再逐步增加阶数,先解决“有没有”再优化“好不好”。
幅度调节这一块,我的实现是“数字衰减加模拟微调”两级结构。先通过DDS芯片的IOUT引脚配合一个电流调节电阻设定基础满幅,再用后级运放组成同相放大器,放大倍数由数字电位器控制。数字电位器选MCP4131这类SPI接口的器件,STM32再分配一个SPI片选给它,这样用户就能在菜单里输入目标幅度,固件自动换算并写入数字电位器。需要注意数字电位器有带宽限制,MCP4131用在低频段完全无所谓,但频率上到几百kHz之后,内部寄生电容会跟滑动电阻形成低通,导致高频幅度跌落,所以我把模拟微调的带宽目标定在500kHz以内,更高频率直接直通不做调节,用固定增益档位代替。
3.3 电源与参考时钟:输出信号质量的根源
很多自制信号发生器项目做完之后发现波形毛糙、频率漂移,问题不在DDS芯片本身,而在电源和时钟。DDS芯片内部是高速数字电路,电源纹波会直接耦合到DAC输出端,对信号纯度的影响是灾难性的。这里我用了三路隔离心思:数字3.3V、模拟3.3V、正负电源轨,每一路都用独立的LDO,而且DDS芯片的模拟地和数字地采用单点接地,在芯片下方直接汇合,避免地平面的数字噪声串进模拟信号通路。
参考时钟的重要性再怎么强调都不过分。AD9850需要外部输入时钟,我直接用了一片温补晶振,频率20MHz,频率稳定度在ppm级别。有人图省事用STLink或者开发板上的晶振直接飞线过去的,结果发现输出频率在温度变化后跟着跑,就是这个原因。温补晶振不贵,但换来的是整台设备频率基准的可靠性,这笔投入非常值得。
4. 固件实现:波形生成、扫频与调制
4.1 频率控制字写入与数字接口时序
AD9850支持并行和串行两种写入方式。并行方式32个引脚一次性写完,速度快但占用IO太多;串行方式通过一个40位的移位寄存器写入,包括32位频率控制字、5位相位控制字和3位控制位。STM32用硬件SPI的MOSI和SCK就能完成这份工作,SCLK每来一个上升沿,芯片内部就把串行数据锁存一位,40位全部送完后,把FQ_UD引脚拉一个上升沿,新频率就正式生效。
下面这段是STM32初始化并写入AD9850的参考代码,采用SPI模式,先写低位后写高位,要注意数据字节序不能反。
void AD9850_Write(uint32_t freq_word) { uint8_t i; uint8_t data[5]; // 40位数据:32位频率控制字 + 0度相位 + 默认控制位 data[0] = (uint8_t)(freq_word & 0xFF); data[1] = (uint8_t)((freq_word >> 8) & 0xFF); data[2] = (uint8_t)((freq_word >> 16) & 0xFF); data[3] = (uint8_t)((freq_word >> 24) & 0xFF); data[4] = 0x00; // 相位为0,控制位全0 for(i = 0; i < 5; i++) { SPI_SendByte(&hspi2, data[i]); } AD9850_FQUD_HIGH; delay_us(1); AD9850_FQUD_LOW; }写完之后有个容易忽略的细节:AD9850在上电后默认处于掉电模式还是工作模式,取决于控制位的配置。控制位第0位是掉电使能,第1位是复位模式。要确保第二字节的最高位和次高位被正确清零,否则芯片吞了数据但输出为零,很多人第一次调设备时遇到“写命令没反应”,就是这里没设置对。
4.2 波形切换与方波输出的双通道设计
AD9850内部自带一个高速比较器,I/OUT引脚出去的正弦信号经过内部低通和比较器整形后,可以在QOUT引脚直接输出方波。这个设计很妙,等于一颗芯片同时给了正弦和方波两路输出,而且方波的频率精度跟正弦完全一致。实际使用中,我会把方波输出接到一个50欧驱动级的缓冲器上,保证方波的上升沿不被负载电容拖慢,实测在2MHz下方波的上升沿能保持在10纳秒以内。
功能设计上还要考虑“同时输出”还是“切换输出”。我最初设计的是单输出口,面板上一个BNC座,通过继电器在正弦和方波之间切换。后来发现调试数字电路时需要方波做时钟,同时又要给模拟前级加正弦激励,单口切来切去非常麻烦,就改成了双BNC座结构,一路固定正弦,一路固定方波。这个改动虽然增加了一个BNC座和一路缓冲器,但使用体验提升非常明显,算是这个项目里性价比最高的硬件改动之一。
4.3 扫频与AM调制功能实现
扫频功能在固件里本质就是一个定时中断任务。定时器每50毫秒触发一次,中断里把当前频率累加一个步进值,重新计算频率控制字并写入AD9850。步进量和扫描时间通过菜单预设,比如从20Hz扫到20kHz,总时间设为10秒,那么每次中断增加约99Hz。我用64位整型保存当前频率,避免在计算频率控制字时产生取整误差。
AM调制则利用了AD9850一个不太起眼的特性:它的DAC参考电流引脚可以通过外加电压控制输出幅度。用另一个定时器产生低频正弦波,再把这个波形的电压叠加到参考电压输入端,就能实现模拟调幅。这个方法的调制深度由外接幅度决定,我实测在1kHz调制信号驱动下,载波输出幅度能平稳变化,包络线失真很小。不过要注意参考电压的输入范围不能超过芯片允许值,否则DAC会饱和,包络波形会削顶。
5. 实测校准、常见问题与排查经验
5.1 用示波器和频谱仪校准幅度与频率
设备装完先别急着盖壳,要做的第一件事是校准频率基准。用一台高精度频率计去测方波输出的频率值,如果偏差大于预期的ppm级别,检查温补晶振是否焊好、电源滤波是否到位。频率偏差通常不是DDS芯片造成的,而是时钟源不准,所以要追查晶振本身。
接下来校准幅度平坦度。把输出接到示波器上,在100Hz、1kHz、10kHz、100kHz、1MHz、2MHz这几个频点分别测量Vpp,记录成表格。你会发现频率越高,输出幅度逐渐往下掉,这是DAC输出能力和后级运放带宽共同作用的结果。针对这个现象,我在固件里做了一张幅度平坦度校正表,每个频段乘一个补偿系数,相当于软件增益校准。校准表数据可以写到Flash里,下次开机自动加载。
| 测试频点 | 未校正幅度 | 校正系数 | 校正后幅度 |
|---|---|---|---|
| 100 Hz | 10.02 Vpp | 1.000 | 10.00 Vpp |
| 10 kHz | 9.97 Vpp | 1.000 | 10.00 Vpp |
| 100 kHz | 9.61 Vpp | 1.010 | 10.00 Vpp |
| 1 MHz | 8.72 Vpp | 1.025 | 9.98 Vpp |
| 2 MHz | 7.85 Vpp | 1.040 | 9.95 Vpp |
这个表格数据是示意用的,真实设备里的校正系数会跟实际运放、PCB走线阻抗都有关系,需要逐台标定。实测下来,做了校正之后,全频段幅度平坦度能够控制在正负0.5dB以内,对于非计量级别的应用已经非常好用了。
5.2 调试中常见的坑:谐波毛刺、幅度跌落、按键失灵
第一个坑是谐波毛刺。最初版本在正弦输出端直接用了一块洞洞板飞线,结果用频谱仪看,2MHz输出的二次谐波只比主信号低30dBc,这完全达不到设计指标。后来排查发现是DAC输出到重建滤波器之间的走线太长,而且地回路不干净,导致数字串扰叠到了模拟信号上。解决办法是把这段走线改成短粗直连,并且滤波器的地引脚单独打孔就近接到主地,改版后再测,二次谐波降到45dBc以下。
第二个坑是方波高频幅度跌落。这个问题一开始没发现,因为只看正弦通道。后来方波输出接到数字电路,发现1MHz以上边沿变软,用示波器一看,上升沿从几纳秒退化到了几十纳秒。原因是方波输出端的50欧串联电阻和负载电容组成了一个低通,拐点频率正好落在1MHz附近。解决方法是减小串联电阻到22欧,同时换用低输入电容的缓冲器,恢复后的上升沿约5纳秒,满足数字电路触发需求。
第三个坑是按键扫描偶发失灵。按键消抖用的软件延时,但中断里有扫频任务在跑,导致消抖时序被切断,表现为快速按两次按键有时只有一次响应。修复方式是把按键扫描放到中断服务函数外面,用定时器标志位驱动,保证消抖逻辑不会被其他任务打断。这个修完之后操作响应灵敏多了。
5.3 现场排查经验速查表
| 故障现象 | 可能原因 | 排查顺序 |
|---|---|---|
| 输出完全没信号 | 控制字没写入、DDS掉电模式 | 先查SPI波形、再看控制位 |
| 频率偏得离谱 | 晶振频率不对、频率控制字溢出 | 用频率计测时钟、核对FTW计算 |
| 波形幅度毛糙 | 电源纹波过大、未加重建滤波 | 示波器测电源、查滤波器焊点 |
| 高频幅度跌落 | 运放带宽不足、输出阻抗过大 | 逐级测增益、断开负载测试 |
| 方波边沿太软 | 负载电容过大、驱动能力不足 | 测输出端Vpp、换低电容缓冲器 |
| 按键重复触发 | 消抖逻辑被中断打断 | 把按键扫描移出中断处理 |
这份速查表是我调了三个晚上总结出来的,每个问题背后都是一次拆机测量、一次波形对比。有了它之后,后来再复刻这台设备的朋友遇到类似问题,基本都是拿表格里的序号就能定位到故障源,省了大量时间。
5.4 个人实际改版建议
再多说一个我改版时验证过的小技巧:如果你打算用这颗方案复刻,可以把AD9850模块和STM32核心板做在一块PCB上,而不是像我最初那样用模块拼接。刚开始用模块拼是方便,但模块之间用杜邦线连接,过长的地线和信号线在地回路里引入各种噪声,尤其高频段的波形质量很难保证。第二版我重新画了PCB,把DDS芯片、STM32、运放、电源电路全部集成到一块双面板上,模拟地数字地分开布线,关键信号走底层做完整地平面。这版一次打样回来,波形质量直接比模块拼接版上了一个台阶,高频杂散下降了将近10dB。
另外在操作界面设计上,建议做“步进调节加直接输入”双模式。步进调节适合快捷微调,比如每次按一下按键频率增加100Hz;直接输入适合设置精确值,比如输入“10.000k”就直接定位到这个频率点。这两种模式缺一不可,我用了一段时间之后深有体会。数字键盘占用IO多一点,但现在MCU的引脚资源完全够用,不用为省IO砍掉操作体验。
6. 实用性扩展方向
这台设备做出来之后,我在实际使用中发现它的扩展空间还很大。比如给输出级加一个固定衰减网络,就能覆盖小信号传感器标定场景;加一个音频功放驱动级,就能当简易音频信号源用。如果后续要做变频输出,也可以把DDS芯片换成带内部PLL的型号,让输出频率进一步拉升到几十MHz,那基本上就可以对标很多入门级商用函数发生器的能力了。
这个项目整体的技术路线是清晰且可复现的:选DDS方案保性能下限,用MCU解放操作界面,靠重建滤波器和电源设计拉高信号质量,最后用固件和校准把设备调到可靠状态。如果有朋友正在犹豫要不要自己动手做一台,我的建议是别怕画板、别省电源、别想一步到位。先搭通最基础的正弦波输出,再逐步加方波、三角波、扫频和调制,每加一个功能就实测一轮,你会得到的不只是一台好用的仪器,还有对DDS原理和信号链设计极其扎实的理解。