写在之前的话:这是刚结束的课设的实验报告,代码多有参考,希望可以帮到你。(源码在文末)
一、课设目的和要求
1.加深学生对课程所学知识的理解,训练学生提高工程应用能力、设计与调测能力,最终提高分析与解决问题的能力,了解先进的EDA芯片使用方法;
2.理解dds硬件模块电路工作原理;
3.掌握硬件描述语言设计方法;
4.掌握系统调试测量方法,实现输出信号并且频率可调,实现正弦波、三角波、方波等多种信号源输出;
5.运用EDA系统软硬件工具解决工程问题的能力;
二、课设主要软硬件环境
硬件:PC机。
软件:Windows系统平台,装有Quartus、Modelsim等软件编译环境。
三、内容(包括研究背景、研究现状、思路、不同实现方案比较等)
1.研究背景
信号发生器作为一种常用的信号源设备,在测试测量领域有着广泛的应用。其为测试电路提供频率和幅度可调的测试信号,常用于电子、通信产品测试过程中。传统的信号发生器采用模拟电路构成。这种信号发生器的电路十分复杂,功能和精度相对较低,且容易受外界干扰影响。近年来,随着数字电路技术的不断发展,基于直接数字频率合成(direct digital frequency synthesis, DDS)技术的信号发生器逐步产生。DDS技术改变了传统信号的产生方式,以数字量的形式生成模拟信号,利用微控制器进行控制,大大简化了电路结构,并具有较高的灵活性。由DDS芯片构成的信号发生器具有信号种类丰富、频率及幅度调节范围广、信号稳定度高等特点。
2.研究现状
信号发生器又称信号源或振荡器,在生产实践和科技领域中有着广泛的应用。各种波形曲线均可以用三角函数方程式来表示。能够产生多种波形,如三角波、锯齿波、矩形波(含方波)、正弦波的电路被称为函数信号发生器。函数信号发生器在电路实验和设备检测中具有十分广泛的用途。例如在通信、广播、电视系统中,都需要射频(高频)发射,这里的射频波就是载波,把音频(低频)、视频信号或脉冲信号运载出去,就需要能够产生高频的振荡器。在工业、农业、生物医学等领域内,如高频感应加热、熔炼、淬火、超声诊断、核磁共振成像等,都需要功率或大或小、频率或高或低的振荡器。DDS信号发生器采用直接数字频率合成 (Direct Digital Synthesis,简称DDS)技术,把信号发生器的频率稳定度、准确度提高到与基准频率相同的水平,并且可以在很宽的频率范围内进行精细的频率调节。采用这种方法设计的信号源可工作于调制状态,可对输出电平进行调节,也可输出各种波形。一个完整周期的函数波形被存储在上面所示的存储器查找表中。
3.不同实验方案比较
方案一:采用模拟锁相环实现
模拟锁相环技术是项比较成熟的技术。应用模拟锁相环,可将基准频率倍频,或分频得到所需的频率,且调节精度可以做到相当高、稳定性也比较好。但模拟锁相环模拟电路复杂,不易调节,成本较高,并且频率调节不便且调节范围小,输出波形的毛刺较多,得不到满意的效果。
方案二:基于FPGA的dds波形发生器
设计思路:
系统模块设计:
采用直接数字频率合成,用 FPGA 器件作为核心控制部件,精度高稳定性好,得到波形平滑,特别是FPGA的高速度,能实现较高频率的波形。控制上更方便,可得到较宽频率范围的波形输出,步进小,外围电路简单易实现。因此采用方案二。
四、源程序(原理图)与结果讨论
DDS全称为直接数字频率合成(Direct Digital Synthesis),其基本原理是在一个周期波形数据下,通过选取其中全部数据或抽样部分数据组成新的波形,由奈奎斯特采样定理可知,最低两个采样点就可以组成一个波形,但实际上最少需要4个点。其原理框图如下:
其主要由相位控制字、频率控制字、相位累加器、波形存储器几部分组成。
波形存储器:存储一个周期波形的离散信号;
频率控制字:用以控制生成的波形频率;
相位累加器:用来控制波形的相位累加,组成完整的波形显示;
相位控制字:用以控制波形起始位置。
实验代码:
1.DDS模块
module DDS(
input clk,
input rst_n,
input [25:0] f_word,
input [1:0] wave_c,
input [11:0] p_word,
input [4:0] amplitude,
output reg [11:0] dac_data
);
localparam DATA_WIDTH = 4'd12;
localparam ADDR_WIDTH = 4'd12;
reg [11:0] addr ;
wire [11:0] dac_data0;
wire [11:0] dac_data1;
wire [11:0] dac_data2;
wire [11:0] dac_data3;
//波形选择
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
dac_data <= 12'd0;
end
else begin
case(wave_c)
2'b00:dac_data <= dac_data0/amplitude; //正弦波
2'b01:dac_data <= dac_data1/amplitude; //三角波
2'b10:dac_data <= dac_data2/amplitude; //锯齿波
2'b11:dac_data <= dac_data3/amplitude; //方波
default:;
endcase
end
end
//相位累加器
reg [31:0] fre_acc;
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
fre_acc <= 0;
end
else begin
fre_acc <= fre_acc + f_word;
end
end
//生成查找表地址
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
addr <= 0;
end
else begin
addr <= fre_acc[31:20] + p_word;
end
end
//正弦波
sin_rom #(
.DATA_WIDTH(DATA_WIDTH),
.ADDR_WIDTH(ADDR_WIDTH)
) inst_sin_rom (
.addr (addr),
.clk (clk),
.q (dac_data0)
);
//三角波
sanjiao_rom #(
.DATA_WIDTH(DATA_WIDTH),
.ADDR_WIDTH(ADDR_WIDTH)
) inst_sanjiao_rom (
.addr (addr),
.clk (clk),
.q (dac_data1)
);
//锯齿波
juchi_rom #(
.DATA_WIDTH(DATA_WIDTH),
.ADDR_WIDTH(ADDR_WIDTH)
) inst_juchi_rom (
.addr (addr),
.clk (clk),
.q (dac_data2)
);
//方波
fangbo_rom #(
.DATA_WIDTH(DATA_WIDTH),
.ADDR_WIDTH(ADDR_WIDTH)
) inst_fangbo_rom (
.addr (addr),
.clk (clk),
.q (dac_data3)
);
endmodule
2.频率设置模块
module F_word_set(
input clk ,
input rst_n ,
input key1_in ,
output reg [25:0] f_word
);
wire key_flag ;
wire key_state ;
reg [3:0] cnt ;
key_filter fword_key (
.clk (clk),
.rst_n (rst_n),
.key_in (key1_in),
.key_flag (key_flag),
.key_state (key_state)
);
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
cnt <= 4'd0;
end
else if (key_flag) begin
if (cnt==4'd10) begin
cnt <= 4'd0;
end
else begin
cnt <= cnt + 1'b1;
end
end
end
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
f_word <= 0;
end
else begin
case(cnt) //x=(2^32)*20/T=(2^32)*20*f(hz)/1000000000
4'd0:f_word = 26'd86; //1Hz
4'd1:f_word = 26'd859; //10Hz
4'd2:f_word = 26'd8590; //100Hz
4'd3:f_word = 26'd42950; //500Hz
4'd4:f_word = 26'd85899; //1kHz
4'd5:f_word = 26'd429497; //5kHz
4'd6:f_word = 26'd858993; //10kHz
4'd7:f_word = 26'd4294967; //50kHz
4'd8:f_word = 26'd8589935; //100kHz
4'd9:f_word = 26'd17179869; //200kHz
4'd10:f_word = 26'd42949673;//500kHz
default:;
endcase
end
end
endmodule
3.按键模块
module key_filter(
input clk ,//系统时钟50MHz
input rst_n ,//系统复位
input key_in ,//按键输入
output reg key_flag ,//输出一个脉冲按键有效信号
output reg key_state //输出按键状态,1为未按下,0为按下
);
parameter IDLE = 4'b0001 ;//空闲状态,读取按键按下的下降沿,读取到下降沿转到下一个状态
parameter FILTER1 = 4'b0010 ;//计数20ms状态,计数结束转到下一个状态
parameter STABLE = 4'b0100 ;//数据稳定状态,等待按键松开上升沿,读取到上升沿转到下一个状态
parameter FILTER2 = 4'b1000 ;//计数20ms状态,计数结束转到空闲状态
parameter TIME_20MS = 20'd1000_000 ;
reg [ 3: 0] state_c ;//寄存器改变状态
reg [ 3: 0] state_n ;//现在状态
wire IDLE_to_FILTER1 ;//IDLE状态转到FILTER1状态条件
wire FILTER1_to_STABLE;//FILTER1状态转到STABLE状态条件
wire STABLE_to_FILTER2;//STABLE状态转到FILTER2状态条件
wire FILTER2_to_IDLE ;//FILTER2状态转到IDLE状态条件
reg key_in_ff0 ;
reg key_in_ff1 ;
reg key_in_ff2 ;
wire key_in_pos ;//检测上升沿标志
wire key_in_neg ;//检测下降沿标志
reg [ 19: 0] cnt ;
wire add_cnt ;
wire end_cnt ;
//状态机第一段,状态转换
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
state_c <= IDLE;
end
else begin
state_c <= state_n;
end
end
//状态机第二段,状态转换条件
always @(*)begin
case(state_c)
IDLE :begin
if(IDLE_to_FILTER1)
state_n = FILTER1;
else
state_n = state_c;
end
FILTER1:begin
if(FILTER1_to_STABLE)
state_n = STABLE;
else
state_n = state_c;
end
STABLE :begin
if(STABLE_to_FILTER2)
state_n = FILTER2;
else
state_n = state_c;
end
FILTER2:begin
if(FILTER2_to_IDLE)
state_n = IDLE;
else
state_n = state_c;
end
default:state_n = IDLE;
endcase
end
//状态转换条件
assign IDLE_to_FILTER1 = key_in_neg ;
assign FILTER1_to_STABLE = state_c==FILTER1 && end_cnt;
assign STABLE_to_FILTER2 = key_in_pos ;
assign FILTER2_to_IDLE = state_c==FILTER2 && end_cnt;
//打两拍,防止亚稳态
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
key_in_ff0 <= 1;
key_in_ff1 <= 1;
key_in_ff2 <= 1;
end
else begin
key_in_ff0 <= key_in;
key_in_ff1 <= key_in_ff0;
key_in_ff2 <= key_in_ff1;
end
end
//下降沿和上升沿检测
assign key_in_pos = (state_c==STABLE) ?(key_in_ff1 && !key_in_ff2):1'b0;
assign key_in_neg = (state_c==IDLE) ?(!key_in_ff1 && key_in_ff2):1'b0;
//计数20ms
always @(posedge clk or negedge rst_n)begin
if(!rst_n)begin
cnt <= 0;
end
else if(add_cnt)begin
if(end_cnt)
cnt <= 0;
else
cnt <= cnt + 1'b1;
end
else begin
cnt <= 0;
end
end
assign add_cnt = state_c==FILTER1 || state_c==FILTER2;
assign end_cnt = add_cnt && cnt== TIME_20MS-1;
//key_flag按键按下输出一个脉冲信号
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
key_flag <= 0;
end
else if(state_c==FILTER1 && end_cnt) begin
key_flag <= 1;
end
else begin
key_flag <= 0;
end
end
//key_state按键按下状态信号
always @(posedge clk or negedge rst_n)begin
if(rst_n==1'b0)begin
key_state <= 1;
end
else if(state_c==STABLE || state_c==FILTER2) begin
key_state <= 0;
end
else begin
key_state <= 1;
end
end
endmodule
4.顶层模块
module DDS_top(
input clk ,
input rst_n ,
input key0_in ,
input key1_in ,
input key2_in ,
output wire [11:0] dac_data
);
wire [1:0] wave_c ;
wire [25:0] f_word ;
wire [4:0] amplitude ;
DDS inst_DDS
(
.clk (clk),
.rst_n (rst_n),
.f_word (f_word),
.wave_c (wave_c),
.p_word (12'd0),
.amplitude(amplitude),
.dac_data (dac_data)
);
F_word_set inst_F_word_set
(
.clk(clk),
.rst_n(rst_n),
.key1_in(key1_in),
.f_word(f_word)
);
wave_set inst_wave_set
(
.clk(clk),
.rst_n(rst_n),
.key0_in(key0_in),
.wave_c(wave_c)
);
amplitude_set inst_amplitude_set(
.clk (clk) ,
.rst_n (rst_n) ,
.key2_in(key2_in) ,
.amplitude(amplitude)
);
endmodule
5.结果与讨论
编译结果:
仿真结果:
正弦波:
三角波:
锯齿波:
方波:
由图可知,按键改变后,各个波形的频率也随之改变,可见设计成功。
报告里只贴了部分代码,这里是我上传的源码,可以直接运行通过。
链接:https://pan.baidu.com/s/1DzySQriSSNpIZ5H0rfgVgQ
提取码:b7mu
–来自百度网盘超级会员V5的分享