一、概述
二、任务书(任务功能介绍)
三.系统设计
1.基本原理
2.系统设计框图
四、各单元设计(Verilog源代码及仿真图)
五、总体电路
1.Verilog源代码及其仿真图
2.引脚分配
六、下载运行结果
七、故障分析与电路改进
八、总结与体会
九、参考文献
HDL(Hardware Description Language,硬件描述语言)是一种描述硬件所做工作的语言。目前,电子系统向集成化、大规模和高速度等方向发展,以硬件描述语言和逻辑综合为基础的自顶向下的电路设计方法在业界得到迅猛发展,HDL在这种形势下显示出了巨大的优势,展望将来HDL在硬件设计领域的地位将与C和C++在软件设计领域地位一样,在大规模数字系统的设计中,它将逐步取代传统的逻辑状态表和逻辑电路图等硬件描述方法 而成为主要的硬件描述工具。
Verilog HDL是工业和学术界的硬件设计者所使用的两种主要的HDL之一,另一种是VHDL。现在它们都已成为IEEE标准。两者各有特点,但Verilog HDL拥有更悠久的历史、更广泛的设计群体,资源也远比VHDL丰富,且非常容易学习掌握。
Quartus简介:
Quartus II 是Altera公司的综合性PLD/FPGA开发软件,支持原理图、VHDL、VerilogHDL以及AHDL(Altera Hardware Description Language)等多种设计输入形式,内嵌自有的综合器以及仿真器,可以完成从设计输入到硬件配置的完整PLD设计流程。Quartus II可以在XP、Linux以及Unix上使用,除了可以使用Tcl脚本完成设计流程外,提供了完善的用户图形界面设计方式。具有运行速度快,界面统一,功能集中,易学易用等特点。Quartus II支持Altera的IP核,包含了LPM/MegaFunction宏功能模块库,使用户可以充分利用成熟的模块,简化了设计的复杂性、加快了设计速度。对第三方EDA工具的良好支持也使用户可以在设计流程的各个阶段使用熟悉的第三方EDA工具。 此外,Quartus II 通过和DSP Builder工具与Matlab/Simulink相结合,可以方便地实现各种DSP应用系统;支持Altera的片上可编程系统(SOPC)开发,集系统级设计、嵌入式软件开发、可编程逻辑设计于一体,是一种综合性的开发平台。
设计内容与设计要求
一、设计内容
设计一个交通灯控制器,具备两相位(任一道路方向,对左转和直行实行分别控制)控制功能,能够显示每个车道当前状态下的剩余时间。
基本要求
1、由两条主干道汇合成十字路口,在每个入口处设置两相位信号灯;分别为直行红、黄、绿灯,左转红、黄、绿灯
2、每个路口信号灯时间为直行绿灯30秒,黄灯5秒 ,红灯85秒 ;左转绿灯20秒 黄灯 5秒 红灯 95秒,红绿灯亮灭按照如下示意图进行。
3、配合红绿灯亮灭,设立倒计时显示,利用LED数码管显示倒计时时间。
4、 建议使用有限状态机实现交通灯控制器各状态间的转换
配时示意图
扩展要求
增加夜间模式,并实现自动切换,夜间模式为每天22:00至次日凌晨6:00间,四个路口都是黄灯闪烁模式。
二、设计要求
1.设计思路清晰,给出状态转移图和整体电路的设计框图;
2.设计各单元电路,给出工作原理说明;完成各单元模块的仿真,并记录结果;
3.完成总体电路设计,并进行总系统电路的仿真测试,并记录结果;
4.进行下载测试和验证,记录验证结果;
5.写出设计报告。
1、基本原理
城市十字交叉路口红绿灯控制系统主要负责控制主干道(东西)直行和左转走向和从干道(南北)直行和左转走向的红绿灯的状态和转换顺序,由于FPGA板的限制,暂将八个数码管和八个LED灯两两一组,共为四组,第一组为东西直行方向,第二组为东西左转方向,第三组为南北直行方向,第四组为南北左转方向,两个LED灯一组时,左边灯亮右边灯灭记为绿灯亮,右边灯亮左边灯灭记为红灯亮,两个灯都亮就是黄灯,当出现黄灯时得闪烁起来。关键是各个状态之间的转换和进行适当的时间延时,正是基于以上考虑,采用如下设计:
S1:当东西直行走向的绿灯亮时,东西左转走向的红灯亮,南北直行走向的红灯亮,南北左转走向的红灯亮,并保持30s
S2:当东西直行走向的黄灯亮时,东西左转走向的红灯亮,南北直行走向的红灯亮,南北左转走向的红灯亮,并保持闪烁5s
S3:当东西直行走向的红灯亮时,东西左转走向的绿灯亮,南北直行走向的红灯亮,南北左转走向的红灯亮,并保持20s
S4:当东西直行走向的红灯亮时,东西左转走向的黄灯亮,南北直行走向的红灯亮,南北左转走向的红灯亮,并保持闪烁5s
S5:当东西直行走向的红灯亮时,东西左转走向的红灯亮,南北直行走向的绿灯亮,南北左转走向的红灯亮,并保持30s
S6:当东西直行走向的红灯亮时,东西左转走向的红灯亮,南北直行走向的黄灯亮,南北左转走向的红灯亮,并保持闪烁5s
S7:当东西直行走向的红灯亮时,东西左转走向的红灯亮,南北直行走向的红灯亮,南北左转走向的绿灯亮,并保持20s
S8:当东西直行走向的红灯亮时,东西左转走向的红灯亮,南北直行走向的红灯亮,南北左转走向的黄灯亮,并保持闪烁5s
S_IDLE:当进入夜间模式时,四个方向都呈现黄灯,并且保持闪烁
在S8结束后又回到S1状态,其余均为S_IDLE状态并周期重复进行。
2.系统设计框图
根据设计要求和系统所具有功能,并参考相关的文献资料经行方案设计画出如下所示的十字路口交通灯控制器系统框图,及为设计的总体方案,框图如下图所示:(显示模块分开显示,之后同步,通过外部开关决定显示时钟或交通灯)
1.div1
module div1(clk,f1);
input clk;
output reg f1;
reg[27:0] scan_cnt;
always@(posedge clk)
begin
if(scan_cnt==24999999)
begin
scan_cnt<=0;
f1<=!f1;
end
else
begin
scan_cnt<=scan_cnt+20'b1;
end
end
endmodule
2.cnt3
module cnt3(clk,Q);
input clk;
output reg[2:0] Q;
always@(posedge clk)
begin
Q<=Q+2'b1;
end
endmodule
3.decode_3_8
module decode_3_8(A,Y);
input [2:0]A;
output reg [7:0]Y;
always@(A)
begin
case(A)
3'b000:Y=8'b1111_1110;
3'b001:Y=8'b1111_1101;
3'b010:Y=8'b1111_1011;
3'b011:Y=8'b1111_0111;
3'b100:Y=8'b1110_1111;
3'b101:Y=8'b1101_1111;
3'b110:Y=8'b1011_1111;
3'b111:Y=8'b0111_1111;
default:Y=8'b1111_1111;
endcase
end
endmodule
4.MUX8To1
module MUX8To1(SEL,A,B,C,D,E,F,G,H,Y);
input[2:0] SEL;
input[3:0] A,B,C,D,E,F,G,H;
output reg[3:0] Y;
always@(SEL)
begin
case(SEL)
3'b000:Y=A;
3'b001:Y=B;
3'b010:Y=C;
3'b011:Y=D;
3'b100:Y=E;
3'b101:Y=F;
3'b110:Y=G;
default:Y=H;
endcase
end
endmodule
5.BCD_7seg
module BCD_7seg(BCD,SEG);
input[3:0] BCD;
output reg[7:0] SEG;
always@(BCD)
begin
case(BCD)
4'd0: SEG=8'b1100_0000;
4'd1: SEG=8'b1111_1001;
4'd2: SEG=8'b1010_0100;
4'd3: SEG=8'b1011_0000;
4'd4: SEG=8'b1001_1001;
4'd5: SEG=8'b1001_0010;
4'd6: SEG=8'b1000_0010;
4'd7: SEG=8'b1111_1000;
4'd8: SEG=8'b1000_0000;
4'd9: SEG=8'b1001_0000;
default:SEG=8'b1111_1111;
endcase
end
endmodule
6.countdown(选取其中一个状态10100010去仿真)
module countdown(Q_120,condition,ews,ewl,sns,snl);
input [6:0]Q_120;
input [7:0]condition;
output reg [6:0]ews,ewl,sns,snl;
always@(Q_120)
begin
case(condition)
8'b0000_0000:begin //S_IDLE状态(0)
ews<=0;
ewl<=0;
sns<=0;
snl<=0;
end
8'b0110_1010:begin //S1状态(1)
ews<=30-Q_120;
ewl<=35-Q_120;
sns<=60-Q_120;
snl<=95-Q_120;
end
8'b0010_1010:begin //S2状态(31)
ews<=35-Q_120;
ewl<=35-Q_120;
sns<=60-Q_120;
snl<=95-Q_120;
end
8'b1001_1010:begin //S3状态(36)
ews<=120-Q_120;
ewl<=55-Q_120;
sns<=60-Q_120;
snl<=95-Q_120;
end
8'b1000_1010:begin //S4状态(56)
ews<=120-Q_120;
ewl<=60-Q_120;
sns<=60-Q_120;
snl<=95-Q_120;
end
8'b1010_0110:begin //S5状态(61)
ews<=120-Q_120;
ewl<=155-Q_120;
sns<=90-Q_120;
snl<=95-Q_120;
end
8'b1010_0010:begin //S6状态(91)
ews<=120-Q_120;
ewl<=155-Q_120;
sns<=95-Q_120;
snl<=95-Q_120;
end
8'b1010_1001:begin //S7状态(96)
ews<=120-Q_120;
ewl<=155-Q_120;
sns<=180-Q_120;
snl<=115-Q_120;
end
8'b1010_1000:begin //S8状态(116)
ews<=120-Q_120;
ewl<=155-Q_120;
sns<=180-Q_120;
snl<=120-Q_120;
end
endcase
end
endmodule
7.count120
module count120(clk,Q_out);
input clk;
output reg [6:0]Q_out;
always@(posedge clk)
begin
if(Q_out<'d120)
begin
Q_out<=1;
Q_out<=Q_out+1;
end
else
begin
Q_out<='d1;
end
end
endmodule
8.state_machine
module state_machine(clk1,Q_120,light);
input clk1;
input [6:0]Q_120;
output reg [7:0]light;
reg [3:0]N_state;
parameter S_IDLE=4'b0000;
parameter S1=4'b0001;
parameter S2=4'b0010;
parameter S3=4'b0011;
parameter S4=4'b0100;
parameter S5=4'b0101;
parameter S6=4'b0110;
parameter S7=4'b0111;
parameter S8=4'b1000;
always@(posedge clk1)
begin
case(N_state)
S_IDLE:if(Q_120=='d0)
begin
N_state<=S1;
light<=8'b0110_1010;
end
S1:if(Q_120=='d30)
begin
N_state<=S2;
light<=8'b0010_1010;
end
S2:if(Q_120=='d35)
begin
N_state<=S3;
light<=8'b1001_1010;
end
S3:if(Q_120=='d55)
begin
N_state<=S4;
light<=8'b1000_1010;
end
S4:if(Q_120=='d60)
begin
N_state<=S5;
light<=8'b1010_0110;
end
S5:if(Q_120=='d90)
begin
N_state<=S6;
light<=8'b1010_0010;
end
S6:if(Q_120=='d95)
begin
N_state<=S7;
light<=8'b1010_1001;
end
S7:if(Q_120=='d115)
begin
N_state<=S8;
light<=8'b1010_1000;
end
S8:if(Q_120=='d120)
begin
N_state<=S1;
light<=8'b0110_1010;
end
default:N_state<=S_IDLE;
endcase
end
endmodule
9.BCD_transcoding
module BCD_transcoding(bitCode, num_1, num_0);
input [6:0] bitCode;
output reg [3:0] num_1,num_0;
integer i;
always@(bitCode)
begin
num_1=4'd0;
num_0=4'd0;
for(i=6;i>=0;i=i-1)
begin
if(num_1>=5)
num_1=num_1+3;
if(num_0>=5)
num_0=num_0+3;
num_1 = num_1<<1;
num_1[0] = num_0[3];
num_0 = num_0<<1;
num_0[0]= bitCode[i];
end
end
endmodule
10.div3
module div3(clk,f3);
input clk;
output reg f3;
reg[27:0] scan_cnt;
always@(posedge clk)
begin
if(scan_cnt==499)
begin
scan_cnt<=0;
f3<=!f3;
end
else
begin
scan_cnt<=scan_cnt+20'b1;
end
end
endmodule
11.select
Module select(circuit,ewsxuan,ewlxuan,snsxuan,snlxuan,Q_miaoxuan,Q_fenxuan,Q_shixuan,bitCode1,bitCode2,bitCode3,bitCode4);
input circuit;
input [6:0]ewsxuan,ewlxuan,snsxuan,snlxuan,Q_miaoxuan,Q_fenxuan,Q_shixuan;
output reg [6:0]bitCode1,bitCode2,bitCode3,bitCode4;
always@(circuit)
begin
if(circuit=='b1)
begin
bitCode1<=ewsxuan;
bitCode2<=ewlxuan;
bitCode3<=snsxuan;
bitCode4<=snlxuan;
end
else
begin
bitCode1<=0;
bitCode2<=Q_shixuan;
bitCode3<=Q_fenxuan;
bitCode4<=Q_miaoxuan;
end
end
endmodule
module divclock(clk,fclock);
input clk;
output reg fclock;
reg[27:0] scan_cnt;
always@(posedge clk)
begin
if(scan_cnt==34721)
begin
scan_cnt<=0;
fclock<=!fclock;
end
else
begin
scan_cnt<=scan_cnt+'b1;
end
end
endmodule
12.clock
module clock(clk,Q_miao,Q_fen,Q_shi);
input clk;
output reg [6:0]Q_miao,Q_fen,Q_shi;
always@(posedge clk)
begin
if(Q_miao<'d59)
begin
Q_miao<=0;
Q_miao<=Q_miao+1;
end
else
begin
Q_miao<='d0;
Q_fen<=Q_fen+1;
if(Q_fen=='d59)
begin
Q_fen<=0;
Q_shi<=Q_shi+1;
if(Q_shi=='d23)
begin
Q_shi<=0;
end
end
end
end
endmodule
1.Verilog源代码
1.LED_show**
module LED_show(cp,LED);
input cp;
output wire[7:0]LED;
wire clk_1hz,clk_2hz;
wire [6:0]Q;
wire [7:0]LED1;
div1 U1 (.clk(cp),
.f1(clk_1hz)
);
div2 U2 (.clk(cp),
.f2(clk_2hz)
);
count120 U3 (.clk(clk_1hz),
.Q_out(Q),
);
state_machine U4(.clk1(clk_1hz),
.Q_120(Q),
.light(LED1)
);
LED_twinkle U5 (.clk2(clk_2hz),
.LED_light(LED1),
.LED_out(LED)
);
endmodule
此段代码即为我设计的交通信号灯LED灯展示的部分,正确的在FPGA板上呈现出来,但由于Quartus II位长的局限性,所以不能将整个循环所展示在仿真图上,故我将代码中两个分频器div1,div2去掉,按比例给clk_1hz,clk_2hz赋予相应的时钟脉冲信号从而完美地得到整个循环的仿真图。
修改代码如下:
module LED_show_yanshi(clk_1hz,clk_2hz,LED);
input clk_1hz,clk_2hz;
output wire[7:0]LED;
wire [6:0]Q;
wire [7:0]LED1;
count120 U3 (.clk(clk_1hz),
.Q_out(Q),
);
state_machine U4(.clk1(clk_1hz),
.Q_120(Q),
.light(LED1)
);
LED_twinkle U5 (.clk2(clk_2hz),
.LED_light(LED1),
.LED_out(LED)
);
endmodule
2.disp_LED
module disp_LED(cp,push,LED_Bit,LED_SEG);
input cp,push;
output [7:0] LED_Bit;
output [7:0] LED_SEG;
wire clk_1Hz,clk_400,clk_1440;
wire[2:0] scan_cnt;
wire[6:0] Q_connect;
wire[7:0] zhonglei;
wire [3:0]Data_00,Data_11,Data_22,Data_33,Data_44,Data_55,Data_66,Data_77;
wire [6:0]ews1,ewl1,sns1,snl1,miao1,fen1,shi1,bit1,bit2,bit3,bit4;
wire [3:0]Data_BCD;
div1 U1 (.clk(cp),
.f1(clk_1hz));
div3 U14 (.clk(cp),
.f3(clk_400));
cnt3 U3(.clk(clk_400),
.Q(scan_cnt)
);
decode_3_8 U4(.A(scan_cnt),
.Y(LED_Bit)
);
MUX8To1 U5(.SEL(scan_cnt),
.A(Data_66),
.B(Data_77),
.C(Data_44),
.D(Data_55),
.E(Data_22),
.F(Data_33),
.G(Data_00),
.H(Data_11),
.Y(Data_BCD)
) ;
BCD_7seg U6(.BCD(Data_BCD),
.SEG(LED_SEG)) ;
countdown U7 (.Q_120(Q_connect),
.condition(zhonglei),
.ews(ews1),
.ewl(ewl1),
.sns(sns1),
.snl(snl1)
);
clock U18 (.clk(clk_1440),
.Q_miao(miao1),
.Q_fen(fen1),
.Q_shi(shi1)
);
divclock U17(.clk(cp),
.fclock(clk_1440));
select U16 (.circuit(push),
.ewsxuan(ews1),
.ewlxuan(ewl1),
.snsxuan(sns1),
.snlxuan(snl1),
.Q_miaoxuan(miao1),
.Q_fenxuan(fen1),
.Q_shixuan(shi1),
.bitCode1(bit1),
.bitCode2(bit2),
.bitCode3(bit3),
.bitCode4(bit4)
);
count120 U8 (.clk(clk_1hz),
.Q_out(Q_connect)
);
state_machine U9 (.clk1(clk_1hz),
.Q_120(Q_connect),
.light(zhonglei)
);
BCD_transcoding U10 (.bitCode(bit1),
.num_1(Data_11),
.num_0(Data_00)
);
BCD_transcoding U11 (.bitCode(bit2),
.num_1(Data_33),
.num_0(Data_22));
BCD_transcoding U12 (.bitCode(bit3),
.num_1(Data_55),
.num_0(Data_44));
BCD_transcoding U13 (.bitCode(bit4),
.num_1(Data_77),
.num_0(Data_66));
endmodule
此段代码即为我设计的交通信号灯LED灯展示的部分,正确的在FPGA板上呈现出来,但由于Quartus II位长的局限性,所以不能将整个循环所展示在仿真图上,故我将代码中两个分频器div1,div3,divclock去掉,按比例给clk_1hz,clk_400hz,clk_1440hz赋予相应的时钟脉冲信号从而完美地得到整个循环的仿真图。
修改代码如下:
module disp_LED_yanshi(clk_1Hz,clk_400,clk_1440,push,LED_Bit,LED_SEG);
input clk_1Hz,clk_400,clk_1440,push;
output [7:0] LED_Bit;
output [7:0] LED_SEG;
wire[2:0] scan_cnt;
wire[6:0] Q_connect;
wire[7:0] zhonglei;
wire [3:0]Data_00,Data_11,Data_22,Data_33,Data_44,Data_55,Data_66,Data_77;
wire [6:0]ews1,ewl1,sns1,snl1,miao1,fen1,shi1,bit1,bit2,bit3,bit4;
wire [3:0]Data_BCD;
cnt3 U3(.clk(clk_400),
.Q(scan_cnt)
);
decode_3_8 U4(.A(scan_cnt),
.Y(LED_Bit)
);
MUX8To1 U5(.SEL(scan_cnt),
.A(Data_66),
.B(Data_77),
.C(Data_44),
.D(Data_55),
.E(Data_22),
.F(Data_33),
.G(Data_00),
.H(Data_11),
.Y(Data_BCD)
) ;
BCD_7seg U6(.BCD(Data_BCD),
.SEG(LED_SEG)) ;
countdown U7 (.Q_120(Q_connect),
.condition(zhonglei),
.ews(ews1),
.ewl(ewl1),
.sns(sns1),
.snl(snl1)
);
clock U18 (.clk(clk_1440),
.Q_miao(miao1),
.Q_fen(fen1),
.Q_shi(shi1)
);
select U16 (.circuit(push),
.ewsxuan(ews1),
.ewlxuan(ewl1),
.snsxuan(sns1),
.snlxuan(snl1),
.Q_miaoxuan(miao1),
.Q_fenxuan(fen1),
.Q_shixuan(shi1),
.bitCode1(bit1),
.bitCode2(bit2),
.bitCode3(bit3),
.bitCode4(bit4)
);
count120 U8 (.clk(clk_1hz),
.Q_out(Q_connect)
);
state_machine U9 (.clk1(clk_1hz),
.Q_120(Q_connect),
.light(zhonglei)
);
BCD_transcoding U10 (.bitCode(bit1),
.num_1(Data_11),
.num_0(Data_00)
);
BCD_transcoding U11 (.bitCode(bit2),
.num_1(Data_33),
.num_0(Data_22));
BCD_transcoding U12 (.bitCode(bit3),
.num_1(Data_55),
.num_0(Data_44));
BCD_transcoding U13 (.bitCode(bit4),
.num_1(Data_77),
.num_0(Data_66));
endmodule
1.故障分析:由于对此课题的认识不透彻,在写代码时发现并没有将状态机应用进去,让各个状态以及各个方向独立完成工作,在LED灯的展示中倒没有出现什么问题,但当到了数码管显示中就会发现从第一个倒计时转到第二个倒计时时就会发现无论怎样都转不过去,而且会出现乱码。
电路改进:除去所有代码,重新加入状态机,并且发现状态机需要作为整个设计的核心内容,建立好120秒正计时器后将其技术的数字作为状态机状态转换的依据,共八个状态循环转换,其余状态均为独立于八个状态之外的全为黄灯状态。完成之后将状态机的每个状态输出传给LED闪烁模块和数码管倒计时模块。
2.故障分析:LED闪烁模块中出现了问题,即为怎样让黄灯闪烁起来,在设计时加入或门,让1hz黄灯信号与2hz信号做或运算。
电路改进:按如上电路分析中所述,做出黄灯位的闪烁。
3.故障分析:数码管倒计时传出的数字为六位的二进制信号,无法将其在数码管上的两位上显示出来,于是想到将其转换为八位的8421BCD码前四位表示两位数的十位数字,后四位表示两位数的个位数字。
电路改进:通过对数电课本的仔细阅读,了解将普通二进制码转换为BCD码的关键,再通过编写代码来实现码转换从而可以分位传给数码管的八个位置去,接着通过数码管动态扫描来展示在数码管上。
4.故障分析:在从普通二进制码转换为8421BCD时,我将倒计时器传出的数字直接在一个代码中将其传入码转换代码中,出现了类似于软件自动维护的问题,经过老师的帮助,将其拆散为五个分代码来写。
电路改进:经过老师的帮助,我将一个代码实现的改为两个代码,其中码转换代码在总文件中需要被调用四次,从而实现从普通二进制代码转化转换为8421BCD码的过程。
电路关键是在进行时序状态转换,倒计时计数,控制黄灯闪烁过程,经过分析,需要一个来判断八个灯状态的判断条件。本电路主要运用一个120计时器,作为程序控制的灵魂,进行各个状态循环,黄灯闪烁的判断和数码管的输入。
程序亮点:为了数码管的个位十位输入,把120计数器引发状态机的状态传入倒数计时,这样与数码管的倒计时数值一致,经过简单数学计算和码转换,就可以把每个状态的计数值换算为数码管的个位十位。这样一来,省去了为数码管单独设置的变量,化简了代码。
优点:代码简单易懂,模块设计清晰明了。
缺陷:由于设定的状态机循环,没有考虑夜间模式,造成了综合时的线路繁杂以及缺少很多子代码,不能完美符合Verilog语言的关注硬件的特点。但是没有任何代码是完美的,这也正是我通过此次编程学到的最大的经验。
待优化:在夜间模式来临时LED灯所呈现出来的全黄灯闪烁总是没有实现,此课题最大的败笔就在这了,下去之后我会继续优化夜间模式直到完美实现。
[1]夏宇闻.Verilog数字系统设计[M].北京: 北京航空航天大学出版社,2008
[2]康华光.电子技术基础(数字部分)[M].北京:高等教育出版社,2006
[3]徐志军,徐光辉.CPLD/FPGA的开发与应用[M].北京:电子工业出 版社,2002
[4]张明.Verilog HDL实用教程[M].成都:电子科技大学出版社,1999