基于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信号发生器的设计与验证相关推荐

  1. 基于FPGA的简易DDS信号发生器的设计(一)

    写这篇文章的本意不是为了探讨AD9767怎么使用,因为9767的控制实在是太简单了,准备好数据直接输出即可,和网上大多数的并行DA输出基本上一模一样,更麻烦的反而是硬件方面.发文的原因是最近一位很细心 ...

  2. 基于FPGA的简易 DDS 信号发生器的设计

    文章目录 前言 一.pandas是什么? 二.ROM 内波形数据写入 1.MIF 2.DDS 模块参考代码 波形仿真 前言 DDS 是直接数字式频率合成器(Direct Digital Synthes ...

  3. 基于 FPGA 的便携式 DDS 信号发生器与示波器

    基于 FPGA 的便携式 DDS 信号发生器与示波器 项目来源:2019年第三届全国大学生FPGA创新设计竞赛 一.设计概述 1.1 设计目的 利用赛灵思公司 A7 系列板卡 EG01.AD9226 ...

  4. FPGA之简易DDS信号发生器设计

    文章目录 前言 一.DDS信号发生器 1.DDS是什么 2.DDS工作原理 二.模块代码 1.调用rom模块储存波形图 2.按键控制模块 2.按键消抖模块 3.DDS生成模块 4.顶层模块 5.RTL ...

  5. 基于FPGA的双通道DDS信号发生器

    硬件:FPGA开发板 ,AD9767双通道DA转换器 软件:ISE,Matlab,Modelsim 最终效果:输出方波,正弦波,三角波以及锯齿波,可以通过按键改变输出波形的频率,频率在1Hz-1MHz ...

  6. 基于FPGA实现的DDS双通道信号发生器

    文章目录 前言 一.DDS是什么? 二.设计步骤 1.DDS的基本结构 1.相位累加器 2.相位调制器 3.ROM数据表的生成 2.对各结构的代码实现 1.DDS顶层代码` 2.DDS主要发生模块 3 ...

  7. 简易DDS信号发生器记录

    简易DDS信号发生器 学习资料:野火 升腾Pro<FPGA Verilog开发实战指南--基于Xilinx Artix7>2021.11.16 1. 理论知识 DDS 是直接数字式频率合成 ...

  8. matlab样本序列的时域波形,基于MATLAB的简易声音信号频谱分析仪设计

    基于MATLAB的简易声音信号频谱分析仪设计 汉宁窗时域波形曲线图 汉宁窗频域特性曲线图 在MATLAB中,生成汉宁窗的函数是hanning.使用该函数进行频谱修正时,先生成一个和待修正的样本具有相同 ...

  9. 基于FPGA的简易数字频率计+上板测试(小梅哥AC620FPGA开发板)

    基于FPGA的简易数字频率计+上板测试(小梅哥AC620FPGA开发板 目录 主要架构 1.计数模块 2.数码显示模块 3.控制信号模块 4.分频模块 例化模块 上板测试图 附:74HC595移位寄存 ...

最新文章

  1. Form表单提交前进行JS验证的3种方式
  2. 3字节转换为有符号整型C语言,3.C语言整型数据
  3. linux安装 mysql-5.7.25_Linux 系统下安装 mysql5.7.25(glibc版)
  4. 传说中的贝叶斯统计到底有什么来头?
  5. 用indesign怎么更换名牌姓名_颚式破碎机如何拆卸?耐磨件怎么更换,可以用多久?答案都在这里...
  6. fcntl函数完成 set_fl()函数还有clr_fl()函数的封装
  7. ih5长图如何滑动_长图怎么一键截取?这样做很简单
  8. Linux常用命令,超强万字总结!
  9. CF1019D-Large Triangle【计算几何,二分】
  10. silverlight游戏在坑内发展
  11. 操作vsam用sequential访问模式REWRITE数据
  12. 小冰单飞的 135 天后,和微软再联手!
  13. uboot之logo显示
  14. 60. 理解 Ajax 性能
  15. python lambda表达式及用法_Python中lambda表达式的常见用法
  16. 最新米酷6.26影视源码+解析接口+步骤
  17. 计算机视觉教程7-3:Openpose配置与实践
  18. mac 硬盘读写速度测试 软件,MAC硬盘速度测试技巧
  19. yylabel html不显示图片,YYLabel富文本
  20. iOS 数据归档解档

热门文章

  1. ant design table column 设置width不生效解决方案
  2. npm install 报错(npm ERR! errno -4048,Error: EPERM: operation not permitted,)解决方法
  3. 如何在JavaScript中获取字符串数组的字符串?
  4. 将分支指针移动到不同的提交而不签出
  5. win11为什么比win10慢 Windows11比Win10慢的解决方法
  6. 日期格式转换,正则匹配后转换;指定时间增加天数加转格式;js时间转换格式
  7. 如何调用windows 的调色板 以及如何打开文件
  8. throwable四参构造_深入分析Java反射(四)-动态代理
  9. python创建线程函数_Python多线程编程(三):threading.Thread类的重要函数和方法...
  10. 关于python中字典描述正确的是_python总结七