当前位置:   article > 正文

FPGA项目(9)——基于FPGA的交通灯设计_fpga交通灯

fpga交通灯

        首先,简要阐述一下本次设计所实现的基本功能。

        系统输入两组时钟,一个是50M时钟,一个是1HZ时钟,另外,系统还有一个复位信号,一个拨码开关信号。输出两组LED灯,分别表示东西方向、南北方向的红绿灯。每组灯为6位宽,表示各个方向的红、黄、绿灯。示意图如下所示:

         要实现:

        东西方向红灯亮,南北方向绿灯亮,保持35S;

        东西方向红灯亮,南北方向黄灯亮,保持5S;

        东西方向绿灯亮,南北方向红灯亮,维持35S;

        东西方向黄灯亮,南北方向红灯亮,维持5S。

        如此反复循环。

        交通灯的自动工作受到拨码开关的控制,开关拨上时,系统正常工作,否则,全部亮红灯。各个状态的时间倒计时会通过数码管显示出来,数码管的高两位显示的是倒计时的时间,后六位可以显示任意指定的数字(可以是日期,可以是学号,等等)

        下面讲解一下verilog实现的过程:

        还是采用自顶层向下的设计思想,整体的原理图如下:

        分为交通灯控制模块,和数码管显示模块。数码管显示模块的内容之前已经介绍过,这里不再详细介绍。但是这次使用的数码管,在硬件上和之前有所不同,但是大致的原理一样。所以这里只给出代码:

  

  1. module segshow(
  2. input sys_clk,sys_rest,
  3. input [26:0] shu,
  4. output reg [2:0] sel,
  5. output reg [6:0] seg_led
  6. );
  7. //parameter MSNUM=14'd50000; //实物使用这个参数
  8. parameter MSNUM=14'd2; //仿真使用这个参数
  9. reg [12:0] MSCNT;
  10. reg MS_flag;
  11. reg [3:0] num_display;
  12. reg [2:0] sel_num; //选择哪一位数码管被点亮
  13. //wire define
  14. wire [3:0] shu0 ; // 个位数
  15. wire [3:0] shu1 ; // 十位数
  16. wire [3:0] shu2 ; // 百位数
  17. wire [3:0] shu3 ; // 千位数
  18. wire [3:0] shu4 ; // 万位数
  19. wire [3:0] shu5 ; // 十万位数
  20. wire [3:0] shu6 ; // 百万位数
  21. wire [3:0] shu7 ; // 千万位数
  22. //提取显示数值所对应的十进制数的各个位
  23. assign shu0 = shu % 4'd10; // 个位数
  24. assign shu1 = shu / 4'd10 % 4'd10 ; // 十位数
  25. assign shu2 = shu / 7'd100 % 4'd10 ; // 百位数
  26. assign shu3 = shu / 10'd1000 % 4'd10 ; // 千位数
  27. assign shu4 = shu / 14'd10000 % 4'd10; // 万位数
  28. assign shu5 = shu / 17'd100000%4'd10; // 十万位数
  29. assign shu6 = shu / 20'd1000000%4'd10; // 百万位数
  30. assign shu7 = shu / 23'd10000000; // 千万位数
  31. always @(posedge sys_clk or negedge sys_rest) begin //产生1ms脉冲
  32. if(!sys_rest)
  33. begin
  34. MSCNT<=13'd0;
  35. MS_flag<=1'b0;
  36. end
  37. else if(MSCNT==MSNUM-1)
  38. begin
  39. MSCNT<=13'd0;
  40. MS_flag<=1'b1;
  41. end
  42. else
  43. begin
  44. MSCNT<=MSCNT+1;
  45. MS_flag<=1'b0;
  46. end
  47. end
  48. always @(posedge sys_clk or negedge sys_rest) begin
  49. if(!sys_rest)
  50. sel_num<=0;
  51. else if(MS_flag)
  52. begin
  53. if(sel_num<3'd7)
  54. sel_num<=sel_num+1;
  55. else
  56. sel_num<=0;
  57. end
  58. else
  59. sel_num<=sel_num;
  60. end
  61. always @(posedge sys_clk or negedge sys_rest) begin
  62. if(!sys_rest)
  63. sel<=3'b000;
  64. else
  65. begin
  66. case(sel_num)
  67. 3'd0: begin
  68. sel<= 3'b000; //显示数码管最低位
  69. num_display<=shu0;
  70. end
  71. 3'd1: begin
  72. sel<= 3'b001; //显示数码管第1位
  73. num_display<=shu1;
  74. end
  75. 3'd2: begin
  76. sel<= 3'b010; //显示数码管第2位
  77. num_display<=shu2;
  78. end
  79. 3'd3: begin
  80. sel<= 3'b011; //显示数码管第3位
  81. num_display<=shu3;
  82. end
  83. 3'd4: begin
  84. sel<= 3'b100; //显示数码管第4位
  85. num_display<=shu4;
  86. end
  87. 3'd5: begin
  88. sel<= 3'b101; //显示数码管第5位
  89. num_display<=shu5;
  90. end
  91. 3'd6: begin
  92. sel<= 3'b110;
  93. num_display<=shu6;
  94. end
  95. 3'd7: begin
  96. sel<= 3'b111; //显示数码管最高位
  97. num_display<=shu7;
  98. end
  99. default sel<= 3'b000;
  100. endcase
  101. end
  102. end
  103. always @(posedge sys_clk or negedge sys_rest) begin
  104. if(!sys_rest)
  105. seg_led<=7'b0111111;
  106. else
  107. begin
  108. case(num_display)
  109. 4'h0 : seg_led <= 7'b0111111;//0
  110. 4'h1 : seg_led <= 7'b0000110;//1
  111. 4'h2 : seg_led <= 7'b1011011;//2
  112. 4'h3 : seg_led <= 7'b1001111;//3
  113. 4'h4 : seg_led <= 7'b1100110;//4
  114. 4'h5 : seg_led <= 7'b1101101;//5
  115. 4'h6 : seg_led <= 7'b1111101;//6
  116. 4'h7 : seg_led <= 7'b0000111;//7
  117. 4'h8 : seg_led <= 7'b1111111;//8
  118. 4'h9 : seg_led <= 7'b1101111;//9
  119. default : seg_led <= 7'b0111111;//0
  120. endcase
  121. end
  122. end
  123. endmodule

        那么重点是LED的控制逻辑。这里的控制,主要用到了状态机,我用的是二段式状态机,先给出代码,再根据代码讲解。

        

  1. module jtd_led(
  2. clk_50m,clk_1hz,rst,k,light1,light2,data
  3. );
  4. input clk_50m;
  5. input clk_1hz;
  6. input rst;
  7. input k; //手动控制信号
  8. output [5:0] light1; //东西方向的灯 绿 黄 红 绿 黄 红
  9. output [5:0] light2; //南北方向的灯 绿 黄 红 绿 黄 红
  10. output [26:0] data;
  11. reg [5:0] light1; //定义信号类型
  12. reg [5:0] light2;
  13. reg [3:0] state ;
  14. reg [3:0] next_state ;
  15. reg [5:0] jishu;
  16. wire [3:0] jishu_ge;
  17. wire [3:0] jishu_shi;
  18. reg [5:0] jishu_num;
  19. parameter S0 = 4'b0000 ;
  20. parameter S1 = 4'b0001 ;
  21. parameter S2 = 4'b0010 ;
  22. parameter S3 = 4'b0100 ;
  23. parameter S4 = 4'b1000 ;
  24. //二段式状态机
  25. always @(posedge clk_50m or negedge rst) begin
  26. if(!rst)
  27. state <= S0;
  28. else
  29. state <= next_state;
  30. end
  31. always @(posedge clk_1hz) begin
  32. if(k==0) begin
  33. case (state)
  34. S0: if (!rst) begin
  35. next_state <= S1;
  36. jishu_num<=6'd35; //状态维持35S
  37. light1 = 6'b001_001; //红灯
  38. light2 = 6'b100_100; //绿灯
  39. end
  40. S1: if (jishu == 6'd0) begin
  41. next_state <= S2;
  42. jishu_num<=6'd5; //维持5S
  43. light1 = 6'b001_001; //红灯
  44. light2 = 6'b010_010; //黄灯
  45. end
  46. S2: if (jishu == 6'd0) begin
  47. next_state <= S3;
  48. jishu_num<=6'd35; //维持35S
  49. light1 = 6'b100_001; //绿灯
  50. light2 = 6'b001_001; //红灯
  51. end
  52. S3: if (jishu == 6'd0) begin
  53. next_state <= S4;
  54. jishu_num<=6'd5; //维持5S
  55. light1 = 6'b010_010; //黄灯
  56. light2 = 6'b001_001; //红灯
  57. end
  58. S4: if (jishu == 6'd0) begin
  59. next_state <= S1;
  60. jishu_num<=6'd35; //状态维持35S
  61. light1 = 6'b001_001; //红灯
  62. light2 = 6'b100_100; //绿灯
  63. end
  64. endcase
  65. end
  66. else //如果K1拨上去了
  67. begin
  68. light1 = 6'b001_001;
  69. light2 = 6'b001_001; //全部亮红灯
  70. end
  71. end
  72. //时钟控制模块 输入1HZ
  73. always @(posedge clk_1hz or negedge rst) begin
  74. if (!rst) begin
  75. jishu <= 6'd0;
  76. end
  77. else if(k==0) begin // 工作在自动模式
  78. if (jishu == 6'd0)
  79. jishu <= jishu_num;
  80. else
  81. jishu <= jishu-1;
  82. end
  83. else
  84. jishu<=jishu; //如果K1拨上去了 时间不变
  85. end
  86. assign jishu_ge=jishu%10;
  87. assign jishu_shi=jishu/10;
  88. assign data=jishu_ge*10000000+jishu_shi*1000000+030616;
  89. endmodule

        重点在于状态机的运转流程,以及状态的切换。程序一开始会从S0状态,一直运行到S4状态,但随后只会在 S1  S2  S3  S4里面循环。S0是给上电复位设置的初始状态。

        在时钟控制模块里面,让jishu这个变量一直减一,在状态机里面,给jishu赋值,当jishu变量减到0时,就进行状态的切换。切换之后,到了下一个状态,又重新对jishu进行赋值。这样就实现的LED灯在不同的状态亮不同的时间了!

        然后时间又被传递后显示模块进行了显示。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小小林熬夜学编程/article/detail/530593
推荐阅读
相关标签
  

闽ICP备14008679号