1、 西北工业大学课 程 设 计 报 告题 目: 波形发生器 学 院: 电子信息学院 班 级: 08041202 学生(学号): 2012301995 学生(姓名): 张雨 日期: 2014 年 1月 20日 摘 要本设计基于FPGA开发板,利用硬件描述语言Verilog进行编程,通过DDS数字频率合成实现频率可调的正弦波、三角波、方波简易发生器。本文所设计的内容就是基于Altera公司的现场可编程门阵列(FPGA)实现数字信号发生器的设计,FPGA具有密度高,功耗低,体积小,可靠性高等特点,设计时可以不必过多考虑具体硬件连接;本设计中应用Verilog硬件描述语言进行描述,使该数字信号发生器可以
2、产生正弦波、方波、三角波、锯齿波四个独立的波形,并能对所产生的四种波形的频率和进行调节。设计输出频率范围是1kz10kHz步进是1KHZ,测量的结果在数码管上显示 。关键词:FPGA Verilog PS2协议 IIC协议 PCF8591目 录目录课程设计目的4设计任务与要求4方案设计与论证5单元电路设计与参数计算11遇到问题的解决方法13结论与心得14参考文献15附录16题目:波形发生器一、 课程设计目的 1)巩固和加深所学电子技术课程的基本知识, 提高综合运用所学知识的能力;2)培养学生根据课题需要选用参考书、查阅手册、图表和文献资料的能力,提高学生独立解决工程实际问题的能力;3)通过设计
3、方案的分析比较、设计计算、元件选绎及电路安装调试等环节初步掌握单实用电路的工程设计方法; 4)提高学生的动手能力掌握常用仪器设备的正确使用方法,学会对简单实用电路的实验调试和对整机指标的测试方法;5)了解与课题有关的电路以及元器件的工程技术规范,能按课程设计任务书的要求编写设计说明书,能正确反映设计和实验成果,能正确绘制电路图等二、 设计任务与要求一) 任务: 利用Verilog HDL或VHDL硬件描述语言及FPGA开发板实现波形发生器和学号循环显示。二) 设计要求: 1、显示学号1) 采用数码管显示;2) 循环显示2个人的学号后四位;2、根据按键输出波形1)根据按键输入不同,分别输出正弦波
4、、方波、三角波(频率=1KHz);2)根据按键改变频率(频率变化范围:1KHz-10KHz,每次频率变化1KHz);3)输出频率在数码管上显示三、 方案设计与论证1、 显示学号:直接给数码管赋值显示学号,设计时钟频率,控制跳变。1)频率部分:开发板的时钟脉冲是50MHz,作为显示脉冲频率太高,因而首先进行分频,分到肉眼可辨别的频率;2)显示计数部分:要求循环显示两人的学号后四位,当CP脉冲的上升沿到来的时候对其进行计数,直到cnt 32d49_999_9993 )数码管显示部分:对于2 )中的CP脉冲上升沿的计数,前两个数码管显示输出19部分,后两面数码管当cnt = 32d24_999_99
5、9的时候显示79,否则显示88,即能实现学号后四位的循环显示2、 根据按键输出波形(一) 总体方案实现及系统框图该设计以FPGA开发平台为核心,将各波形的幅值相位量化数据存储在ROM内,按照设定频率,以相应频率控制字k为步进,对相位进行累加,以累加相位值作为地址码读取存放在存储器内的波形数据,经DA转换和幅度控制、滤波即可得到所需波形。波形发生器采取全数字化结构,用硬件描述语言Verilog设计实现其频率可调可显示。经开发平台的DA转化和外加滤波整形处理波形数据,理论上能够实现任意频率的各种波形。DDS电路一般由参考时钟、相位累加器、波形存储器、D/A转换器(DAC)和低通滤波器(LPF)组成
6、7。其结构框图如图2.5所示。图2.5 DDS基本结构框图其中,为参考时钟频率,为频率控制字,为相位累加器位数,为波形存储器位数,为波形存储器的数据位字长和D/A转换器位数。(二)直接数字频率合成技术原理DDS系统中的参考时钟通常由一个高稳定度的晶体振荡器来产生,用来作为整个系统各个组成部分的同步时钟。频率控制字(Frequency Control Word,FCW)实际上是二进制编码的相位增量值,它作为相位累加器的输入累加值。相位累加器由加法器和寄存器级联构成,它将寄存器的输出反馈到加法器的输入端实现累加的功能。在每一个时钟脉冲,相位累加器把频率字累加一次,累加器的输出相应增加一个步长的相位
7、增量,由此可以看出,相位累加器的输出数据实质上是以为步长的线性递增序列(在相位累加器产生溢出以前),它反映了合成信号的相位信息。相位累加器的输出与波形存储器的地址线相连,相当于对波形存储器进行查表,这样就可以把存储在波形存储器中的信号抽样值(二进制编码值)查出。在系统时钟脉冲的作用下,相位累加器不停的累加,即不停的查表。波形存储器的输出数据送到D/A转换器,D/A转换器将数字量形式的波形幅度值转换成所要求合成频率的模拟量形式信号,从而将波形重新合成出来。若波形存储器中存放的是正弦波幅度量化数据,那么D/A转换器的输出是近似正弦波的阶梯波,还需要后级的低通平滑滤波器进一步抑制不必要的杂波就可以得
8、到频谱比较纯净的正弦波信号。图2.6所示为DDS各个部分的输出信号。由于受到字长的限制,相位累加器累加到一定值后,就会产生一次累加溢出,这样波形存储器的地址就会循环一次,输出波形循环一周。相位累加器的溢出频率即为合成信号的频率。可见,频率控制字K越大,相位累加器产生溢出的速度越快,输出频率也就越高。故改变频率字(即相位增量),就可以改变相位累加器的溢出时间,在参考频率不变的条件下就可以改变输出信号的频率。图2.6 DDS各部分输出波形DDS系统的优点有很多,它的很多特性是其他频率合成技术所没有的,其中最主要的特性有以下三点:(1)DDS技术可以用于产生任意波形基于前面对DDS系统的基本结构分析
9、,很容易理解,只要改变存储在波形存储器中的波形数据,就可以改变输出波形。所以对于任何周期性波形,只要满足采样定理,都可以利用DDS技术来实现。(2)DDS系统具有很高的频率分辨率DDS系统输出频率的分辨率和频点数随相位累加器的位数成指数增长,由可知,在系统时钟频率不变的情况下,只要增大相位累加器的位数,就可以得到几乎是任意小的频率分辨率,可以满足精细频率控制的要求。DDS如此精细的频率分辨率,使其输出频率已十分逼近连续变化。(3)输出频率切换速度快且相位保持连续与锁相频率合成相比,由于DDS系统是一个开环系统,所以当一个新的频率控制字送到时,它会迅速合成这个新的频率,实际的频率切换时间可以达n
10、s级。同时,频率切换时,DDS系统的输出波形的相位是连续的。DDS系统的频率字改变时,输出波形的变化过程可以用图2.12描述。图2.12 频率控制字改变时累加器的输出值和输出波形的变化(仿真)在波形输出到点时,频率字发生了改变(变小),相位累加器的累加值即相位步进变小,其输出值斜率也变小,系统的输出波形的频率也在同时刻变小。DDS系统在频率字发生改变后的一个时钟周期,其输出频率就可以就转换到了新的频率上,也即在频率字的值改变以后,累加器在经过一个时钟周期后就按照新的频率字进行累加,开始合成新的频率。所以我们可以认为DDS的频率切换是在一个系统时钟周期内完成的,系统时钟频率越高,切换速度越快。另
11、外,从前面对DDS技术原理的分析可知,要改变输出频率,实际上改变的是频率字,也就是相位增量。当频率字的值从改变为之后,相位累加器是在已有的累积相位上,再对进行累加,相位函数曲线是连续的。从图2.12也可以看出,只是在频率字改变的瞬间相位函数曲线的斜率发生了突变,相位值并没有发生跳跃,因此DDS能够在频率切换的过程中保持相位连续,输出波形能够平滑地从一个频率过渡到另外一个频率。(三) 1 总体设计模块1 )按键控制模块键盘的处理器如果发现有键被按下或释放将发送扫描码的信息包到计算机。扫描码有两种不同的类型:通码和断码。当一个键被按下就发送通码,当一个键被释放就发送断码。每个按键被分配了唯一的通码
12、和断码。2 )波形控制模块(1)波形产生模块 分别产生三角波,方波,正弦波三种波形,对三种波形在一个周期内采取其中的255个样点数据,clock为系统时钟信号(2)波形显示模块 IIC总线并行转串行模块,利用其D/A转换模块从而实现其产生的波形在示波器上显示IIC通信中只涉及两条信号线,时钟线SCL和数据线SDA。时钟线的下降沿锁存数据。当SCL高电平时,把SDA从高电平拉倒低电平,则表示开始通信;反之,把SDA从低电平拉倒高电平,则表示通信结束。 D/A转换模块:利用8591器件实现数据D/A转换,最终将波形显示在波形显示器上。其中要利用SCL,SDA,VCC,GND,D/A等主要接口,用F
13、PGA实现IIC总线,实现和PCF8591连接,并用8591进行D/A转换,实现波行输出。3)数码管显示部分:开发板的时钟脉冲是50MHz,要求实现的是1KHz到10KHz以步长为1KHz进行变化,所以对50MHz进行10种分频;要求对应显示十个频率,因而利用按键按下的次数进行模10计数,每计一次数,将对应频率进行输出显示。四、单元电路设计与参数计算1、显示学号时钟脉冲为50MHZ,将其分为占空比为50%的频率时钟信号,得到的频率为1HZ的时钟信号作为学号显示的频率2、 根据按键输出波形DDS输出频率关系式计算:输出频率1kHz ,M=50000输出频率2kHz ,M=25000输出频率3kH
14、z ,M=16666输出频率4kHz ,M=12500输出频率5kHz ,M=10000输出频率6kHz ,M=08333输出频率7kHz ,M=07142输出频率8kHz ,M=06250输出频率9kHz ,M=05555输出频率10kHz ,M=05000依次为三角波,方波,正玄波的频率产生数码管显示通过频率控制字的大小换算频率,控制数码管的显示五、遇到问题的解决方法 1、这个问题着实困扰了我们很长时间,之前学习过C+,微机汇编等语言,对一些简单的问题进行编程。突然接触一门新的语言,对我们来说比较陌生甚至让人很不适应,尤为特殊的是Verilog HDL主要为了实现硬件功能,和上述其他语言还
15、是有很大的不同。加之本学期完成数电实验主要用VHDL语言,因此十分陌生。在花了数天时间看其语法后,发现还是与通用语言有许多共通之处的,只不过是表示方法不同而已,只要注意语言之间语法别串用,设计思路还是大体相同,我们需要写好正确并编译无误的程序并分配合适的管脚,实现功能还是相对简单的。总的来说,在初步入门之后,我们才发现Verilog HDL的易读性和通用性有多强。 2、正弦波的波形刚开始不是很正确,原因是采样时取值只用了正半周的数据。解决方法:重新计算采样值,改变程序里面的采样值 3、我们在开始设计前浏览了一定的相关书籍,学习硬件描述预言,查阅开发板的数据手册,详细了解开发板的模块、功能。4、
16、对于题目的要求难以构思,无从下手。开始设计时,对于整个程序的框架还很模糊,于是上网查阅了不少关于基于FPGA的波形发生器的实例,发现应用DDS技术可以很好的解决这一问题。查阅资料了解DDS的其基本原理后基于本次设计的要求提出了我们自己的方案。 5、 但是对于波形发生器所涉及的PS2协议和显示部分所用到的IIC协议,我们无从下手,后来通过网上下载程序不断的修改程序,终于调试出了三种波形,但还是未能实现通过按键不同来产生的不同通码控制信号,从而来改变三种波形的输出,最后只能设计出通过接不同的针脚从而来实现三种波形的转换! 6、正弦波的波形显示出现了错误,其中有一部分的波形不稳定,出现了误差,甚至有
17、时候调不出来波形,与杜邦线,示波器以及针脚,芯片都有一定的关系 7、频率计算出错,调试程序后发现步进值达不到要求,检查后发现频率控制字值设置错误。六、结论与心得对于我们来说,课程设计是一次学习的机会。因为总会遇到一些自己从来没有遇到的问题,锻炼了自己解决问题的能力,也学会了与人合作。这次课设让我加深了对verilog语言的理解,因为掌握不熟练,常会犯一些低级错误,在做的过程中,理解,并运用到实际中,真的提升了自己的能力。当调试出错时,我们认真分析问题,并请教老师和同学,找到问题,并解决。做设计是个综合的工程,需要从整体把握,将复杂逐渐变为简单,做到最后,我们发现一开始的困难都不算什么了,因为我
18、们更深的理解了设计概念和方法。本设计实现了可以输出三种波形发生器,结果证明,频率可以改变,并且可以通过数码管显示,所以该设计正确有效。本系统仍然有着很多可改进的地方,比如可以拓展为输出幅值可调的波形,或者输出任意波形以更贴近实际情况;采样点数可以进一步提高,提高波形的准确度。在以后的学习中,我们会更加认真,用心。把知识灵活运用。真正做到设计。七、 参考文献1 张永瑞 等著. 电子测量技术基础. 西安:西安电子科技大学出版社. 2004. 1-152 林占江,林放 著. 电子测量仪器原理与使用. 北京:电子工业出版社. 2006. 1-213 张学峰,胡长江. 功能各异的各种任意波形发生器. 国
19、外电子测量技术. 2000,4. 17-184 毛敏. 基于DDS的高精度方波信号发生器的研究. 西安电子科技大学工学硕士论文. 2006. 5-65 张有正 等著. 频率合成技术. 北京:人民邮电出版社. 1984. 1-336杜慧敏、赵全良著基于Verilog的FPGA设计基础西安电子科技大学出版社7王金明VerilogHDL程序设计教程人民邮电出版社8PCF8591芯片手册【9】DEO芯片手册附录:(各模块程序代码)1、显示学号module abc_fp(clk,a1,a2,a3,a4);input clk;output6:0 a1;output6:0 a2;output6:0 a3;o
20、utput6:0 a4;reg31:0 cnt;always (posedge clk )if(cnt 32d49_999_999) cnt = cnt+1b1;else cnt = 32d0;assign a1 = 7b1001111;assign a2 = 7b0000100;assign a3 = (cnt = 32d24_999_999) ? 7b0001111:7b0000000;assign a4 = (cnt = 32d24_999_999) ? 7b0000100:7b0000000;Endmodule2、 波形发生器module verilog_iicps2(clk,rst_
21、n,ps2k_clk,ps2k_data,ps2_byte,ps2_byte1, ps2_state,led_out,led_out1,scl,sda,scl1,scl2,sda1,sda2,scpl,scpl_fb,scpl_sin,led_out2);input clk; /时钟50MHzinput rst_n; /复位信号input ps2k_clk; /ps2接口时钟信号 input ps2k_data; /ps2数据信号output 7:0 ps2_byte; /1byte数值,按键扫描output 7:0 ps2_byte1;output ps2_state; /键盘当前状态ps2
22、_state=1表示当前有键被按下output led_out;output led_out1;output led_out2;output scl;output sda;output scl1;output sda1;output scl2;output sda2;output 7:0 scpl;output 7:0 scpl_fb;output 7:0 scpl_sin;reg ps2k_clk_r0,ps2k_clk_r1,ps2k_clk_r2; /ps2k_clk状态寄存? reg 24:0 count2;reg 24:0 count1;reg 24:0 count3;reg 24:
23、0 count_4;reg 24:0 count5;reg 24:0 count1_fb;reg 24:0 count1_sin;reg div_clk;reg led_out;reg led_out1;reg led_out2;reg plxs_clk;reg sin_clk;reg7:0 numb;reg7:0 numb_fb;reg7:0 numb_sin;reg7:0 data;reg7:0 data_sin;reg7:0 data_fb;reg 8:0 count_data;reg 8:0 count_datafb;reg 8:0 count_datasin;reg scl;reg
24、scl1;reg scl2;reg sda;reg sda1;reg sda2;reg flag;reg 7:0 scpl;reg 7:0 scpl_fb;reg 7:0 scpl_sin;reg 19:0 count_jc;reg 19:0 count_jcfb;reg 19:0 count_jcsin;reg 7:0 cnt;reg 7:0 cnt1;reg 7:0 cnt2;reg 19:0 count_pl;reg 19:0 fb_pl;reg 19:0 sin_pl;reg g_clk;wire neg_ps2k_clk; /ps2k_clk下降沿标志位always (posedge
25、 clk or negedge rst_n)begin if(!rst_n) begin ps2k_clk_r0 =1b0; ps2k_clk_r1 =1b0; ps2k_clk_r2 =1b0; end else begin ps2k_clk_r0 =ps2k_clk; ps2k_clk_r1 =ps2k_clk_r0; ps2k_clk_r2 =ps2k_clk_r1; endendassign neg_ps2k_clk=ps2k_clk_r1 & ps2k_clk_r2; /检测下降沿1有效reg7:0 ps2_byte_r; /pc接收ps2一个字节数据存储器reg7:0 temp_d
26、ata; /当前接收数据寄存器reg3:0 num; /计数寄存器always (posedge clk or negedge rst_n)begin if(!rst_n) begin num=4d0; temp_data=8d0; end else if(neg_ps2k_clk)begin /检测到下降沿 case (num) 4d0: num=num+1b1; /起始位不采样 4d1: begin num=num+1b1; temp_data0=ps2k_data; /bit0 end 4d2: begin num=num+1b1; temp_data1=ps2k_data; /bit1
27、 end 4d3: begin num=num+1b1; temp_data2=ps2k_data; /. end 4d4: begin num=num+1b1; temp_data3=ps2k_data; end 4d5: begin num=num+1b1; temp_data4=ps2k_data; end 4d6: begin num=num+1b1; temp_data5=ps2k_data; end 4d7: begin num=num+1b1; temp_data6=ps2k_data; /bit6 end 4d8: begin num=num+1b1; temp_data7=p
28、s2k_data; /bit7 end 4d9: begin num=num+1b1; /奇偶校验不处理 end 4d10:begin num=4d0; /结束位num清零end default: ; /应答位不处理 endcase endendreg key_f0; /松键标志位,置1表示接收到数据8hf0,再接收到下一个数据后清零?reg ps2_state_r; /键盘当前状态,ps2_state_r=1表示有键被按下/reg flag=0;always (posedge clk or negedge rst_n) begin /接收数据的相应处理,这里只对1byte的键值进行处理 if
29、(!rst_n)begin key_f0 = 1b0; ps2_state_r = 1b0; end else if(num=4d10) begin /刚传送完一个字节数据 if(temp_data=8hf0)key_f0=1b1; else begin if(!key_f0)begin /说明有键按下 ps2_state_r=1b1; ps2_byte_r=temp_data; /锁存当前键值 / if(flag) transport =temp_data; / flag=flag+1b1; end else begin ps2_state_r=1b0; key_f0=1b0; end en
30、d end endalways (negedge ps2_state_r)begin if(ps2_state_r=0) transport =ps2_byte_r;endreg7:0 transport;reg7:0 ps2_asci; /接收数据的相应ASCII码 reg7:0 ps2_asci1; reg count; always (ps2_byte_r) begin count=count+1; / if(count=1)begin case (ps2_byte_r)/键值转换为ASCII码,这里做的比较简单8h45: ps2_asci = zero;8h16: ps2_asci =
31、 one;8h1E: ps2_asci = two;8h26: ps2_asci = three;8h25: ps2_asci = four;8h2E: ps2_asci = five;8h36: ps2_asci = six;8h3D: ps2_asci = seven;8h3E: ps2_asci = eight;8h46: ps2_asci = nine; default: ps2_asci = nothing;endcase/end/else ps2_asci = nothing;endalways (posedge ps2_state_r) begin if(ps2_state_r=
32、1)begin case (transport)/键值转换为ASCII码,这里做的比较简单8h45: ps2_asci1 = zero;8h16: ps2_asci1 = one;8h1E: ps2_asci1 = two;8h26: ps2_asci1 = three;8h25: ps2_asci1 = four;8h2E: ps2_asci1 = five;8h36: ps2_asci1 = six;8h3D: ps2_asci1 = seven;8h3E: ps2_asci1 = eight;8h46: ps2_asci1 = nine; default:ps2_asci1 = noth
33、ing; endcase end else ps2_asci1 = nothing;endassign ps2_byte = ps2_asci; assign ps2_byte1 = ps2_asci1 ;assign ps2_state = ps2_state_r;parameter zero = 8b1100_0000, one = 8b1111_1001, two = 8b1010_0100, three = 8b1011_0000, four = 8b1001_1001, five = 8b1001_0010, six = 8b1000_0010, seven = 8b1111_100
34、0, eight = 8b1000_0000, nine = 8b1001_0000, nothing = 8b1111_1111;always ( posedge clk)beginif ( count2=500 ) begin div_clk=div_clk; count2=0; endelse count2=count2+1; led_out=div_clk;endalways (posedge ps2_state) begin cnt=cnt+1; case(cnt) 8d01:count_pl=20d50000; 8d02:count_pl=20d25000; 8d03:count_
35、pl=20d16666; 8d04:count_pl=20d12500; 8d05:count_pl=20d10000; 8d06:count_pl=20d08333; 8d07:count_pl=20d07142; 8d08:count_pl=20d06250; 8d09:count_pl=20d05555; 8d10:count_pl=20d05000; 8d11:begin fb_pl=20d50000; count_pl=1b0; end 8d12:begin fb_pl=20d25000; count_pl=1b0; end 8d13:begin fb_pl=20d16666; co
36、unt_pl=1b0; end 8d14:begin fb_pl=20d12500; count_pl=1b0; end 8d15:begin fb_pl=20d10000; count_pl=1b0; end 8d16:begin fb_pl=20d08333; count_pl=1b0; end 8d17:begin fb_pl=20d07142; count_pl=1b0; end 8d18:begin fb_pl=20d06250; count_pl=1b0; end 8d19:begin fb_pl=20d05555; count_pl=1b0; end 8d20:begin fb_pl=20d05000;