DDS信号发生器加强版(双通道,发送波形的频率可控,相位可控,种类可控)
目的:设计一个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信号发生器加强版(双通道,发送波形的频率可控,相位可控,种类可控)的更多相关文章
- (DDS)正弦波形发生器——幅值、频率、相位可调(二)
(DDS)正弦波形发生器--幅值.频率.相位可调(二) 主要关于调相方面 一.项目任务: 设计一个幅值.频率.相位均可调的正弦波发生器. 频率每次增加10kHz 相位每次增加 PI/2 幅值每次增加两 ...
- (DDS)正弦波形发生器——幅值、频率、相位可调(一)
(DDS)正弦波形发生器--幅值.频率.相位可调 一.项目任务: 设计一个幅值.频率.相位均可调的正弦波发生器. 频率每次增加1kHz. 相位每次增加 2*PI/256 幅值每次增加两倍 二.文章内容 ...
- 【小梅哥FPGA进阶教程】第十一章 四通道幅频相可调DDS信号发生器
十一.四通道幅频相可调DDS信号发生器 本文由山东大学研友袁卓贡献,特此感谢 实验目标 实现多通道可调信号发生器 实验平台 芯航线FPGA核心板.ADDA模块 实验现象 实现基于FPGA的多通道可调信 ...
- 基于小脚丫DDS 调频 调幅 调相 切换波形 AD5601输出模拟波形
先讲讲里面的矩阵键盘,矩阵键盘列有下拉电阻,默认全为0000,默认行输入为1111,当有按键按下的时候,列输入会被拉高,这时控制行的输出做行扫描,电子琴用key_flag_r0电平作为使能,这里用ke ...
- 基于DDS的任意波形发生器
实验原理 DDS的原理 DDS(Direct Digital Frequency Synthesizer)直接数字频率合成器,也可叫DDFS. DDS是从相位的概念直接合成所需波形的一种频率合成技术. ...
- 基于FPGA的DDS任意波形发生器设计
一.简介 DDS技术最初是作为频率合成技术提出的,由于其易于控制,相位连续,输出频率稳定度高,分辨率高, 频率转换速度快等优点,现在被广泛应用于任意波形发生器(AWG).基于DDS技术的任 ...
- H5录音音频可视化-实时波形频谱绘制、频率直方图
这段时间给GitHub Recorder开源库添加了两个新的音频可视化功能,比以前单一的动态波形显示丰富了好多(下图后两行是不是比第一行看起来丰满些):趁热打铁写了一个音频可视化相关扩展测试代码,下面 ...
- 电赛总结(四)——波形发生芯片总结之AD9854
一.特性参数 ·300M内部时钟频率 ·可进行频移键控(FSK),二元相移键控(BPSK),相移键控(PSK),脉冲调频(CHIRP),振幅调制(AM)操作 ·正交的双通道12位D/A转换器 ·超高速 ...
- 数字信号处理专题(1)——DDS函数发生器环路Demo
一.前言 会FPGA硬件描述语言.设计思想和接口协议,掌握些基本的算法是非常重要的,因此开设本专题探讨些基于AD DA数字信号处理系统的一些简单算法,在数字通信 信号分析与检测等领域都会或多或少有应用 ...
随机推荐
- cookie、sessionStorage、localStorage的区别?
数据存储位置 三者都是存储在游览器本地的 区别在于cookie是服务器端写入的,而sessionStorage.localStorage是由前端写入的 生命周期 cookie的生命周期是由服务器端写入 ...
- 实战|Linux大文件切割
一个执着于技术的公众号 日常工作中需要对日志文件进行分析,当日志文件过大时,Linux中使用vim.cat.grep.awk等这些工具对大文件日志进行分析将会成为梦魇,具体表现在: 执行速度缓慢,文件 ...
- 关于div及display
1.DIV div被看作是一个盒子,可以设置width.height.这个盒子其实是由三部分构成width(height).padding.border.在默认情况下,所见到的div是border和p ...
- 新作!分布式系统韧性架构压舱石OpenChaos
摘要:本文首先以现今分布式系统的复杂性和稳定性的需求引出混沌工程概念,并阐述了OpenChaos在传统混沌工程上的优化与创新. 背景 随着Serverless,微服务(含服务网格)与越来越多的容器化架 ...
- RabbitMQ从概念到使用、从Docker安装到RabbitMQ整合Springboot【1.5w字保姆级教学】
@ 目录 一.前言 二.RabbitMQ作用 1. 异步处理 2. 应用解耦 3. 流量控制 三.RabbitMQ概念 1. RabbitMQ简介 2. 核心概念 四.JMS与AMQP比较 五.Rab ...
- [java并发编程]基于信号量semaphore实现限流器
目录 一.什么是信号量 二.信号量类Semaphore 三.实现限流器 欢迎关注我的博客,更多精品知识合集 一.什么是信号量 "信号量"在编程术语中使用单词semaphore,那什 ...
- 好客租房40-react组件基础综合案例-案例需求分析
实现 案例的数据 渲染评论列表 有评论 没有评论 暂无评论 获取评论信息 包括评论人和受控组件 发表评论 更新评论 //导入react import React from 'react' import ...
- Zookeeper安装学习(二)
学习内容:Zookeeper集群安装(Zookeeper版本:Zookeeper3.5.7:注:master,s1,s2都需要部署) 解压安装: (1)在主机 master 解压 Zookeeper ...
- javaweb开发案例
1.实验3 (1)当运行Servlet时,碰到"空指针异常"错误怎么处理? 答:应提示用户操作有误,或设置对象值为空字符串或一个默认值,或是不执行某操作,直接跳转到其他处理中. ( ...
- vision transformer
VIT 总览 Step1 Step2