之前的博客讲到了DDS的基本原理,现在用Verilog代码实现DDS,能够产生四种波形,方波,三角波,正弦波,锯齿波,用按键来控制频率和选择波形。其中按键消抖模块来自小梅哥的FPGA自学笔记设计与验证这本书,产生波形的数据可以借助matlab或者mif小精灵这个软件来生成,将产生的数据存储到ROM中,按照一定的地址读出ROM中的数据,将读出的数据按照一定的时序送给DAC,不同的DAC时序不一样,可参照相关的数据手册。
module DDS_Module(
Clk,
Rst_n,
EN,
Fword,
Key1,
Pword,
DA_Clk,
DA_Data
);
input Clk;/*系统时钟*/
input Rst_n;/*系统复位*/
input EN;/*DDS模块使能*/
input Key1;
input [31:0]Fword;/*频率控制字*/
input [11:0]Pword;/*相位控制字*/
output DA_Clk;/*DA数据输出时钟*/
output reg [13:0]DA_Data;/*D输出输出A*/
reg [31:0]Fre_acc;
reg [13:0]Rom_Addr;
reg [1:0] wave_sel;
wire [13:0]DA_Data1;
wire [13:0]DA_Data2;
wire [13:0]DA_Data3;
wire [13:0]DA_Data4;
wire key_flag,key_state;
key_filter key_filter1(
.Clk(Clk),
.Rst_n(Rst_n),
.key_in(Key1),
.key_flag(key_flag),
.key_state(key_state)
);
always@(posedge Clk or negedge Rst_n)
if(!Rst_n)
wave_sel <= 2'b0;
else if(key_flag && (!key_state))
wave_sel <= wave_sel + 1'b1;
else
wave_sel <= wave_sel;
always@(*)begin
case(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
end
/*---------------相位累加器------------------*/
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 <= 14'd0;
else if(!EN)
Rom_Addr <= 14'd0;
else
Rom_Addr <= Fre_acc[31:18] + Pword;
/*----------例化查找表ROM-------*/
ddsrom ddsrom(
.address(Rom_Addr),
.clock(Clk),
.q(DA_Data1)
);
fangbo fangbo(
.address(Rom_Addr),
.clock(Clk),
.q(DA_Data2)
);
/*
sanjian sanjiao(
.address(Rom_Addr),
.clock(Clk),
.q(DA_Data3)
);
*/
/*
juchi juchi(
.address(Rom_Addr),
.clock(Clk),
.q(DA_Data4)
);
*/
/*----------输出DA时钟----------*/
assign DA_Clk = (EN)?Clk:1'b1;
endmodule
//按键消抖模块
module key_filter(
Clk, //50M时钟输入
Rst_n, //模块复位
key_in, //按键输入
key_flag, //按键标志信号
key_state //按键状态信号
);
input Clk;
input Rst_n;
input key_in;
output reg key_flag;
output reg key_state;
localparam
IDEL = 4'b0001,
FILTER0 = 4'b0010,
DOWN = 4'b0100,
FILTER1 = 4'b1000;
reg [3:0]state;
reg [19:0]cnt;
reg en_cnt; //使能计数寄存器
//对外部输入的异步信号进行同步处理
reg key_in_sa,key_in_sb;
always@(posedge Clk or negedge Rst_n)
if(!Rst_n)begin
key_in_sa <= 1'b0;
key_in_sb <= 1'b0;
end
else begin
key_in_sa <= key_in;
key_in_sb <= key_in_sa;
end
reg key_tmpa,key_tmpb;
wire pedge,nedge;
reg cnt_full;//计数满标志信号
//使用D触发器存储两个相邻时钟上升沿时外部输入信号(已经同步到系统时钟域中)的电平状态
always@(posedge Clk or negedge Rst_n)
if(!Rst_n)begin
key_tmpa <= 1'b0;
key_tmpb <= 1'b0;
end
else begin
key_tmpa <= key_in_sb;
key_tmpb <= key_tmpa;
end
//产生跳变沿信号
assign nedge = !key_tmpa & key_tmpb;
assign pedge = key_tmpa & (!key_tmpb);
always@(posedge Clk or negedge Rst_n)
if(!Rst_n)begin
en_cnt <= 1'b0;
state <= IDEL;
key_flag <= 1'b0;
key_state <= 1'b1;
end
else begin
case(state)
IDEL :
begin
key_flag <= 1'b0;
if(nedge)begin
state <= FILTER0;
en_cnt <= 1'b1;
end
else
state <= IDEL;
end
FILTER0:
if(cnt_full)begin
key_flag <= 1'b1;
key_state <= 1'b0;
en_cnt <= 1'b0;
state <= DOWN;
end
else if(pedge)begin
state <= IDEL;
en_cnt <= 1'b0;
end
else
state <= FILTER0;
DOWN:
begin
key_flag <= 1'b0;
if(pedge)begin
state <= FILTER1;
en_cnt <= 1'b1;
end
else
state <= DOWN;
end
FILTER1:
if(cnt_full)begin
key_flag <= 1'b1;
key_state <= 1'b1;
state <= IDEL;
en_cnt <= 1'b0;
end
else if(nedge)begin
en_cnt <= 1'b0;
state <= DOWN;
end
else
state <= FILTER1;
default:
begin
state <= IDEL;
en_cnt <= 1'b0;
key_flag <= 1'b0;
key_state <= 1'b1;
end
endcase
end
always@(posedge Clk or negedge Rst_n)
if(!Rst_n)
cnt <= 20'd0;
else if(en_cnt)
cnt <= cnt + 1'b1;
else
cnt <= 20'd0;
always@(posedge Clk or negedge Rst_n)
if(!Rst_n)
cnt_full <= 1'b0;
else if(cnt == 20'd999_999)
cnt_full <= 1'b1;
else
cnt_full <= 1'b0;
endmodule
//DDS顶层模块
module DDS_top(
input CLK50M,
input Rst_n,
input Key,
input Key1,
output [3:0]led,
output DACA_CLK,
output DACB_CLK,
output DACA_WRT,
output DACB_WRT,
output [13:0]DAC_DATA1,
output [13:0]DAC_DATA2
);
wire D_CLK;
assign DACA_CLK = D_CLK;
assign DACB_CLK = D_CLK;
assign DACA_WRT = D_CLK;
assign DACB_WRT = D_CLK;
assign DAC_DATA2 = DAC_DATA1;
pll pll(
.inclk0(CLK50M),
.c0(D_CLK)
);
wire [31:0]Fword;
wire [3:0]Fword_sel;
DDS_Module DDS_Module0(
.Clk(D_CLK),
.Rst_n(Rst_n),
.Key1(Key1),
.EN(1),
.Fword(Fword),
.Pword(0),
.DA_Clk(),
.DA_Data(DAC_DATA1)
);
Fword_Set Fword_Set(
.Clk(CLK50M),
.Rst_n(Rst_n),
.Key(Key),
.Fword(Fword),
.Fword_sel(Fword_sel)
);
assign led = ~Fword_sel;
endmodule
//频率设置模块
module Fword_Set(
Clk,
Rst_n,
Key,
Fword,
Fword_sel
);
input Clk;
input Rst_n;
input Key;
output reg[31:0]Fword;
output reg[3:0]Fword_sel;
wire key_flag, key_state;
key_filter key_filter0(
.Clk(Clk),
.Rst_n(Rst_n),
.key_in(Key),
.key_flag(key_flag),
.key_state(key_state)
);
always@(posedge Clk or negedge Rst_n)
if(!Rst_n)
Fword_sel <= 4'd0;
else if(key_flag && (!key_state))
Fword_sel <= Fword_sel + 1'b1;
else
Fword_sel <= Fword_sel;
always@(*)begin
case(Fword_sel)
0: Fword <= 344; //10Hz
1: Fword <= 1718; //50Hz
2: Fword <= 3436; //100Hz
3: Fword <= 17180; //500Hz
4: Fword <= 34360; //1KHz
5: Fword <= 171799; //5KHz
6: Fword <= 343597; //10KHz
7: Fword <= 1717987; //50KHz
8: Fword <= 3435974; //100KHz
9: Fword <= 17179869; //500KHz
10: Fword <= 34359738; //1MHz
11: Fword <= 68719477; //2MHz
12: Fword <= 103079215; //3MHz
13: Fword <= 137438953; //4MHz
14: Fword <= 171798692; //5MHz
15: Fword <= 343597384; //10MHz
endcase
end
endmodule