《数字电路与系统设计》
EDA实验报告
班级:021014
学号:021012**
姓名:张**
西安电子科技大学电子工程学院
双路并行交通灯实验设计
一、 实验功能介绍
本系统是根据实际交通情况,利用verilog语言设计,并在Basys2 FPGA开发板上实现的双路并行交通灯。该系统有下面4个状态:
1. 道路1的红灯转绿灯,同时道路2的黄灯转红灯,时间持续10秒钟;
2. 道路1的绿灯转黄灯,同时道路2的红灯接着亮,时间持续2秒钟;
3. 道路1的黄灯转红灯,同时道路2 的红灯转绿灯,时间持续10秒钟;
4. 道路1的红灯持续亮,同时道路2的绿灯转黄灯,时间持续2秒钟;
交通灯满足每条支路的工作状态为:
支路上的每盏灯由开发板上的LED灯代替,同时开发板上的数码管也实时显示两条路上灯的剩余点亮时间,同时每盏灯的点亮时间可在程序中自行设计。系统中设置了一个复位键,复位键按下,系统立马回复到状态1.
二、 实验条件
1.Basys2 FPGA开发板
Basys2 FPGA开发板是一个电路设计实现平台,任何人都可以通过它来搭建一个真正的数字电路。Basys2是围绕着一个Spartan-3E FPGA芯片和一个Atmel AT90USB USB控制器搭建的,它提供了完整、随时可以使用的硬件平台,并且它适合于从基本逻辑器件到复杂控制器件的各种主机电路。
主要特点如下:Xilinx Spartan 3E FPGA,10万或25万门 ,FPGA特性18位乘法器,72位高速双端口Block RAM,以及500MHz+运算能力 ,USB2.0高速接口提供FPGA配置和数据传输,Xilinx Platform Flash ROM可以无限次存储FPGA配置 ,用户可配置晶振(25,50,100MHz),另附可连接第二个时钟晶振的插座 ,三个内置稳压器(1.2V,2.5V,和3.3V),允许使用3.5V-5.5V的外部电源供电 ,8个用户可编程LED指示灯,4个七段数码管显示器,4个按键开关,8个滑动开关,1个PS/2接口和1个8位VGA显示接口 ,4个6针用户扩展接口,可以用来连接Digilent PMOD附属电路板 ,需要Adept2.0或更新版本软件来进行操作。
2.仿真软件 Modelsim SE 6.5e
ModelSim是业界最优秀的HDL语言仿真软件,它能提供友好的仿真环境,是业界唯一的单内核支持VHDL和Verilog混合仿真的仿真器。它采用直接优化的编译技术、Tcl/Tk技术、和单一内核仿真技术,编译仿真速度快,编译的代码与平台无关,便于保护IP核,个性化的图形界面和用户接口,为用户加快调错提供强有力的手段,是FPGA/ASIC设计的首选仿真软件。
3.电子设计软件Xilinx ISE Design Suite 13.2
Xilinx ISE Design Suite是利用新技术来降低总设计成本的电子设计套件软件,并且实现了比任何其它 PLD 解决方案更高的性能。借助 Xilinx ISE Design Suite 的突破性技术提高系统级设计效率并加快产品投产。 ISE Design Suite 采用各种方法来实现团队设计、功耗优化以及简化 IP 集成,从而分发挥 Xilinx 目标设计平台在配置逻辑、嵌入式和 DSP 设计方面的潜力。
4.开发语言--Verilog HDL
Verilog HDL就是在用途最广泛的C语言的基础上发展起来的一种硬件描述语言,它是由GDA(Gateway Design Automation)公司的PhilMoorby在1983年末首创的,最初只设计了一个仿真与验证工具,之后又陆续开发了相关的故障模拟与时序分析工具。1985年Moorby推出它的第三个商用仿真器Verilog-XL,获得了巨大的成功,从而使得Verilog HDL迅速得到推广应用。1989年CADENCE公司收购了GDA公司,使得VerilogHDL成为了该公司的独家专利。1990年CADENCE公司公开发表了Verilog HDL,并成立LVI组织以促进Verilog HDL成为IEEE标准,即IEEE Standard 1364-1995.
Verilog HDL的最大特点就是易学易用,如果有C语言的编程经验,可以在一个较短的时间内很快的学习和掌握,因而可以把Verilog HDL内容安排在与ASIC设计等相关课程内部进行讲授,由于HDL语言本身是专门面向硬件与系统设计的,这样的安排可以使学习者同时获得设计实际电路的经验。与之相比,VHDL的学习要困难一些。但Verilog HDL较自由的语法,也容易造成初学者犯一些错误,这一点要注意。
三、 实验过程
1. 系统组成框图:
同时系统还有Reset复位输入,当Reset按下时,系统立马转成初始状态,上述框图是建立在Reset键未按下基础上的。
2. 模块划分及各个模块的详细功能:
组成系统的模块有:周期信号生成模块,LED状态判断模块,交通灯计时模块,数字分离模块,数码管动态显示模块。
a) 周期信号生成模块
利用内部的50MHZ的时钟信号生成周期可定的信号。
b) LED状态判断模块
只要每一秒的上升沿到来,就会根据目前的状态判断是否时间已经到达需要转换至下一个状态。只要状态一改变,立即控制灯,以改变LED灯的状态。
c) 交通灯计时模块
利用生成的周期信号同时计算两条路上亮灯的持续时间,即为交通灯的秒数。
d) 数字分离模块
将十进制的秒数分离为单独的十位和个位。
e) 数码管动态显示模块
根据数字分离的四个数字,利用产生的周期信号循环点亮四个数码管。
3. 流程图及流程图详细介绍:
a) 周期信号生成模块
该模块的输入为系统自带的50MHZ的时钟,输出一个周期已知的信号。思想就是累计系统的时钟信号,当累积到一定程度(Clock_count)时,对变量(Clock_Output)取反,这样就产生了一个周期可调的信号。
b) LED状态判断模块
该模块输入是周期1Sec的信号,输出的是开发板上Led灯的明灭情况。先将输出的变量Light的八位二进制数定义为八个LED灯的串口地址,再定义四个状态与交通灯的四个状态相对应,如下表:
设定一个累计计时变量State_Second_count,在每次信号上升沿到来时判断状态的累计时间有没有满,满足后立即更换状态,将状态值返回给变量Light,从而控制开发板上的Led灯实时变化。
c) 交通灯计时模块
该模块输入是自产生的周期1Sec的信号Clock_1s,输出的是变量Second_1和Second_2。先定义两个计时变量Second_1和Second_2分别代表的是第一路灯和第二路灯的剩余点亮时间。再定义一个状态变量Own_State,与交通灯的四个状态相对应,对应表为:
在每个信号上升沿到来时,判断有没有计时变量到0,有的话改变状态变量并给计时变量重新赋值。
d) 数字分离模块
模块输入是数字Num,输出的是数字Num的高低位数字对应的数码管地址值。数字Num先经过hex2dec模块,分离为十位数字Num_High和个位数字Num_Low,再经过display_single模块,输出每个数字的地址值display_high,display_low。
e) 数码管动态显示模块
模块输入的是周期2mSec的信号Clock_2ms,交通灯两路显示时间的对应的数码管地址的赋值display_high_1, display_high_2, display_low_1, display_low_2。输出为开发板上数码管动态显示。先将变量Led_Display_Control的四位二进制数定义为四个数码管的地址值,变量Led_Display的七位二进制数定义为数码管的七段Led灯的地址。模块实现的思想就是2mSec为周期,循环点亮每个数码管,并将四个值依次赋给Led_Display,从而实现数码管的动态显示。
4. 详细的程序清单及程序注释:
这部分包括上述五个模块的具体程序,同时加了一个串口定义清单。其中第一个第二个还有第五个模块程序因为是放在了主程序中,所以就没有写成module~ endmodule的形式。第三个模块是按照module~ endmodule的形式写的,第四个模块则是几个module综合起来的。
a) 周期信号生成模块
//生成周期为1Sec的信号//
parameter clock_1s_value=25000*1000;
reg [24:0] clock_1s_counter=25'b0;
reg clock_1s=1'b0;
always @(posedge clock or posedge reset)
begin
if(reset)
begin
clock_1s_counter<=25'b0;
clock_1s<=1'b0;
end
else
begin
clock_1s_counter<=clock_1s_counter+1'b1;
if(clock_1s_counter==clock_1s_value)
begin
clock_1s_counter<=25'd0;
clock_1s<=~clock_1s;
end
end
end
b) LED状态判断模块
//只要每一秒的上升沿到,就会根据目前的状态判断是否时间已经到达需要转换至下一状态//
reg [1:0] state=2'b0;
reg [3:0] state_second_counter=4'b0; always @(posedge clock_1s or posedge reset)
begin
if(reset)
begin
state<=2'b0;
state_second_counter<=4'b0;
end
else
begin
state_second_counter<=state_second_counter+4'd1;
case (light)
s0,s2:
if(state_second_counter==4'd10)
begin
state_second_counter<=4'd0;
if(state==2'd3)
state<=2'd0;
else
state<=state+2'd1;
end
s1,s3:
if(state_second_counter==4'd2)
begin
state_second_counter<=4'd0;
if(state==2'd3)
state<=2'd0;
else
state<=state+2'd1;
end
endcase
end
end
//只要状态以改变,立刻控制灯,以改变LED灯的状态//
always @(state)
begin
case (state)
2'd0: begin light=s0; end
2'd1: begin light=s1; end
2'd2: begin light=s2; end
2'd3: begin light=s3; end
endcase
end
c) 交通灯计时模块
//输入为周期1Sec的信号//
module trafic_second_counter(clock, second_1, second_2,reset);
input wire clock,reset;
output reg [6:0] second_1=7'd10;
output reg [6:0] second_2=7'd13;
reg [1:0] own_state=2'b0;
always @(posedge clock or posedge reset)
begin
if(reset)
begin
second_1=7'd10;
second_2=7'd13;
own_state=2'b0;
end
else
begin
if(second_1==7'd0||second_2==7'd0)
begin
if(own_state==2'd3)
own_state=2'b0;
else
own_state=own_state+2'd1;
case (own_state)
2'd0:
begin
second_1=7'd10;
second_2=7'd13;
end
2'd1:
begin
second_1=7'd2;
second_2=7'd2;
end
2'd2:
begin
second_1=7'd13;
second_2=7'd10;
end
2'd3:
begin
second_1=7'd2;
second_2=7'd2;
end
endcase
end
else
begin
second_1=second_1-1'b1;
second_2=second_2-1'b1;
end
end
end
endmodule
d) 数字分离模块
//三个module组合而成,包括display,hex2dec,display_single //
module display(num,display_high,display_low);
input [6:0] num;
output[6:0] display_high,display_low;
wire[3:0] num_high,num_low;
hex2dec hex2dec_dut(num, num_high, num_low);
display_single display_high_loc(num_high, display_high);
display_single display_low_loc (num_low, display_low);
endmodule
module hex2dec(num,num_high,num_low);
input [6:0] num;
output[3:0] num_high,num_low;
reg[7:0] ROM [0:99];
initial
begin
$readmemb("rom_hex2dec.txt",ROM);
end
assign {num_high,num_low} = ROM[num];
endmodule
module display_single(num,led_display_value);
input [3:0] num;
output reg [6:0] led_display_value;
always@(*)
case(num)
4'd0: led_display_value=7'b0000001;
4'd1: led_display_value=7'b1001111;
4'd2: led_display_value=7'b0010010;
4'd3: led_display_value=7'b0000110;
4'd4: led_display_value=7'b1001100;
4'd5: led_display_value=7'b0100100;
4'd6: led_display_value=7'b0100000;
4'd7: led_display_value=7'b0001111;
4'd8: led_display_value=7'b0000000;
4'd9: led_display_value=7'b0000100;
4'd10: led_display_value=7'b0001000;
4'd11: led_display_value=7'b1100000;
4'd12: led_display_value=7'b0110001;
4'd13: led_display_value=7'b1000010;
4'd14: led_display_value=7'b0110000;
4'd15: led_display_value=7'b0111000;
endcase
endmodule
e) 数码管动态显示模块
//以2ms为周期循环点亮数码管//
reg [1:0] display_state=2'b00;
always @(posedge clock_2ms or posedge reset)
begin
if (reset)
display_state<=2'b00;
else
display_state<=display_state+2'b1;
end
always @(posedge clock_2ms)
if (reset)
begin
led_display_control<=4'b1111;
led_display<=7'd0;
end
else
begin
case(display_state)
2'b00:
begin
led_display_control<=4'b0111;
led_display<=display_low_2;
end
2'b01:
begin
led_display_control<=4'b1011;
led_display<=display_high_2;
end
2'b10:
begin
led_display_control<=4'b1101;
led_display<=display_low_1;
end
2'b11:
begin
led_display_control<=4'b1110;
led_display<=display_high_1;
end
endcase
end
endmodule
f) 串口引脚定义表
NET "clock" LOC = B8;
NET "reset" LOC = A7;
NET "light[7]" LOC = G1;
NET "light[6]" LOC = P4;
NET "light[5]" LOC = N4;
NET "light[4]" LOC = N5;
NET "light[3]" LOC = P6;
NET "light[2]" LOC = P7;
NET "light[1]" LOC = M11;
NET "light[0]" LOC = M5;
NET "led_display_control[3]" LOC = F12;
NET "led_display_control[2]" LOC = J12;
NET "led_display_control[1]" LOC = M13;
NET "led_display_control[0]" LOC = K14;
NET "led_display[6]" LOC = L14;
NET "led_display[5]" LOC = H12;
NET "led_display[4]" LOC = N14;
NET "led_display[3]" LOC = N11;
NET "led_display[2]" LOC = P12;
NET "led_display[1]" LOC = L13;
NET "led_display[0]" LOC = M12;
四、 实验结果
利用Modelsim SE 6.5e软件进行仿真,截图如下:
0111,1011,1101,1110是依次点亮四个数码管,完成了数码管的动态显示。
上面的截图是LED灯的实时状态,可以发现一共有四个状态在循环,分别是01001000,00101000,10000100,10000010,分别代表交通灯的四个状态。他们之间的持续时间分别为0.05Sec,0.01Sec,0.05Sec,0.01Sec。说明实验得到了预期的结果。
因为仿真时得出波形的时间较慢,所以在Test文件中,将周期信号生成模块中的时间阈值减小了去100倍,也就是仿真时每个状态的持续时间变缩短为原来的200倍。
五、 实验结论与自己的心得
1. 实验结论:
本次实验完成了既定任务,将程序烧录进开发板后,Led和数码管工作正常,各状态之间的跳转没有出现问题,软件仿真也能够很好的说明实验的结果。
2. 实验心得:
EDA理论课结束后,自己对于硬件描述语言还是很不了解,对于verilog HDL的了解也只仅限于书本而已。实验课开始后自己又由于其他的事情导致没有及时上课,使自己了解学习的进度远落后于其他同学。其他同学已经能熟练烧录程序的时候我还在看程序怎么使用。
当自己想设计一个交通灯的时候还是有挺多困难的,实验中,先逐步摸索各模块程序的功能,努力为自己所用,通过不断的修改测试加深了对各程序的了解。实验中也遇到了很多问题,例如对verilog HDL了解不到位程序出错,阻塞赋值等,这还需要实验来加深对理论的理解。
实验过程中,同学,学长学姐,还有李甫老师给予了很大的帮助,非常感谢。