跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客GitHub 精选镜像工具UI配色美学隐私政策关于联系
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
C算法

FPGA 中 DDS 方案设计:频率、幅度与波形可调

综述由AI生成在 FPGA 中实现 DDS(直接数字频率合成)的方案。内容涵盖 DDS 基本原理,包括频率控制字、相位控制字、相位累加器、波形数据表及 DAC 转换等核心模块。详细阐述了代码实现过程,涉及控制模块、DDS 主模块及 IP 核 ROM 配置,并提供了 MATLAB 生成波形数据的示例代码。最后展示了仿真与实际输出结果,验证了频率、幅度及波形的可调性。

编程诗人发布于 2026/4/6更新于 2026/5/2235 浏览
FPGA 中 DDS 方案设计:频率、幅度与波形可调

1. DDS 原理简介

DDS 技术是从波形相位概念出发,直接对相应的波形数据进行抽样,得到不同的相位,通过 DAC 转换成模拟波形,最后通过低通滤波器平滑输出所需频率的波形。

文章配图

两个重要参数解释:

频率控制字 FTW:一般为整数,数值大小控制输出信号的频率大小,数值越大输出信号频率越高。实际输出的信号的频率与频率控制字关系为:

频率控制字 = 脉冲频率 * 2^N / 时钟频率

相位控制字 P_WORD:一般为整数,数值大小控制输出信号的相位偏移,主要用于相位的信号调制。

一个普通的 DDS 设计应该由:相位累加器,相位调制器,波形数据表,DAC 转换组成。

相位累加器:是整个 DDS 的核心,用于控制波形的相位累加,组成完整的波形显示。 相位累加器的输入为频率控制字,表示相位增量,其位宽为 N。

文章配图

相位调制器:接收相位累加器输出的相位码,在这里加上一个相位偏移值 P,主要用于信号的相位调制。

波形数据表:波形数据表 ROM 中存有一个完整周期的正弦波信号。例如:假设波形数据 ROM 的地址位宽为 12 位,储存数据位宽为 8 位,即 ROM 有 2^12=4096 个存储空间,每个存储空间可以存储 1 字节数据。将一个周期的正弦波信号,沿横轴等间隔采样 4096 次,每次采集的信号幅度用 1 字节数据表示,最大值为 255,最小值为 0。将 4096 次采样结果按顺序写入 ROM 的 4096 个存储单元,一个完整周期正弦波的数字幅度信号就写入了波形数据表 ROM 中。波形数据表 ROM 以相位调制器传入的相位码为 ROM 读地址,将地址对应存储单元的电压幅值数字量进行输出。

文章配图

DAC 转换:将输入的电压幅值数字量转换为模拟量输出。根据奈奎斯特采样定理,频率控制字的最大值应小于 2^N / 2。

文章配图

运行流程为:

文章配图

相位累加器得到的相位码是如何实现 ROM 寻址的呢?

对于 N 位的相位累加器,其对应的相位累加值为 2^N,如果正弦 ROM 中存储单元的个数也是 2^N 的话,那这个问题就很容易解决,但是这对 ROM 的存储容量要求较高。

在实际中,我们使用相位累加器的高几位来对 ROM 进行寻址,也就是说并不是每个系统时钟都对 ROM 进行数据读取,而是多个时钟读取一次,因为这样能保证相位累加器溢出时,从正弦 ROM 表中取出正好一个正弦周期的样点。

因此,相位累加器每计数 2^N 次,对应一个正弦周期。而相位累加器 1 秒钟计数 fclk 次(工作时钟频率),当频率控制字 FTW 为 1 时,DDS 输出的时钟频率就是频率分辨率。当 FTW 增加时,相位累加器溢出的频率增加,对应 DDS 输出信号频率就变成了 FTW 倍的 DDS 频率分辨率。

例如: 假设 ROM 的存储单元个数为 4096,每个存储数据用 8 位二进制表示。即 ROM 地址线宽为 12,数据线宽为 8;相位累加器位宽设置为 N=32。 由于 ROM 地址线位宽为 12,所以相位调制器的输出位宽也应该为 12。(因为 DDS 原理就是通过相位调制器的输出去 ROM 寻址)在相位调制器中与相位控制字进行累加时,用相位累加器的高 12 位累加,而低位只与频率控制字累加。

以频率控制字 FTW=1 为例,相位累加器的低 20 位一直加 1,直到低 20 位溢出而向高 12 位进位,此时 ROM 为 0,也就是说,ROM 的 0 地址中的数据被读了 2^20 次,继续往下,ROM 的 4096 个点全部都会读 2^20 次,最终输出的波形频率应该是参考时钟频率的 1/2^20,周期被扩大了 2^20 倍。同样当频率控制字为 100 时,所以最终输出频率是上述的 100 倍。

2. 代码实现

本次实验的硬件平台为 AC101-EDA,开发软件为 Quartus13.1。

文章配图

由上节对 DDS 原理的介绍,可以分为以下几个模块。

文章配图

2.1 控制模块

频率控制模块、相位控制模块、幅度控制模块这三个模块的逻辑一模一样,即:指定一个按键,通过按键的值将对应的参数进行改变。下面以幅度控制模块进行举例说明。

当系统检测到按键被按下后,将变量 cnt 进行计数:

文章配图

即用 cnt 来表示按键的按下的次数,这里是当 cnt 按下 5 次后,被清零。其中 key_flag 表示按键按下,由按键消抖模块输出。

amplitude 的值由 cnt 的值决定,用一个 case 语句即可实现。

文章配图

其他两个模块几乎一模一样,这里不再赘述。

2.2 DDS 实现模块

文章配图

文章配图

还需要设计一个波形选择的功能,可按如下实现。

文章配图

其中 dac_data0、dac_data1、dac_data2、dac_data3 分别对应四个 rom 的输出。

文章配图

2.3 ip 核 ROM 的实现

在 Quartus13.1 中,rom 使用 ip 核进行实现:由于实验所用的开发板的 DAC 为 8 位,所以 ROM 的数据位宽这里也设置为 8。

文章配图

文章配图

总共使用 4 个 ROM,分别对应正弦波、三角波、方波、锯齿波,ROM 所需的.mif 文件由 matlab 实现。如正弦波文件的 matlab 代码如下:

cclc; %清除命令行命令 clear all; %清除工作区变量,释放内存空间 F1=1; %信号频率 Fs=2^12; %采样频率 P1=0; %信号初始相位 N=2^12; %采样点数 t=[0:1/Fs:(N-1)/Fs]; %采样时刻 ADC=2^7 - 1; %直流分量 A=2^7; %信号幅度 %生成正弦信号 s=A*sin(2*pi*F1*t + pi*P1/180) + ADC; plot(s); %绘制图形 %创建 mif 文件 fild = fopen('sin_wave_4096x8.mif','wt'); %写入 mif 文件头 fprintf(fild, '%s\n','WIDTH=8;'); %位宽 fprintf(fild, '%s\n\n','DEPTH=4096;'); %深度 fprintf(fild, '%s\n','ADDRESS_RADIX=UNS;'); %地址格式 fprintf(fild, '%s\n\n','DATA_RADIX=UNS;'); %数据格式 fprintf(fild, '%s\t','CONTENT'); %地址 fprintf(fild, '%s\n','BEGIN'); %开始 for i = 1:N s0(i) = round(s(i)); %对小数四舍五入以取整 if s0(i) <0 %负 1 强制置零 s0(i) = 0 end fprintf(fild, '\t%g\t',i-1); %地址编码 fprintf(fild, '%s\t',':'); %冒号 fprintf(fild, '%d',s0(i)); %数据写入 fprintf(fild, '%s\n',';'); %分号,换行 end fprintf(fild, '%s\n','END;'); %结束 fclose(fild);

注意确保生成的.mif 文件位于 Quartus 的工程目录下。

文章配图

DAC 驱动模块:

开发板上的 DAC 是 MCP4802,采用的 SPI 通信。代码部分参考相关 SPI 通信文档。

在 Quartus 中查看 RTL 视图:

文章配图

3. 实验结果

3.1 仿真结果

文章配图

3.2 实际输出结果

3.2.1 波形选择

文章配图

3.2.2 频率控制

文章配图

3.2.3 幅度控制

文章配图

目录

  1. 1. DDS 原理简介
  2. 2. 代码实现
  3. 2.1 控制模块
  4. 2.2 DDS 实现模块
  5. 2.3 ip 核 ROM 的实现
  6. 3. 实验结果
  7. 3.1 仿真结果
  8. 3.2 实际输出结果
  9. 3.2.1 波形选择
  10. 3.2.2 频率控制
  11. 3.2.3 幅度控制
  • 💰 8折买阿里云服务器限时8折了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 🤖 一键搭建Deepseek满血版了解详情
  • 一键打造专属AI 智能体了解详情
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • MC.JS WEBMC1.8 与传统 JavaScript 开发效率对比
  • Python GUI 开发指南:Tkinter 与 PyQt5 对比及安装教程
  • Photoshop 集成 ComfyUI AI 绘画功能指南
  • MySQL 表操作实战指南:创建、修改与删除详解
  • 使用 copilot-api 实现 GitHub Copilot 兼容 OpenAI 与 Anthropic 生态
  • Python 爬虫 403 错误处理:Selenium 与普通请求对比
  • 使用 FastAPI 和 HTML/CSS/JavaScript 构建博客系统示例
  • Studio One 7 核心功能解析:从创作到母带的一体化 DAW 工作流
  • uv 虚拟环境管理:venv 创建、激活与 Python 版本指定
  • DeepSeek-R1-Distill-Qwen-1.5B 本地部署实战:vLLM+Open WebUI 低显存方案
  • 前端实现 PC 网站微信扫码授权登录
  • 2023 年网络安全 HW 行动蓝队面试常见问题与解答
  • Vue 3 开发实战:10 个提升效率的核心技巧
  • FAIR plus 机器人全产业链接会:2026 深圳展会前瞻
  • 前端实现视频画中画功能 - 主页面与小窗同步控制
  • QoderWork:一款桌面级通用 AI Agent 助手
  • 秋叶绘世 Stable Diffusion 整合包与 ComfyUI 使用指南
  • AI 驱动的小程序开发:从零构建“打工了马”实战复盘
  • 双指针算法进阶:从三角形计数到四数之和
  • 通用人工智能平台功能解析与商业化应用场景指南

相关免费在线工具

  • 加密/解密文本

    使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

  • Gemini 图片去水印

    基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

  • Markdown转HTML

    将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online

  • HTML转Markdown

    将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online