设计一个自动售报机,报纸价钱为八角,纸币有1角,2角,5角,一元。该自动售报机不考虑投币为大额面值等特殊情况。
下图为自动售报机的状态转移图:
S0~S7为状态机的8个状态,下角标代表已投币的总和,八个状态分别代表没有投币、已投币1角、已投币2角、已投币3角、已投币4角、已投币5角、已投币6角、已投币7角。
M代表输入,M1表示投入1角硬币,M2表示投入2角硬币,M5表示投入5角硬币,M10表示投入一元。
data_out = 1表示给出报纸,data_out_return1 = 1表示找回1角硬币,data_out_return2 = 1表示找回2角硬币。
代码如下:
module auto_sellor(current_state, data_out, data_out_return1, data_out_return2, clk, rst_n, data_in);
parameter state_width = 3, data_in_width = 3;
output [state_width-1:0]current_state;
output data_out, data_out_return1, data_out_return2;
input [data_in_width-1:0]data_in;
input clk, rst_n;
reg [state_width-1:0]current_state, next_state;
reg data_out, data_out_return1, data_out_return2;
always@(current_state or data_in)
case(current_state)
3'b000:case(data_in)//0
3'b000:begin
next_state <= 3'b000;//0+0=0
data_out <= 1'b0;
data_out_return1 <= 1'b0;
data_out_return2 <= 1'b0;
end
3'b001:begin
next_state <= 3'b001;//0+1=1
data_out <= 1'b0;
data_out_return1 <= 1'b0;
data_out_return2 <= 1'b0;
end
3'b010:begin
next_state <= 3'b010;//0+2=2
data_out <= 1'b0;
data_out_return1 <= 1'b0;
data_out_return2 <= 1'b0;
end
3'b011:begin
next_state <= 3'b101;//0+5=5
data_out <= 1'b0;
data_out_return1 <= 1'b0;
data_out_return2 <= 1'b0;
end
3'b100:begin
next_state <= 3'b000;//0+10=10
data_out <= 1'b1;
data_out_return1 <= 1'b0;
data_out_return2 <= 1'b1;
end
endcase
3'b001:case(data_in)//1
3'b000:begin
next_state <= 3'b001;//1+0=0
data_out <= 1'b0;
data_out_return1 <= 1'b0;
data_out_return2 <= 1'b0;
end
3'b001:begin
next_state <= 3'b010;//1+1=2
data_out <= 1'b0;
data_out_return1 <= 1'b0;
data_out_return2 <= 1'b0;
end
3'b010:begin
next_state <= 3'b011;//1+2=3
data_out <= 1'b0;
data_out_return1 <= 1'b0;
data_out_return2 <= 1'b0;
end
3'b011:begin
next_state <= 3'b110;//1+5=6
data_out <= 1'b0;
data_out_return1 <= 1'b0;
data_out_return2 <= 1'b0;
end
endcase
3'b010:case(data_in)//2
3'b000:begin
next_state <= 3'b010;//2+0=2
data_out <= 1'b0;
data_out_return1 <= 1'b0;
data_out_return2 <= 1'b0;
end
3'b001:begin
next_state <= 3'b011;//2+1=3
data_out <= 1'b0;
data_out_return1 <= 1'b0;
data_out_return2 <= 1'b0;
end
3'b010:begin
next_state <= 3'b100;//2+2=4
data_out <= 1'b0;
data_out_return1 <= 1'b0;
data_out_return2 <= 1'b0;
end
3'b011:begin
next_state <= 3'b111;//2+5=7
data_out <= 1'b0;
data_out_return1 <= 1'b0;
data_out_return2 <= 1'b0;
end
endcase
3'b011:case(data_in)//3
3'b000:begin
next_state <= 3'b011;//3+0=3
data_out <= 1'b0;
data_out_return1 <= 1'b0;
data_out_return2 <= 1'b0;
end
3'b001:begin
next_state <= 3'b100;//3+1=4
data_out <= 1'b0;
data_out_return1 <= 1'b0;
data_out_return2 <= 1'b0;
end
3'b010:begin
next_state <= 3'b101;//3+2=5
data_out <= 1'b0;
data_out_return1 <= 1'b0;
data_out_return2 <= 1'b0;
end
3'b011:begin
next_state <= 3'b000;//3+5=8
data_out <= 1'b1;
data_out_return1 <= 1'b0;
data_out_return2 <= 1'b0;
end
endcase
3'b100:case(data_in)//4
3'b000:begin
next_state <= 3'b000;//4+0=4
data_out <= 1'b0;
data_out_return1 <= 1'b0;
data_out_return2 <= 1'b0;
end
3'b001:begin
next_state <= 3'b101;//4+1=5
data_out <= 1'b0;
data_out_return1 <= 1'b0;
data_out_return2 <= 1'b0;
end
3'b010:begin
next_state <= 3'b110;//4+2=6
data_out <= 1'b0;
data_out_return1 <= 1'b0;
data_out_return2 <= 1'b0;
end
3'b011:begin
next_state <= 3'b000;//4+5=9
data_out <= 1'b1;
data_out_return1 <= 1'b1;
data_out_return2 <= 1'b0;
end
endcase
3'b101:case(data_in)//5
3'b000:begin
next_state <= 3'b101;//5+0=5
data_out <= 1'b0;
data_out_return1 <= 1'b0;
data_out_return2 <= 1'b0;
end
3'b001:begin
next_state <= 3'b110;//5+1=6
data_out <= 1'b0;
data_out_return1 <= 1'b0;
data_out_return2 <= 1'b0;
end
3'b010:begin
next_state <= 3'b111;//5+2=7
data_out <= 1'b0;
data_out_return1 <= 1'b0;
data_out_return2 <= 1'b0;
end
3'b011:begin
next_state <= 3'b000;//5+5=10
data_out <= 1'b1;
data_out_return1 <= 1'b0;
data_out_return2 <= 1'b1;
end
endcase
3'b110:case(data_in)//6
3'b000:begin
next_state <= 3'b110;//6+0=6
data_out <= 1'b0;
data_out_return1 <= 1'b0;
data_out_return2 <= 1'b0;
end
3'b001:begin
next_state <= 3'b111;//6+1=7
data_out <= 1'b0;
data_out_return1 <= 1'b0;
data_out_return2 <= 1'b0;
end
3'b010:begin
next_state <= 3'b000;//6+2=8
data_out <= 1'b01
data_out_return1 <= 1'b0;
data_out_return2 <= 1'b0;
end
endcase
3'b111:case(data_in)//7
3'b000:begin
next_state <= 3'b111;//7+0=7
data_out <= 1'b0;
data_out_return1 <= 1'b0;
data_out_return2 <= 1'b0;
end
3'b001:begin
next_state <= 3'b000;//7+1=8
data_out <= 1'b1;
data_out_return1 <= 1'b0;
data_out_return2 <= 1'b0;
end
endcase
endcase
always@(posedge clk or rst_n)
if(!rst_n)
current_state <= 3'b000;
else
current_state <= next_state;
endmodule
上述代码中大的case语句里current_state分别对应S0到S7,即当前已投币的数目总和;而每个大case中的小case里的data_in则对应M0,M1,M2,M5,M10这几个投入硬币的数目。