十字路口交通信号灯控制系统
主要任务
- 设计一个用于十字路口的交通灯控制器,能显示十字路口东西、南北两个方向的红、黄、绿的指示状态;
- 具有倒计时的功能,用两组数码管作为东西和南北方向的倒计时显示,主干道直行(绿灯)60秒后,左转(绿灯)40秒;支干道直行(绿灯)45秒后,左转(绿灯)30秒,在每次绿灯变成红灯的转换过程中,要亮黄灯5秒作为过渡。黄灯每秒闪亮一次。
- 只考虑直行和左转车辆控制信号灯,右转车辆不受信号灯控制, 南北向车辆与东西向车辆交替方向,同方向等待车辆应先方向直行车辆而后放行左转车辆。
开发平台
系统开发工具 | Vivado |
---|---|
系统开发语言 | Verilog |
仿真平台 | 杰创EDA远程二代网页版 |
时序分析
首先弄清楚主干路和支干路在一个周期内的变化状况,如图所示:
电路原理图
此电路原理图是在杰创EDA远程二代网页版上进行绘制的,如图所示
设计思路
交通信号灯系统控制的原理框图如图所示,将系统分成4个模块:
- 主控制器模块
- 定时计数器模块
- 分频计数器模块
- 译码模块
主控制器模块
主控制器模块原理上是一个状态机,依据要求设计,设计出信号灯点亮规律的状态转换表,如表所示,其中0表示灭,1表示亮,状态表显示了信号灯在运行过程中每个状态应该持续的时间,以及状态之间的转换顺序。依据分频计数器,当分频计数器的时钟达到了对应时间则切换为下一个状态,就可以实现控制信号灯的亮灭。
图中有八个状态,实际编程的时候还应该符加四个状态,用于表示黄灯的闪烁,这四个状态对应黄灯为0,表示黄灯熄灭,1s切换一次状态就可以达到黄灯每秒闪烁一次的效果,符加状态如下表所示:
分频计数器模块
整个系统采用的时钟是1khz,原因是为了显示四位数码管上多位数字,而信号灯的状态切换是以秒为单位进行的,因此需要将1khz的时钟信号转化成1hz的,设计分频计数器,每500个周期,分频时钟信号反转一次。
定时器模块
状态机上共有8个状态,以这8个状态为周期进行循环,系统执行一个周期共计需要195秒,因此设计定时计数器进行计数,定时到195秒时就归零重新计时。
译码模块
在讲译码模块之前,先讲一讲四位数码管如何使用,七段数码管是电子开发过程中常用的输出显示设备,本项目使用的是一个四八位一体,共阴极型七段数码管。右图是本实验用到的四八位一体,共阴极型,左图为单个静态数码管。
由于此设计七段数码管公共端连接到GND(共阴极型),当数码管的中的那一个段(a,b,c,d,e,f,g)被输入高电平,则相应的这一段被点亮。反之则不亮。四位一体的七段数码管在单个静态数码管的基础上加入了用于选择哪一位数码管的位选信号(1,2,3,4)端口。四个数码管的a,b,c,d,e,f,g,h,dp都连接在了一起,4个数码管分别由各自的 位选信号来控制,当位选信号为低电平时该位数码管被选择。同一时刻只有一位数码管被选中并点亮,下一时刻则切换到相邻位数码管,但因为切换速度很快,在视觉暂留效应的帮助下,我们看到的就是四位数码管被整体点亮。
为此可以设计出每个数字的译码表,如表所示
数字 | 十六进制下编码 |
---|---|
0 | 7’h7e |
1 | 7’h30 |
2 | 7’h6d |
3 | 7’h79 |
4 | 7‘h33 |
5 | 7’h5b |
6 | 7’h5f |
7 | 7’h70 |
8 | 7’h7f |
9 | 7’h7b |
输出数据的时候,在管脚上输出相应的编码,控制时钟以快速频率切换就可以实现显示两位数字效果。默认使用两位数字来显示倒计时,有红灯倒计时大于99秒的情况,也就是超出两位数字所表示的范围,规定超过99秒则不显示
实现
主控制模块
module traffic_light (
clk,
rst_n,
count,
ew,
sn
);
input clk,rst_n;
input [7:0] count;
output [5:0] ew,sn;
reg [5:0] ew,sn;
reg [3:0] pre_state,next_state;
reg [12:0] counter=13'b0;
reg clk_5hz=1'b0;
parameter
S0=4'b0000, //主干路四个状态
S1=4'b0001,
S2=4'b0010,
S3=4'b0011,
S4=4'b0100, //支干路四个状态
S5=4'b0101,
S6=4'b0110,
S7=4'b0111,
S8=4'b1000, //主干路直行黄灯
S9=4'b1001, //主干路左转黄灯
S10=4'b1010, //支干路直行黄灯
S11=4'b1011; //支干路左转黄灯
always @ (negedge clk or negedge rst_n)
begin
if(!rst_n)
pre_state<=S0;
else
pre_state<=next_state;
end
always @ (negedge clk) begin //这段代码是用来实现黄灯的闪烁功能
if(count>=60&&count<65)
begin
counter <=counter+1'b1;
if (counter == 'd499)begin //计数,形成0.5秒的时钟
clk_5hz <= !clk_5hz;
counter <= 'd0;
end
end
else if(count>=105&&count<110)
begin
counter <=counter+1'b1;
if (counter == 'd499)begin
clk_5hz <= !clk_5hz;
counter <= 'd0;
end
end
else if(count>=155&&count<160)
begin
counter <=counter+1'b1;
if (counter == 'd499)begin
clk_5hz <= !clk_5hz;
counter <= 'd0;
end
end
else if(count>=190&&count<195)
begin
counter <=counter+1'b1;
if (counter == 'd499)begin
clk_5hz <= !clk_5hz;
counter <= 'd0;
end
end
else
counter <='d0;
end
always @ (clk or pre_state)
begin
next_state<=3'bxxx;
if(count>=60 && count<65) begin //主干路直行黄灯
if(clk_5hz) next_state<=S8;
else
next_state <=S1; end
else if(count==8'd65) //主干路左转绿灯
next_state<=S2;
else if(count>=8'd105 && count<8'd110)begin //主干路左转黄灯
if(clk_5hz) next_state <=S9;
else
next_state<=S3;end
else if (count==8'd110) //支干路直行绿灯
next_state<=S4;
else if (count>=8'd155 && count<8'd160)begin //支干路直行黄灯
if(clk_5hz) next_state <=S10;
else
next_state<=S5;end
else if (count==8'd160) //支干路左转绿灯
next_state<=S6;
else if (count>=8'd190 && count<8'd195)begin //支干路左转黄的
if(clk_5hz) next_state <=S11;
else
next_state<=S7