基于FPGA的简易DDS信号发生器的设计与验证
基于FPGA的简易DDS信号发生器的设计与验证
- 一,理论介绍
- 补充:举例理解
- 二,代码实现
- 1,实验目标
- 2,MATLAB代码
- 3,verilog代码及实现思路
一,理论介绍
DDS 是直接数字式频率合成器(Direct Digital Synthesizer)的英文缩写,是一项关键的数字化技术。作为设计人员,我们习惯称它为信发生器,一般用它产生正弦、锯齿、方波等不同波形或不同频率的信号波形,在电子设计和测试中得到广泛应用。
DDS 的基本结构主要由相位累加器、相位调制器、波形数据表 ROM、D/A 转换器等四大结构组成,其中较多设计还会在数模转换器之后增加一个低通滤波器。
实现的原理如下图所示:
系统时钟 CLK 为整个系统的工作时钟,频率为 fCLK ;频率字输入 F_WORD,一般为整数,数值大小控制输出信号的频率大小,数值越大输出信号频率越高,反之,输出信号频率越低,后文中用 K 表示;相位字输入P_WORD,为整数,数值大小控制输出信号的相位偏移,主要用于相位的信号调制,后文用 P 表示;设输出信号为 CLK_OUT,频率为 fOUT。
相位累加器是整个 DDS 的核心,在这里完成相位累加,生成相位码。相位累加器的输入为频率字输入 K,表示相位增量,设其位宽为 N,满足等式K=2N∗fOUT/fCLKK=2^{N} *f_{OUT}/f_{CLK}K=2N∗fOUT/fCLK
波形数据表 ROM中存有一个完整周期的正弦波信号。假设波形数据 ROM的地址位宽为 12 位,存储数据位宽为 8位,即 ROM有 2122^{12}212 = 4096个存储空间,每个存储空间可存储 1字节数据。将一个周期的正弦波信号,沿横轴等间隔采样2122^{12}212 = 4096 次,每次采集的信号幅度用 1 字节数据表示,最大值为 255,最小值为 0。将 4096 次采样结果按顺序写入 ROM的 4096 个存储单元,一个完整周期正弦波的数字幅度信号写入了波形数据表 ROM 中。波形数据表 ROM 以相位调制器传入的相位码为 ROM 读地址,将地址对应存储单元中的电压幅值数字量输出。
补充:举例理解
设:ROM 存储单元个数为 4096,每个存储数据用 8 位二进制表示。即,ROM 地址线宽度为 12,数据线宽度为 8;相位累加器位宽 N = 32。
根据上述条件可以知道,相位调制器位宽 M = 12(需要进行相位选择,因此其位宽与ROM地址位宽一致),那么根据 DDS 原理。那么在相位调制器中与相位控制字进行累加时,应用相位累加器的高 12 位累加。而相位累加器的低20 位只与频率控制字累加。我们以频率控制字 K = 1为例,相位累加器的低 20位一直会加 1,直到低 20位溢出向高 12 位进位,此时 ROM 为 0,也就是说,ROM 的 0 地址中的数据被读了 2202^{20}220 次,继续下去,ROM中的 4096个点,每个点都将会被读2202^{20}220次,最终输出的波形频率应该是参考时钟频率的 1 /2202^{20}220,周期被扩大了2202^{20}220倍。同样当频率控制字为 100 时,相位累加器的低 20 位一直会加 100,那么,相位累加器的低 20 位溢出的时间比上面会快 100 倍,则 ROM 中的每个点相比于上面会少读 100次,所以最终输出频率是上述的 10 倍。
假设有1000个点,从0+1+2+…+1000,对比0+100+200+…+1000前者数1000次,后者数10次,相差100倍。因此就是100倍的差距。
二,代码实现
1,实验目标
使用questasim实现DDS波形的显示,显示四种波形,分别为正弦波方波,三角波与锯齿波。先使用MATLAB生产.coe
文件然后在使用ISE14.7进行代码的书写。实验仿真结果如下
2,MATLAB代码
%% wave_16384x8
clc ; %清除命令行
clear all ; %清除工作区变量,释放内存空间
F1 = 1 ; %信号频率 sin(2*pi*f*t + a)
Fs = 2^12 ; %采样频率
P1 = 0 ; %信号初始初始相位
N = 2^12 ; %采样点数
t = [0 : 1/Fs:(N - 1)/Fs]; %采样时刻
ADC = 2^7 - 1; %直流分量
A = 2^7; %信号幅度
s1 = A*sin(2*pi*F1*t + pi*P1/180) + ADC ; %正弦波信号
s2 = A*square(2*pi*F1*t + pi*P1/180) + ADC; %方波信号
s3 = A*sawtooth(2*pi*F1*t + pi*P1/180,0.5) + ADC; %三角波信号
s4 = A*sawtooth(2*pi*F1*t + pi*P1/180) + ADC; %锯齿波信号
%创建coe文件
plot(s4)
fild = fopen('wave_16384x8.coe','wt');
%写入coe头文件
fprintf(fild, '%s\n','MEMORY_INITIALIZATION_RADIX=10;');%十进制
fprintf(fild, '%s\n','MEMORY_INITIALIZATION_VECTOR=');
for j = 1:4for i = 1:Nif j == 1 %打印正弦信号数据s0(i) = round(s1(i)); %对小数四舍五入以取整end if j == 2 %打印方波信号数据s0(i) = round(s2(i)); %对小数四舍五入以取整endif j == 3 %打印三角波信号数据s0(i) = round(s3(i)); %对小数四舍五入以取整endif j == 4 %打印锯齿波信号数据s0(i) = round(s4(i)); %对小数四舍五入以取整endif s0(i) <0 %负 1 强制置零s0(i) = 0endif j == 4 && i == Nfprintf(fild, '%d',s0(i)); %数据写入fprintf(fild, '%s',';'); %最后一个数使用分号结束elsefprintf(fild, '%d',s0(i)); %数据写入fprintf(fild, '%s\n',','); %逗号,换行endend
end
fclose(fild)
3,verilog代码及实现思路
实际上就是读.coe
文件里的数据。但是由于我们产生了四个波形,因此需要对地址进行控制,其次为了控制频率与初相。
首先是对于波形输出的选择。这里控制相位累加器单次累加值可以控制频率,控制相位偏移量可以控制波形的初相。这里生成500HZ,初相为pi/2的波形。
核心代码如下
`timescale 1ps / 1ps
//-----------------------------------------------------------------------------------
// Copyright :This document is only for personal learning reference and research.
// Module: dds
// File: dds.v
// Author: meng guodong
// E-mail: 823300630@qq.com
// Time : 2021-02-20 10:15:32
// Description:
// Revision: 1.0
//-------------------------------------------------------------------------------------------------
module dds (//system signalsinput clk ,input rst_n ,//others signalsinput [3:0] wave_select ,output [7:0] data_out
);//========================================================================\
// =========== Define Parameter and Internal signals ===========
//========================================================================/
parameter sin_wave = 4'b0001 , //正弦波squ_wave = 4'b0010 , //方波tri_wave = 4'b0100 , //三角波saw_wave = 4'b1000 ; //锯齿波
parameter FREQ_CTRL = 32'd42949 , //相位累加器单次累加值PHASE_CTRL = 12'd1024 ; //相位偏移量reg [31:0] fre_add; //相位累加器
reg [11:0] rom_addr_reg; //相位调制后的相位码
reg [13:0] rom_addr ; //ROM 读地址
//需要输出的波形频率为 500Hz,初相位为π/2的信号
//=============================================================================
//************** Main Code **************
//=============================================================================
//fre_add:相位累加器
always @ (posedge clk or negedge rst_n)
begin if(!rst_n)fre_add <= 'd0;elsefre_add <= fre_add + FREQ_CTRL;
end
//rom_addr_reg
always @ (posedge clk or negedge rst_n)
begin if(!rst_n)rom_addr_reg <= 'd0;elsecase (wave_select) sin_wave : rom_addr_reg <= fre_add[31:20] + PHASE_CTRL;squ_wave : rom_addr_reg <= fre_add[31:20] + PHASE_CTRL;tri_wave : rom_addr_reg <= fre_add[31:20] + PHASE_CTRL;saw_wave : rom_addr_reg <= fre_add[31:20] + PHASE_CTRL;default : ;endcase
end //rom_addr
always @ (posedge clk or negedge rst_n)
begin if(!rst_n)rom_addr <= 'd0;elsecase (wave_select) sin_wave : rom_addr <= rom_addr_reg + 14'd4096*0 ;squ_wave : rom_addr <= rom_addr_reg + 14'd4096*1 ;tri_wave : rom_addr <= rom_addr_reg + 14'd4096*2 ;saw_wave : rom_addr <= rom_addr_reg + 14'd4096*3 ;default : ;endcase
end dds_inst dds_inst_0 (.clka(clk), // input clka.addra(rom_addr), // input [13 : 0] addra.douta(data_out) // output [7 : 0] douta
);
endmodule
关注公众号:果冻空间 回复:A-003 即可获取工程源码
基于FPGA的简易DDS信号发生器的设计与验证相关推荐
- 基于FPGA的简易DDS信号发生器的设计(一)
写这篇文章的本意不是为了探讨AD9767怎么使用,因为9767的控制实在是太简单了,准备好数据直接输出即可,和网上大多数的并行DA输出基本上一模一样,更麻烦的反而是硬件方面.发文的原因是最近一位很细心 ...
- 基于FPGA的简易 DDS 信号发生器的设计
文章目录 前言 一.pandas是什么? 二.ROM 内波形数据写入 1.MIF 2.DDS 模块参考代码 波形仿真 前言 DDS 是直接数字式频率合成器(Direct Digital Synthes ...
- 基于 FPGA 的便携式 DDS 信号发生器与示波器
基于 FPGA 的便携式 DDS 信号发生器与示波器 项目来源:2019年第三届全国大学生FPGA创新设计竞赛 一.设计概述 1.1 设计目的 利用赛灵思公司 A7 系列板卡 EG01.AD9226 ...
- FPGA之简易DDS信号发生器设计
文章目录 前言 一.DDS信号发生器 1.DDS是什么 2.DDS工作原理 二.模块代码 1.调用rom模块储存波形图 2.按键控制模块 2.按键消抖模块 3.DDS生成模块 4.顶层模块 5.RTL ...
- 基于FPGA的双通道DDS信号发生器
硬件:FPGA开发板 ,AD9767双通道DA转换器 软件:ISE,Matlab,Modelsim 最终效果:输出方波,正弦波,三角波以及锯齿波,可以通过按键改变输出波形的频率,频率在1Hz-1MHz ...
- 基于FPGA实现的DDS双通道信号发生器
文章目录 前言 一.DDS是什么? 二.设计步骤 1.DDS的基本结构 1.相位累加器 2.相位调制器 3.ROM数据表的生成 2.对各结构的代码实现 1.DDS顶层代码` 2.DDS主要发生模块 3 ...
- 简易DDS信号发生器记录
简易DDS信号发生器 学习资料:野火 升腾Pro<FPGA Verilog开发实战指南--基于Xilinx Artix7>2021.11.16 1. 理论知识 DDS 是直接数字式频率合成 ...
- matlab样本序列的时域波形,基于MATLAB的简易声音信号频谱分析仪设计
基于MATLAB的简易声音信号频谱分析仪设计 汉宁窗时域波形曲线图 汉宁窗频域特性曲线图 在MATLAB中,生成汉宁窗的函数是hanning.使用该函数进行频谱修正时,先生成一个和待修正的样本具有相同 ...
- 基于FPGA的简易数字频率计+上板测试(小梅哥AC620FPGA开发板)
基于FPGA的简易数字频率计+上板测试(小梅哥AC620FPGA开发板 目录 主要架构 1.计数模块 2.数码显示模块 3.控制信号模块 4.分频模块 例化模块 上板测试图 附:74HC595移位寄存 ...
最新文章
- Form表单提交前进行JS验证的3种方式
- 3字节转换为有符号整型C语言,3.C语言整型数据
- linux安装 mysql-5.7.25_Linux 系统下安装 mysql5.7.25(glibc版)
- 传说中的贝叶斯统计到底有什么来头?
- 用indesign怎么更换名牌姓名_颚式破碎机如何拆卸?耐磨件怎么更换,可以用多久?答案都在这里...
- fcntl函数完成 set_fl()函数还有clr_fl()函数的封装
- ih5长图如何滑动_长图怎么一键截取?这样做很简单
- Linux常用命令,超强万字总结!
- CF1019D-Large Triangle【计算几何,二分】
- silverlight游戏在坑内发展
- 操作vsam用sequential访问模式REWRITE数据
- 小冰单飞的 135 天后,和微软再联手!
- uboot之logo显示
- 60. 理解 Ajax 性能
- python lambda表达式及用法_Python中lambda表达式的常见用法
- 最新米酷6.26影视源码+解析接口+步骤
- 计算机视觉教程7-3:Openpose配置与实践
- mac 硬盘读写速度测试 软件,MAC硬盘速度测试技巧
- yylabel html不显示图片,YYLabel富文本
- iOS 数据归档解档
热门文章
- ant design table column 设置width不生效解决方案
- npm install 报错(npm ERR! errno -4048,Error: EPERM: operation not permitted,)解决方法
- 如何在JavaScript中获取字符串数组的字符串?
- 将分支指针移动到不同的提交而不签出
- win11为什么比win10慢 Windows11比Win10慢的解决方法
- 日期格式转换,正则匹配后转换;指定时间增加天数加转格式;js时间转换格式
- 如何调用windows 的调色板 以及如何打开文件
- throwable四参构造_深入分析Java反射(四)-动态代理
- python创建线程函数_Python多线程编程(三):threading.Thread类的重要函数和方法...
- 关于python中字典描述正确的是_python总结七