Verilog 实现状态机自动售卖机
教学视频:https://www.bilibili.com/video/BV1Ve411x75W?p=33&spm_id_from=pageDriver&vd_source=19ae31dff4056e52d2729a4ca212602b
功能需求
使用1元、2元、5元面值的纸币进行支付,获取6元的物品,不设找零
- 输入:1元,2元,5元
- 判定条件:>=6元
- 输出:可以交货(输入额满足判断条件)
代码思路:使用状态机进行逻辑设计(详细教学可以看最上面的链接)
verilog
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) begin
if(!rst_n)
cstate <= IDLE;
else
cstate <= nstate;
end
//组合逻辑实现状态变迁
always @(*) begin
case(cstate)
IDLE : begin
if(one_yuan||two_yuan||five_yuan)
nstate = IN_1;
else
nstate = IDLE;
end
IN_1 : begin
if(one_yuan||two_yuan||five_yuan)
nstate = IN_2;
else
nstate = IN_1;
end
IN_2 : begin
if(money_sum >= MONEY_PAY)
nstate = DONE;
else if(one_yuan||two_yuan||five_yuan)
nstate = IN_3;
else
nstate = IN_2;
end
IN_3 : begin
if(money_sum >= MONEY_PAY)
nstate = DONE;
else if(one_yuan||two_yuan||five_yuan)
nstate = IN_4;
else
nstate = IN_3;
end
IN_4 : begin
if(money_sum >= MONEY_PAY)
nstate = DONE;
else if(one_yuan||two_yuan||five_yuan)
nstate = IN_5;
else
nstate = IN_4;
end
IN_5 : begin
if(money_sum >= MONEY_PAY)
nstate = DONE;
else if(one_yuan||two_yuan||five_yuan)
nstate = IN_6;
else
nstate = IN_5;
end
IN_6 : begin
if(money_sum >= MONEY_PAY)
nstate = DONE;
else if(one_yuan||two_yuan||five_yuan)
nstate = DONE;
else
nstate = IN_6;
end
DONE : nstate = IDLE;
default : ;
endcase
end
//当前状态输入钱币的累计计算
always @(posedge clk or negedge rst_n) begin
if(!rst_n)
money_sum <= 'b0;
else begin
case(cstate)
DONE : money_sum <= 'b0;
default : begin
if(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 ;
end
endcase
end
end
//状态机的输出赋值
always @(posedge clk or negedge rst_n) begin
if(!rst_n)
done <= 'b0;
else if(cstate == DONE)
done <= 1'b1;
else
done <= 'b0;
end
endmodule
测试文件:
verilog
`timescale 1ns/1ps
module 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 begin
rst_n = 0;
one_yuan =0 ;
two_yuan =0 ;
five_yuan =0 ;
#200;
rst_n = 1;
for(i=0;i<50;i=i+1)begin
task_random_pay();
end
#5000;
end
integer 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
endtask
always @(posedge clk) begin
if(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 ;
end
endmodule
仿真结果
波形:
结果: