资源描述
北京联合大学
课程设计报告
课程名称: 电工电子技术课程设计
实验名称:基于Verilog HDL的出租车计费器的程序设计
学 院:自动化学院 专 业:物流工程
班 级:自动化物流1201B 成 绩:
姓 名: 学 号:
2015年 1 月 23 日
前言:本次课程设计主要是基于FPGA芯片,使用硬件描述语言Verilog HDL,采用“自顶向下”的设计方法,编写一个出租车计费器芯片,并使用Quartus II6.0软件仿真平台。本文主要描述了出租车计费器的设计思路与模块划分。把出租车计费器划分为两大模块,共同实现了出租车计费以及预置和模拟汽车启动、停止、暂停等功能,并动态扫描显示车费数目。最后,使用Quartus II6.0仿真平台对每个模块和主程序分别进行了仿真,并对仿真出来的波形作了分析。
Verilog HDL和VHDL是目前世界上最流行的两种硬件描述语言(HDL:Hardware Description Language),均为IEEE标准,被广泛地应用于基于可编程逻辑器件的项目开发。二者都是在20世纪80年代中期开发出来的,前者由Gateway Design Automation公司(该公司于1989年被Cadence公司收购)开发,后者由美国军方研发。
HDL语言以文本形式来描述数字系统硬件结构和行为,是一种用形式化方法来描述数字电路和系统的语言,可以从上层到下层来逐层描述自己的设计思想。即用一系列分层次的模块来表示复杂的数字系统,并逐层进行验证仿真,再把具体的模块组合由综合工具转化成门级网表,接下去再利用布局布线工具把网表转化为具体电路结构的实现。目前,这种自顶向下的方法已被广泛使用。
本次设计的目的就是在掌握计算机组成原理理论的基础上,了解EDA技术,掌握Verilog HDL硬件描述语言的设计方法和思想,通过学习的Verilog HDL语言结合电子电路的设计知识理论联系实际,掌握所学的课程知识,通过本课程设计,达到巩固和综合运用计算机原理中的知识,理论联系实际,巩固所学理论知识,并且提高自己通过所学理论分析、解决计算机实际问题的能力。
通过这次EDA方面的课程设计,可以提高我们对EDA领域及通信电路设计领域的认识,有利于培养我们在通信电路EDA方面的设计能力。特别有利于锻炼我们独立分析问题和解决问题的能力。设计过程的复杂加老师的严格要求有益于培养我们严谨的工作作风。
目录
一、Verilog HDL语言的功能、设计方法及Quartus II6.0设计流程 1
1.1 Verilog HDL语言的功能、设计方法 1
1.2 Quartus II6.0设计流程 2
二、整体设计方案 3
2.1设计要求 3
2.2设计原理 3
2.3电路符号 3
2.4设计方法 4
三、上机步骤及模拟仿真 4
3.1新建第一个工程 4
3.2生成一个控制模块 5
3.3新建第二个工程 5
3.4生成译码显示模块 6
3.5新建第三个工程 6
3.6进入仿真界面 7
3.7赋值及仿真 8
四、试验箱实物模拟 10
4.1管脚配置选择 10
4.2选择线箱blatterfally11 10
4.3试验箱效果验证 11
五、课程设计及工作进程 12
六、参考文献 12
七、实验总结 12
八、附录实验代码清单 12
8.1控制模块实验代码清单 13
8.2译码显示模块实验代码清单 16
20 / 23
一、 Verilog HDL语言的功能、设计方法及Quartus II6.0设计流程
1.1 Verilog HDL语言的功能、设计方法
Verilog HDL语言以文本形式来描述数字系统硬件结构和行为,是一种用形式化方法来描述数字电路和系统的语言,可以从上层到下层来逐层描述自己的设计思想。即用一系列分层次的模块来表示复杂的数字系统,并逐层进行验证仿真,再把具体的模块组合由综合工具转化成门级网表,接下去再利用布局布线工具把网表转化为具体电路结构的实现。目前,这种自顶向下的方法已被广泛使用。Verilog HDL既是一种行为描述语言,也是一种结构描述语言。如果按照一定的规则和风格编写代码,就可以将功能行为模块通过工具自动转化为门级互连的结构模块。这意味着利用Verilog语言所提供的功能,就可以构造一个模块间的清晰结构来描述复杂的大型设计,并对所需的逻辑电路进行严格的设计。下面列出的是Verilog语言的主要功能:
(1) 可描述顺序执行或并行执行的程序结构;
(2) 用延迟表示式或事件表达式来明确地控制过程的启动时间;
(3) 通过命名的事件来触发其他过程里的激活行为或停止行为;
(4) 提供了条件和循环等程序结构;
(5) 提供了可带参数且非零延续时间的任务程序结构;
(6) 提供了可定义新的操作符的函数结构;
(7) 提供了用于建立表达式的算术运算符、逻辑运算符和位运符;
(8) 提供了一套完整的表示组合逻辑基本元件的原语;
(9) 提供了双向通路和电阻器件的描述;
(10)可建立MOS器件的电荷分享和衰减模型;
(11)可以通过构造性语句精确地建立信号模型;
Verilog HDL设计方法:
1.自下而上的设计方法
自下而上的设计是传统的设计方法,是从基本单元出发,对设计进行逐层划分的过程。这种设计方法与用电子元件在模拟实现板上建立一个系统的步骤有密切的关系。优、缺点分别如下:
优点:设计人员对这种设计方法比较熟悉;实现各个子模块所需的时间较短。
缺点:对系统的整体功能把握不足;由于必须先对多个子模块进行设计,因此实现整个系统的功能所需的时间长;另外,对设计人员之间相互协作也有较高的要求。
2.自上而下的设计方法
自上而下的设计是从系统级开始,把系统划分为基本单元,然后再把基本单元划分为下一层次的基本单元,直到可用EDA元件实现为止。这种方法的优、缺点如下。
优点:在设计周期开始就做好了系统分析;由于设计的主要仿真和调试过程是在高层完成的,所以能够早期发现结构设计上的错误,避免了设计工作的浪费,方便了系统的划分和整个项目的管理,可减少设计人员劳动,避免了重复设计。
缺点:得到的最小单元不标准,且制造成本高。
3.混合的设计方法
复杂数字逻辑电路和系统设计过程,通常是以上两种设计方法的结合。设计时需要考虑多个目标的综合平衡。在高层系统用自上而下的设计方法实现,而使用自下而上的方法从库元件或以往设计库中调用已有的设计单元。混合设计方法兼有以上两种方法的优点,并且可使用先进的矢量测试方法。
1.2 Quartus II6.0设计流程
(1)设计输入:可以采用原理图输入、HDL语言描述及波形输入等几种方式。
(2)编译:先根据设计要求设定编译参数和编译策略,如器件的选择、逻辑综合方式的选择等。然后根据设定的参数和策略对设计项目进行逻辑综合和器件适配,并产生报告文件、延时信息文件及编程文件,供分析仿真和编程使用。
(3)仿真:仿真包括功能仿真、时序仿真和定时分析,可以利用软件的仿真功能来验证设计项目的逻辑功能是否正确。
(4)编程与验证:用经过仿真确认后的编程文件通过编程器(Programmer)将设计下载到实际芯片中,最后测试芯片在系统中的实际运行性能。
在设计过程中,如果出现错误,则需重新回到设计输入阶段,改正错误或调整电路后重复上述过程。
二、 整体设计方案
2.1 设计要求
(1)实现计费功能,计费标准为:按行驶里程计费,起步价为6.00元,并在车行驶3km后按1.2元/km计费,当计费器达到或超过20元时,每千米加收50%的车费,车辆停止和暂停时不计费。
(2)现场模拟汽车的启动、停止、暂停、换挡等状态。
(3)设计数码管动态扫描电路,将车费和路程显示出来,各有两位小数。
2.2 设计原理
设计该出租车有启动键,停止键,暂停键和档位键。启动键为脉冲触发信号,当其为一个脉冲时,表示车已经启动,并根据车速的选择和基本车速发出相应频率的脉冲(计费脉冲)以此来实现车费和路程的计数,同时车费显示起步价;当停止键为高电平时,表示汽车熄火,同时停止发出脉冲,此时车费和路程计数清零;当暂停键为高电平时,表示汽车暂停并停止发出脉冲,此时车费和路程计数暂停;档位键用于改变车速,不同的档位对应着不同的车速,同时路程计数的速度也不同。
该出租车计费器分为两大模块,即控制模块和译码显示模块。系统框架图如图1所示,控制模块实现了计费和路程的计数,并且通过不同的档位来控制车速。译码显示模块实现十进制数到4位十进制数的转换,以及车费和路程的显示。
计费时钟
控制模块
显示模块
档位
停止
暂停
启动
图1:系统框图
2.3 电路符号
出租车计费器的电路符号如图2所示。输入信号:计费时钟脉冲clk;译码高频时钟clk20mhz;汽车启动键start;汽车停止键stop;汽车暂停键pause;档位speedup[1..0]。输出信号:数码管地址选择信号费用m_one[3..0],m_ten[3..0]
m_hun[3..0], m_tho3..0];路程d_ one[3..0], d_ ten[3..0], d_ hun[3..0],
d_ tho[3..0]
图2 计费器的电路符号
2.4 设计方法
自底向上的混合编辑 采用混合编辑法,设计不同的模块,最后在原理图编辑器中连接各模块作为顶层设计,其电路如图3所示,其中guange1是控制模块,guange2是译码显示模块。
图3 出租车计费器电路图
三、上机步骤及模拟仿真
3.1 新建第一个工程,命名为guange1并选择如图所示芯片,分别如图4和图5所示。
图4 新建工程1 图5 选择相应芯片
3.2 选择使用Verilog HDL File语言输入控制模块代码运行成功以后点击creat/update生成一个控制模块,如图6所示。
图7 生成的控制模块
3.3新建第二个工程,命名为guange2并选择如图所示芯片,分别如图8和图9所示。
图8新建工程2 图9 选择相应芯片
3.4选择使用Verilog HDL File语言输入控制模块代码运行成功以后点击creat/update生成一个译码显示模块,如图10所示。
图10 生成的译码显示模块
3.5 新建第三个工程,并命名为guange3,选择相应的芯片。将第一个工程及第二个工程产生的文件放入第三个工程的文件夹中,新建Block Diagram/Schematic File文件,分别调用控制模块和译码显示模块,调用输入和输出端将电路图连接如图11所示。
图11 整体电路图
3.6 选择Vector Waveform File 并调用所有输入和输出端进入仿真界面,分别如图12、图13和图14所示。
图12选择Vector Waveform File
图13 调用所有输入和输出端
图14 进入仿真页面
3.7 分别对clk和高频clk1进行赋值如图15和图16所示,并给start一个高电平,间隔一段时间再给pause赋值一个高电平,给speedup赋值一个2档的电平。其仿真结果如图17所示。
图15 给clk赋值 图16 给clk1赋值
图17 仿真结果
结合前面各模块的输入、输出端功能介绍和各模块仿真图像说明,可以看出,该综合模块正常运行。换成十进制显示以后可以看出,起步价为6.00元,距离为3公里时,费用变为7.20元,距离为4公里时,费用为8.40元,符合预期逻辑,具有可行性。
四、 实验箱实物模拟
4.1 点击assignments-pin planner进行管脚配置选择,如图18所示
图18 管脚配置选择
4.2 点击programmer选择线箱blatterfally11,如图19所示。
图19选择线箱blatterfally11
4.3点击start将程序导入线箱中,进行效果验证,结果如图20和图21所示所示。
图20 试验箱实物模拟
如上图所示,数码管的前四位表示的是出租车的计数费用,6表示的是起步价6元钱,后两位是小数点;数码管的后四位表示的是出租车的行驶路程,后两位是小数点,15表示的是0.15公里,其逻辑符合预期功能,利用换挡键可实现不同档位的行驶速度,按下pause键,路程和费用暂停计数,按下stop键,路程和费用清零。其逻辑符合预期功能。
图21 试验箱实物模拟
如上图所示,当路程为17.51km时,计数费用为25.80元,符合预期设计效果
五、 课程设计工作进程
5.1 设计小组的分工及工作安排
管水城:主要负责该命题的确立及该实验框架的构思设计,模块的的设计,实验代码的设计与修改,试验箱实物模拟。
欧阳慧:主要负责资料的收集及代码的书写与修改,各模块图的仿真。
5.2 设计中遇到的问题以及解决方法:在控制模块和译码显示模块分别仿真成功以后,连接两模块并进行综合仿真出现的主要问题是计费输出无信号,不能达到预期的出租车的计费效果,在老师的指导下,在仿真界面中,我们调用了insert monery输出端,最终达到了预期的设计效果。
六、 参考文献
《基于QuartusII的数字系统Verilog HDL设计实例详解》 周润景,苏良碧编著,电子工业出版社,2010年5月出版。
七、 实验总结
本次课程设计要求基于可编程逻辑器件,使用硬件描述语言Verilog HDL编写一个出租车计费器控制器芯片,并用Quartus II6.0软件平台进行仿真。根据自己对出租车从启动计费到停车过程的理解,其过程可描述为预置、模拟汽车启动、停止、暂停等功能,并动态扫描显示车费数目。由此必需设计出2个大的模块:一是控制模块,此模块控制汽车的加速或匀速状态;二是动态里程显示模块,此模块的主要功能是随时显示车行的路程和计数费用。
在整个设计过程当中,首先要根据模块设计所要达到的要求编写源代码,在编写完后编译的过程中经常会出现程序编译错误。根据系统提示,我找到了错误的位置,然后查询错误的原因。通过和同学探讨,或者请教老师,所有的问题都一一解决了
在整个电路设计完毕并仿真成功后发现,其实整个电路设计实现的功能还是比较实用和易于操作的,而自己也为此付出了许多:从根据课题要求查找相关资料,学习硬件语言,到自己能够独立编写小程序;从对Quartus II6.0软件平台的摸索,一次次修改程序,到仿真得到较满意的结果;在设计过程中遇到了很多困难,在指导老师的指引和同学的帮助下,通过不断探索学习,使问题得到了一定的解决。终于使出租车计费器各模块的功能正常运行,仿真成功,进而,整个计费器系统成功仿真运行成功。
通过这两个星期的课程设计的学习,我从中学习到了很多,对可编程逻辑器件,Verilog HDL语言,Quartus II6.0软件平台有了一定的了解,尤其是用Verilog HDL语言编程和仿真。在本次设计中最大的收获是在不断地发现问题,分析问题,解决问题的过程中培养了自己的科研能力,为今后的学习和工作积累了一定的经验。
八、 附录实验代码清单
8.1控制模块实验代码清单
Module guange1(money,distance,clk,start,stop,pause,speedup);
input clk; //记费时钟
input start; //汽车启动
input stop; //汽车停止
input pause; //汽车暂停
input[1:0] speedup; //挡位(4个挡位)
output[12:0] money; //车费
output[12:0] distance;//路程
reg[12:0] money;
reg[12:0] distance;
reg[12:0] money_reg; //车费寄存器
reg[12:0] distance_reg;//路程寄存器
reg[3:0] num; //控制车速的记数器
reg[12:0] dis; //千米记数器
reg d;
always@(posedge clk)
begin
if(stop) //汽车停止,记费和路程清零
begin money_reg<='d0;
distance_reg<='d0;
dis<='d0;
num<='d0;
end
else if(start) //启动后,起步价为6块钱
begin money_reg<='d6;
distance_reg<='d0;
dis<='d0;
num<='d0;
end
else
begin
if(!start&&!speedup&&!pause&&!stop) //1档
begin
if(num=='d9)
begin num<='d0;
distance_reg<=distance_reg+1;
dis<=dis+1;
end
else
begin num<=num+1;end
end
else if(!start&&speedup=='b01&&!pause&&!stop) //2档
begin
if(num=='d9)
begin num<='d0;
distance_reg<=distance_reg+2;
dis<=dis+2;
end
else
begin num<=num+1;end
end
else if(!start&&speedup=='b10&&!pause&&!stop) //3档
begin
if(num=='d9)
begin num<='d0;
distance_reg<=distance_reg+5;
dis<=dis+5;
end
else
begin num<=num+1;end
end
else if(!start&&speedup=='b11&&!pause&&!stop) //4档
begin
distance_reg<=distance_reg+1;
dis<=dis+1;
end
end
if(dis>='d100)
begin d<='d1;dis<='d0;end
else
begin d<='d0;end
if(distance_reg>='d300) //如果超过3公里,按照1.2元每公里计算
begin
if(money_reg<'d2000&&d=='d1)
begin money_reg<=money_reg+'d12;end
else if(money_reg>='d2000&&d=='d1) //当记费器达到一个20元时,每公里加收50%的车费
begin money_reg<=money_reg+'d18;end
end
money<=money_reg;
distance<=distance_reg;
end
endmodule
8.2译码显示模块实验代码清单
module guange2(clk1,money_in,distance_in,m_one,m_ten,m_hun,m_tho,d_one,d_ten,d_hun,d_tho);
//output[7:0]scan;
//output[6:0]seg7;
//output dp;
output[3:0] m_one,m_ten,m_hun,m_tho;
output[3:0] d_one,d_ten,d_hun,d_tho;
input clk1;
input[12:0] money_in;
input[12:0] distance_in;
//reg[7:0] scan;
//reg[6:0] seg7;
//reg dp;
reg clk2;
//reg[3:0] comb1_a,comb1_b,comb1_c,comb1_d,omb2_a,comb2_b,comb2_c,comb2_d;
reg[3:0] m_one,m_ten,m_hun,m_tho;
reg[3:0] d_one,d_ten,d_hun,d_tho;
reg[15:0] count;
reg[15:0] comb1;
reg[3:0] comb1_a,comb1_b,comb1_c,comb1_d;
reg[15:0] comb2;
reg[3:0] comb2_a,comb2_b,comb2_c,comb2_d;
//reg[2:0] cnt;
always @(posedge clk1)
begin
//if(count=='d10000)
//begin clk2<=~clk2;count<='d0;end
//else
//begin count<=count+1;end
if(comb1<money_in)
begin
if(comb1_a=='d9&&comb1_b=='d9&&comb1_c=='d9)
begin
comb1_a<='b0000;
comb1_b<='b0000;
comb1_c<='b0000;
comb1_d<=comb1_d+1;
comb1<=comb1+1;
end
else if(comb1_a=='d9&&comb1_b=='d9)
begin
comb1_a<='b0000;
comb1_b<='b0000;
comb1_c<=comb1_c+1;
comb1<=comb1+1;
end
else if(comb1_a=='d9)
begin
comb1_a<='b000;
comb1_b<=comb1_b+1;
comb1<=comb1+1;
end
else
begin
comb1_a<=comb1_a+1;
comb1<=comb1+1;
end
end
else if(comb1==money_in)
begin
m_one<=comb1_a;
m_ten<=comb1_b;
m_hun<=comb1_c;
m_tho<=comb1_d;
end
else if(comb1>money_in)
begin
comb1_a<='b0000;
comb1_b<='b0000;
comb1_c<='b0000;
comb1_d<='b0000;
comb1<='d0;
end
if(comb2<distance_in)
begin
if(comb2_a=='d9&&comb2_b=='d9&&comb2_c=='d9)
begin
comb2_a<='b0000;
comb2_b<='b0000;
comb2_c<='b0000;
comb2_d<=comb2_d+1;
comb2_a<=comb2+1;
end
else if(comb2_a=='d9&&comb2_b=='d9)
begin
comb2_a<='b0000;
comb2_b<='b0000;
comb2_c<=comb2_c+1;
comb2<=comb2+1;
end
else if(comb2_a=='d9)
begin
comb2_a<='b0000;
comb2_b<=comb2_b+1;
comb2<=comb2+1;
end
else
begin
comb2_a<=comb2_a+1;
comb2<=comb2+1;
end
end
else if(comb2==distance_in)
begin
d_one<=comb2_a;
d_ten<=comb2_b;
d_hun<=comb2_c;
d_tho<=comb2_d;
end
else if(comb2>distance_in)
begin
comb2_a<='b0000;
comb2_b<='b0000;
comb2_c<='b0000;
comb2_d<='b0000;
comb2<='d0;
end
end
endmodule
展开阅读全文