基于FPGA的任意波形DDS发生器
说明:
1.采用XINLNUX平台,使用rom加载coe文件,产生波形,
2.频率调节使用的是加载读取ROM速度的不同产生频率变换。
3.对于调节频率的加减,写入按键值进去控制读取ROM地址加载的速度就可以。或者改变输入的全局时钟的频率,对应的输出频率也会改变的。
4.对于输出的8为数据。后面加上DAC就可以下载程序上板子测试啦。
一、测试如图:
频率计算:一个周期:5470ns-4730ns=740ns=1.351Mhz(这个是最低的)
后面的第三个频率可以达到5.5MHZ
同样的也可以先把全局时钟倍频到100MHZ,200hz,或者跟高的频率,那么输出的dds的频率将会更高。
二、步骤
1.生成COE文件:用于配置dds,保存到工程下,待会要用
打开vivado,IP核里面找到
2…配置ROM:
选择位宽为8位,深度256,也可以选择其他的,需要和你的COE文件格式匹配就行。
这里找到第一步生成的文件加载进去。
然后撸代码:(加的有按键消抖的程序,仿真但是没有用到)
主程序:
module top_dds #(
parameter INPUT_WIDTH = 3,
parameter OUTPUT_WIDTH = 8
)(
input wire sys_clk,
input sys_rst_n,
input [INPUT_WIDTH - 1 : 0] key,
output [OUTPUT_WIDTH - 1 : 0] dds_sin,
output [15: 0] dds_sin2 ,
output [OUTPUT_WIDTH - 1 : 0] fangbo,
output [OUTPUT_WIDTH - 1 : 0] sanjiao,
output [OUTPUT_WIDTH - 1 : 0] juci
);
wire [2:0] key_value;
wire ena;
reg [7:0]cnt;
reg [15:0]cnt2;
assign ena = 1;
key_debounce u_key_debounce1(
.sys_clk (sys_clk ), //外部50M时钟
.sys_rst_n (sys_rst_n ), //外部复位信号,低有效
.key (key[0] ), //外部按键输入
.key_flag ( ), //按键数据有效信号
.key_value (key_value[0]) //按键消抖后的数据
);
key_debounce u_key_debounce2(
.sys_clk (sys_clk ), //外部50M时钟
.sys_rst_n (sys_rst_n ), //外部复位信号,低有效
.key (key[1] ), //外部按键输入
.key_flag ( ), //按键数据有效信号
.key_value (key_value[1]) //按键消抖后的数据
);
key_debounce u_key_debounce3(
.sys_clk (sys_clk ), //外部50M时钟
.sys_rst_n (sys_rst_n ), //外部复位信号,低有效
.key (key[2] ), //外部按键输入
.key_flag ( ), //按键数据有效信号
.key_value (key_value[2] ) //按键消抖后的数据
);
//dds IP 核:rom
//正弦波COE文件位宽8,深度256
sin u_sin (
.clka(sys_clk), // input wire clka
.ena(ena), // input wire ena
.addra(cnt), // input wire [7 : 0] addra
.douta(dds_sin) // output wire [7 : 0] douta
);
//正弦波这个采用的COE文件不一样,位宽16,深度256
sin2 u_sin2 (
.clka(sys_clk), // input wire clka
.ena(ena), // input wire ena
.addra(cnt2), // input wire [7 : 0] addra
.douta(dds_sin2) // output wire [7 : 0] douta
);
//方波COE文件位宽8,深度256
dds_fangbo u_dds_fangbo (
.clka(sys_clk), // input wire clka
.ena(ena), // input wire ena
.addra(cnt), // input wire [7 : 0] addra
.douta(fangbo) // output wire [7 : 0] douta
);
//三角波COE文件位宽8,深度256
dds_sanjiao u_dds_sanjiao (
.clka(sys_clk), // input wire clka
.ena(ena), // input wire ena
.addra(cnt), // input wire [7 : 0] addra
.douta(sanjiao) // output wire [7 : 0] douta
);
//锯齿波COE文件位宽8,深度256
dds_juci u_dds_juci (
.clka(sys_clk), // input wire clka
.ena(ena), // input wire ena
.addra(cnt), // input wire [7 : 0] addra
.douta(juci) // output wire [7 : 0] douta
);
/*按键值寄存*/
/*reg [2:0]key_integer;
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
key_integer <= 0;
else if(key_value[0] == 0)
key_integer <= key_integer+ 1'b1;
else
key_integer <= key_integer;
end
reg [2:0]key_integer1;
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
key_integer1 <= 0;
else if(key_value[1] == 0)
key_integer1 <= key_integer1+ 1'b1;
else
key_integer1 <= key_integer1;
end
reg [2:0]key_integer2;
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
key_integer2 <= 0;
else if(key_value[2] == 0)
key_integer2 <= key_integer2+ 1'b1;
else
key_integer2 <= key_integer2;
end
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
cnt <= 8'd0;
else if(key_integer == 1'b1 &&(cnt <=100 ))
cnt <= cnt+1'b1;
else
cnt <= 0;
end
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
cnt <= 8'd0;
else if(key_integer1 == 0 &&(cnt <=250 ))
cnt <= cnt+1'b1;
else
cnt <= 0;
end
*/
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
cnt <= 8'd0;
else if(key[0] == 0 &&(cnt <250 ))
cnt <= cnt+3'd7;
else if(key[1] == 0 &&(cnt <250 ))
cnt <= cnt+4'd15;
else if(key[2] == 0 &&(cnt <250 ))
cnt <= cnt+5'd31;
else
cnt <= 0;
end
//步进不一样
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
cnt2 <= 16'd0;
else if(key[0] == 0 &&(cnt2 <65536 ))
cnt2 <= cnt2+'d4;//这个已经达到1G了。后口的更大
else if(key[1] == 0 &&(cnt2 <65536 ))
cnt2 <= cnt2+'d15;
else if(key[2] == 0 &&(cnt2 <65536 ))
cnt2 <= cnt2+'d25;
else
cnt2 <= 0;
end
endmodule
加的原子哥的按键消抖,仿真没有用到
//----------------------------------------------------------------------------------------
// File name: key_debounce
module key_debounce(
input sys_clk, //外部50M时钟
input sys_rst_n, //外部复位信号,低有效
input key, //外部按键输入
output reg key_flag, //按键数据有效信号
output reg key_value //按键消抖后的数据
);
//reg define
reg [31:0] delay_cnt;
reg key_reg;
//*****************************************************
//** main code
//*****************************************************
always @(posedge sys_clk or negedge sys_rst_n) begin
if (!sys_rst_n) begin
key_reg <= 1'b1;
delay_cnt <= 32'd0;
end
else begin
key_reg <= key;
if(key_reg != key) //一旦检测到按键状态发生变化(有按键被按下或释放)
delay_cnt <= 32'd1000000; //给延时计数器重新装载初始值(计数时间为20ms)
else if(key_reg == key) begin //在按键状态稳定时,计数器递减,开始20ms倒计时
if(delay_cnt > 32'd0)
delay_cnt <= delay_cnt - 1'b1;
else
delay_cnt <= delay_cnt;
end
end
end
always @(posedge sys_clk or negedge sys_rst_n) begin
if (!sys_rst_n) begin
key_flag <= 1'b0;
key_value <= 1'b1;
end
else begin
if(delay_cnt == 32'd1) begin //当计数器递减到1时,说明按键稳定状态维持了20ms
key_flag <= 1'b1; //此时消抖过程结束,给出一个时钟周期的标志信号
key_value <= key; //并寄存此时按键的值
end
else begin
key_flag <= 1'b0;
key_value <= key_value;
end
end
end
endmodule
仿真激励文件:
module top_dds_tb();
reg sys_clk;
reg sys_rst_n;
reg [2:0] key;
wire [7:0] dds_sin;
wire [15:0] dds_sin2;
wire [7:0] fangbo ;
wire [7:0] sanjiao;
wire [7:0] juci;
reg [3:0]cnt_key;
top_dds u_top_dds(
.sys_clk (sys_clk),
.sys_rst_n (sys_rst_n),
.key (key),
.dds_sin (dds_sin),
.dds_sin2 (dds_sin2),
.fangbo (fangbo),
.sanjiao (sanjiao),
.juci (juci)
);
initial begin
#5 sys_clk=0;
sys_rst_n=0;
#10
sys_rst_n = 1;
key <= 3'b111;
#200
key <= 3'b110;
#10000
key <= 3'b101;
#10000
key <= 3'b011;
end
always #10 sys_clk =~sys_clk;
/*always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
begin
key <= 3'b111;
cnt_key <=0;
end
else if(cnt_key == 4'd10000)
key <= 3'b010;
else if (cnt_key == 4'd20000) begin
key <= 3'b001;
end
else if(cnt_key == )
else
cnt_key <= cnt_key + 1'b1;
end*/
endmodule