基于FPGA的交通灯——香樟路
前言
本设计的香樟路交通灯根据实际香樟路交通灯情况进行模拟设计,在FPGA
开发板与外接拓展模块,再现香樟路交通灯功能。
设计内容如下情况:
1、 在香樟路口设置三组红绿交通灯。
2、 从韶山路由北向南的方向始终处于通行状态,从韶山路由南向香樟路拐弯的方向始终处于通行状态。
3、 从韶山路由北向香樟路拐弯的方向的通行时间为50秒,从韶山路由南向北方
向的通行时间为25秒。
4、 从香樟路向韶山路南方向拐弯的时间为25秒,从香樟路向韶山路北方向拐弯
的时间为80秒。
5、 所有方向停车的时间均为5秒。
一、系统设计
根据实验任务,我们可以大致规划出系统的控制流程:交通灯控制模块将需要显示的时间 数据连接到数码管显示模块,同时将状态信号连接到led灯控制模块,然后数码管显示模块和 led灯控制模块驱动交通信号灯外设工作。系统总体框架图如图所示
总共有三个模块组成,RTL视图如下:

二、硬件设计
拓展外接电路如下:

交通信号灯扩展模块共13个LED灯。 上图中四个2位共阳型数码管分别对应不同的路口,每个路口用两位数码管显示当前状态的剩余时间。需要注意的是,数码管由PNP型三极管驱动,当三极管的基极为低电平时,数码管相应的位被选通,所以交通信号灯扩展模块的位选信号是低电平有效的。
PCB的3D视觉图如下:

三.软件设计
1.顶层设计
顶层设计完成了对其它三个子模块的例化、实现了子模块间 的信号连接、并将led灯和数码管的驱动信号输出给外接设备(交通信号灯外设)。
2.交通灯控制设计
交通灯控制模块是本次实验的核心代码,这个模块 控制信号灯的状态转换,将实时的状态信号state[1:0]输出给led灯控制模块(led),同时将各个方向的实时时间数据输出给数码管显示模块 (seg_led)。
//*****************************************************
//** main code
//*****************************************************
//计数周期为0.5s的计数器
always @ (posedge sys_clk or negedge sys_rst_n)begin
if(!sys_rst_n)
clk_cnt <= 25'b0;
else if (clk_cnt < WIDTH - 1'b1)
clk_cnt <= clk_cnt + 1'b1;
else
clk_cnt <= 25'b0;
end
//产生频率为1hz的时钟
always @(posedge sys_clk or negedge sys_rst_n)begin
if(!sys_rst_n)
clk_1hz <= 1'b0;
else if(clk_cnt == WIDTH - 1'b1)
clk_1hz <= ~ clk_1hz;
else
clk_1hz <= clk_1hz;
end
//切换交通信号灯工作的6个状态,并产生数码管要显示的时间数据
always @(posedge clk_1hz or negedge sys_rst_n)begin
if(!sys_rst_n)begin
state <= 3'd0;
time_cnt <= TIME_LED_50; //状态1持续的时间
end
else begin
case (state)
3'b000: begin //状态1,time_cnt=50s
s2_time <= time_cnt - 1'b1;//s2数码管要显示的时间数据
n4_time <= time_cnt + TIME_LED_5 - 1'b1;//n4数码管要显示的时间数据
e2_time <= time_cnt + TIME_LED_25 + TIME_LED_5 + TIME_LED_5 - 1'b1;//e2数码管要显示的时间数据
e1_time <= time_cnt - 1'b1;//e1数码管要显示的时间数据
if (time_cnt > 1)
begin //time_cnt等于1的时候切换状态
time_cnt <= time_cnt - 1'b1;
state <= state;
end
else
begin
time_cnt <= TIME_LED_5; //状态2持续的时间
state <= 3'b001; //切换到状态2
end
end
3'b001: begin //状态2,time_cnt=5s
s2_time <= time_cnt - 1'b1;//s2数码管要显示的时间数据
n4_time <= time_cnt - 1'b1;//n4数码管要显示的时间数据
e2_time <= time_cnt + TIME_LED_25 + TIME_LED_5 - 1'b1;//e2数码管要显示的时间数据
e1_time <= time_cnt - 1'b1;//e1数码管要显示黄灯的时间数据
if (time_cnt > 1)begin
time_cnt <= time_cnt - 1'b1;
state <= state;
end
else begin
time_cnt <= TIME_LED_25; //状态3持续的时间
state <= 3'b010; //切换到状态3
end
end
3'b010: begin //状态3,time_cnt=25s
s2_time <= time_cnt + TIME_LED_25 + TIME_LED_5 + TIME_LED_5 - 1'b1;//s2数码管要显示的时间数据
n4_time <= time_cnt - 1'b1;//n4数码管要显示的时间数据
e2_time <= time_cnt + TIME_LED_5 - 1'b1;//e2数码管要显示的时间数据
e1_time <= time_cnt + TIME_LED_5 - 1'b1;//e1数码管要显示的时间数据
if (time_cnt > 1)begin
time_cnt <= time_cnt - 1'b1;
state <= state;
end
else begin
time_cnt <= TIME_LED_5; //状态4持续的时间
state <= 3'b011; //切换到转态4
end
end
3'b011: begin //状态4,time_cnt=5s
s2_time <= time_cnt + TIME_LED_25 + TIME_LED_5 - 1'b1;//s2数码管要显示的时间数据
n4_time <= time_cnt - 1'b1;//n4数码管要显示的时间数据
e2_time <= time_cnt - 1'b1;//e2数码管要显示的时间数据
e1_time <= time_cnt - 1'b1;//e1数码管要显示的时间数据
if (time_cnt > 1)
begin
time_cnt <= time_cnt - 1'b1;
state <= state;
end
else
begin
time_cnt <= TIME_LED_25;
state <= 3'b100; //切换到状态5
end
end
3'b100: begin //状态5,time_cnt=25s
s2_time <= time_cnt + TIME_LED_5 - 1'b1;//s2数码管要显示的时间数据
n4_time <= time_cnt + TIME_LED_50 + TIME_LED_5 + TIME_LED_5 - 1'b1;//n4数码管要显示的时间数据
e2_time <= time_cnt - 1'b1;//e2数码管要显示的时间数据
e1_time <= time_cnt + TIME_LED_50 + TIME_LED_5 - 1'b1;//e1数码管要显示的时间数据
if (time_cnt > 1)
begin
time_cnt <= time_cnt - 1'b1;
state <= state;
end
else
begin
time_cnt <= TIME_LED_5;
state <= 3'b101; //切换到状态1
end
end
3'b101: begin //状态6,time_cnt=5s
s2_time <= time_cnt - 1'b1;//s2数码管要显示的时间数据
n4_time <= time_cnt + TIME_LED_50 + TIME_LED_5 - 1'b1;//n4数码管要显示的时间数据
e2_time <= time_cnt - 1'b1;//e2数码管要显示的时间数据
e1_time <= time_cnt + TIME_LED_50 - 1'b1;//e1数码管要显示的时间数据
if (time_cnt > 1)
begin
time_cnt <= time_cnt - 1'b1;
state <= state;
end
else begin
time_cnt <= TIME_LED_50;
state <= 3'b000; //切换到状态1
end
end
default: begin
state <= 3'b000;
time_cnt <= TIME_LED_50;
end
endcase
end
end
实际香樟路交通状况图:

S0:50s计数时间,N4路为红灯,显示时间55s,E1为绿灯,显示时间50s,E2为红灯,显示时间85s,S2为绿灯,显示时间50s
S1:5s计数时间,N4路为红灯,显示时间5s,E1为黄灯,显示时间5s,E2为红灯,显示时间35s,S2为黄灯,显示时间5s
S2:25s计数时间,N4路为绿灯,显示时间25s,E1为红灯,显示时间30s,E2为红灯,显示时间30s,S2为红灯,显示时间60s
S3:5s计数时间,N4路为黄灯,显示时间5s,E1为红灯,显示时间5s,E2为红灯,显示时间5s,S2为红灯,显示时间35s
S4:25s计数时间,N4路为红灯,显示时间85s,E1为绿灯,显示时间80s,E2为绿灯,显示时间25s,S2为红灯,显示时间25s
3.数码管显示设计
接收交通灯控制模块传递过来的实时时间数据,并以此驱动对应的数码管,将数据显示出来。
//*****************************************************
//** main code
//*****************************************************
ssign data_s2_0 = s2_time / 10; //取出s2时间数据的十位
assign data_s2_1 = s2_time % 10; //取出s2时间数据的个位
assign data_e1_0 = e1_time / 10; //取出e1时间数据的十位
assign data_e1_1 = e1_time % 10; //取出e1时间数据的个位
assign data_e2_0 = e2_time / 10; //取出e2时间数据的十位
assign data_e2_1 = e2_time % 10; //取出e2时间数据的个位
assign data_n4_0 = n4_time / 10; //取出n4时间数据的十位
assign data_n4_1 = n4_time % 10; //取出n4时间数据的个位
//计数1ms
always @ (posedge sys_clk or negedge sys_rst_n) begin
if (!sys_rst_n)
cnt_1ms <= 15'b0;
else if (cnt_1ms < WIDTH - 1'b1)
cnt_1ms <= cnt_1ms + 1'b1;
else
cnt_1ms <= 15'b0;
end
//计数器,用来切换数码管点亮的6个状态
always @ (posedge sys_clk or negedge sys_rst_n) begin
if (!sys_rst_n)
cnt_state <= 2'd0;
else if (cnt_1ms == WIDTH - 1'b1)
cnt_state <= cnt_state + 1'b1;
else
cnt_state <= cnt_state;
end
//先显示数码管的十位,然后是个位
always @ (posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n) begin
sel <= 8'b00000000;
num <= 4'b0;
end
else if(en) begin
case (cnt_state)
3'd0 : begin
sel <= 8'b11111110; //S2东西方向数码管的十位
num <= data_s2_0;
end
3'd1 : begin
sel <= 8'b11111101; //S2东西方向数码管的个位
num <= data_s2_1;
end
3'd2 : begin
sel <= 8'b11111011; //E1南北方向数码管的十位
num <= data_e1_0;
end
3'd3 : begin
sel <= 8'b11110111; //E1南北方向数码管的个位
num <= data_e1_1 ;
end
3'd4 : begin
sel <= 8'b11101111; //E2东西方向数码管的十位
num <= data_e2_0;
end
3'd5 : begin
sel <= 8'b11011111; //E2东西方向数码管的个位
num <= data_e2_1;
end
3'd6 : begin
sel <= 8'b10111111; //N4南北方向数码管的十位
num <= data_n4_0;
end
3'd7 : begin
sel <= 8'b01111111; //N4南北方向数码管的个位
num <= data_n4_1 ;
end
default : begin
sel <= 8'b11111111;
num <= 4'b0;
end
endcase
end
else begin
sel <= 8'b11111111;
num <= 4'b0;
end
end
//数码管要显示的数值所对应的段选信号
always @ (posedge sys_clk or negedge sys_rst_n) begin
if (!sys_rst_n)
seg_led <= 8'b0;
else begin
case (num)
4'd0 : seg_led <= 8'b1100_0000;
4'd1 : seg_led <= 8'b1111_1001;
4'd2 : seg_led <= 8'b1010_0100;
4'd3 : seg_led <= 8'b1011_0000;
4'd4 : seg_led <= 8'b1001_1001;
4'd5 : seg_led <= 8'b1001_0010;
4'd6 : seg_led <= 8'b1000_0010;
4'd7 : seg_led <= 8'b1111_1000;
4'd8 : seg_led <= 8'b1000_0000;
4'd9 : seg_led <= 8'b1001_0000;
default : seg_led <= 8'b1100_0000;
endcase
end
end
4.LED灯控制设计
根据接收到的实时状态信号state[1:0],驱动led发光。
module led (
input sys_clk , //系统时钟
input sys_rst_n , //系统复位
input [3:0] state , //交通灯的状态
output reg [12:0] led //红黄绿LED灯发光使能
);
//parameter define
parameter TWINKLE_CNT = 20_000_000; //让黄灯闪烁的计数次数
//reg define
reg [24:0] cnt; //让黄灯产生闪烁效果的计数器
//计数时间为0.2s的计数器,用于让黄灯闪烁
always @(posedge sys_clk or negedge sys_rst_n)begin
if(!sys_rst_n)
cnt <= 25'b0;
else if (cnt < TWINKLE_CNT - 1'b1)
cnt <= cnt + 1'b1;
else
cnt <= 25'b0;
end
//在交通灯的状态里,使相应的led灯发光
always @(posedge sys_clk or negedge sys_rst_n)begin
if(!sys_rst_n)
led <= 13'b1_100_100_100_100;
else begin
case(state)
3'b000:led<=13'b1_100_010_100_010; //led寄存器
3'b001: begin
led[5:1]<=5'b100_00;
led[12:7]<=6'b1_100_00;
if(cnt == TWINKLE_CNT - 1'b1) //计数满0.2秒让黄灯的亮灭状况切换一次
//产生闪烁的效果
begin
led[0] <= ~led[0];
led[6] <= ~led[6]; end
else
begin
led[0] <= led[0];
led[6] <= ~led[6]; end
end
3'b010:led<=13'b1_010_100_100_100;
3'b011: begin
led[8:0]<=9'b100_100_100;
led[12:10]<=3'b1_00;
if(cnt == TWINKLE_CNT - 1'b1)
led[9] <= ~led[9];
else
led[9] <= led[9];
end
3'b100:led<=13'b1_100_010_010_100;
3'b101: begin
led[2:0]<=3'b100;
led[12:4]<=9'b1_100_010_00;
if(cnt == TWINKLE_CNT - 1'b1)
led[3] <= ~led[3];
else
led[3] <= led[3];
end
default:led<=13'b1_100_100_100_100;
endcase
end
end
endmodule

1万+

被折叠的 条评论
为什么被折叠?



