基于FPGA的交通灯——香樟路

基于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                

总结

本设计是在普通交通灯设计基础上面结合实际香樟路的交通情况进行模拟设计,其设计原理与普通交通灯设计原理近似,只需要增加状态的转换与数码管与led显示的数量。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值