• FPGA刷题——交通灯+售卖机


    目录

    交通灯

    自动售卖机


    交通灯和售卖机是常常作为状态机考察的题目,这种题目并不难,需要理清楚状态转移的过程,下面是2道例题

    交通灯

    要求实现一个交通红绿灯,具有红黄绿三个小指示灯和一个行人按钮,正常情况下,机动车道指示灯按照60时钟周期绿灯,5个时钟周期黄灯,10个时钟周期红灯循环。当行人按钮按下,如果剩余绿灯时间大于10个时钟,则缩短为10个时钟,小于10个时钟则保持不变。

    注:机动车道的指示灯和人行道指示灯应该是配对的,当机动车道的灯为绿或者黄时,人行道的灯为红;当机动车道的灯为红时,人行道的灯为绿,为简便起见,只考虑机动车道的指示灯。

    模块的信号接口图如下:

    输入描述:

    clk:系统时钟信号

    rst_n:复位信号,低电平有效

    pass_request:行人按钮信号,当该信号为1,表示按钮按下,如果剩余绿灯时间大于10个时钟,则缩短为10个时钟,小于10个时钟则保持不变。

    输出描述:

    clock:交通灯倒计时读数

    red:该信号为1,表示红灯亮,为0表示红灯不亮

    yellow:该信号为1,表示黄灯亮,为0表示黄灯不亮

    green:该信号为1,表示黄灯亮,为0表示黄灯不亮

    题解思路

    首先考虑实现正常情况下的功能:机动车道指示灯按照60时钟周期绿灯,5个时钟周期黄灯,10个时钟周期红灯循环

    首先设置一个倒计时的计数器,每个时钟计数器输出减一,当计数器计数到0时,切换切换显示灯颜色,同时重置计数器为相应颜色的持续时间。

    三个颜色的指示灯之间的转化可以使用一个简单的状态机实现。在红灯状态下,红灯亮,其余两个灯灭。而且当cnt==0,即倒计时结束时切换到黄灯,否则停留在红灯状态。在黄灯灯状态下,黄灯亮,其余两个灯灭。而且当cnt==0,即倒计时结束时切换到绿灯,否则停留在黄灯状态。在绿灯状态下,绿灯亮,其余两个灯灭。而且当cnt==0,即倒计时结束时切换到红灯,否则停留在绿灯状态。

    再考虑实现当行人按钮按下的情况:如果剩余绿灯时间大于10个时钟,则缩短为10个时钟,小于10个时钟则保持不变。

    因此首先判断当前是否是绿灯,绿灯倒计时是否大于10,行人按钮是否被按下,如果这三个条件同时满足,则把倒计时置为10。

    分析完成之后,可以画出状态转移图如下:

     代码如下:

    1. module traffic(
    2. input clk,
    3. input reset,
    4. input pass_request,//行人按钮信号
    5. output wire [7:0]clock,//交通灯倒计时读数
    6. output reg red_out ,//该信号为1,表示红灯亮,为0表示红灯不亮
    7. output reg yellow_out ,//该信号为1,表示黄灯亮,为0表示黄灯不亮
    8. output reg green_out //该信号为1,表示黄灯亮,为0表示黄灯不亮
    9. );
    10. reg [7:0] cnt;//计数秒数
    11. reg [2:0] current_state;
    12. reg [2:0] next_state;
    13. parameter IDLE =3'd0;
    14. parameter GREEN =3'd1;
    15. parameter YELLOW=3'd2;
    16. parameter RED =3'd3;
    17. parameter PASS =3'd4;
    18. always@(posedge clk)begin
    19. if(reset)begin
    20. current_state<=3'd0;
    21. end
    22. else begin
    23. current_state<=next_state;
    24. end
    25. end
    26. always@(*)begin
    27. if(reset)begin
    28. next_state=IDLE;
    29. end
    30. else begin
    31. case(current_state)
    32. IDLE :begin
    33. next_state=GREEN;
    34. end
    35. GREEN :begin
    36. if(cnt>9&&pass_request==1)begin
    37. next_state=PASS;
    38. end
    39. else if (cnt==0)begin
    40. next_state=YELLOW;
    41. end
    42. end
    43. YELLOW:begin
    44. if (cnt==0)begin
    45. next_state=RED;
    46. end
    47. end
    48. RED :begin
    49. if (cnt==0)begin
    50. next_state=GREEN;
    51. end
    52. end
    53. PASS :begin
    54. if (cnt==0)begin
    55. next_state=YELLOW;
    56. end
    57. end
    58. endcase
    59. end
    60. end
    61. always@(posedge clk)begin
    62. if(reset)begin
    63. cnt<=8'd0;
    64. red_out <=1'd0;
    65. yellow_out<=1'd0;
    66. green_out <=1'd0;
    67. end
    68. else begin
    69. case(current_state)
    70. IDLE:begin
    71. cnt<=8'd60;
    72. end
    73. GREEN :begin
    74. green_out <=1'd1;//绿灯亮
    75. if(cnt==8'd0)begin//跳转黄灯
    76. green_out <=1'd0;
    77. yellow_out<=1'd1;
    78. cnt <=8'd5;
    79. end
    80. else if(cnt>8'd9&&pass_request==1) begin
    81. cnt<=8'd9;
    82. end
    83. else begin
    84. cnt<=cnt-8'd1;
    85. end
    86. end
    87. YELLOW:begin
    88. if(cnt==8'd0)begin//跳转红灯
    89. green_out <=1'd0;
    90. yellow_out<=1'd0;
    91. red_out <=1'd1;
    92. cnt <=8'd10;
    93. end
    94. else begin
    95. cnt<=cnt-8'd1;
    96. end
    97. end
    98. RED :begin
    99. if(cnt==8'd0)begin//跳转绿灯
    100. green_out <=1'd1;
    101. yellow_out<=1'd0;
    102. red_out <=1'd0;
    103. cnt <=8'd60;
    104. end
    105. else begin
    106. cnt<=cnt-8'd1;
    107. end
    108. end
    109. PASS:begin
    110. if(cnt==8'd0)begin//跳转黄灯
    111. green_out <=1'd0;
    112. yellow_out<=1'd1;
    113. red_out <=1'd0;
    114. cnt <=8'd5;
    115. end
    116. else begin
    117. cnt<=cnt-8'd1;
    118. end
    119. end
    120. endcase
    121. end
    122. end
    123. assign clock=cnt;
    124. endmodule

    没有行人按下时: 有行人按下时:


    自动售卖机

    描述

    请设计状态机电路,实现自动售卖机功能,A饮料5元钱,B饮料10元钱,售卖机可接收投币5元钱和10元钱,每次投币只可买一种饮料,考虑找零的情况。

    电路的接口如下图所示。sel信号会先于din信号有效,且在购买一种饮料时值不变。

    sel为选择信号,用来选择购买饮料的种类,sel=0,表示购买A饮料,sel=1,表示购买B饮料;

    din表示投币输入,din=0表示未投币,din=1表示投币5元,din=2表示投币10元,不会出现din=3的情况;

    drinks_out表示饮料输出,drinks_out=0表示没有饮料输出,drinks_out=1表示输出A饮料,drinks_out=2表示输出B饮料,不出现drinks_out =3的情况,输出有效仅保持一个时钟周期;

    change_out表示找零输出,change_out=0表示没有找零,change_out=1表示找零5元,输出有效仅保持一个时钟周期。

    接口电路图如下:

    输入描述:

       input                clk   ,
       input                rst_n ,
       input                sel   ,//sel=0,5$dranks,sel=1,10&=$drinks
       input          [1:0] din   ,//din=1,input 5$,din=2,input 10$

    输出描述:

       output   reg  [1:0] drinks_out,
       output    reg        change_out  

    按照题目的描述,自动售卖机的运行流程是:选择饮料——给钱——找零——出饮料——初始界面

    我们也可以按照这个流程来写状态机:

     状态机的难点在于找零操作上,解决方法是:在select(选择饮料)状态根据sel信号赋值给cnt0;在pay状态根据din信号赋值给cnt1,如果cnt1大于cnt0,意味着需要找钱,零钱=cnt1-cnt0

    代码如下:

    1. module sale(
    2. input clk ,
    3. input rst ,
    4. input sel ,//sel=0,5$dranks,sel=1,10&=$drinks
    5. input [1:0] din ,//din=1,input 5$,din=2,input 10$
    6. output reg [2:0] drinks_out,//drinks_out=1,output 5$ drinks,drinks_out=2,output 10$ drinks
    7. output reg [3:0] change_out
    8. );
    9. reg[3:0]cnt0;//饮料价格
    10. reg[3:0]cnt1;//给的钱
    11. reg [2:0] state;
    12. parameter idle =3'd0;
    13. parameter select=3'd1;
    14. parameter pay =3'd2;
    15. parameter money =3'd3;
    16. parameter drink =3'd4;
    17. parameter calculate=3'd5;
    18. always@(posedge clk)begin
    19. if(rst)begin
    20. cnt0 <=4'd0;
    21. cnt1 <=4'd0;
    22. drinks_out<=1'd0;
    23. change_out<=3'd0;
    24. state<=idle;
    25. end
    26. else begin
    27. case(state)
    28. idle :begin
    29. cnt0 <=4'd0;
    30. cnt1 <=4'd0;
    31. drinks_out<=1'd0;
    32. change_out<=3'd0;
    33. state<=select;
    34. end
    35. select:begin
    36. if(sel==1'd0)begin//选择A饮料
    37. cnt0 <=4'd10;
    38. end
    39. else if(sel==1'd1) begin//选择B饮料
    40. cnt0 <=4'd5;
    41. end
    42. state<=pay;
    43. end
    44. pay:begin
    45. if(din==2'd2)begin//投币10元
    46. cnt1 <=4'd10;
    47. end
    48. else if(din==2'd1) begin//投币5元
    49. cnt1 <=4'd5;
    50. end
    51. else if(din==2'd0)begin//投币0元
    52. cnt1 <=4'd0;
    53. end
    54. state<=calculate;
    55. end
    56. calculate:begin
    57. if(cnt1>cnt0)begin
    58. state<=money;
    59. end
    60. else begin
    61. state<=drink;
    62. end
    63. end
    64. money:begin
    65. change_out<=cnt1-cnt0;
    66. state<=drink;
    67. end
    68. drink:begin
    69. if(sel==1'd0)begin//输出A饮料
    70. drinks_out<=3'd1;
    71. end
    72. else if(sel==1'd1) begin//输出B饮料
    73. drinks_out<=3'd2;
    74. end
    75. state<=idle;
    76. end
    77. endcase
    78. end
    79. end
    80. endmodule

    买B饮料,给10元的情况

     

  • 相关阅读:
    在 macOS 上的多个 PHP 版本之间切换
    MyBatisPlus使用自定义JsonTypeHandler实现自动转化JSON
    优橙内推天津专场——5G网络优化(中高级)工程师
    华为悦盒ec6108v9c使用ADB卡刷Linux(Ubuntu)
    Autosar实践——DEM配置
    无头双向链表的实现 —— Java【数据结构】
    Ubuntu系统安装
    Java-List<Map>的复制 深拷贝与浅拷贝
    (数据科学学习手札157)pandas新增case_when方法
    金融信贷行业如何准确——大数据精准定位获客渠道
  • 原文地址:https://blog.csdn.net/weixin_46188211/article/details/126728797