基于FPGA的双通道DDS信号发生器
硬件:FPGA开发板 ,AD9767双通道DA转换器
软件:ISE,Matlab,Modelsim
最终效果:输出方波,正弦波,三角波以及锯齿波,可以通过按键改变输出波形的频率,频率在1Hz-1MHz可调,输出波形的电压通过旋钮可调
一、生成波形数据
第一步,通过Matlab生成波形数据文件,数据最终存储在FPGA的ROM中,以.coe结尾。这里以生成正弦信号为例,由于AD9767是14位的DA转换芯片,所以生成的数据位宽也是14位。
clear;
clc;radix=2; %进制的格式
width=14; %数据的位宽
depth=1024; %数据的深度fid =fopen ('sin.coe','w');
fprintf(fid,'MEMORY_INITIALIZATION_RADIX=%d;\n',radix);
fprintf(fid,'MEMORY_INITIALIZATION_VECTOR=\n');for i=0:depth-1sin_data=floor((sin(2*pi*i/depth)+1)*0.5*(2^width-1));data=dec2bin(sin_data,width); %十进制到二进制的转换if (i~=depth-1) fprintf(fid,'%s,\n',data); elsefprintf(fid,'%s;',data); %最后一行以分号结尾end
endfclose (fid);
生成的.coe文件需要符合语法规范,将生成的coe文件保存到生成的Rom IP核中。
二、FPGA程序部分设计
系统的整体框架分为FPGA和AD9767模块两部分,FPGA产生两路数字信号,AD9767模块将数字信号数模转换后经过滤波后输出。
FPGA部分中,输出信号的频率由频率控制字决定。每经过一个时钟周期,加法器就将频率控制字与相位累加寄存器相加,最后得到的结果作为波形数据表的读取地址。同时相加结果反馈到加法器的输入端,使得每次相加都可以实现读取地址的递增,当累加次数足够多相位累加寄存器溢出,读取地址“归零”,如此循环往复输出正弦波信号。
1.顶层模块AD9767_DDS的设计
通过按键key1实现频率控制字的控制,按键key2实现波形的选择,led灯用来指示现在输出的波形。
module AD9767_DDS(input sclk, input rst_n,input key1,input key2,output [1:0]led,output DACA_CLK, //通道1时钟信号output DACB_CLK, //通道2时钟信号output DACA_WRT, //通道1使能信号output DACB_WRT, //通道2使能信号output [13:0]DAC_DATA1, //通道1输出数据output [13:0]DAC_DATA2 //通道2输出数据
);assign D_CLK = sclk;assign DACA_CLK = D_CLK;assign DACB_CLK = D_CLK;assign DACA_WRT = D_CLK;assign DACB_WRT = D_CLK;wire [31:0]Fword;wire [1:0]wave_sel; //控制输出波形形状wire [2:0]Fword_sel;//改变频率控制字DDS_Module DDS_Module0(.clk(D_CLK),.rst_n(rst_n),.EN(1'b1),.key(key2),.Fword(Fword),.Pword(10'd0),.wave_sel(wave_sel),.DA_Clk(),.DA_Data(DAC_DATA1));DDS_Module DDS_Module1(.clk(D_CLK),.rst_n(rst_n),.EN(1'b1),.key(key2),.Fword(Fword),.Pword(10'd512), //相对于通道1有180度的偏移.DA_Clk(),.DA_Data(DAC_DATA2));Fword_Set Fword_Set_inst(.clk(sclk),.rst_n(rst_n),.key(key1),.Fword(Fword),.Fword_sel(Fword_sel));assign led = ~wave_sel;endmodule
2.信号产生模块DDS_Module的设计
累加器是32位的,而数据深度是1024也就是十位的,取累加器的高十位作为读取地址。例化四个ROM模块分别存储不同的波形数据,通过按键按下控制输出的波形。
module DDS_Module(input clk,input rst_n,input EN,input key,input [31:0] Fword,/*频率控制字*/input [9:0] Pword,/*相位控制字*/output reg [1:0] wave_sel,/*波形选择字*/output DA_Clk,/*DA数据输出时钟*/output reg [13:0] DA_Data/*D输出输出A*/
);wire key_neg, key_out;wire [13:0] DA_Data1,DA_Data2,DA_Data3,DA_Data4;key_detect key_detect2(.sclk(clk),.rst_n(rst_n),.key_in(key),.key_neg(key_neg),.key_out(key_out));always@(posedge clk or negedge rst_n)if(!rst_n)wave_sel <= 2'd0;else if(key_neg == 1 && !key_out)wave_sel <= wave_sel + 1'b1;elsewave_sel <= wave_sel;always@(*)begincase(wave_sel)0: DA_Data <= DA_Data1; //选择正弦波 1: DA_Data <= DA_Data2; //选择方波2: DA_Data <= DA_Data3; //选择三角波3: DA_Data <= DA_Data4; //选择锯齿波default: DA_Data <= DA_Data1;endcase
endreg [31:0] Fre_acc; reg [9:0] Rom_Addr;/*rom深度1024*//*---------------相位累加器------------------*/ always @(posedge clk or negedge rst_n)if(!rst_n)Fre_acc <= 32'd0;else if(!EN)Fre_acc <= 32'd0; else Fre_acc <= Fre_acc + Fword;/*----------生成查找表地址---------------------*/ always @(posedge clk or negedge rst_n)if(!rst_n)Rom_Addr <= 10'd0;else if(!EN)Rom_Addr <= 10'd0;elseRom_Addr <= Fre_acc[31:22] + Pword; /*----------例化查找表ROM SIN-------*/ ddsrom ddsrom_inst(.addra(Rom_Addr),.clka(clk),.douta(DA_Data1));/*----------例化查找表ROM -------*/ square square_inst(.addra(Rom_Addr),.clka(clk),.douta(DA_Data2));/*----------例化查找表ROM sawtooth-------*/ sawtooth sawtooth_inst(.addra(Rom_Addr),.clka(clk),.douta(DA_Data3));/*----------例化查找表ROM sawtooth_juci-------*/ sawtooth_juci sawtooth_juci_inst(.addra(Rom_Addr),.clka(clk),.douta(DA_Data4));/*----------输出DA时钟----------*/assign DA_Clk = (EN)?clk:1'b1;endmodule
3.频率选择模块Fword_Set的设计
通过按钮选择频率控制字Fword,信号频率=Fword*2^累加器数据位宽/时钟频率。本来打算加一个扫频的功能,但是效果还没实现。
module Fword_Set(input clk,input rst_n,input key,output reg[31:0]Fword,output reg[2:0]Fword_sel,output reg[19:0]cnt_time
);parameter HUN_HZ = 8600,TWOK_HZ = 171799,ONE_HZ = 86;parameter IDLE = 2'd0,INCREASE = 2'd1,PAUSE = 2'd2;wire key_neg, key_out;reg [1:0] state;reg [4:0] cnt_latency;reg flag;wire [19:0] divider;wire [19:0] word;assign word = (Fword>>13)*(Fword>>13);always @(posedge clk or negedge rst_n) beginif(!rst_n) cnt_latency <= 'd0; else if(cnt_latency == 5'd22)cnt_latency <= 'd0;elsecnt_latency <= cnt_latency + 5'd1;endalways @(posedge clk or negedge rst_n) beginif(!rst_n) flag <= 1'd0; else if(cnt_time >= divider && cnt_latency == 5'd18)flag <= 1'd1;elseflag <= 1'd0;endkey_detect key_detect1(.sclk(clk),.rst_n(rst_n),.key_in(key),.key_neg(key_neg),.key_out(key_out));always @(posedge clk or negedge rst_n) beginif(!rst_n) cnt_time <= 'd0; else if((Fword_sel == 3'd0) && (flag == 1'b0))cnt_time <= cnt_time + 20'd1;elsecnt_time <= 20'd0;endalways@(posedge clk or negedge rst_n)if(!rst_n)Fword_sel <= 3'd0;else if(Fword_sel < 3'd5) beginif(key_neg == 1 && !key_out)Fword_sel <= Fword_sel + 1'b1;elseFword_sel <= Fword_sel;endelseFword_sel <= 3'd0;always@(posedge clk)begincase(Fword_sel)0: begincase(state)IDLE: Fword <= HUN_HZ;INCREASE:Fword <= Fword + ONE_HZ; PAUSE: Fword <= Fword;default:Fword <= Fword;endcaseend1: Fword <= 86; //1Hz 85.89934592 2^32*20/10^92: Fword <= 16063; //187kHz3: Fword <= 85999; //1kHz4: Fword <= 85999346; //1MHz default:Fword <= Fword; endcaseendalways@(posedge clk or negedge rst_n)beginif(!rst_n)state <= IDLE;else if(Fword_sel == 3'd0 && flag == 1'b1)state <= INCREASE;else if(Fword_sel == 3'd0 && Fword <= TWOK_HZ)state <= PAUSE;else state <= IDLE;enddiv div_inst(//8599*8599*500000/(Fword^2).clk (clk),.dividend (20'd550000),.divisor (word),.quotient (divider));endmodule
三、AD9767模块
参考了这篇文章,做了以下改进:
1.在调试的过程中,发现原本小的贴片电感在使用过程中发热,不适用于电流大的场景,改成大的绕线电感。
2.原来的小旋扭电位器调节幅值并不方便,改用大旋钮的电位器。
测试视频:b站链接
工程文件:gitee
基于FPGA的双通道DDS信号发生器相关推荐
- 基于FPGA的简易DDS信号发生器的设计与验证
基于FPGA的简易DDS信号发生器的设计与验证 一,理论介绍 补充:举例理解 二,代码实现 1,实验目标 2,MATLAB代码 3,verilog代码及实现思路 一,理论介绍 DDS 是直接数字式频率 ...
- 基于FPGA的简易DDS信号发生器的设计(一)
写这篇文章的本意不是为了探讨AD9767怎么使用,因为9767的控制实在是太简单了,准备好数据直接输出即可,和网上大多数的并行DA输出基本上一模一样,更麻烦的反而是硬件方面.发文的原因是最近一位很细心 ...
- 基于 FPGA 的便携式 DDS 信号发生器与示波器
基于 FPGA 的便携式 DDS 信号发生器与示波器 项目来源:2019年第三届全国大学生FPGA创新设计竞赛 一.设计概述 1.1 设计目的 利用赛灵思公司 A7 系列板卡 EG01.AD9226 ...
- 基于FPGA的简易 DDS 信号发生器的设计
文章目录 前言 一.pandas是什么? 二.ROM 内波形数据写入 1.MIF 2.DDS 模块参考代码 波形仿真 前言 DDS 是直接数字式频率合成器(Direct Digital Synthes ...
- 基于FPGA实现的DDS双通道信号发生器
文章目录 前言 一.DDS是什么? 二.设计步骤 1.DDS的基本结构 1.相位累加器 2.相位调制器 3.ROM数据表的生成 2.对各结构的代码实现 1.DDS顶层代码` 2.DDS主要发生模块 3 ...
- FPGA之简易DDS信号发生器设计
文章目录 前言 一.DDS信号发生器 1.DDS是什么 2.DDS工作原理 二.模块代码 1.调用rom模块储存波形图 2.按键控制模块 2.按键消抖模块 3.DDS生成模块 4.顶层模块 5.RTL ...
- 基于STC89C52RC芯片 高频DDS信号发生器AD9851信号源方波正弦波系统设计
[01]设计大致思路 一开始是使用按键进行频率输出数值的增加或者减少,后改进成使用EC11调节输出数值,使数值的输出更加顺滑流畅. [02]参考资料 链接:https://pan.baidu.com/ ...
- 双通道幅频相可调DDS 信号发生器
DDS 基本原理 DDS(Direct Digital Synthesizer)即数字合成器,是一种新型的频率合成技术,具有相对带宽大,频率转换时间短.分辨率高和相位连续性好等优点.较容易实现频率.相 ...
- BGD 通信15-1 150206102 王嘉良 DDS信号发生器
DDS信号发生器的设计 DDS(DiFeet Digital Frequency Synthesis)即直接数字式频率合成,是从相位概念出发直接合成所需波形的一种频率合成技术.与传统信号源所采用的用模 ...
最新文章
- python画人脸关键点
- 【Paper】2015_异构无人机群鲁棒一致性协议设计_孙长银
- VUE 使用中踩过的坑
- 面向对象的程序开发技术C++教学课件系列之二
- matlab 高斯迭代代码_主动降噪与双麦降噪原理与实现前篇——LMS算法的matlab实现...
- linux设备驱动归纳总结(八):1.总线、设备和驱动【转】
- miui8.2 是android 7.0,因与MIUI 8.2撞车 小米5暂缺失安卓7.0
- Layer success 层弹出后的成功回调方法
- liunx破解root密码精简版
- 深度学习笔记:利用预训练模型之特征提取训练小数据集上的图像分类器
- aspjpeg组件在2008R2下“ActiveX 部件不能创建对象”
- Sprite Renderer
- 第六感38只19.9/吹风机29.9/长虹电暖器69/按摩护腰垫39/情侣卫衣54.9
- 甲骨文数据库基本知识
- 多入库口、出库口的提升系统仿真测试案例
- wordpress后台管理(七)说说管理:发表说说、所有说说
- 计算机电子琴歌声号码,电子琴歌音色节奏一览表.xls
- python词频统计之红楼梦_用 Python 分析《红楼梦》,后四十回是曹雪芹所写
- 一键seo提交收录_关于SEO行业中的某些信息,你究竟应该相信谁?又或者谁都不要信!...
- redhat 新开启一个ssh端口