基于FPGA的交通灯

基于FPGA的交通灯


前言

交通信号灯往往由红、绿、黄三种颜色的灯组成。红灯亮的时候,禁止通行;绿灯亮的时候,可以通行;黄灯亮的时候,提示通行时间已经结束,马上要转换为红灯。

本设计采用Verilog HDL语言编写,实现了十字路口的交通灯设计。




一、系统设计

根据实验任务,我们可以大致规划出系统的控制流程:交通灯控制模块将需要显示的时间 数据连接到数码管显示模块,同时将状态信号连接到led灯控制模块,然后数码管显示模块和 led灯控制模块驱动交通信号灯外设工作。系统总体框架图如图所示
RTL视图


二、硬件设计

拓展外接电路如下:
拓展电路

三.软件设计

1.顶层设计

顶层设计完成了对其它三个子模块的例化、实现了子模块间 的信号连接、并将led灯和数码管的驱动信号输出给外接设备(交通信号灯外设)。

traffic_light u0_traffic_light(
    .sys_clk                (sys_clk),   
    .sys_rst_n              (sys_rst_n),      
    .ew_time                (ew_time),
    .sn_time                (sn_time),
    .state                  (state)
);
seg_led    u1_seg_led(
    .sys_clk                (sys_clk)  ,
    .sys_rst_n              (sys_rst_n),
    .ew_time                (ew_time),
    .sn_time                (sn_time), 
    .en                     (1'b1),   
    .sel                    (sel), 
    .seg_led                (seg_led)
);
led   u2_led(
    .sys_clk                (sys_clk  ),
    .sys_rst_n              (sys_rst_n),
    .state                  (state    ),
    .led                    (led      )
); 

2.交通灯控制设计

交通灯控制模块是本次实验的核心代码,这个模块 控制信号灯的状态转换,将实时的状态信号state[1:0]输出给led灯控制模块(led),同时将各个方向的实时时间数据输出给数码管显示模块 (seg_led)。

//计数周期为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
/切换交通信号灯工作的4个状态,并产生数码管要显示的时间数据
always @(posedge clk_1hz or negedge sys_rst_n)begin
    if(!sys_rst_n)begin        
        state <= 2'd0;
        time_cnt <= TIME_LED_G ;            //状态1持续的时间
    end 
    else begin
        case (state)
            2'b0:  begin                    //状态1
                ew_time <= time_cnt + TIME_LED_Y - 1'b1;//东西方向数码管要显示的时间数据
                sn_time <= time_cnt - 1'b1;             //南北方向数码管要显示的时间数据
                if (time_cnt > 1)begin      //time_cnt等于1的时候切换状态
                    time_cnt <= time_cnt - 1'b1;
                    state <= state;
                end 
                else begin
                    time_cnt <= TIME_LED_Y; //状态2持续的时间
                    state <= 2'b01;         //切换到状态2
                end 
            end 
            2'b01:  begin                   //状态2
                ew_time <= time_cnt  - 1'b1;
                sn_time <= time_cnt  - 1'b1; 
                if (time_cnt > 1)begin
                    time_cnt <= time_cnt - 1'b1;
                    state <= state;
                end 
                else begin
                    time_cnt <= TIME_LED_G; //状态3持续的时间
                    state <= 2'b10;         //切换到状态3
                end 
            end 
            2'b10:  begin                   //状态3
                ew_time <= time_cnt  - 1'b1;
                sn_time <= time_cnt + TIME_LED_Y - 1'b1; 
                if (time_cnt > 1)begin
                    time_cnt <= time_cnt - 1'b1;
                    state <= state;
                end 
                else begin
                    time_cnt <= TIME_LED_Y; //状态4持续的时间
                    state <= 2'b11;         //切换到转态4
                end 
            end 
            2'b11:  begin                   //状态4
                ew_time <= time_cnt  - 1'b1;
                sn_time <= time_cnt  - 1'b1; 
                if (time_cnt > 1)begin
                    time_cnt <= time_cnt - 1'b1;
                    state <= state;
                end 
                else begin
                    time_cnt <= TIME_LED_G;
                    state <= 2'b0;          //切换到状态1
                end 
            end         
            default: begin
                state <= 2'b0;
                time_cnt <= TIME_LED_G;  
            end 
        endcase
    end 
end                 

3.数码管显示设计

接收交通灯控制模块传递过来的实时时间数据,并以此驱动对应的数码管,将数据显示出来。


//计数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 
//计数器,用来切换数码管点亮的4个状态
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  <= 4'b1111;
        num  <= 4'b0;
    end 
    else if(en) begin       
        case (cnt_state) 
            3'd0 : begin     
                sel <= 4'b1110;              //驱动东西方向数码管的十位  
                num <= data_ew_0;
            end       
            3'd1 : begin     
                sel <= 4'b1101;              //驱动东西方向数码管的个位
                num <= data_ew_1;
            end 
            3'd2 : begin 
                sel <= 4'b1011;              //驱动南北方向数码管的十位
                num  <= data_sn_0;
            end
            3'd3 : begin 
                sel <= 4'b0111;              //驱动南北方向数码管的个位
                num  <= data_sn_1 ;    
            end
            default : begin     
                sel <= 4'b1111;                     
                num <= 4'b0;
            end 
        endcase
    end
    else  begin
          sel <= 4'b1111;
          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发光。

//计数时间为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 <= 6'b100100;                                                            
    else begin                                                                       
        case(state)                                                                   
            2'b00:led<=6'b100010;        //led寄存器从高到低分别驱动:东西向                        
                                         //红绿黄灯,南北向红绿黄灯                                            
            2'b01: begin                                                             
                led[5:1]<=5'b10000;                                                  
                if(cnt == TWINKLE_CNT - 1'b1)  //计数满0.2秒让黄灯的亮灭状况切换一次
                                               //产生闪烁的效果                                 
                    led[0] <= ~led[0];                                               
                else                                                                 
                    led[0] <= led[0];                                                
            end                                                                      
            2'b10:led<=6'b010100;                                                    
            2'b11: begin                                                             
                led[5:4]<=2'b00;                                                     
                led[2:0]<=3'b100;                                                    
                if(cnt == TWINKLE_CNT - 1'b1)                                            
                    led[3] <= ~led[3];                                               
                else                                                                 
                    led[3] <= led[3];                                               
            end                                                                      
            default:led<=6'b100100;                                                  
        endcase                                                                      
    end                                                                              
end
endmodule 

总结

实现了简单十字路口的控制,可以调整切换时间。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值