Verilog 实现状态机自动售卖机
教学视频:https://www.bilibili.com/video/BV1Ve411x75W?p=33&spm_id_from=pageDriver&vd_source=19ae31dff4056e52d2729a4ca212602b
功能需求
使用1元、2元、5元面值的纸币进行支付,获取6元的物品,不设找零
- 输入:1元,2元,5元
- 判定条件:>=6元
- 输出:可以交货(输入额满足判断条件)
代码思路:使用状态机进行逻辑设计(详细教学可以看最上面的链接)
module vlg_design(input clk ,input rst_n ,input one_yuan ,input two_yuan ,input five_yuan ,output reg done
);//变量声明
localparam IDLE =4'd0 ,IN_1 =4'd1 ,IN_2 =4'd2 ,IN_3 =4'd3 ,IN_4 =4'd4 ,IN_5 =4'd5 ,IN_6 =4'd6 ,DONE =4'd7 ;localparam MONEY_PAY = 4'd6;reg [3:0] cstate,nstate;
reg [3:0] money_sum;//时序逻辑,锁存状态
always @(posedge clk or negedge rst_n) beginif(!rst_n)cstate <= IDLE;elsecstate <= nstate;
end//组合逻辑实现状态变迁
always @(*) begincase(cstate)IDLE : beginif(one_yuan||two_yuan||five_yuan)nstate = IN_1;elsenstate = IDLE;endIN_1 : beginif(one_yuan||two_yuan||five_yuan)nstate = IN_2;elsenstate = IN_1;end IN_2 : beginif(money_sum >= MONEY_PAY)nstate = DONE;else if(one_yuan||two_yuan||five_yuan)nstate = IN_3;elsenstate = IN_2;end IN_3 : beginif(money_sum >= MONEY_PAY)nstate = DONE;else if(one_yuan||two_yuan||five_yuan)nstate = IN_4;elsenstate = IN_3;end IN_4 : beginif(money_sum >= MONEY_PAY)nstate = DONE;else if(one_yuan||two_yuan||five_yuan)nstate = IN_5;elsenstate = IN_4;end IN_5 : beginif(money_sum >= MONEY_PAY)nstate = DONE;else if(one_yuan||two_yuan||five_yuan)nstate = IN_6;elsenstate = IN_5;end IN_6 : beginif(money_sum >= MONEY_PAY)nstate = DONE;else if(one_yuan||two_yuan||five_yuan)nstate = DONE;elsenstate = IN_6;end DONE : nstate = IDLE;default : ;endcase
end//当前状态输入钱币的累计计算
always @(posedge clk or negedge rst_n) beginif(!rst_n)money_sum <= 'b0;else begincase(cstate)DONE : money_sum <= 'b0;default : beginif(one_yuan)money_sum <= money_sum + 4'd1;else if(two_yuan) money_sum <= money_sum + 4'd2;else if(five_yuan) money_sum <= money_sum + 4'd5;else ;endendcaseend
end//状态机的输出赋值
always @(posedge clk or negedge rst_n) beginif(!rst_n)done <= 'b0;else if(cstate == DONE)done <= 1'b1;elsedone <= 'b0;
endendmodule
测试文件:
`timescale 1ns/1psmodule tb_top();reg clk;
reg rst_n;
reg one_yuan;
reg two_yuan;
reg five_yuan;wire done;vlg_design u_vlg_design(.clk (clk),.rst_n (rst_n),.one_yuan (one_yuan),.two_yuan (two_yuan),.five_yuan (five_yuan),.done (done)
);//产生时钟
initial clk = 1;
always #10 clk = ~clk;integer i;//测试激励产生
initial beginrst_n = 0;one_yuan =0 ;two_yuan =0 ;five_yuan =0 ;#200;rst_n = 1;for(i=0;i<50;i=i+1)begintask_random_pay();end#5000;endinteger random_data;task task_random_pay;begin #1000;random_data = {$random}%3;@(posedge clk);if(random_data == 0)one_yuan <= 1'd1;else if(random_data == 1)two_yuan <= 1'd1;else if(random_data == 2)five_yuan <= 1'd1;@(posedge clk);one_yuan <=0 ;two_yuan <=0 ;five_yuan <=0 ;end
endtaskalways @(posedge clk) beginif(one_yuan)$display("Pay 1 yuan.");else if(two_yuan)$display("Pay 2 yuan.");else if(five_yuan)$display("Pay 5 yuan.");else if(done)$display("Got you want.\n*********\n");else ;
endendmodule
仿真结果
波形:
结果: