用verilog实现24小时计时功能的十字路口交通信号灯(支持直行与左转)

       众所周知,车辆上路,通常靠右行驶,所以右转是不需要红绿灯的限制的。首先,我们把十字路口分为东西走向(设为1)和南北走向(设为2)。将东西左转南北设为1r,将南北左转东西设为2r。接着,构思一下红绿灯的状态变换,如下图所示(随便扣了张图,自己做了点补充,字用鼠标写的,不代表本人手写水平):

       这里,其实我的设计跟实际生活中的情况是有出入的,通常实际生活中南北或东西方向同一时间只能进行单向通行,以保证更加的安全,而本图中假设南北或东西方向同一时间是能进行双向通行的,以减少工作量,实际上,只要多增加一倍的状态,也能达到生活中红绿灯的效果。

       最后,我们再给程序加上24小时时钟功能,通过六个数码管来显示时间。

       废话不多说,直接上代码:

头文件:

module ten_word(

    input wire                  clk_i,
    input wire                  sysrst_li,
    output wire                 r1_o,
    output wire                 y1_o,
    output wire                 g1_o,
    output wire                 r2_o,
    output wire                 y2_o,
    output wire                 g2_o,
    output wire                 r1r_o,
    output wire                 y1r_o,
    output wire                 g1r_o,
    output wire                 r2r_o,
    output wire                 y2r_o,
    output wire                 g2r_o,
    output                 [7:0]seg,
    output                 [7:0]seg1,
    output                 [3:0]sel,
    output                 [1:0]sel1

    );


    wire                    tick1s;
    wire              [3:0] data0;
    wire              [3:0] data1;
    wire              [3:0] data2;
    wire              [3:0] data3;
    wire              [3:0] data4;
    wire              [3:0] data5;

    
    tick_1s inst_tick_1s (

        .clk_i                      (clk_i),
        .rst_i                      (~sysrst_li),
        .tick1s_o                   (tick1s)
    );

    

    tl_fsm inst_tl_fsm (

        .clk_i                      (clk_i),
        .rst_i                      (~sysrst_li),
        .tick1s_i                   (tick1s),
        .r1_o                       (r1_o),
        .y1_o                       (y1_o),
        .g1_o                       (g1_o),
        .r2_o                       (r2_o),
        .y2_o                       (y2_o),
        .g2_o                       (g2_o),
        .r1r_o                      (r1r_o),
        .y1r_o                      (y1r_o),
        .g1r_o                      (g1r_o),
        .r2r_o                      (r2r_o),
        .y2r_o                      (y2r_o),
        .g2r_o                      (g2r_o)
    );

    digital inst_digital(

         .clk_i(clk_i),
         .rst_i(~sysrst_li),
         .data0(data0),
         .data1(data1),
         .data2(data2),
         .data3(data3),
         .data4(data4),
         .data5(data5),
         .seg(seg),
         .seg1(seg1),
         .sel(sel),
         .sel1(sel1)
    );

clock inst_clock(

         .clk_i(clk_i),
         .rst_i(~sysrst_li),
         .tick1s_o(tick1s),
         .data0(data0),
         .data1(data1),
         .data2(data2),
         .data3(data3),
         .data4(data4),
         .data5(data5)
);

    

endmodule

一秒计时器代码:

module tick_1s (

    input wire              clk_i,
    input wire              rst_i,
    output wire             tick1s_o
    );

parameter num_1s = 100_000_000;
reg [26:0]cnt_1s;
always@(posedge clk_i)
  begin
    if(rst_i) begin
      cnt_1s = 0;
    end
    else
      begin
        if(cnt_1s == num_1s) cnt_1s <= 0;
        else cnt_1s <= cnt_1s+1;
      end
   end
assign tick1s_o = (cnt_1s == num_1s) ? 1 : 0;


endmodule

数码管(共阴极)显示代码:

module digital(

  input clk_i,
  input rst_i,
  input [3:0]data0,
  input [3:0]data1,
  input [3:0]data2,
  input [3:0]data3,
  input [3:0]data4,
  input [3:0]data5,
  output reg[7:0]seg,
  output reg[7:0]seg1,
  output reg[3:0]sel,
  output reg[1:0]sel1
);

reg[15:0]cnl;
reg clk1k;
always@(posedge clk_i)
  begin
    if(rst_i)
    begin
      cnl=0;
      clk1k=0;
    end
    else if(cnl>=49999)
    begin
      clk1k=~clk1k;
      cnl=0;
    end
    else cnl<=cnl+1;
  end
reg [3:0]tub;
reg [3:0]tub1;
reg [5:0]state;
always@(posedge clk1k)
  begin
    if(rst_i)
    begin
      tub=0;
      state=0;
      sel=0;
      sel1=0;
      tub1=0;
    end
    else
    begin
      case(state)

        0:begin tub1=data0;sel1=2'b10;state=1;end
        1:begin tub1=data1;sel1=2'b01;state=2;end
        2:begin tub=data2;sel=4'b1000;state=3;end
        3:begin tub=data3;sel=4'b0100;state=4;end
        4:begin tub=data4;sel=4'b0010;state=5;end
        5:begin tub=data5;sel=4'b0001;state=0;end
        default:state<=0;
      endcase
    end
  end
always@(*)
  if(rst_i)
    seg=8'b00110000;
  else
    case(tub)
      4'd0:seg=8'b00111111;
      4'd1:seg=8'b00000110;
      4'd2:seg=8'b01011011;
      4'd3:seg=8'b01001111;
      4'd4:seg=8'b01100110;
      4'd5:seg=8'b01101101;
      4'd6:seg=8'b01111101;
      4'd7:seg=8'b00000111;
      4'd8:seg=8'b01111111;
      4'd9:seg=8'b01101111;
      default:seg=8'b00110000;
    endcase
    always@(*)
  if(rst_i)
    seg1=8'b00110000;
  else
    case(tub1)
      4'd0:seg1=8'b00111111;
      4'd1:seg1=8'b00000110;
      4'd2:seg1=8'b01011011;
      4'd3:seg1=8'b01001111;
      4'd4:seg1=8'b01100110;
      4'd5:seg1=8'b01101101;
      4'd6:seg1=8'b01111101;
      4'd7:seg1=8'b00000111;
      4'd8:seg1=8'b01111111;
      4'd9:seg1=8'b01101111;
      default:seg1=8'b00110000;
    endcase

endmodule

24小时时钟代码:

module clock(

  input clk_i,
  input rst_i,
  input tick1s_o,
  output reg[3:0]data0,
  output reg[3:0]data1,
  output reg[3:0]data2,
  output reg[3:0]data3,
  output reg[3:0]data4,
  output reg[3:0]data5
);
reg [5:0] second;
reg [5:0] minute;
reg [4:0] hour;
always@(posedge clk_i)
  begin
    if(rst_i) begin
      second = 0;
    end else begin
       if(second==59&&tick1s_o)begin
         second = 0;
       end else if(tick1s_o)begin
         second = second + 1;
       end else begin
         second = second;
       end
     end
  end
always@(posedge clk_i)
  begin
    if(rst_i) minute = 0;
    else
      begin
       if(minute==59&&second==59&&tick1s_o) minute = 0;
       else if(second==59&&tick1s_o) minute <= minute + 1;
       else minute = minute;
      end
   end
always@(posedge clk_i)
  begin
    if(rst_i) hour = 0;
    else
      begin
        if(hour==23&&minute==59&&second==59&&tick1s_o) hour=0;
        else if(minute==59&&second==59&&tick1s_o) hour <= hour + 1;
        else hour <= hour;
      end
  end
always@(posedge clk_i)
  begin
    if(rst_i) begin
      data0 = 0;
      data1 = 0;
      data2 = 0;
      data3 = 0;
      data4 = 0;
      data5 = 0;
    end else begin
      data0 = hour/10;
      data1 = hour%10;
      data2 = minute/10;
      data3 = minute%10;
      data4 = second/10;
      data5 = second%10;
    end
  end

endmodule

红绿灯FSM代码:

module tl_fsm (
    input wire                  clk_i,
    input wire                  rst_i,
    input wire                  tick1s_i,    
    output reg                  r1_o,
    output reg                  y1_o,
    output reg                  g1_o,
    output reg                  r2_o,
    output reg                  y2_o,
    output reg                  g2_o,
    output reg                  r1r_o,
    output reg                  y1r_o,
    output reg                  g1r_o,
    output reg                  r2r_o,
    output reg                  y2r_o,
    output reg                  g2r_o
    );
    reg [4:0]                   cnt1;
    reg                         load1;
    reg                         load2;
    reg                         load3;
    reg                         load4;
    reg                         load5;
    reg                         load6;
    reg                         load7;
    reg                         load8;
    always @(posedge clk_i) begin
        if(rst_i)
            cnt1 <= 5'd0;
        else if(load1)
            cnt1 <= 5'd20;
        else if(load2)
            cnt1 <= 5'd3;
        else if(load3)
            cnt1 <= 5'd20;
        else if(load4)
            cnt1 <= 5'd3;
        else if(load5)
            cnt1 <= 5'd20;
        else if(load6)
            cnt1 <= 5'd3;
        else if(load7)
            cnt1 <= 5'd20;
        else if(load8)
            cnt1 <= 5'd3;
        else if(tick1s_i)
            cnt1 <= cnt1 - 1'b1;
        else
            cnt1 <= cnt1;
    end
    //fsm template
    reg [8:0]               cstate, nstate;
    parameter               S_IDLE              = 9'b0_0000_0001,
                            S_G2                = 9'b0_0000_0010,
                            S_Y1                = 9'b0_0000_0100,
                            S_G2r               = 9'b0_0000_1000,
                            S_Y2                = 9'b0_0001_0000,
                            S_G1                = 9'b0_0010_0000,
                            S_Y3                = 9'b0_0100_0000,
                            S_G1r               = 9'b0_1000_0000,
                            S_Y4                = 9'b1_0000_0000;
    always @(posedge clk_i) begin
        if(rst_i)
            cstate <= S_IDLE;
        else
            cstate <= nstate;
    end
    always @(*) begin
        r1_o = 1'b0;
        y1_o = 1'b0;
        g1_o = 1'b0;
        r2_o = 1'b0;
        y2_o = 1'b0;
        g2_o = 1'b0;
        r1r_o= 1'b0;
        y1r_o= 1'b0;
        g1r_o= 1'b0;
        r2r_o= 1'b0;
        y2r_o= 1'b0;
        g2r_o= 1'b0;
        load1 = 1'b0;
        load2 = 1'b0;
        load3 = 1'b0;
        load4 = 1'b0;
        load5 = 1'b0;
        load6 = 1'b0;
        load7 = 1'b0;
        load8 = 1'b0;
        nstate = S_IDLE;
        case(cstate)
            S_IDLE: begin
                y1_o = 1'b1;
                y2_o = 1'b1;
                r1r_o = 1'b1;
                r2r_o = 1'b1;
                load1 = 1'b1;
                nstate = S_G2;
            end
            S_G2: begin
                g2_o = 1'b1;
                r1_o = 1'b1;
                r1r_o = 1'b1;
                r2r_o = 1'b1;
                if(cnt1 == 5'd0) begin
                    load2 = 1'b1;
                    nstate = S_Y1;                    
                end else begin
                    nstate = S_G2;
                end            
            end
            S_Y1: begin
            y2_o = 1'b1;
                y2r_o = 1'b1;
                r1r_o = 1'b1;
                r1_o = 1'b1;
                if(cnt1 == 5'd0) begin
                    load3 = 1'b1;
                    nstate = S_G2r;                    
                end else begin
                    nstate = S_Y1;
                end            
            end
            S_G2r: begin
            r2_o = 1'b1;
                r1_o = 1'b1;
                r1r_o = 1'b1;
                g2r_o = 1'b1;
                if(cnt1 == 5'd0) begin
                    load4 = 1'b1;
                    nstate = S_Y2;                    
                end else begin
                    nstate = S_G2r;
                end            
            end
            S_Y2: begin
            r2_o = 1'b1;
                y1_o = 1'b1;
                r1r_o = 1'b1;
                y2r_o = 1'b1;
                if(cnt1 == 5'd0) begin
                    load5 = 1'b1;
                    nstate = S_G1;                    
                end else begin
                    nstate = S_Y2;
                end            
            end
             S_G1: begin
            r2_o = 1'b1;
                g1_o = 1'b1;
                r1r_o = 1'b1;
                r2r_o = 1'b1;
                if(cnt1 == 5'd0) begin
                    load6 = 1'b1;
                    nstate = S_Y3;                    
                end else begin
                    nstate = S_G1;
                end            
            end
            S_Y3: begin
            r2_o = 1'b1;
                y1_o = 1'b1;
                y1r_o = 1'b1;
                r2r_o = 1'b1;
                if(cnt1 == 5'd0) begin
                    load7 = 1'b1;
                    nstate = S_G1r;                    
                end else begin
                    nstate = S_Y3;
                end            
            end
            S_G1r: begin
            r2_o = 1'b1;
                r1_o = 1'b1;
                g1r_o = 1'b1;
                r2r_o = 1'b1;
                if(cnt1 == 5'd0) begin
                    load8 = 1'b1;
                    nstate = S_Y4;                    
                end else begin
                    nstate = S_G1r;
                end            
            end
             S_Y4: begin
            y2_o = 1'b1;
                r1_o = 1'b1;
                y1r_o = 1'b1;
                r2r_o = 1'b1;
                if(cnt1 == 5'd0) begin
                    load1 = 1'b1;
                    nstate = S_G2;                    
                end else begin
                    nstate = S_Y4;
                end            
            end
            default: nstate = S_IDLE;
        endcase
    end    

 endmodule   

仿真波形图:

       代码设置的时间比较长,所以波形只展示出了部分,代码适用于下板子时使用,仿真的时候可以更改一秒定时器的参数大小,压缩一下波形,另外,也可以调整vivado的仿真时间,有些版本(如21.2)无法通过更改方框内的数来改变仿真时间,这时我们可以直接在settings里面进行更改。

testbench代码:


module tb_ten_word(
    
    );
    reg                 clk=1'b0;
    reg                rst=1'b1;
    reg               tick1s=1'b0;    
    wire                 r1;
    wire                 y1;
    wire                 g1;
    wire                 r2;
    wire                 y2;
    wire                 g2;
    wire                 r1r;
    wire                 y1r;
    wire                 g1r;
    wire                 r2r;
    wire                 y2r;
    wire                 g2r;
    wire                 [7:0]seg;
    wire                 [7:0]seg1;
    wire                 [3:0]sel;
    wire                 [1:0]sel1;
    reg             [2:0]cnt2;

    wire              [3:0] data0;
    wire              [3:0] data1;
    wire              [3:0] data2;
    wire              [3:0] data3;
    wire              [3:0] data4;
    wire              [3:0] data5;



   digital inst_digital(
         .clk_i(clk),
         .rst_i(rst),
         .data0(data0),
         .data1(data1),
         .data2(data2),
         .data3(data3),
         .data4(data4),
         .data5(data5),
         .seg(seg),
         .seg1(seg1),
         .sel(sel),
         .sel1(sel1)
    );
clock inst_clock(
         .clk_i(clk),
         .rst_i(rst),
         .tick1s_o(tick1s),
         .data0(data0),
         .data1(data1),
         .data2(data2),
         .data3(data3),
         .data4(data4),
         .data5(data5)
);


 tl_fsm inst_tl_fsm (
        .clk_i                      (clk),
        .rst_i                      (rst),
        .tick1s_i                   (tick1s),
        .r1_o                       (r1),
        .y1_o                       (y1),
        .g1_o                       (g1),
        .r2_o                       (r2),
        .y2_o                       (y2),
        .g2_o                       (g2),
        .r1r_o                      (r1r), 
        .y1r_o                      (y1r),
        .g1r_o                      (g1r),
        .r2r_o                      (r2r),
        .y2r_o                      (y2r),
        .g2r_o                      (g2r)
    );

               
 

   
           

 initial begin
      #100 rst=1'b0;
  end  
 always
    #10 clk=~clk;
    
    

     always @(posedge clk) begin
        if(rst)
            cnt2 <= 5'b00000;
        else if(cnt2 == 5'b00101)begin
            cnt2 <= 5'b00000;         
            tick1s = 1'b1;
        end
        else begin
            cnt2 <= cnt2 + 1'b1;
            tick1s = 1'b0;
        end
    end    
    
    
 
endmodule

       上板测试(添加视频麻烦,不添加了):

       最后,声明一下,代码并非全部是我自己敲的,稍微借鉴了一下其他博文的内容,同时也参考了老师上课给的代码模板,发出来留个纪念,虽然能力不强,但通过自己的努力做出一样东西还是挺有成就感的。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值