南昌大学eda实验报告

更新时间:2024-05-06 11:12:01 阅读量: 综合文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

实 验 报 告

课程名称: EDA技术实用教程 指导老师: 学生姓名:

学 号:

专业班级: 通信工程134班

2015年 12月 7 日

目 录

实验一、全加器设计实验 实验二、模可变计数器设计实验 实验三、序列信号发生和检测器设计实验 实验四、交通灯控制器设计实验 实验五、多功能数字钟设计实验 实验六、出租车计费器设计实验 本课程总结

一、全加器设计实验

(一)实验目的

1、熟悉建立文件夹和建立工程的整个过程。 2、学会建立波形文件。

3、学会将文件下载到板子上。 (二)设计要求

完成设计、仿真、调试、下载、硬件测试等环节,在EDA实验装置上实现模可变计数器功能,具体要求如下:

1、利用书上的程序,完成实验目的,实现两个一位二进制数的相加,并将进位输出。

(三)主要仪器设备

1、微机 1台 2、QuartusII集成开发软件 1套 3、EDA实验装置 1套 (四)实验思路

由于要用到例化语句,所以需要将文件都放在一个文件夹里然后创建工程。选择文件夹和名称。

添加文件

选择实验室用的芯片

选择仿真工具

半加器真值表如下 A B SO CO 0 0 0 0 0 1 1 0 1 0 1 0 1 1 0 1 其中A和B为输入信号,SO为和值输出,CO为进位输出。程序如下。 module banjia(A,B,SO,CO); input A,B; output SO,CO; assign SO=A^B; assign CO=A&B; Endmodule

由真值表可得输入信号A和B异或可作为和值输出,相与可作为进位输出。

全加器真值表如下 Ain Bin Cin Cout Sum 0 0 0 0 0 0 1 0 0 1 1 0 0 0 1 1 1 0 1 0 0 0 1 0 1 0 1 1 1 0 1 0 1 1 0 1 1 1 1 1 ain和bin为输入信号,cin为进位信号与ain和bin一起相加,cout为进位出书,sum为和值输出。程序如下。

module quanjia(ain,bin,cin,cout,sum); output cout,sum; input ain,bin,cin; wire net1,net2,net3;

banjia U1(ain,bin,net1,net2);

banjia U2(.A(net1),.SO(sum),.B(cin),.CO(net3)); or U3(cout,net2,net3); Endmodule

这里用了例化语句调用了一个半加器的模块让ain与bin通过半加器的相加之后的和值net1作为一个输入信号再与进位信号cin相加作为和值sum,ain与bin相加产生的进位信号net2和ain与bin的和值net1与cin相加产生的进位信号net3相或作为整体的进位输出cout,便可完成真值表的要求。 (五)时序仿真 添加文件

添加引脚

然后对输入信号进行赋值,赋值为周期性信号。编译后保存。

仿真后效果如下

将程序烧入板子如下

(六)实验总结

因为这个是第一次进EDA实验室,对软件硬件都不了解。遇到很多的简单问题,也就是操作上的不熟练。对照书本上的步骤一步一步操作,才能完成。真应该加强动手能力。通过这次实验理解了全加器的原理和例化语句的使用,初步对EDA实验产生了兴趣。

二、模可变计数器设计

(一) 实验目的

1、进一步熟悉实验装置和QuartusⅡ软件的使用; 2、进一步熟悉和掌握EDA设计流程; 3、学习简单组合、时序电路的EDA设计;

4、学习计数器中二进制码到BCD码的转换技巧; 5、学习实验装置上数码管的输出方法。 (二) 设计要求

完成设计、仿真、调试、下载、硬件测试等环节,在EDA实验装置上实现模可变计数器功能,具体要求如下:

按键按下时模为10-99之间(具体数值自行1、设置一个按键控制改变模值,

确定)的数,没按下时模为100-199之间(具体数值自行确定)的数; 2、计数结果用三位数码管十进制显示。

(三) 主要仪器设备 1、微机 1台 2、QuartusII集成开发软件 1套 3、EDA实验装置 1套 (四) 实验思路 总体程序如下

module jishuqi (CLK,rst,M,SG,en,q,d); input CLK,rst,en; input M; output SG; reg[7:0] cnt; reg clk1; reg[7:0] SG; reg sel;

output reg[11:0] q; reg[11:0] model; reg[3:0] a; output reg d;

wire[3:0] gw,sw,bw; assign gw[3:0]=q[3:0]; assign sw[3:0]=q[7:4]; assign bw[3:0]=q[11:8]; always @(M) if (M) model=12'b000000110000; else model=12'b000100000000; always @(posedge CLK) begin

cnt=cnt+1; if (cnt==200) begin clk1=1'b1; cnt=0; end

else clk1=1'b0; if (sel<2) sel=sel+1; else sel=0; end

always @(posedge CLK or negedge rst) begin if(!rst) q=0;else if(en) begin if(q

if (gw==9) begin q=q+7; if (sw==9) q=q+96; end else q=q+1; end else q=0;end end always @(q) begin

if(q

0:SG<=8'b00111111; 1:SG<=8'b00000110; 2:SG<=8'b01011011; 3:SG<=8'b01001111; 4:SG<=8'b01100110; 5:SG<=8'b01101101; 6:SG<=8'b01111101; 7:SG<=8'b00000111; 8:SG<=8'b01111111; 9:SG<=8'b01101111; default: SG=8'b11111111; endcase end endmodule

分频模块

分频模块由时钟频率的分频作为计数脉冲,每200个系统脉冲有一个技术脉冲,同时可以利用系统脉冲进行循环选择SEL来进行循环扫码。程序如下 always @(posedge CLK) begin cnt=cnt+1; if (cnt==200) begin clk1=1'b1; cnt=0; end

else clk1=1'b0; if (sel<2) sel=sel+1; else sel=0;

选择模块由M选择,M为1时模是30,M为0时模为100。 always @(M) if (M) model=12'b000000110000; else model=12'b000100000000; 计数模块

计数模块如下,由于q为16进制数,我们需要的输出为BCD码,故进行调整。平常时q来一个脉冲加1,当加到个位为9时,也就是1001,将其加7变为16也就是0,实现了个位由9到0的BCD计数,同时也会向十位进1。当十位和个位同时,为9时,再加上个位向十位进的1就是加7,q位加96也就是十位加6,

十位会清零同时个位也会清零,同时向百位进1,实现了正常的十进制BCD码计数。Rst则为清零信号,en为使能信号。 always @(posedge CLK or negedge rst) begin if(!rst) q=0;else if(en) begin if(q

if (gw==9) begin q=q+7; if (sw==9) q=q+96; end else q=q+1; end else q=0;end End

当计数到顶后有个标志位d标志是否计到顶。 always @(q) begin

if(q

循环扫码模块如下,由于sel的变化频率和系统时钟相同,所以肉眼辨别不出来在跳动,可以通过其分别选择数码管并将个位十位百位呈现在数码管上,同时配

有译码程序。 always @(sel) begin case (sel) 0: a=bw; 1: a=sw; 2: a=gw; default: a=0; endcase case (a)

0:SG<=8'b00111111; 1:SG<=8'b00000110; 2:SG<=8'b01011011; 3:SG<=8'b01001111; 4:SG<=8'b01100110; 5:SG<=8'b01101101; 6:SG<=8'b01111101; 7:SG<=8'b00000111;

(五) 实验截图

仿真时用CLK代替分频频率便于观察.总体图

Rst可以实现计数的清零。

当M为1时实现了模30的计数,同时标志位为1

当M为0时实现了模100的计数,同时标志位为1

使能信号en为0时计数保持不变

(六) 实验总结

初步进行了自己设计程序和仿真一系列工作,加深了对设计过程和语句使用的理解。进而对软硬件的操作使用都有了进一步的熟练,遇到的基础问题也能想办法去解决了,不像第一次那样手足无措了。语法语句也大概有了了解。

三、序列信号发生和检测器设计

(一) 实验目的

1、 进一步熟悉EDA实验装置和QuartusⅡ软件的使用方法; 2、

3、

(二) 设计要求

完成设计、仿真、调试、下载、硬件测试等环节,在EDA实验装置上实现一个串行序列信号发生器和一个序列信号检测器的功能,具体要求如下:

其最后6BIT数据用LED1、 先用设计011101101100100100序列信号发生器,

显示出来;

2、 再设计一个序列信号检测器,检测上述序列信号,若检测到串行序列“110110”则输出为“1”,否则输出为“0”;

(三) 主要仪器设备 1、微机 1台 2、QuartusII集成开发软件 1套 3、EDA实验装置 1套

(四) 实验思路

首先画出状态转移图

学习有限状态机法进行数字系统设计; 学习使用原理图输入法进行设计。

总体程序如下

module xulieji2(clk,rst,en,date,SOUT);

parameter s0=1,s1=2,s2=3,s3=4,s4=5,s5=6,s6=7; input clk,rst,en; output date,SOUT; wire SOUT; reg[8:0] cnt; reg[6:0] ST,NST; reg[5:0] date; reg[16:0] sdate;

assign SOUT=(NST==s6);

always @ ( posedge clk or negedge rst ) begin if(!rst) begin ST<=s0; date<=6'b000000; sdate<=17'b011101101100100100; cnt<=16;end else if(en) begin ST<=NST; date[5:1]<=date[4:0]; date[0]<=sdate[cnt]; cnt<=cnt-1;;end else cnt<=0; case(ST) s0: begin if(date[0]==1'b1) NST<=s1;else NST<=s0;end s1: begin if(date[0]==1'b1) NST<=s2;else NST<=s0;end s2: begin if(date[0]==1'b0) NST<=s3;else NST<=s2;end s3: begin if(date[0]==1'b1) NST<=s4;else NST<=s0;end s4: begin if(date[0]==1'b1) NST<=s5;else NST<=s0;end s5: begin if(date[0]==1'b0) NST<=s6;else NST<=s2;end s6: begin if(date[0]==1'b0) NST<=s0;else NST<=s4;end default: NST<=s0; endcase end endmodule

这里用到了状态机技术,状态机可以方便的设置程序满足什么条件然后

去往什么状态,利用状态机可以实现检测到110110时的状态,同时可以在不满足时准确的调往正确的状态以便于下一步的判断。

状态机简写为FSM(Finite State Machine),主要分为2大类:第一类,若输出只和状态有关而与输入无关,则称为Moore状态机;第二类,输出不仅和状态有关而且和输入有关系,则称为Mealy状态机。要特别注意的是,因为Mealy状态机和输入有关,输出会受到输入的干扰,所以可能会产生毛刺(Glitch)现象,

使用时应当注意。事实上现在市面上有很多EDA工具可以很方便的将状态图的描述转换成可以综合的程序代码。

状态机可归纳为4个要素,即现态、条件、动作、次态。这样的归纳,主要是出于对状态机的内在因果关系的考虑。“现态”和“条件”是因,“动作”和“次态”是果。详解如下:

①现态:是指当前所处的状态。 ②条件:又称为“事件”,当一个条件被满足,将会触发一个动作,或者执行一次状态的迁移。

③动作:条件满足后执行的动作。动作执行完毕后,可以迁移到新的状态,也可以仍旧保持原状态。动作不是必需的,当条件满足后,也可以不执行任何动作,直接迁移到新状态。

④次态:条件满足后要迁往的新状态。“次态”是相对于“现态”而言的,“次态”一旦被激活,就转变成新的“现态”了。 赋值模块

parameter s0=1,s1=2,s2=3,s3=4,s4=5,s5=6,s6=7; input clk,rst,en; output date,SOUT; wire SOUT; reg[8:0] cnt; reg[6:0] ST,NST; reg[5:0] date; reg[16:0] sdate;

assign SOUT=(NST==s6);

s1到s6为状态机的不同状态,clk为控制序列输入的信号,rst为清零信号,en为使能信号,SOUT为检测到序列110110时的输出信号1,cnt为控制哪一位数据进行检测的数,ST和NST为状态机现在的状态和下一时刻将要到来的状态,

当检测到状态为s6时,通过assign date为检测到的6为数据,sdate为输入序列,

SOUT=(NST==s6)可以让SOUT输出为1. 输入序列模块

always @ ( posedge clk or negedge rst ) begin if(!rst) begin ST<=s0; date<=6'b000000; sdate<=17'b011101101100100100; cnt<=16;end else if(en) begin ST<=NST; date[5:1]<=date[4:0]; date[0]<=sdate[cnt]; cnt<=cnt-1;;end else cnt<=0;

Clk为序列输入信号,rst为清零信号,rst为低电平时将初始状态设为s0,初始6位待检测数据为000000,17位输入序列为011101101100100100,先从最高位从

左往右输入,所以cnt开始时为16。en为使能信号,当en为1时可以将下一状态NST赋予现在状态ST,同时将序列进行移位,待检测信号进行输入,同时cnt减1指向下一数据。如果en为0,则保持现在的状态不进行工作。 状态转移模块 case(ST) s0: begin if(date[0]==1'b1) NST<=s1;else NST<=s0;end s1: begin if(date[0]==1'b1) NST<=s2;else NST<=s0;end s2: begin if(date[0]==1'b0) NST<=s3;else NST<=s2;end s3: begin if(date[0]==1'b1) NST<=s4;else NST<=s0;end s4: begin if(date[0]==1'b1) NST<=s5;else NST<=s0;end s5: begin if(date[0]==1'b0) NST<=s6;else NST<=s2;end s6: begin if(date[0]==1'b0) NST<=s0;else NST<=s4;end default: NST<=s0; endcase end Endmodule

通过这个状态转移语句可以正确的实现检测到110110便可使状态到达s6,即便序列为110110110时也是可以的,原理附状态转移图。 (五) 时序仿真

可以清楚的看出,当检测到110110序列时sout便为1,即便是连续的110110110也可以检测出来,证明了这个程序的正确性。 (六) 实验总结

要求画出状态转移图,我把书上的状态机部分仔细阅读,参考了书上的程序编写了这个程序,一开始检查的时候不符合要求,后来检查是状态转移图弄错了,修改之后进行仿真,便得到了正确的结果。状态机在EDA的程序设计中应用广泛。经过这次实验深刻掌握了状态机技术和状态转移图的画法,进一步激发了我对eda的兴趣。

四、 交通灯控制器设计

(一) 实验目的 1、 2、

学习与日常生活相关且较复杂数字系统设计;

进一步熟悉EDA实验装置和QuartusⅡ软件的使用方法;

3、 学习二进制码到BCD码的转换; (二) 设计要求

完成设计、仿真、调试、下载、硬件测试等环节,在型EDA实验装置上实现一个由一条主干道和一条乡间公路的汇合点形成的十字交叉路口的交通灯控制器功能,具体要求如下:

、MY(主黄)、MG(主绿)、CR(乡红)、CY(乡黄)、1、 有MR(主红)

CG(乡绿)六盏交通灯需要控制; 2、

交通灯由绿转红前有4秒亮黄灯的间隔时间,由红转绿没有间隔时间;

3、 乡间公路右侧各埋有一个串连传感器,当有车辆准备通过乡间公路时,发出请求信号S=1,其余时间S=0;

4、 平时系统停留在主干道通行(MGCR)状态,一旦S信号有效,经主道黄灯4秒(MYCR)状态后转入乡间公路通行(MRCG)状态,但要保证主干道通行大于一分钟后才能转换;

5、 一旦S信号消失,系统脱离MRCG状态,即经乡道黄灯4秒(MRCY)状态进入MGCR状态,即使S信号一直有效,MRCG状态也不得长于20秒钟; 6、 控制对象除红绿灯之外,还包括分别在主干道和乡间公路各有一个两位十进制倒计时数码管显示。 (三) 主要仪器设备 1、微机 1台 2、QuartusII集成开发软件 1套 3、EDA实验装置 1套 (四) 实验思路 总体程序如下

程序大体分为S=1与S=0的情况,不同情况对应不同处理方法,每一次COUNTER均为0时根据S的1和0来改变数码管的计数的灯的情况,具体原理在注释中有。 module jiaotong (S,clk,LED,COUNTER,LED1,sel); input clk;

reg CPB; //时钟 input S;

output [2:0] sel;

reg [2:0] sel; //指明乡村路口是否有汽车的通行信号 reg [3:0]a;

output [5:0] LED; //信号灯的显示 output [7:0] LED1; //显示时间的十位 output [8:0] COUNTER; //数码的显示 reg [5:0] LED;

reg [7:0] COUNTER; reg [7:0] LED1;

reg [35:0]i; reg flag1; reg flag2;

reg [7:0] cnt; initial begin

flag2='b0; flag1='b0;

COUNTER[7:0]='D60;

LED[5:0]<=6'b001100; //主干道是绿灯乡村道是红灯 end

always @(posedge clk) begin cnt=cnt+1;

if (cnt==1000) begin CPB=1'b1; cnt=0; end else CPB=1'b0; end

always @(posedge clk) begin

if (sel<1) sel=sel+1; else sel=0; end //sel为数码管选择 always @(posedge clk) begin

if(COUNTER[3:0]==4'D0 && COUNTER[7:4]==4'D0) //在数码管是60时判断

是否有信号s的出现

begin

if(S) //S为1即乡村想中断的情况下 begin

if(LED[5:0]==6'b001100) begin

LED[5:0]<=6'b010100; //表示主干道是黄灯而乡村是红

COUNTER[7:4]<=4'D0; //显示的是4秒钟 COUNTER[3:0]<=4'D4; end

else if(LED[5:0]==6'b010100) //表示4秒钟过后的乡村开始通

路了

begin

LED[5:0]<=6'b100001; //表示主干道是红灯而乡村是绿

COUNTER[7:4]<=4'D2; //显示的是20秒钟 COUNTER[3:0]<=4'D0; flag1=1'b1; end

else if(LED[5:0]=='b100001) //表示20秒过后主干道通行了

begin

LED[5:0]<='b100010; //表示主干道是红灯而

乡村是黄灯

COUNTER[7:4]<=4'D0; //显示的是4秒钟 COUNTER[3:0]<=4'D4; flag1='b0; end

else if(LED[5:0]=='b100010) begin

LED[5:0]<='b001100; //主干道是绿灯乡村道是

红灯

COUNTER[7:4]<=4'D6; //显示的是60秒钟 COUNTER[3:0]<=4'D0; end end else //S为0即乡村不想中断的情况下 begin

if(LED[5:0]=='b010100) //表示4秒钟过后的乡村开始通路了 begin

LED[5:0]<='b100001; //表示主干道是红灯而乡村是

绿灯

COUNTER[7:4]<=4'D2; //显示的是20秒钟 COUNTER[3:0]<=4'D0;

flag1=1'b1; //表示可以开始进行20秒的检查是否乡村 end

else if(LED[5:0]=='b100001) //表示20秒过后主干道可以通行

begin

LED[5:0]<='b100010; //表示主干道是红灯而乡村

是黄灯

COUNTER[7:4]<=4'D0; //显示的是4秒钟 COUNTER[3:0]<=4'D4; flag1='b0; end else if(LED[5:0]=='b100010) //表示4秒过后主干道通行了 begin

LED[5:0]<='b001100; //表示主干道是绿灯而乡村

是红灯

COUNTER[7:4]<=4'D6; //显示的是60秒钟 COUNTER[3:0]<=4'D0;end else

if(LED[5:0]=='b001100) begin

flag2='b1; //60秒过后才可以让乡村中断主干道 LED[5:0]<='b001100;//主干道是绿灯乡村道是红灯 COUNTER[7:4]<=4'D6; //再次显示60秒钟 COUNTER[3:0]<=4'D0; end end end else

begin

if(S && (flag2=='b1)) //表示乡村道路有信号并且可以让乡村道路通行

了,乡村想中断

begin

LED[5:0]<='b010100; //表示主干道是黄灯而乡村是红灯 COUNTER[7:4]<=4'D0; //显示的是4秒钟 COUNTER[3:0]<=4'D4; flag2='b0; end else begin

if(COUNTER[3:0]==4'D0) //正常计数 begin

COUNTER[7:4]=COUNTER[7:4]-4'D1; COUNTER[3:0]=4'D9; end else

COUNTER[3:0]=COUNTER[3:0]-4'D1; end end if(flag1=='b1) begin //乡村不想绿灯了,想中断其20秒的绿灯

if(!S) begin

flag2='b0; flag1='b0;

LED[5:0]<='b100010; //表示主干道是红灯而乡村是黄灯 COUNTER[7:4]<=4'D0; //显示的是4秒钟 COUNTER[3:0]<=4'D4; end end end

always @(sel) begin case (sel)

0: a=COUNTER[7:4]; //1数码管为十位

1: a=COUNTER[3:0]; default: a=0; endcase case (a)

0:LED1[7:0]='b00111111; 1:LED1[7:0]='b00000110; 2:LED1[7:0]='b01011011; 3:LED1[7:0]='b01001111; 4:LED1[7:0]='b01100110; 5:LED1[7:0]='b01101101; 6:LED1[7:0]='b01111101; 7:LED1[7:0]='b00000111; 8:LED1[7:0]='b01111111; 9:LED1[7:0]='b01101111; default: LED1[7:0]=8'b11111111; endcase end

endmodule 赋值模块 input clk;

reg CPB; //时钟 input S;

output [2:0] sel;

reg [2:0] sel; //指明乡村路口是否有汽车的通行信号 reg [3:0]a;

output [5:0] LED; //信号灯的显示 output [7:0] LED1; //显示时间的十位 output [8:0] COUNTER; //数码的显示 reg [5:0] LED;

reg [7:0] COUNTER; reg [7:0] LED1; reg [35:0]i; reg flag1; reg flag2;

reg [7:0] cnt; initial begin

flag2='b0; flag1='b0;

COUNTER[7:0]='D60;

LED[5:0]<=6'b001100;

Clk为系统时钟1KHz,可以作为扫描频率,将其分频之后的CPB作为秒的计数频率,S为乡道是否想中断主道的信号,sel为循环扫描信号,LED为信号灯的显示,LED1为显示时间的十位,COUNTER为时间数码的显示。

Flag1和flag2的处理方法

当flag为1即在乡道20秒运行的过程中才为1,这时配合语句 if(flag1=='b1) begin //乡村不想绿灯了,想中断其20秒的绿灯

if(!S) begin

flag2='b0; flag1='b0;

LED[5:0]<='b100010; //表示主干道是红灯而乡村是黄灯 COUNTER[7:4]<=4'D0; //显示的是4秒钟 COUNTER[3:0]<=4'D4;

就是在这时一旦检测到S为0即乡道没车的时候,让乡道黄灯转入主道60秒的计时。

当flag2为1即在主道60之后才为1,这时配合语句

乡村 if(S && (flag2=='b1)) //表示乡村道路有信号并且可以让乡村道路通行了,

想中断

begin

LED[5:0]<='b010100; //表示主干道是黄灯而乡村是红灯 COUNTER[7:4]<=4'D0; //显示的是4秒钟 COUNTER[3:0]<=4'D4; flag2='b0; End

即S=1同时flag2为1时才可转入乡道的20秒计时。通过这两个信号正确地完成需要的功能。 分频模块

输出CPB为1秒的信号 always @(posedge clk) begin cnt=cnt+1;

if (cnt==1000) begin CPB=1'b1; cnt=0; end else CPB=1'b0; 数码管扫描模块

循环扫码模块如下,由于sel的变化频率和系统时钟相同,所以肉眼辨别不出来在跳动,可以通过其分别选择数码管并将个位十位百位呈现在数码管上,同时配有译码程序。

always @(sel) begin case (sel)

0: a=COUNTER[7:4]; //1数码管为十位 1: a=COUNTER[3:0]; default: a=0; endcase case (a)

0:LED1[7:0]='b00111111; 1:LED1[7:0]='b00000110;

2:LED1[7:0]='b01011011; 3:LED1[7:0]='b01001111; 4:LED1[7:0]='b01100110; 5:LED1[7:0]='b01101101; 6:LED1[7:0]='b01111101; 7:LED1[7:0]='b00000111; 8:LED1[7:0]='b01111111; 9:LED1[7:0]='b01101111; default: LED1[7:0]=8'b11111111; endcase end

endmodule

(五) 时序仿真 总体图

在主道开始60秒的计数过程中即使S为1也不会转入乡道运行

在主道60秒计数结束后可以转入乡道的20秒,在乡道的20秒过程中如果S为0则又返回主道计数

(六) 实验总结

这次实验是从EDA实验以来遇到的最复杂的代码,其中的if语句众多,而且嵌套也多,开始的时候摸不到头脑,编译的时候在这些语句上也是出错最多了。还好有一定的代码基础,我就在此基础上进行了一些修改和改进,仿真也非常的成功,去实验室进行烧程序进板子的时候,也很快。所以,这次实验的验收也很快。这也大大的促使我学习的动力,就想在下一次的实验中,学到更多。

五、 多功能数字钟设计

(一) 实验目的

1、 学习综合且较复杂数字系统设计; 2、

学习多层次、多模块数字系统设计;

3、 学习数码管扫描显示电路设计; (二) 设计要求

完成设计、仿真、调试、下载、硬件测试等环节,在型EDA实验装置上由简单到复杂实现多功能数字钟功能,具体要求如下: 1、 2、 3、 4、 5、 6、 7、

数码管扫描显示时、分、秒;

具有正常计时和调时、调分、调秒等校时功能; 经设置应具有整点报时功能; 经设置应具有跑表功能; 经设置应具有闹钟功能; 音乐闹钟功能;

液晶显示:年、月、日、时、分、秒、星期;

以下部分为扩展要求:

8、 自动闰年、闰月的万年历功能; (三) 主要仪器设备 1、微机 1台 2、QuartusII集成开发软件 1套 3、EDA实验装置 1套 (四) 实验思路

整个程序采用模块化的设计方法。 基本计数模块

整个程序采用BCD码计数,即每一位要显示的数据都用3位二进制数来表示。根据设计要求,技术模块应有模60,模24和模100的计数,可以用模10的模6的和模24的三个模块通过例化元件一步步实现,而且计数模块应具有计数清零和锁存的功能。

模10通过使能端en完成计数和锁存ncr清零,cp为计数脉冲,Q为数据输出。 module counter10(Q,nCR,EN,CP); input nCR,EN,CP; output [3:0] Q; reg [3:0] Q;

always @(posedge CP or negedge nCR) begin

if (~nCR) Q<=4'b0000; else if (~EN) Q<=Q;

else if ( Q==4'b1001) Q<=4'b0000; else Q<=Q+1'b1; end endmodule

模6原理与模10相同

module counter6(Q,nCR,EN,CP); input nCR,EN,CP; output [3:0] Q; reg [3:0] Q;

always @(posedge CP or negedge nCR) begin

if (~nCR) Q<=4'b0000; else if (~EN) Q<=Q;

else if ( Q==4'b0101) Q<=4'b0000; else Q<=Q+1'b1; end endmodule

模60通过例化模10和模6的元件,二者计数脉冲相同,进位通过模6的使能段en在模10的为9的下一个脉冲时进行使能选通从而进位,否则锁存数据。 module counter6(Q,nCR,EN,CP); input nCR,EN,CP; output [3:0] Q; reg [3:0] Q;

always @(posedge CP or negedge nCR) begin

if (~nCR) Q<=4'b0000; else if (~EN) Q<=Q;

else if ( Q==4'b0101) Q<=4'b0000; else Q<=Q+1'b1; end endmodule

模100与模60原理相同

module counter100(Cnt,nCR,EN,CP); input nCR,EN,CP; output [7:0] Cnt; wire [7:0] Cnt; wire ENP;

counter10 UC0(Cnt[3:0],nCR,EN,CP); counter10 UC1(Cnt[7:4],nCR,ENP,CP); assign ENP=(Cnt[3:0]==4'b1001); endmodule

模24计数也分为高位和低位,低位为9时下一个脉冲向高位进1同时低位清零,ncr为清零信号,en为使能信号完成计数和锁存,CP为计数脉冲,当满足高位大于2或者低位大于9(实际不可能实现,只是让程序更严密)或者计数到23时,下一个脉冲清零,否则正常计数加1,从而完成模24的计数。 module counter24(CntH,CntL,nCR,EN,CP); input nCR,EN,CP;

output [3:0] CntH,CntL;

reg [3:0] CntH,CntL;

always @(posedge CP or negedge nCR) begin

if (~nCR) {CntH,CntL}<=8'h00;

else if (~EN) {CntH,CntL}<={CntH,CntL};

else if ((CntH>2)||(CntL>9)||((CntH==2)&&(CntL>=3))) {CntH,CntL}<=8'h00;

else if ((CntH==2)&&(CntL<3)) begin CntH<=CntH; CntL<=CntL+1'b1; end

else if (CntL==9) begin CntH<=CntH+1'b1; CntL<=4'b0000; end else begin CntH<=CntH; CntL<=CntL+1'b1; end end Endmodule 分频模块

输入为1KHz的信号,调用了三个模10的计数模块,一个为10时作为下一个的使能端信号从而让下一个模10模块进行计数,这样就可以通过二进制数计数时个个位的变化规律进行分频获得想要的频率的脉冲信号,程序中获得了100HZ,500HZ,和1HZ的信号。

module Divided_Frequency(_1HZOut,_500HZOut,nCR,_1KHZIn,_100HZ); input nCR,_1KHZIn;

output _1HZOut,_500HZOut,_100HZ; supply1 Vdd; wire [11:0] Q; wire EN1,EN2;

counter10 DUO(Q[3:0],nCR,Vdd,_1KHZIn); counter10 DU1(Q[7:4],nCR,EN1,_1KHZIn); counter10 DU2(Q[11:8],nCR,EN2,_1KHZIn); assign EN1=(Q[3:0]==4'h9);

assign EN2=(Q[3:0]==4'h9&Q[7:4]==4'h9); assign _1HZOut=Q[11]; assign _500HZOut=Q[0]; assign _100HZ=Q[3]; endmodule 主时钟模块

主时钟模块调用了两个模60和一个模24的基本计数模块,以完成正常的时钟计数,当检测到有调时调分信号时便让分或时进位,否则秒为59的下一个脉冲作为分的计数信号使分进1,分为59同时秒为59时的下一个脉冲时作为时的计数信号使时进1,用if语句实现。使能端则一直为1,计数脉冲接分频后的一秒。用1KHZ的频率对计数进行扫描获得进位信号。

module top_clock(Hour,Minute,Second,nCR,_1HZ,AdjMinKey,AdjHrKey,HZ); input nCR,_1HZ,AdjMinKey,AdjHrKey,HZ; output [7:0] Hour,Minute,Second; wire [7:0] Hour,Minute,Second; supply1 Vdd;

reg [7:0] MinCP,HrCP;

counter60 UT1(Second,nCR,Vdd,_1HZ); counter60 UT2(Minute,nCR,Vdd,!MinCP);

counter24 UT3(Hour[7:4],Hour[3:0],nCR,Vdd,!HrCP); always@(posedge HZ)

begin if (AdjMinKey) MinCP=(Second==8'h59); else MinCP=1'b1; end

always@(posedge HZ)

begin if (AdjHrKey) HrCP=({Minute,Second}==16'h5959); else HrCP=1'b1; end Endmodule 闹钟模块

设置了分和时的计数模块,调用了模60和模24的模块。为了消抖动,脉冲技术端接一秒的信号,调时调分信号非后接使能段,这样既可以正常计数又可以在不用使能端时保持信号又可以消抖动。然后设置了比较程序,当主时钟的输出与闹钟设置的相等而且闹钟ctrlbell为1时便输出闹钟结果,否则闹钟一直输出为0,从而完成正常的功能。 module

Bell(Alarn_Clock,Hour,Minute,Second,Set_Hr,Set_Min,SetHrKey,SetMinKey,_500HZ,_1KHZIn,_1HZ,CtrlBell); output Alarn_Clock;

output [7:0] Set_Hr,Set_Min; wire [7:0] Set_Hr,Set_Min; wire Alarn_Clock;

input _500HZ,_1KHZIn,_1HZ;

input SetHrKey,SetMinKey,CtrlBell; input [7:0] Hour,Minute,Second; supply1 Vdd;

wire HrH_EQU,HrL_EQU,MinH_EQU,MinL_EQU; wire Time_EQU;

counter60 SU1(Set_Min,Vdd,!SetMinKey,_1HZ);

counter24 SU2(Set_Hr[7:4],Set_Hr[3:0],Vdd,!SetHrKey,_1HZ); Comparator SU4(HrH_EQU,Set_Hr[7:4],Hour[7:4]); Comparator SU5(HrL_EQU,Set_Hr[3:0],Hour[3:0]);

Comparator SU6(MinH_EQU,Set_Min[7:4],Minute[7:4]); Comparator SU7(MinL_EQU,Set_Min[3:0],Minute[3:0]);

assign Time_EQU=(HrH_EQU && HrL_EQU && MinH_EQU && MinL_EQU);

assign Alarn_Clock=CtrlBell ? Time_EQU:1'b0; endmodule

module Comparator(EQU,A,B) ;

input [3:0] A,B; output EQU;

assign EQU=(A==B); endmodule 秒表模块

秒表的输入脉冲为100Hz即1毫秒,调用了一个模100的计数模块和两个模60的计数模块。毫秒为99时下一个脉冲向秒进1,秒为59时同时毫秒为99时的下一个脉冲向分进1,使能端进行计数与保持。清零端应该单独设置,否则会将主时钟也清零了。用1KHZ的频率对计数进行扫描获得进位信号。 module stopwatch(Minute,Second,haomiao,nCR,en,_100HZ,HZ); input nCR,_100HZ,en,HZ;

output [7:0] Minute,Second,haomiao; wire [7:0] Minute,Second,haomiao; reg [7:0] miaoCP,SECP;

counter100 UT1(haomiao,nCR,en,_100HZ); counter60 UT2(Second,nCR,en,!miaoCP); counter60 UT3(Minute,nCR,en,!SECP); always@(posedge HZ)

begin if (haomiao==8'h99) miaoCP=(haomiao==8'h99); else miaoCP=(haomiao==8'h99); end

always@(posedge HZ)

begin if ({Second,haomiao}==16'h5999) SECP=(Second==8'h99); else SECP=({Second,haomiao}==16'h5999); end endmodule 整点报时模块

只有当分为59切秒为55时,让报警信号输出时长为5秒的信号,计数脉冲为1秒的信号。

module Radio(Alarn_Radio,Minute,Second,_1HZ); input _1KHZ;

input [7:0] Minute,Second; output Alarn_Radio; reg Alarn_Radio;

always@(Minute,Second) if (Minute==8'h59) case (Second)

8'h55:Alarn_Radio=1'b1; 8'h56:Alarn_Radio=1'b1; 8'h57:Alarn_Radio=1'b1; 8'h58:Alarn_Radio=1'b1; 8'h59:Alarn_Radio=1'b1; default: Alarn_Radio=1'b0; endcase

else Alarn_Radio=1'b0; endmodule

顶层模块

调用上述的各个模块,设置一个报警信号为闹钟与整点报时的相或输出。再设置循环扫码模块和选择显示模块,让主时钟秒表和闹钟的输出信号均可显示在数码管上并且互不影响。扫描频率均为1KHZ。 module

complete_clock(LED_Hr,LED_Min,LED_Sec,Alarn,AdjMinKey,AdjHrKey,SetHrKey,SetMinKey,stopwatchnCR,stopwatchen,_1KHZIn,_1HZ,CtrlBell,Mode1,Mode2,nCR,sel,SG); input

_1KHZIn,nCR,AdjMinKey,AdjHrKey,SetHrKey,SetMinKey,CtrlBell,Mode1,Mode2,stopwatchnCR,stopwatchen;

output [7:0] LED_Hr,LED_Min,LED_Sec,Alarn,SG,_1HZ; wire [7:0] LED_Hr,LED_Min,LED_Sec; wire _500HZ,_1HZ,_100HZ; wire [7:0]

Hour,Minute,Second,stopwatchHour,stopwatchMinute,stopwatchSecond; wire [7:0] Set_Hr,Set_Min; wire Alarn_Clock,Alarn_Radio; reg [3:0]a; reg [2:0] sel; reg [7:0] SG; output [2:0] sel;

Divided_Frequency U0(_1HZ,_500HZ,nCR,_1KHZIn,_100HZ); top_clock

U1(Hour,Minute,Second,nCR,_1HZ,AdjMinKey,AdjHrKey,_1KHZIn); Radio U2(Alarn_Radio,Minute,Second,_1HZ); Bell

U3(Alarn_Clock,Hour,Minute,Second,Set_Hr,Set_Min,SetHrKey,SetMinKey,_500HZ,_1KHZIn,_1KHZIn,CtrlBell);

stopwatch(stopwatchHour,stopwatchMinute,stopwatchSecond,stopwatchnCR,stopwatchen,_100HZ,_1KHZIn);

assign Alarn=Alarn_Clock||Alarn_Radio; _3To1MUX

Mu1(LED_Hr,Mode1,Mode2,Set_Hr,Hour,stopwatchHour,_1KHZIn); _3To1MUX

Mu2(LED_Min,Mode1,Mode2,Set_Min,Minute,stopwatchMinute,_1KHZIn); _3To1MUX

Mu3(LED_Sec,Mode1,Mode2,8'h00,Second,stopwatchSecond,_1KHZIn); always @(posedge _1KHZIn) begin

if (sel<5) sel=sel+1; else sel=0;

end always @(sel) begin

case (sel)

0: a=LED_Hr[7:4]; 1: a=LED_Hr[3:0]; 2: a=LED_Min[7:4]; 3: a=LED_Min[3:0]; 4: a=LED_Sec[7:4]; 5: a=LED_Sec[3:0]; default: a=0; endcase case (a)

0:SG<=8'b00111111; 1:SG<=8'b00000110; 2:SG<=8'b01011011; 3:SG<=8'b01001111; 4:SG<=8'b01100110; 5:SG<=8'b01101101; 6:SG<=8'b01111101; 7:SG<=8'b00000111; 8:SG<=8'b01111111; 9:SG<=8'b01101111; default: SG=8'b11111111; endcase end endmodule

module _3To1MUX(out,se1,se2,y,x,z,HZ); input [7:0] x,y,z; output [7:0] out; reg [7:0] out; input se1,se2,HZ;

always@(posedge HZ)

begin if (se1) out=x;

else if (se2) out=y; else out=z; end

endmodule (五) 时序仿真

仿真中用1KHZ信号代替1HZ信号。

可以看出在主时钟是可以进行调时和调分,秒正常计数,也可以进行进位。

可以看出在分为59秒从55开始,有时长为5秒的整点报时信号。

可以看出通过闹钟的调整位可以调整闹钟的时间,并且和主时钟相等时输出报警

信号为1

可以看出秒表可以进行正常的清零、计数和使能端控制秒表的功能,并且也可正常进位。 (六) 实验总结

虽然之前的课程做过数字中,但第一次EDA来做。整个程序采用模块例化的思想,使整个程序应用起来清晰明了,而且可以灵活运用底层的模块来实现不同的功能,还有就是如何正确地进行例化元件。实验过程中,在老师的提醒下,又增添了去抖动语句,使得实际操作中更加灵活。

八、课程总结

一个学期的EDA课程已经结束,我觉得对本阶段本课程的学习进行总结是很有必要的。

首先,很庆幸上学期决定选EDA作为专业选修课,而且可以有一个严格优秀的老师进行授课。正是因为杨老师在实验过程中对我们的“高标准,严要求”才让我真正的在做实验,真正的在学习一门语言和一门课程。不像之前的某些实验,在课程结束后,能够总结的只有这门课程我抄过实验报告。

其次,在学习一门语言的过程中,自己动手编程和实际操作尤为重要。理论的学习是动手操作的前提。前几周杨老师给我们介绍了课本上的相关基础知识:EDA的技术概述,组合电路的Verilog设计,时序电路的Verilog设计,Verilog状态机设计技术等等。当然仅仅课堂上的学习是不够的,课后我也认真的学习Verilog的语法知识和一些其他部分要求。我们大部分的课程是在实验室,自己动手编程和操作,这让我收获颇丰。由于之前也学习过一些语言,但都是课本学习,为了考试而进行的知识背诵,所以我的实际操作能力不强。就比如,第一次EDA实验,软件的使用不会,硬件也不会,遇到操作问题就很慌乱。但是经过这一学期的实验,我的动手能力提高了一大截。由起初的拿别人的代码自己读懂,到修改别人的代码,最后到自己编写一些功能,真的觉得自己学到了很多,也收获很多。如果不去自己编程,不去自己动手操作,那语言这门工具,你就不能说你会使用了。 最后,我的受挫耐压能力也提高不少。到现在发现,细节决定成败是

有一定的道理的。编程来说,每一种可能发生的情况,每一个很小的细节都要考虑到。有可能就一个if语句错了,效果就出不来。实验过程中,遇到很多次仿真可以,实物效果出不来的情况。就是要多考虑,仿真与实际的差别,然后做一些调整。之前的基础实验做得还是比较顺,最后一个进阶实验遇到很多没有想过的问题。也花费挺多时间精力去修改调整的,在实验室调试就做了3个早上,真的有过许多放弃的念头。不管怎样也坚持下来了,最后也请教同学,帮我看硬件,发现了错误:一次分频太大板子不能识别。并对代码进行了细节的调整,最终实现了该有的效果。虽然中间的过程让自己感到苦恼过,但实验成功的那一刻,一切是值得的。真的让我细心许多,多考虑细节。

本文来源:https://www.bwwdw.com/article/j3vg.html

Top