请设计状态机电路,实现自动售卖机功能,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
问题分析:
整个过程可以分为6个状态,sel先选,din次选,接着00、01、10三个状态跳转。值得注意的是买十块的可以先投5块、再投十块。
`timescale 1ns/1ns
module sale(
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,//drinks_out=1,output 5$ drinks,drinks_out=2,output 10$ drinks
output reg change_out
);
reg [2:0] c_state,n_state;
parameter idle = 3'd0,
S1 = 3'd1,//5元买5元饮料
S2 = 3'd2,//10元买5元饮料找5块
S3 = 3'd3,//5元买十元饮料
S4 = 3'd4,//加了5块,不找
S5 = 3'd5;//加了10块,找5块
always@(posedge clk or negedge rst_n)
if(!rst_n)
c_state<=idle;
else
c_state <= n_state;
always@(*)
if(sel== 1'b0)begin
case(c_state)
idle:begin
case(din)
2'b00: n_state <= idle;
2'b01: n_state <= S1;
2'b10: n_state <= S2;
endcase
end
S1:begin
case(din)
2'b00: n_state <= idle;
2'b01: n_state <= S1;
2'b10: n_state <= S2;
endcase
end
S2:begin
case(din)
2'b00: n_state <= idle;
2'b01: n_state <= S1;
2'b10: n_state <= S2;
endcase
end
S3:begin
case(din)
2'b00: n_state <= idle;
2'b01: n_state <= idle;
2'b10: n_state <= idle;
endcase
end
S4:begin
case(din)
2'b00: n_state <= idle;
2'b01: n_state <= idle;
2'b10: n_state <= idle;
endcase
end
S5:begin
case(din)
2'b00: n_state <= idle;
2'b01: n_state <= idle;
2'b10: n_state <= idle;
endcase
end
endcase
end
else begin
case(c_state)
idle:begin
case(din)
2'b00: n_state <= idle;
2'b01: n_state <= S3;
2'b10: n_state <= S4;
endcase
end
S1:begin
case(din)
2'b00: n_state <= idle;
2'b01: n_state <= idle;
2'b10: n_state <= idle;
endcase
end
S2:begin
case(din)
2'b00: n_state <= idle;
2'b01: n_state <= idle;
2'b10: n_state <= idle;
endcase
end
S3:begin
case(din)
2'b00: n_state <= S3;
2'b01: n_state <= S4;
2'b10: n_state <= S5;
endcase
end
S4:begin
case(din)
2'b00: n_state <= idle;
2'b01: n_state <= S3;
2'b10: n_state <= S4;
endcase
end
S5:begin
case(din)
2'b00: n_state <= idle;
2'b01: n_state <= S3;
2'b10: n_state <= S4;
endcase
end
endcase
end
always@(*)
if(!rst_n)begin
drinks_out <= 0;
change_out <=0;
end
else begin
case(c_state)
idle:begin
drinks_out <= 0;
change_out <=0;
end
S1:begin
drinks_out <= 2'd1;
change_out <=1'd0;
end
S2:begin
drinks_out <= 2'd1;
change_out <=1'd1;
end
S3:begin
drinks_out <= 0;
change_out <=0;
end
S4:begin
drinks_out <=2'd2;
change_out <=0;
end
S5:begin
drinks_out <= 2'd2;
change_out <=1'd1;
end
endcase
end
endmodule