设计任务
基本要求功能:
- 投币:只接受5角或者1元的硬币。
- 找零:只输出5角的找零。
- 输出饮料:输出饮料的同时指示灯亮。
- 进行购买饮料操作:按下一次只能进行一次购买饮料操作。
- 显示操作:在每次投完硬币后,显示当前的钱数,按照二进制计数,5角计数一次,1元计数两次。
拓展功能:
- 在此基础上可以提供多种不同价格的饮料贩卖功能
- 模拟真实投币过程,实现按键防抖动的功能。
- 将显示操作的数值用发光二极管表示为数值
设计原理:
- (1) 硬件设计:自动售饮料机有按键,用于选择购买特定的饮料。这些按键在板子上用按钮表示,用于选择购买的饮料。投币器可以接收 1 元硬币和 5 角硬币,检测硬币的额度以及数量。输出部分包括两个输出口,一个用于释放饮料,另一个用于找零,通过LED灯的显示完成饮料和找零的释放。界面上需要显示投币总额和找零值,可能借助数码显示器或LED等来显示这些信息。
- (2)状态机设计:设计一个状态机来管理自动贩卖机的运行状态,包括等待投币、检查投币是否足够、释放饮料、找零等状态。这个状态机需要能够切换状态,根据用户的操作和系统的状态改变来进行相应的输出和动作。其中可将五个状态简化为四个状态进行,即当前钱数为0元,当前钱数为0.5元,当前钱数为1元,当前钱数为1.5元的四个状态,同时有输出状态CO和Kout分别表示找零和释放饮料操作。
- (3) 找零设计:找零原理:当用户投入的金额超过饮料的价格时,系统需要计算找零。在本次设计中,由于只找零 5 角,在只有1元和5角输入的限制下,知道最多只有状态为2元的情况需要找找零,这个时候默认跳到状态为1.5元的时候并且输出CO为1完成找零,并在合适的时机释放找零。
- (4)释放饮料设计:当输入金额状态为1.5元时,释放饮料。
-
设计代码:
/*
时钟信号50MHZ
复位信号rstn
状态机包含:
输入 输出
状态为:0 0.5 1 1.5
*/
module ks(clk,rstn,kin,kout,co);
input clk,rstn; //50MHZ的时钟信号和复位信号
input [1:0] kin; // kin = 2'10为输入一元 2'01为输入0.5元
output reg co; // 当co = 1时,表示贩卖机需要退回0.5元
output reg kout; // 当kout = 1时表示出饮料
// 状态转移
parameter [1:0]state1 = 2'b00; // 表示当前贩卖机为0.0元
parameter [1:0]state2 = 2'b01; // 表示当前贩卖机为0.5元
parameter [1:0]state3 = 2'b10; // 表示当前贩卖机为1.0元
parameter [1:0]state4 = 2'b11; // 表示当前贩卖机为1.5元
reg [1:0] pre;
// 定义临时状态机
reg [1:0] state;
// 不能持续输入
always@(posedge clk or negedge rstn) begin
if(!rstn) begin // 复位信号重置状态
state <= state1; // 将贩卖机状态重置为初状态
kout <= 0; // 不出饮料
co <= 0;
end
else begin case(state)
state1: if (kin ==2'b00) begin // 没有输入钱
state <= state1; // 保持当前状态
if(kin == pre) begin co <= co;kout <= kout; end // 保持输出状态,便于观察
else begin co <= 0; // 输出为0表示不退钱
kout <= 0; // 输出为0 表示不出饮料
end
end
else if(kin == 2'b01) begin // 放了5角钱
co <= 0; // 输出为0表示不退钱
kout <= 0; // 输出为0 表示不出饮料
state <= state2; // 状态跳转到5角钱
end else if(kin == 2'b10) begin // 放了1元钱
co <= 0; // 输出为0表示不退钱
kout <= 0; // 输出为0 表示不出饮料
state <= state3; // 状态跳转到1元钱
end else begin // 输入为无效状态
co <= 0; // 输出为0表示不退钱
state <= state1; // 保持当前状态
kout <= 0; // 输出为0 表示不出饮料
end
state2: if (kin ==2'b00 || kin == pre) begin // 没有输入钱
state <= state2; // 保持当前状态
if(kin == pre) begin co <= co;kout <= kout; end // 保持输出状态,便于观察
else begin co <= 0; // 输出为0表示不退钱
kout <= 0; // 输出为0 表示不出饮料
end
end
else if(kin == 2'b01) begin // 放了5角钱
kout <= 0; // 输出为0 表示不出饮料
co <= 0; // 输出为0表示不退钱
state <= state3; // 状态跳转到5角钱
end else if(kin == 2'b10) begin // 放了1元钱
co <= 0; // 输出为0表示不退钱
kout <= 1; // 输出为0 表示不出饮料
state <= state4; // 状态跳转到1元钱
end else begin // 输入为无效状态
co <= 0; // 输出为0表示不退钱
state <= state2; // 保持当前状态
kout <= 0; // 输出为0 表示不出饮料
end
state3: if (kin ==2'b00 || (kin == pre)) begin // 没有输入钱
if(kin == pre) begin co <= co;kout <= kout; end // 保持输出状态,便于观察
else begin co <= 0; // 输出为0表示不退钱
kout <= 0; // 输出为0 表示不出饮料
end
state <= state3; // 保持当前状态
end
else if(kin == 2'b01) begin // 放了5角钱
co <= 0; // 输出为0表示不退钱
kout <= 1; // 输出为0 表示不出饮料
state <= state4; // 状态跳转到1.5元钱
end else if(kin == 2'b10) begin // 放了1元钱
kout <= 1; // 输出为0 表示不出饮料
co <= 1; // 输出为0表示退钱
state <= state4; // 状态跳转到1元钱
end else begin // 输入为无效状态
co <= 0; // 输出为0表示不退钱
state <= state3; // 保持当前状态
kout <= 0; // 输出为0 表示不出饮料
end
state4: if (kin ==2'b00 || kin== pre) begin // 没有输入钱
if(kin == pre) begin co <= co;kout <= kout; end // 保持输出状态,便于观察
else begin co <= 0; // 输出为0表示不退钱
kout <= 0; // 输出为0 表示不出饮料
end
state <= state1; // 回到初始状态
end
else if(kin == 2'b01) begin // 放了5角钱
co <= 0; // 输出为0表示不退钱
kout <= 0; // 输出为0 表示不出饮料
state <= state2; // 状态跳转到5角钱
end else if(kin == 2'b10) begin // 放了1元钱
kout <= 0; // 输出为0 表示不出饮料
co <= 0; // 输出为0表示不退钱
state <= state3; // 状态跳转到1元钱
end else begin // 输入为无效状态
co <= 0; // 输出为0表示不退钱
state <= state1; // 回到初始状态
kout <= 0; // 输出为0 表示不出饮料
end
default: begin
state <= state1; // 状态跳转到初始状态
co <= 0; // 输出为0表示不退钱
kout <= 0; // 输出为0 表示不出饮料
end
endcase
pre = kin;
end
end
endmodule