尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

基于DDS技术的多波形信号发生器:从原理到FPGA/STM32实现

基于DDS技术的多波形信号发生器:从原理到FPGA/STM32实现 简介这是一套基于FPGA实现的DDS直接数字频率合成信号发生器Verilog工程面向数字电路、嵌入式系统及FPGA初学者与课程设计者解决常见波形生成实验中频率精度低、波形种类少、参数调节不灵活等问题。资源共1244个文件涵盖152个Verilog源码核心逻辑与顶层模块、46个COE初始化文件用于ROM存储正弦/三角/锯齿波采样数据、70个XDC约束文件含时钟与IO分配、5个MATLAB M脚本自动生成COE与占空比控制逻辑以及大量TCL、DO、LOG等Vivado工程脚本与仿真日志压缩包大小为130.61MB。已有6315人学习下载。用户可一键运行仿真查看波形输出图直接加载至Vivado 2018.3工程即可综合实现矩形波占空比采用独立逻辑生成而非查表提升灵活性配套完整ROM生成流程与幅度/频率/占空比三级可调机制便于深入理解DDS原理与FPGA工程实践全流程。1. 项目概述从需求到实现的DDS信号发生器最近在整理一个老项目一个基于直接数字频率合成DDS技术的多波形信号发生器。这个项目的核心目标很明确要能稳定输出正弦波、锯齿波、三角波和矩形波这四种基础波形并且频率、幅度和占空比这三个关键参数必须可调。这听起来像是电子实验室里的标准设备功能但自己动手从零搭建从选型、画原理图、写代码到调试整个过程下来对DDS的理解会深入好几个层次。无论是用于测试模拟电路、校准传感器还是作为嵌入式系统开发中的信号源这样一个自制的信号发生器都极具实用价值和学习意义。DDS技术相比传统的模拟振荡器或锁相环频率合成其优势在于频率分辨率极高、切换速度极快并且相位连续可调。实现上核心就是一个相位累加器、一个波形查找表和一个数模转换器。市面上虽然有成熟的DDS芯片比如ADI的AD9833/9834系列但为了获得更高的灵活性和对底层原理的透彻掌握我选择了基于FPGA或高性能MCU如STM32系列的纯数字方案来构建核心外接一个高速DAC来完成数模转换。这样波形的生成、参数的调整逻辑完全掌握在自己手里后期想扩展任意波形合成功能也轻而易举。2. 核心架构设计与技术选型解析2.1 为什么选择DDS而非其他方案在决定做信号发生器时首先面临的是技术路线的选择。除了DDS常见的还有模拟振荡器如文氏电桥、RC振荡器和基于PLL的频率合成。模拟方案电路简单但频率稳定度和精度较差频率调节通常需要更换电容或电阻无法实现程控。PLL方案频率稳定度高但频率切换速度相对较慢且实现复杂波形生成比较困难。DDS方案的核心优势正好切中了我们的需求第一极高的频率分辨率。频率调谐字FTW的位数决定了频率分辨率例如使用32位的相位累加器在100MHz的系统时钟下频率分辨率可以达到惊人的0.023 Hz100MHz / 2^32。这意味着你可以极其精细地调节输出频率。第二极快的频率切换速度。DDS的频率切换本质上就是改变FTW的数值这在一个系统时钟周期内就能完成几乎是“瞬时”的。第三相位连续可调。通过相位控制字POW可以直接调整输出波形的初始相位这在通信和测量系统中非常有用。第四波形灵活性。只要你能在查找表LUT中存储相应的波形数据就能合成出任意波形这为我们实现正弦、锯齿、三角、方波提供了基础。注意DDS的输出频率受限于奈奎斯特采样定理即最高输出频率理论上不能超过系统时钟频率的一半。在实际工程中考虑到滤波器的设计难度和信号质量通常将最高输出频率限制在时钟频率的40%以下。例如100MHz的时钟建议输出频率不要超过40MHz。2.2 系统整体架构拆解一个完整的DDS信号发生器系统可以分为数字核心和模拟前端两大部分。数字核心部分主控制器负责参数设置通过按键、编码器或上位机、波形选择、系统控制以及DDS核心的逻辑驱动。可以选择STM32这类MCU或者直接使用FPGA作为主控和DDS核心。DDS核心引擎这是心脏。包含相位累加器一个N位的加法器每个时钟周期累加一次频率调谐字FTW。其输出通常取高M位作为波形查找表的地址。波形查找表LUT一个只读存储器预先存储了一个或多个完整周期的波形幅度数据。例如对于一个深度为1024、宽度为14位的正弦波LUT就存储了1024个14位精度的正弦波采样点。相位控制与幅度调制模块在查表前可以对相位累加器的输出加上一个相位偏移字POW来实现相位调制。查表输出的数据再乘以一个幅度控制字ACW即可实现幅度的数字控制。接口逻辑将处理后的数字波形数据以特定的时序如并行、SPI发送给外部的数模转换器。模拟前端部分数模转换器DAC将数字核心输出的离散幅度代码转换为阶梯状的模拟电压。DAC的分辨率如12位、14位和转换速率更新率直接决定了输出波形的精度和最高频率。重构滤波器低通滤波器DAC输出的信号是阶梯状的包含大量高频谐波镜像频率分量。必须使用一个截止频率略高于所需最高输出频率的低通滤波器来平滑波形滤除这些高频杂散得到干净的模拟信号。输出放大与调理电路滤波器后的信号幅度较小且可能包含直流偏置。需要经过运放构成的放大器和电平移位电路将信号调整到所需的电压范围例如0-3.3V ±5V等并提高带负载能力。2.3 关键器件选型考量主控/FPGA选型如果追求极致的灵活性和性能如希望生成非常复杂的波形或需要多通道同步FPGA是首选例如Xilinx的Spartan-6或Intel的Cyclone IV系列入门级芯片。如果更看重开发便捷性和成本且对波形频率要求不是极高比如目标频率在几百KHz以内那么使用带DAC和DMA的MCU如STM32F4系列更为合适。STM32可以通过查表DMA自动搬运的方式软件模拟DDS。DAC选型这是影响输出波形质量的关键。主要看两个参数分辨率和建立时间。分辨率如14位决定了幅度控制的精细度和波形失真度。建立时间或更新率则与最高输出频率相关。对于1MHz的正弦波DAC的更新率至少需要达到20MSPS以上。可以选择并行接口的高速DAC如AD9708也可以选择SPI接口但速率足够的DAC如ADI的AD5689。运放选型输出调理电路中的运放需要根据信号带宽和摆幅要求选择。对于音频范围通用运放如NE5532即可。对于更高频率1MHz则需要选择高速、高压摆率的运放如AD8065、OPA695等并注意其压摆率是否跟得上信号的最大变化率。3. 核心模块实现细节与参数计算3.1 DDS核心的Verilog/HDL实现如果采用FPGA方案DDS核心可以用硬件描述语言轻松实现。以下是一个简化的相位累加器和查找表模块的思路。module dds_core ( input wire clk, // 系统时钟如100MHz input wire rst_n, input wire [31:0] ftw, // 频率调谐字32位 input wire [1:0] wave_sel, // 波形选择00-正弦01-锯齿10-三角11-方波 input wire [13:0] amp_word, // 幅度控制字14位 input wire [15:0] duty_cycle, // 占空比控制字用于方波0-65535对应0-100% output reg [13:0] dac_data // 输出给DAC的14位数据 ); // 相位累加器 reg [31:0] phase_acc; always (posedge clk or negedge rst_n) begin if (!rst_n) phase_acc 32d0; else phase_acc phase_acc ftw; end // 取相位累加器的高位作为查找表地址假设LUT深度为1024取高10位 wire [9:0] lut_addr phase_acc[31:22]; // 相位截断会引入相位噪声但能减小LUT尺寸 // 波形查找表ROM reg [13:0] sine_lut [0:1023]; reg [13:0] sawtooth_lut [0:1023]; reg [13:0] triangle_lut [0:1023]; // 初始化LUT可以使用$readmemh从文件加载或在代码中计算生成 initial begin for (int i0; i1024; ii1) begin sine_lut[i] 8192 8191 * $sin(2.0 * 3.1415926 * i / 1024.0); // 生成14位有符号数偏移到0-16383范围 sawtooth_lut[i] i * 16; // 锯齿波线性增长 triangle_lut[i] (i 512) ? (i * 32) : (1023 - i) * 32; // 三角波 end end reg [13:0] wave_data_raw; // 波形选择器 always (*) begin case(wave_sel) 2b00: wave_data_raw sine_lut[lut_addr]; 2b01: wave_data_raw sawtooth_lut[lut_addr]; 2b10: wave_data_raw triangle_lut[lut_addr]; 2b11: begin // 方波根据占空比和相位高比特位比较产生 wave_data_raw (phase_acc[31:16] duty_cycle) ? 14h3FFF : 14h0; end default: wave_data_raw sine_lut[lut_addr]; endcase end // 幅度控制乘法运算实际可能用移位或查找表简化 wire [27:0] amp_mult_result wave_data_raw * amp_word; // 14位 * 14位 28位 // 取结果的高14位作为最终输出相当于右移14位 always (posedge clk) begin dac_data amp_mult_result[27:14]; end endmodule参数计算示例 假设系统时钟F_clk 100MHz相位累加器位数N 32频率调谐字FTW 42949673。 输出频率F_out (FTW * F_clk) / 2^N (42949673 * 100e6) / 4294967296 ≈ 1.0000000 MHz。 可以看到通过设置FTW我们可以精确地得到1MHz的输出分辨率高达0.023Hz。3.2 基于STM32的软件DDS实现对于MCU方案虽然没有硬件的相位累加器但可以通过定时器触发DMA来自动搬运波形数据到DAC实现“准DDS”。构建波形数组在内存中预先计算好一个周期的波形数据数组。例如对于1K个点的正弦波数组sin_table[1000]。配置定时器定时器的溢出频率决定了DAC的更新率即F_update Timer_Clock / (ARR1)其中ARR是自动重装载值。配置DMA将DMA源地址指向波形数组目标地址指向DAC的数据寄存器。设置DMA为循环模式。配置DAC使能DAC并设置为由定时器触发、DMA供给数据。频率控制要改变输出频率不是改变FTW而是改变波形数组的步进指针。我们可以设置一个“相位累加器”变量在定时器中断中累加一个步进值相当于FTW然后取这个累加器的高位作为波形数组的索引。通过改变步进值就能改变遍历波形数组的速度从而改变输出频率。这种方法称为“直接表查找法”其频率分辨率受限于数组大小和定时器精度。// STM32 HAL 库示例片段 uint16_t sine_table[1024]; uint32_t phase_acc 0; uint32_t phase_inc 42949673; // 对应目标频率的步进值需要计算 void TIM2_IRQHandler(void) { // 假设定时器2触发DAC if(__HAL_TIM_GET_FLAG(htim2, TIM_FLAG_UPDATE) ! RESET) { __HAL_TIM_CLEAR_FLAG(htim2, TIM_FLAG_UPDATE); phase_acc phase_inc; uint16_t index phase_acc 22; // 取高10位作为索引1024点表 HAL_DAC_SetValue(hdac, DAC_CHANNEL_1, DAC_ALIGN_12B_R, sine_table[index]); } }实操心得在STM32上实现时定时器中断的频率不宜设置过高否则会消耗大量CPU资源。更好的方法是利用DMA的“半传输”和“传输完成”中断在后台自动更新波形数组中的一部分数据来实现频率和波形的动态改变这样对CPU的占用率极低。3.3 幅度与占空比控制实现幅度控制在数字域实现最为精确。对于查找表输出的数据wave_data例如范围0-16383乘以一个幅度系数amp_coef例如0.0-1.0的浮点数或对应整数再输出给DAC。为了防止溢出需要做饱和处理。在FPGA中乘法器会消耗资源可以预先计算不同幅度下的LUT或者使用移位相加来近似。占空比控制矩形波矩形波的占空比调节在数字域非常简单。我们只需要一个计数器在波形周期内比较计数器的值与一个设定的阈值。计数器小于阈值时输出高电平大于阈值时输出低电平。通过改变这个阈值与周期总长度的比例就能调节占空比。在FPGA的DDS核心代码示例中我们利用相位累加器的高16位与duty_cycle字进行比较来实现此功能。4. 硬件电路设计与PCB布局要点4.1 模拟输出电路设计DAC之后的模拟电路至关重要它决定了最终输出信号的质量。电流输出型DAC的I-V转换许多高速DAC是电流输出型如AD9708。需要用一个运放构成跨阻放大器TIA将电流转换为电压。反馈电阻Rf决定了转换比例Vout Iout * Rf。必须选择低偏置电流、低噪声的运放并且Rf两端可以并联一个小电容几pF以补偿相位裕度防止振荡。Vout ---/\/\/\---- Rf | |--- 运放输出 Iout ----||------ | | --- | | | | GND GND重构滤波器设计这是滤除DAC输出中高频采样分量的关键。通常使用巴特沃斯或切比雪夫有源低通滤波器因为它们在通带内具有较平坦的响应。截止频率Fc应略高于你需要的最高输出频率F_max例如Fc 1.2 * F_max。滤波器的阶数越高阻带衰减越快但电路也更复杂相位非线性更严重。对于大多数应用2阶或4阶滤波器已经足够。可以使用FilterLab这类工具进行设计和仿真。输出缓冲与电平移位滤波器输出的信号驱动能力可能较弱且可能含有直流偏置。需要一级同相放大器进行缓冲和增益调整。如果要求输出双极性电压如±5V则需要用运放搭建一个加法电路将单极性信号与一个负的参考电压相加实现电平移位。4.2 PCB布局与接地技巧高速数字电路和精密模拟电路共存于一块板子上布局布线不当会引入严重噪声。电源分割与滤波为数字部分FPGA/MCU、DAC数字电源和模拟部分DAC模拟电源、运放使用独立的电源网络。在电源入口处使用磁珠或0欧电阻进行隔离。每个芯片的电源引脚附近都必须放置一个0.1μF的陶瓷去耦电容并尽可能靠近引脚。对于高速器件还需要并联一个1-10μF的钽电容或陶瓷电容。地平面处理推荐使用完整的接地平面。可以采用“单点接地”或“分区接地”策略。将模拟地和数字地在一点连接通常选择在DAC芯片下方或电源入口处。确保模拟部分的地回路不被高速数字信号线割裂。信号走线DAC的数字输入线数据线、时钟线要尽量短并远离模拟输出走线。DAC的模拟输出走线应非常简短并用地线包围进行屏蔽。重构滤波器和运放周围的元件布局要紧凑反馈电阻和电容的走线要短以减少寄生效应。时钟信号线要做好阻抗控制必要时使用端接电阻。踩坑记录在一次设计中我将DAC的模拟输出走线绕了很长一段距离才接到滤波器结果输出正弦波在几十MHz时出现了明显的振铃和失真。后来缩短走线并用地线隔离后波形质量大幅改善。另一个常见问题是电源噪声如果发现输出波形上有固定频率的毛刺很可能是开关电源的噪声耦合在电源路径上增加π型滤波电路电感电容通常能有效缓解。5. 系统调试与性能优化实战5.1 上电调试流程电源检查首先不插主芯片上电测量所有电源电压是否准确、稳定。用示波器查看电源纹波应小于50mV对于精密模拟部分要求更高。时钟与复位插入芯片检查主时钟是否起振复位电路是否正常工作。可以用示波器测量晶振引脚。数字通信先调试MCU/FPGA与DAC的配置接口如SPI。写一个简单的测试程序向DAC写入固定的值用示波器测量DAC的模拟输出是否随之变化验证通信链路和DAC基本功能。DDS核心功能在数字逻辑调试工具如FPGA的SignalTap II或ChipScope中观察相位累加器是否正常累加查找表地址和数据是否正确。设置一个固定的FTW看DAC输出的数字码是否呈周期性变化。模拟输出观测连接示波器到最终的模拟输出端。先输出一个低频如1KHz的正弦波。观察波形是否光滑有无明显的台阶说明DAC分辨率不足或滤波器截止频率过低、毛刺数字噪声干扰或失真运放非线性或滤波不当。5.2 关键性能指标测试与优化频率准确度与稳定度使用高精度的频率计测量输出信号的频率与理论值对比。长期观察频率漂移这主要取决于系统时钟的稳定度晶振的温漂和时漂。如需高稳定度应选用温补晶振TCXO或恒温晶振OCXO。频谱纯度对于正弦波使用频谱分析仪观察输出正弦波的频谱。关注无杂散动态范围SFDR即主信号幅度与最大杂散信号幅度的差值。杂散可能来源于相位截断误差由于只用相位累加器的高位去寻址LUT低位被舍弃这会在输出频谱中引入周期性的相位误差表现为杂散。增加LUT深度或使用相位抖动技术可以改善。幅度量化误差LUT数据位宽有限对正弦幅度的量化会产生谐波失真。增加LUT数据位宽DAC分辨率可以改善。DAC的非线性DAC本身的微分非线性DNL和积分非线性INL会引入谐波。选择高性能的DAC。电源和地噪声表现为宽频带的底噪抬高或特定频率的杂散。方波上升/下降时间测量方波从10%到90%幅度的上升时间。这主要由输出运放的压摆率决定。压摆率SR的单位是 V/μs要输出一个幅度为Vpp频率为F的正弦波需要满足SR 2 * π * F * Vpp。对于方波要求更严因为其包含丰富的高次谐波。5.3 常见问题与排查技巧速查表现象可能原因排查思路与解决方法无输出或输出恒定电压1. DAC未正确配置或未使能。2. 数字数据未送达DAC。3. 运放电路供电错误或损坏。1. 检查DAC的配置寄存器通过逻辑分析仪抓SPI/I2C时序。2. 用示波器或逻辑分析仪检查DAC数据线和时钟线。3. 测量运放电源引脚电压检查输入/输出是否虚焊。输出波形频率不对1. 系统时钟频率设置错误。2. 频率调谐字FTW计算或传输错误。3. 定时器MCU方案分频系数算错。1. 测量系统时钟实际频率。2. 核对FTW计算公式在代码中打印或在线查看FTW值。3. 重新计算定时器ARR和PSC值。正弦波失真非光滑1. 重构滤波器截止频率过低或设计不当。2. DAC更新率不足违反奈奎斯特定律。3. LUT点数太少波形量化粗糙。1. 检查滤波器参数提高截止频率或阶数。2. 提高系统时钟或降低输出频率。3. 增加波形查找表的深度点数。波形上有高频毛刺1. 数字开关噪声耦合到模拟部分。2. 电源去耦不足。3. 信号走线过长形成天线。1. 优化PCB布局加强数字/模拟隔离。2. 在芯片电源引脚就近增加高质量去耦电容。3. 缩短关键模拟走线用地线屏蔽。输出幅度无法调至最大/最小1. 幅度控制算法存在溢出或饱和。2. 运放增益设置或供电范围限制。3. DAC参考电压不准。1. 检查幅度乘法运算后的位宽处理进行饱和限幅。2. 检查运放电路放大倍数和电源轨确保其输出范围覆盖期望值。3. 测量DAC的参考电压源是否稳定、准确。改变频率时波形相位跳变1. 改变FTW时相位累加器被错误复位或加载。2. MCU方案中更新步进值时未考虑相位连续性。1. 确保改变FTW时只写入新值不清零相位累加器寄存器。2. 在MCU中应采用“相位累加”方式而不是直接重置数组索引。多通道输出不同步各通道的DDS核心使用不同的时钟或相位累加器起点。使用同一个主时钟驱动所有DDS核心并通过一个同步信号同时复位所有相位累加器确保它们从同相位开始。6. 功能扩展与进阶玩法基础功能实现稳定后这个DDS信号发生器平台还有巨大的扩展潜力。任意波形合成AWG这是最直接的扩展。只需要将固定的波形查找表替换为一块可读写的存储器如RAM通过上位机将自定义的波形数据点下载到RAM中DDS核心即可循环读取这些数据并输出从而生成任意形状的波形。这需要主控具备较大的存储空间和高速数据传输接口如USB、以太网。调制功能在DDS中频率调谐字FTW、相位偏移字POW和幅度控制字都是数字端口。我们可以用另一个信号如音频信号、数字序列来实时调制这些字从而实现调频FM、调相PM和调幅AM。例如将音频ADC采集的数据叠加到FTW上就能输出FM调制波。扫频输出让FTW按照一定规律线性、对数随时间自动变化输出信号的频率就会连续扫描。这在网络分析、阻抗测量中非常有用。需要主控编程实现一个扫频算法并平滑地更新FTW值。多通道与相位同步如果需要产生多路具有特定相位关系的信号如正交的I/Q信号可以搭建多个相同的DDS核心并让它们共享同一个系统时钟和频率字但赋予不同的初始相位偏移字POW。这样可以精确控制多路信号之间的相位差。上位机软件控制为项目开发一个简单的PC端图形界面通过USB虚拟串口或USB CDC协议与硬件通信。在界面上可以图形化地设置波形、频率、幅度、占空比甚至绘制任意波形并下载极大提升设备的易用性和功能性。这个DDS信号发生器项目从概念到实现贯穿了数字电路、模拟电路、嵌入式编程和信号处理多个领域的知识。调试过程中遇到的每一个问题无论是频谱上的一个杂散还是波形上的一个毛刺都是加深对底层原理理解的绝佳机会。当你最终看到示波器上显示出干净、稳定、参数可控的标准波形时那种成就感是直接使用商用设备无法比拟的。它不仅仅是一个工具更是一个凝结了知识与实践的作品。本文还有配套的精品资源点击获取
返回列表