目的:设计一个DDS,可以输出两个波形,输出的波形的周期可以修改,相位可以修改,种类也可以修改

输入:clk,reset,一个控制T的按键,一个控制相位的按键,一个控制波形种类的按键。

思路:双通道——需要两个DDS。

     波形种类可控——每个DDS需要四个ROM分别存放正弦波,三角波,锯齿波,方波。

   频率可控——一个频率控制按钮,按一下切换一次频率,可供选择的频率是固定的,用计数器来设计。

      相位可控——一个相位控制按钮,按一下切换一次相位,可供选择的相位是固定的,用计数器来设计。

      有按钮——引入按键消抖模块,提高准确性。

   可控——计数器+查找表 可以实现简单切换。(其他,如矩阵键盘等,后续)

建模:

     

细节:输出波形的周期与频率控制的关系

  ROM存储一个波形,而相位累加器的内存存储一个波形的离散点。一般来说相位累加器内存大于ROM。而取点间隔就是频率控制字。

  比如ROM是十位【9:0】,而相位累加器是【15:0】,那么取点时相位累加器应该取高10位来ROM中取幅度,即【15:6】,这样子输出的波形的周期会随着频率控制字(即取点步长)的大小而改变。如果频率比较小(如2),那么取ROM中一个点要停留很多个系统时钟周期,且ROM中每个点都会被取到,输出的波形周期就长,如果频率比较大(如128),那么取ROM中一个点只停留一个系统时钟周期,且会跳过ROM中的某些点,输出的波形周期就短。

验证结果:

第一行:按键控制频率

第二行:按键控制波形

代码:

module DDS_advanced(
clk,
reset,
f_change_A,
f_change_B,
p_change_A,
p_change_B,
wave_change_A,
wave_change_B,
dout_A,
dout_B
);
input clk ;
input reset ;
input f_change_A ;
input f_change_B ;
input p_change_A ;
input p_change_B ;
input wave_change_A ;
input wave_change_B ;
output wire[9:0]dout_A ;
output wire[9:0]dout_B ; reg [1:0]f_cnt_A ;//设置A通道的频率选择按钮的消抖,计数
wire tx_fA ;
wire f_change_A_sign ;
buttopn_debounde
#(
.delay(1000)
)
buttopn_debounde_fA (//消抖,取释放符号为+1信号
.clk(clk),
.tx(f_change_A),
.reset(reset),
.bd_tx(tx_fA),
.release_sign(f_change_A_sign)
);
always@(posedge clk or negedge reset)//计数
if (!reset)
f_cnt_A <= 2'd0 ;
else if(f_change_A_sign)
f_cnt_A <= f_cnt_A + 1'd1 ;
else
f_cnt_A <= f_cnt_A ; reg [1:0]p_cnt_A ;//设置A通道的相位选择按钮的消抖,计数
wire tx_pA ;
wire p_change_A_sign ;
buttopn_debounde
#(
.delay(1000)
)
buttopn_debounde_pA (//消抖,取释放符号为+1信号
.clk(clk),
.tx(p_change_A),
.reset(reset),
.bd_tx(tx_pA),
.release_sign(p_change_A_sign)
);
always@(posedge clk or negedge reset)//计数
if (!reset)
p_cnt_A <= 2'd0 ;
else if(p_change_A_sign)
p_cnt_A <= p_cnt_A + 1'd1 ;
else
p_cnt_A <= p_cnt_A ; reg [1:0]wave_change_cnt_A ;//设置A通道的波形选择按钮的消抖,计数
wire tx_wavea ;
wire wave_change_A_debounde_sign ;
buttopn_debounde
#(
.delay(1000)
)
buttopn_debounde_waveA (//消抖,取释放符号为+1信号
.clk(clk),
.tx(wave_change_A),
.reset(reset),
.bd_tx(tx_wavea),
.release_sign(wave_change_A_debounde_sign)
);
always@(posedge clk or negedge reset)//计数
if (!reset)
wave_change_cnt_A <= 2'd0 ;
else if(wave_change_A_debounde_sign)
wave_change_cnt_A <= wave_change_cnt_A + 1'd1 ;
else
wave_change_cnt_A <= wave_change_cnt_A ; reg [1:0]f_cnt_B ;//设置B通道的频率选择按钮的消抖,计数
wire tx_fB ;
wire f_change_B_sign ;
buttopn_debounde
#(
.delay(1000)
)
buttopn_debounde_fB (//消抖,取释放符号为+1信号
.clk(clk),
.tx(f_change_B),
.reset(reset),
.bd_tx(tx_fB),
.release_sign(f_change_B_sign)
);
always@(posedge clk or negedge reset)//计数
if (!reset)
f_cnt_B <= 2'd0 ;
else if(f_change_B_sign)
f_cnt_B <= f_cnt_B + 1'd1 ;
else
f_cnt_B <= f_cnt_B ; reg [1:0]p_cnt_B ;//设置B通道的相位选择按钮的消抖,计数
wire tx_pB ;
wire p_change_B_sign ;
buttopn_debounde
#(
.delay(1000)
)
buttopn_debounde_pB (//消抖,取释放符号为+1信号
.clk(clk),
.tx(p_change_B),
.reset(reset),
.bd_tx(tx_pB),
.release_sign(p_change_B_sign)
);
always@(posedge clk or negedge reset)//计数
if (!reset)
p_cnt_B <= 2'd0 ;
else if(p_change_B_sign)
p_cnt_B <= p_cnt_B + 1'd1 ;
else
p_cnt_B <= p_cnt_B ; reg [1:0]wave_change_cnt_B ;//设置B通道的波形选择按钮的消抖,计数
wire tx_waveb ;
wire wave_change_B_debounde_sign ;
buttopn_debounde
#(
.delay(1000)
)
buttopn_debounde_waveB (//消抖,取释放符号为+1信号
.clk(clk),
.tx(wave_change_B),
.reset(reset),
.bd_tx(tx_waveb),
.release_sign(wave_change_B_debounde_sign)
);
always@(posedge clk or negedge reset)//计数
if (!reset)
wave_change_cnt_B <= 2'd0 ;
else if(wave_change_B_debounde_sign)
wave_change_cnt_B <= wave_change_cnt_B + 1'd1 ;
else
wave_change_cnt_B <= wave_change_cnt_B ; DDS_Module channel_A(//A通道连线
.clk(clk) ,
.reset(reset) ,
.f_ctrl(f_cnt_A) ,
.p_ctrl(p_cnt_A) ,
.wave_ctrl(wave_change_cnt_A) ,
.dout(dout_A)
); DDS_Module channel_B(//B通道连线
.clk(clk) ,
.reset(reset) ,
.f_ctrl(f_cnt_B) ,
.p_ctrl(p_cnt_B) ,
.wave_ctrl(wave_change_cnt_B) ,
.dout(dout_B)
); endmodule
module DDS_Module(
clk ,
reset ,
f_ctrl ,
p_ctrl ,
wave_ctrl ,
dout
);
input clk ;
input reset ;
input [1:0]wave_ctrl ;
input [1:0]f_ctrl ;//(频率选择按钮)
input [1:0]p_ctrl ;
output reg [9:0]dout ; reg [4:0]frequen;
always@(*)
case(f_ctrl)
0:frequen = 5'd2 ;//输出周期:(65536/2 )* 20ns = 655360ns
1:frequen = 5'd4 ;//输出周期:(2^16/4 )* 20ns = 327680ns
2:frequen = 5'd8 ;//输出周期:(2^16/8 )* 20ns = 163840ns
3:frequen = 5'd16 ;//输出周期:(2^16/4 )* 20ns = 81920ns
endcase //频率控制字寄存器(频率)(大于1的时候,后面相位累加器输出到实时相位时要砍掉它的位宽)
reg [4:0]f_regist ;//(取值限制为2的倍数)
always @ (posedge clk)
f_regist <= frequen ; //相位累加器 (f * t)
reg [15:0]p_add ;
always@(posedge clk or negedge reset )
if(!reset )
p_add <= 0 ;
else
p_add <= p_add + f_regist ; reg [9:0]phase_cv;
always@(*)
case(p_ctrl)
0:phase_cv = 10'd128 ;//45°
1:phase_cv = 10'd256 ;//90°
2:phase_cv = 10'd512 ;//135°
3:phase_cv = 10'd640 ;//180°
endcase
//相位控制字寄存器(初始相位)(相位偏移量)
reg [9:0]p_regist ;
always @ (posedge clk)
p_regist <= phase_cv ; //实时相位
reg [9:0]p_now ;
always@(posedge clk or negedge reset )
if(!reset )
p_now <= 0 ;
else
p_now <= p_add[15:6] + p_regist ; //取相位累加器的前10位 wire [9:0]wave_sin ;
wire [9:0]wave_square ;
wire [9:0]wave_triangular;
wire [9:0]wave_sawtooth;
always@(*)//波形选择
case(wave_ctrl)
0: dout = wave_sin ;
1: dout = wave_triangular ;
2: dout = wave_square ;
3: dout = wave_sawtooth ;
endcase rom_sin rom_sin(//正弦波
.clka(clk),
.addra(p_now),
.douta(wave_sin)
); rom_triangular rom_triangular(//三角波
.clka(clk),
.addra(p_now),
.douta(wave_triangular)
); rom_square rom_square(//方波
.clka(clk),
.addra(p_now),
.douta(wave_square)
); rom_sawtooth rom_sawtooth(//锯齿波
.clka(clk),
.addra(p_now),
.douta(wave_sawtooth)
); endmodule
module buttopn_debounde(
clk,
tx,
reset,
bd_tx,
release_sign
);
input tx ;
input clk ;
input reset ;
output reg bd_tx ;
output reg release_sign ;//按下释放信号 reg [1:0]edge_detect_regist;
always@(posedge clk or negedge reset)//输入信号的移位寄存器
begin
if (!reset)
edge_detect_regist <= 2'd0 ;
else
begin
edge_detect_regist[0] <= tx ;
edge_detect_regist[1] <= edge_detect_regist[0] ;
//等效于 edge_detect_regist <={ edge_detect_regist[0] , tx }
end
end wire neg_edge , pos_edge ;
assign neg_edge = ( edge_detect_regist == 2'b10 ) ? 1 : 0 ;//下降沿
assign pos_edge = ( edge_detect_regist == 2'b01 ) ? 1 : 0 ;//上升沿 parameter delay = 20000000 / 20 ;//抖动20ms reg [3:0]state ;
reg [19:0]counter1 ;
always@(posedge clk or negedge reset)
begin
if (!reset)
state <= 4'd0 ;//空闲态
else if ( ( neg_edge ) && ( state == 4'd0 ) )
state <= 4'd1 ;//按下消抖态
else if ( ( state == 4'd1 ) && (( delay - 1) > counter1 ) && ( pos_edge ) )
state <= 4'd0 ;//空闲态
else if ( ( state == 4'd1 ) && (( delay - 1) <= counter1 ) )
state <= 4'd2 ;//按下态
else if ( ( pos_edge ) && ( state == 4'd2 ) )
state <= 4'd3 ;//释放消抖态
else if ( ( state == 4'd3 ) && (( delay - 1) > counter1 ) && ( neg_edge ) )
state <= 4'd2 ;//按下态
else if ( ( state == 4'd3 ) && (( delay - 1) <= counter1 ) )
state <= 4'd0 ;//空闲态
end always@(posedge clk or negedge reset)
begin
if (!reset)
counter1 <= 5'd0 ;
else if ( ( neg_edge ) || ( pos_edge ) )
counter1 <= 5'd0 ;
else if ( ( state == 4'd1 ) && (! neg_edge ) && (! pos_edge ) )
counter1 <= counter1 + 1'd1 ;
else if ( ( state == 4'd3 ) && (! neg_edge ) && (! pos_edge ) )
counter1 <= counter1 + 1'd1 ;
end always@(posedge clk or negedge reset)
begin
if (!reset)
bd_tx <= 1'd1 ;//空闲态
else
case(state)
0:bd_tx <= 1'd1 ;
1:bd_tx <= 1'd1 ;
2:bd_tx <= 1'd0 ;
3:bd_tx <= 1'd0 ;
endcase
end reg pre_sign ;
always@(posedge clk or negedge reset)
begin
if (!reset)
pre_sign <= 1'd1 ;//空闲态
else if( ( state == 4'd1 ) && (( delay - 1) <= counter1 ) )
pre_sign <= 1'd0 ;
else if ( state == 4'd2 )
pre_sign <= 1'd1 ;
end always@(posedge clk or negedge reset)
begin
if (!reset)
release_sign <= 1'd0 ;//空闲态
else if( ( state == 4'd3 ) && (( delay - 1) <= counter1 ) )
release_sign <= 1'd1 ;
else if ( state == 4'd0 )
release_sign <= 1'd0 ;
end endmodule
`timescale 1ns / 1ps
module DDS_advanced_tb(
);
reg clk ;
reg reset ;
reg f_change_A ;
reg f_change_B ;
reg p_change_A ;
reg p_change_B ;
reg wave_change_A ;
reg wave_change_B ;
wire [9:0]dout_A ;
wire [9:0]dout_B ;
DDS_advanced DDS_advanced_sim(
clk,
reset,
f_change_A,
f_change_B,
p_change_A,
p_change_B,
wave_change_A,
wave_change_B,
dout_A,
dout_B
); initial clk = 1 ;
always #10 clk = ! clk ;
initial
begin
reset = 0 ;
f_change_A = 1 ;
f_change_B = 1 ;
p_change_A = 1 ;
p_change_B = 1 ;
wave_change_A = 1 ;
wave_change_B = 1 ;
#201 ;
reset = 1 ;
#90000 ; wave_change_A = 0 ;
#910000 ; wave_change_A = 1 ;
f_change_B = 0 ;
#910000 ; f_change_B = 1 ;
wave_change_A = 0 ;
#910000 ; wave_change_A = 1 ;
f_change_B = 0 ;
#910000 ; f_change_B = 1 ;
wave_change_A = 0 ;
#910000 ; f_change_B = 0 ;
wave_change_A = 1 ;
#910000 ; f_change_B = 1 ;
wave_change_A = 0 ;
#910000 ; f_change_B = 0 ;
wave_change_A = 1 ;
#910000 ; f_change_B = 1 ;
#910000 ;//验证波形和频率控制 reset = 0 ;//验证相位控制
#201 ;
reset = 1 ;
p_change_B = 0 ;
f_change_A = 0 ;
f_change_B = 0 ;
#200
f_change_A = 1 ;
f_change_B = 1 ;
#910000 ;
p_change_B = 1 ;
#910000 ; p_change_B = 0 ;
#910000 ;
p_change_B = 1 ;
#910000 ; p_change_B = 0 ;
#910000 ;
p_change_B = 1 ;
#910000 ; p_change_B = 0 ;
#910000 ;
p_change_B = 1 ;
#910000 ; $stop;
end
endmodule

 

  

DDS信号发生器加强版(双通道,发送波形的频率可控,相位可控,种类可控)的更多相关文章

  1. (DDS)正弦波形发生器——幅值、频率、相位可调(二)

    (DDS)正弦波形发生器--幅值.频率.相位可调(二) 主要关于调相方面 一.项目任务: 设计一个幅值.频率.相位均可调的正弦波发生器. 频率每次增加10kHz 相位每次增加 PI/2 幅值每次增加两 ...

  2. (DDS)正弦波形发生器——幅值、频率、相位可调(一)

    (DDS)正弦波形发生器--幅值.频率.相位可调 一.项目任务: 设计一个幅值.频率.相位均可调的正弦波发生器. 频率每次增加1kHz. 相位每次增加 2*PI/256 幅值每次增加两倍 二.文章内容 ...

  3. 【小梅哥FPGA进阶教程】第十一章 四通道幅频相可调DDS信号发生器

    十一.四通道幅频相可调DDS信号发生器 本文由山东大学研友袁卓贡献,特此感谢 实验目标 实现多通道可调信号发生器 实验平台 芯航线FPGA核心板.ADDA模块 实验现象 实现基于FPGA的多通道可调信 ...

  4. 基于小脚丫DDS 调频 调幅 调相 切换波形 AD5601输出模拟波形

    先讲讲里面的矩阵键盘,矩阵键盘列有下拉电阻,默认全为0000,默认行输入为1111,当有按键按下的时候,列输入会被拉高,这时控制行的输出做行扫描,电子琴用key_flag_r0电平作为使能,这里用ke ...

  5. 基于DDS的任意波形发生器

    实验原理 DDS的原理 DDS(Direct Digital Frequency Synthesizer)直接数字频率合成器,也可叫DDFS. DDS是从相位的概念直接合成所需波形的一种频率合成技术. ...

  6. 基于FPGA的DDS任意波形发生器设计

    一.简介       DDS技术最初是作为频率合成技术提出的,由于其易于控制,相位连续,输出频率稳定度高,分辨率高, 频率转换速度快等优点,现在被广泛应用于任意波形发生器(AWG).基于DDS技术的任 ...

  7. H5录音音频可视化-实时波形频谱绘制、频率直方图

    这段时间给GitHub Recorder开源库添加了两个新的音频可视化功能,比以前单一的动态波形显示丰富了好多(下图后两行是不是比第一行看起来丰满些):趁热打铁写了一个音频可视化相关扩展测试代码,下面 ...

  8. 电赛总结(四)——波形发生芯片总结之AD9854

    一.特性参数 ·300M内部时钟频率 ·可进行频移键控(FSK),二元相移键控(BPSK),相移键控(PSK),脉冲调频(CHIRP),振幅调制(AM)操作 ·正交的双通道12位D/A转换器 ·超高速 ...

  9. 数字信号处理专题(1)——DDS函数发生器环路Demo

    一.前言 会FPGA硬件描述语言.设计思想和接口协议,掌握些基本的算法是非常重要的,因此开设本专题探讨些基于AD DA数字信号处理系统的一些简单算法,在数字通信 信号分析与检测等领域都会或多或少有应用 ...

随机推荐

  1. 1.8 常见Linux发行版本有哪些?

    新手往往会被 Linux 众多的发行版本搞得一头雾水,我们首先来解释一下这个问题. 从技术上来说,李纳斯•托瓦兹开发的 Linux 只是一个内核.内核指的是一个提供设备驱动.文件系统.进程管理.网络通 ...

  2. 一文了解RPC框架原理

    点击上方"开源Linux",选择"设为星标" 回复"学习"获取独家整理的学习资料! 1.RPC框架的概念 RPC(Remote Proced ...

  3. 【Pandas vs SQL】数据分析代码逐行比对,孰优孰劣?

    在数据分析领域,pandas是python数据分析基础工具,SQL是数据库最常用分析语言.二者有相通的地方,也有很大的语法不同,做起数据分析来,谁将更胜一筹呢? 做过业务开发.跟数据库打交道比较多的小 ...

  4. .NET性能优化-为结构体数组使用StructLinq

    前言 本系列的主要目的是告诉大家在遇到性能问题时,有哪些方案可以去优化:并不是要求大家一开始就使用这些方案来提升性能. 在之前几篇文章中,有很多网友就有一些非此即彼的观念,在实际中,处处都是开发效率和 ...

  5. PHP反序列化链分析

    前言 基本的魔术方法和反序列化漏洞原理这里就不展开了. 给出一些魔术方法的触发条件: __construct()当一个对象创建(new)时被调用,但在unserialize()时是不会自动调用的 __ ...

  6. MongoDB 常用启动参数

    每日一句 Once you choose your way of life, be brave to stick it out and never return. 生活的道路一旦选定,就要勇敢地走到底 ...

  7. Pandas复杂查询、数据类型转换、数据排序

    Pandas高级操作 1.复杂查询 (1)逻辑运算 以DataFrame其中一列进行逻辑计算,会产生一个对应的bool值组成的Series 于是我们可以利用返回的bool列表进行一系列的数据查询 (2 ...

  8. React简单教程-3-样式

    前言 在上一章 React 简单教程-2-ts 和组件参数 中我们新建的子组件 Displayer 没有样式,显得平平无奇,这一篇我们将给他美化一下. CSS 文件 一般的做法,是在你的组件级目录下新 ...

  9. QT 基于QScrollArea的界面嵌套移动

    在实际的应用场景中,经常会出现软件界面战场图大于实际窗体大小,利用QScrollArea可以为widget窗体添加滚动条,可以实现小窗体利用滚动条显示大界面需求.实现如下: QT创建一个qWidget ...

  10. Linux系列之安装JDK

    卸载open jdk #查看jdk [root@localhost tools]# rpm -qa | grep jdk java-1.8.0-openjdk-headless-1.8.0.65-3. ...