基于FPGA的波形发生器.docx
《基于FPGA的波形发生器.docx》由会员分享,可在线阅读,更多相关《基于FPGA的波形发生器.docx(33页珍藏版)》请在冰豆网上搜索。
基于FPGA的波形发生器
课程设计报告
题目:
波形发生器
日期:
2015年1月19日
一、课程设计目的
1)巩固和加深所学电子技术课程的基本知识,提高综合运用所学知识的能力;
2)培养学生根据课题需要选用参考书、查阅手册、图表和文献资料的能力,提高学生独立解决工程实际问题的能力
3)通过设计方案的分析比较、设计计算、元件选绎及电路安装调试等环节.初步掌握单实用电路的工程设计方法.
4)提高学生的动手能力.掌握常用仪器设备的正确使用方法,学会对简单实用电路的实验调试和对整机指标的测试方法,
5)了解与课题有关的电路以及元器件的工程技术规范,能按课程设计任务书的要求编写设计说明书,能正确反映设计和实验成果,能正确绘制电路固等.
二、设计任务与要求
一)任务:
●数码管显示学号
●设计基于FPGA波形发生器
二)设计要求:
1.显示学号
a.用四位数码管显示
b.循环显示同组2人的学号后四位
2.根据按键输入产生波形
a)根据标准键盘输入不同,分别输出正弦波、方波、三角波(频率=1KHz)
b)根据标准键盘改变频率(频率变化范围:
1KHz-10KHz,每次频率变化1KHz)
c)输出频率在数码管上显示
三、方案设计与论证
首先是对设计要求的分析,然后说明本次课程设计采用的方案,并给出总体设计方框原理图。
(1)对设计要求的总体分析:
电路总体由四个模块组成:
键盘模块:
实现对按键信号输入及处理,生成频率控制字与波形控制字
数码管显示:
将频率控制字输入进行显示
波形发生模块:
对于要求的三种波形建立ROM阵列储存点列数据,建立i2c协议定义,控制字输入实现波形筛选与控制
波形选择模块:
根据输入选择波形种类的输出
(2)实现方案:
实验一:
学号循环显示
设计思想:
对系统50MHz的时钟信号进行分频,由时钟得到一个num值,通过对num值0或1的判断来选择显示不同的学号,从而使学号得以循环。
实验二:
波形发生器
设计过程由上而下,先建立各个模块之间的联系,然后针对各自模块功能进行内部编程。
再对出现的问题进行修改。
我们的核心模块是波形发生模块,首先将三种波形发生器分别得到,通过内部I2c协议使得波形在示波器上得以实现;
键盘模块负责提供控制信号,编写内部程序,使得按键动作作为信号输出;输出的控制字在波形发生模块中根据代码进行筛选及其控制
数码管显示:
仅仅将键盘输出的频率字进行码制转换即可。
波形选择过程:
由键盘输入值来定义一个数值,根据其值不同,输出波形不同。
总体电路的RTL视图
四、单元电路设计与参数计算
学号的循环显示模块
·选择clk频率为50Mhz,周期20ns。
·上升沿翻转,cnt=cnt+1,经实验尝试,cnt计满需要的次数取
。
因此其周期为
×20ns。
·当cnt计满时,定义num为变量,通过复位信号实现num的取值为0或1。
·给num取0或1时(使用case语句)分别赋予两个人的学号,从而使学号得以循环。
波形发生器部分:
1)键盘模块
键盘包括数据线、时钟线、vcc和gnd,采用第二套扫描码,按键按下时,键盘将相应的通码数据发送到FPGA,根据第二套扫描码集可以确定哪个键被按下。
2)数码管输出模块
用parameter定义字符数据,使用always@()定义敏感变量,当时钟序列的上升沿到来时,触发case函数,从而选择正确的数值进输出。
3)波形发生器和波形选择模块
Wave1,2,3负责波形的产生,包含i2c协议,输出sda和scl,内部如下:
FPGA中的波形发生器控制电路通过外部控制信号、高速时钟来产生控制ROM波形数据表的地址,输出信号的频率由ROM地址的变化速率决定,变化越快,输出频率越高。
波形数据表ROM用于存放波形数据,可以存放正弦波、矩形波、三角波。
本实验中存放波形数据的ROM是8位宽度,256个数据深度。
五、遇到问题的解决方法
问题1.对于波形的取样点问题:
一开始我们学习使用代码进行编程实现采样点赋值,然而在观察波形的时候发现精度太差,于是我们花费了整整一天的时间进行优化,最后使用rom文件实现更高精度的调用
问题2.对于i2c协议的定义
通过短暂的学习了解,我们初步认识了i2c协议,一开始我们将协议独立为一个模块,但是由于不了解接口定义,所以验证无法通过,我们只好学习别人照猫画虎,将I2c直接写入波形发生模块,得到了正确结果
问题3.对于频率控制的问题
我们提出了三个设想:
A.通过控制改变键盘控制字,通过一个分频模块来得到基准频率,根据控制字得到理想频率
B.通过改变i2c协议中的频率代码实现波形显示的频率改变
C.通过改变采样点的采样个数来改变频率输出,我们采样点256个,如果全部逐点扫描得到基础频率,当我们隔点扫描的时候,便会实现分频效果,但是不能按要求实现1KHZ的逐步变化
经过分析,我们认为第一种方法最好,但是在处理接口方面出了一点问题导致控制不能实现;然后我们尝试对第二种方法进行修改,效果同样不理想,所以最终我们的频率模块不能得到实现。
六、收获与体会:
通过本次课程设计我们第一次接触到了VerilogHDL语言,因为有了c语言的基础对于编程内容的理解相对不困难,对于我们最大的挑战是对于语言的规范,例如,当我们想定义乘法运算的时候,尝试了直接的(*)运算式,结果出现了错误,后来我们采用了累加器实现了特定功能。
在整个课设过程中,我们查阅了很多的资料,从教科书,网上的论文一直到其他同学的成果,我们都很虚心地进行了借鉴,可能代码不是我们全部自己输入的,但是我们通过亲自设计顶层模块然后根据需求调用,很好的实现了不同程序的修改兼容,这是我们的成果,感到高兴,也有些许遗憾,本次课程设计时间仓促,没能详尽了解语言知识。
在与同学的合作中,我们彼此学习到了对方的长处,在设计过程中发挥各自长处,是我们的设计过程事半功倍。
希望今后有机会进一步学习代码语言,实现软硬件的应用,不断提升自己的能力。
附录:
一、顶层模块
//=====================顶层模块===============================
modulewaveform(clk,rst,ps2k_clk,ps2k_data,ps2_byte,ps2_sel,seg_0,seg_1,seg_2,seg_3,
ps2_0,ps2_1,ps2_2,SCL1,SDA1,SCL2,SDA2,SCL3,SDA3,SCL,SDA);
inputclk;
inputrst;
inputps2k_clk;//ps2接口时钟
inputps2k_data;//ps2数据信号
output[7:
0]ps2_byte;//频率值
output[1:
0]ps2_sel;//选择波形
outputps2_0,ps2_1,ps2_2;
wire[7:
0]ps2_byte;////1byte键值
wireps2_state;//按键状态标志位
wire[1:
0]ps2_sel;
wire[7:
0]dout;
outputSCL1,SDA1;
outputSCL2,SDA2;
outputSCL3,SDA3;
outputSCL,SDA;
output[7:
0]seg_0;
output[7:
0]seg_1;
output[7:
0]seg_2;
output[7:
0]seg_3;
ps2scanU4(//按键扫描模块
.clk(clk),
.rst(rst),
.ps2k_clk(ps2k_clk),
.ps2k_data(ps2k_data),
.ps2_byte(ps2_byte),
.ps2_state(ps2_state),
.ps2_sel(ps2_sel),
.ps2_0(ps2_0),
.ps2_1(ps2_1),
.ps2_2(ps2_2),
);
segU5(
.clk(clk),
.Res(ps2_byte),
.seg_0(seg_0),
.seg_1(seg_1),
.seg_2(seg_2),
.seg_3(seg_3),
);
wave1U1(clk,rst,SCL1,SDA1);
wave2U2(clk,rst,SCL2,SDA2);
wave3U3(clk,rst,SCL3,SDA3);
wireps2_0;
wireps2_1;
wireps2_2;
selU6(ps2_0,ps2_1,ps2_2,clk,rst,SCL1,SDA1,SCL2,SDA2,SCL3,SDA3,SDA,SCL);
endmodule
二、键盘模块
//=============================键盘接收模块===================================
/*当按键A时选择正弦波,LED0亮
当按键S时选择正弦波,LED1亮
当按键D时选择正弦波,LED2亮
当重新选择波形时,频率改为默认值*/
moduleps2scan(clk,rst,ps2k_clk,ps2k_data,ps2_byte,ps2_sel,ps2_state,led,ps2_0,ps2_1,ps2_2);
inputclk;
inputrst;
inputps2k_clk;
inputps2k_data;
regps20,ps21,ps22;
outputps2_0,ps2_1,ps2_2;
outputled;
output[7:
0]ps2_byte;//ps2数据信号
output[1:
0]ps2_sel;
outputps2_state;//标注键盘当前状态,1表示有按键按下
regled;
reg[15:
0]count;
integernum1,a,b;
initialbegin
num1=0;
a=0;
b=0;
end
always@(posedgeclkornegedgerst)
if(!
rst)
count<=16'b0;
elsebegin
count<=count+1'b1;
if(count==16'hffff)
begin
count<=16'b0;
num1<=num1+1;
if(num1==4)
num1<=0;
end
end
regps2k_clk_r0,ps2k_clk_r1,ps2k_clk_r2;//ps2k_clk状态寄存器
wireneg_ps2k_clk;//ps2k_clk下沿标志位
always@(posedgeclkornegedgerst)begin
if(!
rst)begin
ps2k_clk_r0<=1'b0;
ps2k_clk_r1<=1'b0;
ps2k_clk_r2<=1'b0;
end
elsebegin
ps2k_clk_r0<=ps2k_clk;//锁存状态,进行滤波
ps2k_clk_r1<=ps2k_clk_r0;
ps2k_clk_r2<=ps2k_clk_r1;
end
end
assignneg_ps2k_clk=~ps2k_clk_r1&ps2k_clk_r2;
reg[7:
0]ps2_byte_r;//PC接收来自ps2的一个字节数据寄存器
reg[7:
0]temp_data;//当前接收数据寄存器
reg[3:
0]num;//计数寄存器
always@(posedgeclkornegedgerst)begin
if(!
rst)begin
num<=4'd0;
temp_data<=8'd0;
end
elseif(neg_ps2k_clk)begin
case(num)
4'd0:
num<=num+1'b1;
4'd1:
begin
num<=num+1'b1;
temp_data[0]<=ps2k_data;
end
4'd2:
begin
num<=num+1'b1;
temp_data[1]<=ps2k_data;
end
4'd3:
begin
num<=num+1'b1;
temp_data[2]<=ps2k_data;
end
4'd4:
begin
num<=num+1'b1;
temp_data[3]<=ps2k_data;
end
4'd5:
begin
num<=num+1'b1;
temp_data[4]<=ps2k_data;
end
4'd6:
begin
num<=num+1'b1;
temp_data[5]<=ps2k_data;
end
4'd7:
begin
num<=num+1'b1;
temp_data[6]<=ps2k_data;
end
4'd8:
begin
num<=num+1'b1;
temp_data[7]<=ps2k_data;
end
4'd9:
begin
num<=num+1'b1;
end
4'd10:
begin
num<=4'd0;
end
default:
;
endcase
end
end
regkey_f0;//松键标志位,1表示收到数据8f0;
regps2_state_r;//键盘当前状态,1表示按下
always@(posedgeclkornegedgerst)begin
if(!
rst)begin
key_f0<=1'b0;
ps2_state_r<=1'b0;
end
elseif(num==4'd10)//传送完一个字节
begin
if(temp_data==8'hf0)begin
key_f0<=1'b1;
led<=0;
end
elsebegin
if(!
key_f0)begin//
ps2_state_r<=1'b1;
led<=1;
ps2_byte_r<=temp_data;
end
elsebegin
ps2_state_r<=1'b0;
key_f0<=1'b0;
end
end
end
end
reg[1:
0]ps2_asci_1;
reg[7:
0]ps2_asci;
always@(ps2_byte_r)begin
case(ps2_byte_r)
8'h16:
ps2_asci<=8'hf9;//1
8'h1E:
ps2_asci<=8'ha4;//2
8'h26:
ps2_asci<=8'hb0;//3
8'h25:
ps2_asci<=8'h99;//4
8'h2E:
ps2_asci<=8'h92;//5
8'h36:
ps2_asci<=8'h82;//6
8'h3D:
ps2_asci<=8'hf8;//7
8'h3E:
ps2_asci<=8'h80;//8
8'h46:
ps2_asci<=8'h90;//9
8'h45:
ps2_asci<=8'hc0;//0
8'h1c:
beginps2_asci_1<=2'b00;ps20<=1'b1;ps21<=1'b0;ps22<=1'b0;end//A
8'h1b:
beginps2_asci_1<=2'b01;ps20<=1'b0;ps21<=1'b1;ps22<=1'b0;end//S
8'h23:
beginps2_asci_1<=2'b10;ps20<=1'b0;ps21<=1'b0;ps22<=1'b1;end//D
/*8'h55:
begincase(ps2_asci)//+
8'h90,8'hc0:
ps2_asci<=8'hc0;//0
8'hf9,8'ha4,8'hb0,8'h99,8'h92,8'h82,8'hf8,8'h80:
ps2_asci<=ps2_asci+1'h01;
default;
endcase
end
8'h4E:
begincase(ps2_asci)//-
8'hc0:
ps2_asci<=8'h90;//9
8'hf9:
ps2_asci<=8'hf9;//1
8'ha4,8'hb0,8'h99,8'h92,8'h82,8'hf8,8'h80,8'h90:
ps2_asci<=ps2_asci-1'h01;
default;
endcase
end*/
default:
ps2_asci<=8'hf9;
endcase
end
assignps2_byte=ps2_asci;
assignps2_0=ps20;
assignps2_1=ps21;
assignps2_2=ps22;
assignps2_sel=ps2_asci_1;
assignps2_state=ps2_state_r;
endmodule
三、数码管显示模块
/*********************数码管显示模块*******************************/
moduleseg(clk,seg_0,seg_1,seg_2,seg_3,Res);
inputclk;
input[7:
0]Res;
outputreg[7:
0]seg_0;
outputreg[7:
0]seg_1;
outputreg[7:
0]seg_2;
outputreg[7:
0]seg_3;
parameter
seg0=8'hc0,
seg1=8'hf9,
seg2=8'ha4,
seg3=8'hb0,
seg4=8'h99,
seg5=8'h92,
seg6=8'h82,
seg7=8'hf8,
seg8=8'h80,
seg9=8'h90;
always@(posedgeclk)begin
case(Res)
8'hc0:
beginseg_0<=seg0;seg_1<=seg1;seg_2<=seg0;seg_3<=seg0;end
8'hf9:
beginseg_0<=seg1;seg_1<=seg0;seg_2<=seg0;seg_3<=seg0;end
8'ha4:
beginseg_0<=seg2;seg_1<=seg0;seg_2<=seg0;seg_3<=seg0;end
8'hb0:
beginseg_0<=seg3;seg_1<=seg0;seg_2<=seg0;seg_3<=seg0;end
8'h99:
beginseg_0<=seg4;seg_1<=seg0;seg_2<=seg0;seg_3<=seg0;end
8'h92:
beginseg_0<=seg5;seg_1<=seg0;seg_2<=seg0;seg_3<=seg0;end
8'h82:
beginseg_0<=seg6;seg_1<=seg0;seg_2<=seg0;seg_3<=seg0;end
8'hf8:
beginseg_0<=seg7;seg_1<=seg0;seg_2<=seg0;seg_3<=seg0;end
8'h80:
beginseg_0<=seg8;seg_1<=seg0;seg_2<=seg0;seg_3<=seg0;end
8'h90:
beginseg_0<=seg9;seg_1<=seg0;seg_2<=seg0;seg_3<=seg0;end
endcase
end
endmodule
四、波形产生模块
//
modulewave1(
inputclock,
inputreset,
outputSCL1,
inoutSDA1
);
RomAddressCtrl1U11(Done_Sig1,clock,reset,isStart1,RomAddress1);
rom_sinU12(RomAddress1,clock,q1);
iic1U13(clock,reset,isStart1,q1,Done_Sig1,SCL1,SDA1);
wireDone_Sig1;
wire[1:
0]isStart1;
wire[10:
0]RomAddress1;
wire[7:
0]q1;
endmodule
子模块一
moduleRomAddressCtrl1(Done_Sig,clock,reset,isStart,RomAddress);
inputDone_Sig;
inputclock;
inputreset;
//input[7:
0]FreqChoose;
output[1:
0]isStart;
//output[7:
0]I2CAddress;
output[10:
0]RomAddress;
reg[3:
0]i;
reg[1:
0]RegisStart;
//reg[7:
0]RegI2CAddress;
reg[10:
0]RegRomAddress;
always@(posedgeclockornegedgereset)
if(!
reset)
begin
i<=4'd0;
//RegI2CAddress<=8'd0;
RegisStart<=2'b00;
end
else
case(i)
0:
if(Done_Sig)beginRegisStart<=2'b00;i<=i+1'b1;RegRomAddress<=RegRomAddress+8'd41;end
elsebeginRegisStart<=2'b01;end
1: