自动售货机设计与仿真
自动售货机销售价值分别为4元和5元的两种不同商品。可接受1元硬币或5元、10元的纸币。自动售货机设有确认键,经确认后,自动售货机开始售卖工作。如投入金额不足以支付商品则直接退还投入货币,反之则售出商品并予以找零。设计以LED灯的亮灭情况表示售出商品与否并以LED灯闪烁的次数来表示找零数目。本实例给出自动售货机的源代码和测试代码及仿真波形图。
1.引脚分配
自动售货机引脚图如图6-11所示,8个输入引脚和3个输出引脚,各引脚含义如下。
输入引脚:
clk:系统时钟50MHz
reset:异步复位
ack: 确认键,经确认后,自动售货机开始售卖工作。
choice4、choice5:分别代表选择价值4元和5元的商品。每次按下choice4和choice5则内部商品价值寄存器choice分别进行+4和+5操作。
coin1、coin5、coin10:分别对应投入1元、5元、10元的货币。每次按下coin1、coin5、coin10内部寄存器coin分别进行+1、+5和+10操作。
输出引脚:
led_change:显示找零,以led闪烁次数表示内部寄存器change的值。
led_choice4、led_choice5:灯亮分别表示成功售出4元商品和5元商品
2.设计思路
整个自动售货机程序主要分为三部分功能块:售货处理模块和售货显示及找零模块。
①售货处理模块中,设定内部寄存器choice、coin分别记录欲购商品价值、投入货币金额。每次按下coin1、coin5、coin10寄存器coin分别进行+1、+5和+10操作。而每次按下choice4和choice5寄存器choice分别进行+4和+5操作并改变标志位c1和c2的值。ack确认后判断投入货币是否足以购买商品(即比较choice和coin大小),以此为依据给status赋值来表示自动售货机的工作状态并对寄存器change赋值表示退币找零的数目。具体工作如下:
当coin>choice时,赋值:status<=2'b10,change<=coin-choice。
当coin<choice时,赋值:status<=2'b01,change<=coin。
当coin==choice时,如果coin>0,赋值:status<=2'b10,change<=coin-choice。否则,赋值status<=2'b01,change<=0。
②售货显示和退币找零模块则根据status的值判断工作状态。当status==2'b01时,说明交易不成功,则自动售货机不输出商品仅退币。当status==2'b10时,说明交易成功,输出购买的商品并找零。
3.设计注意事项
① 设计中注意时钟频率的问题,由于50MHz的系统时钟频率过快,会影响显示时观察结果,因此需要对系统时钟进行合理分频。
②设计中注意按键的消抖问题,每次按键后需要间隔一段时间才执行下一次按键操作,否则会造成误操作。因而依据此项原则结合分频方法设计适合的按键消抖方案,并通过计算给出两次按键之间的间隔有效时间。
③ 自动售货机每次交易完成后,即退币找零操作结束后,应将售货处理模块中的choice、coin以及change的值清零,以免影响下次交易。
4. 源代码
module smartseller (clk,reset,ack,coin1,coin5,coin10,choice4,choice5,led_choice4,led_choice5,led_change);
input clk, reset, ack;
input coin1, coin5, coin10, choice4, choice5;
output led_choice4, led_choice5, led_change;
reg led_choice4, led_choice5, led_change;
reg c1, c2;
reg [1:0] status; //自动售货机工作状态
reg [4:0] choice, coin, change; //欲购商品价值、投入金额、退币找零
reg [5:0] count; //退币找零操作的计数
reg clk_out1,clk_out2; //分频后时钟
reg [25:0] cnt1,cnt2;
reg[7:0] tag; //消抖标签
wire clear; //退币找零清零允许标志
always@ (posedge clk or negedge reset) //将时钟频率从50MHz降100Hz和1Hz
begin
if(!reset)
begin
cnt1<=0;
cnt2<=0;
clk_out1<=0;
clk_out2<=0;
end
else
begin
if (cnt1<250000)
cnt1<= cnt1+1'b1;
else
begin
clk_out1<=~clk_out1;
cnt1<=0;
end
if (cnt2<25000000)
cnt2<= cnt2+1'b1;
else
begin
clk_out2<=~clk_out2;
cnt2<=0;
end
end
end
always@(posedge clk_out1 or negedge reset) //消除抖动模块
if(!reset)
tag[7:0]<=8'b00000000;
else
begin
if(tag<30)
tag[7:0]<=tag[7:0]+1'b1;
else
tag<=8'b00000000;
end
always@ (posedge clk_out1 or negedge reset) //售货处理模块
begin
if(!reset)
begin
status<=0;
choice<=0;
coin<=0;
change<=0;
c1<=0;
c2<=0;
end
else if(clear) //退币找零操作结束后清零
begin
coin<=0;
choice<=0;
c1<=0;
c2<=0;
change<=0;
end
else
begin
begin
if(!coin1&&!tag) //投入1元
coin<=coin+1'b1;
else if(!coin5&&!tag) //投入5元
coin<=coin+4'b0101;
else if(!coin10&&!tag) //投入10元
coin<=coin+4'b1010;
else if(!choice4&&!tag) //欲购价值4元的商品
begin
choice<=choice+4'b0100;
c1<=1;
end
else if(!choice5&&!tag) //欲购价值5元的商品
begin
choice<=choice+4'b0101;
c2<=1;
end
else
begin
coin<=coin;
choice<=choice;
c1<=c1;
c2<=c2;
end
end
if(ack) //确认交易
begin //比较 coin和choice的大小
if(coin<choice) //货币不足以购物
begin
change<=coin;
status<=2'b01;
end
else if(coin>choice) //货币可以购物
begin
change<=coin-choice;
status<=2'b10;
end
else if(coin==choice&&coin>0) //投入货币刚好够买货物
begin
change<=coin-choice;
status<=2'b10;
end
else
begin
change<=0;
status<=2'b00;
end
end
else
begin
status<=status;
change<=change;
end
end
end
always@ (posedge clk_out2 or negedge reset) //售出货物及退币找零模块
begin
if(!reset)
begin
led_choice4<=0;
led_choice5<=0;
led_change<=0;
count<=0;
end
else
begin
count<=2*change; //退币操作计数
if(status==2'b01) //投入货币不足以购买商品
begin
led_choice4<=0;
led_choice5<=0;
if(count>0) //退币
begin
led_change<=led_change+1'b1;
count<=count-1'b1;
end
else
led_change<=0;
end
else if(status==2'b10) //投入货币可以购买货物
begin
led_choice4<=c1;
led_choice5<=c2;
if(count>0) //找零
begin
led_change<=led_change+1'b1;
count<=count-1'b1;
end
else
led_change<=0;
end
else
begin
led_choice4<=led_choice4;
led_choice5<=led_choice5;
led_change<=led_change;
end
end
end
assign clear =(count==1)?1'b1:1'b0; //coin、choice及change清零信号
endmodule
5.测试代码
测试每次按下coin1、coin5、coin10,寄存器coin是否分别进行+1、+5和+10操作。而每次按下choice4和choice5寄存器choice是否分别进行+4和+5操作。检测货币不足购买货物和货币足够购买货物时,表示商品的led_choice4、led_choice5以及表示找零的led_change是否正常工作。
`timescale 1ns / 1ps
module tst_seller;
reg clk,reset,ack;
reg coin1,coin5,coin10;
reg choice4,choice5;
wire led_choice4,led_choice5,led_change;
smartseller user (.clk(clk), .reset(reset), .ack(ack), .coin1(coin1), .coin5(coin5), .coin10(coin10),
.choice4(choice4), .choice5(choice5), .led_choice4(led_choice4), .led_choice5(led_choice5), .led_change(led_change));
initial
begin
clk = 0; reset = 1; ack = 0; coin1 = 1; coin5 = 1; coin10 = 1; choice4 = 1;
choice5 = 1; #1000 $finish;
end
initial
$monitor($time,,clk,,reset,, ack,, coin1,, coin5,, coin10,, choice4,,choice5,, led_choice4,, led_choice5,, led_change);
always #5 clk=~clk;
initial
fork
#10 reset=0; #50 reset=1;
#100 coin1=0; #110 coin1=1;
#120 choice4=0; #130 choice4=1;
#150 ack=1; #250 ack=0;
#300 reset=0; #320 reset=1;
#350 coin5=0; #360 coin5=1;
#400 choice4=0; #410 choice4=1;
#450 ack=1; #550 ack=0;
#600 reset=0; #620 reset=1;
#650 coin10=0; #660 coin10=1;
#700 choice5=0; #710 choice5=1;
#800 ack=1; #900 ack=0;
#950 reset=0; #1000 reset=1;
join
endmodule
6.仿真波形图与分析
可以观察到在第一次交易中coin1按下后,coin值相应地由5'h00变为5'h01,表示投入1元。而choice4按下后,choice值由5'h00变为5'h04,表示欲购商品的价值为4元。当ack确认后,由于投入货币不足以购买货物,因此表示货物的led灯并未亮起,而表示找零的led_change闪烁1次表示退还投入的金额。在第二次交易中coin5按下后,coin值相应地由5'h00变为5'h05,表示投入5元。而choice4按下后,choice值由5'h00变为5'h04,表示欲购商品的价值为4元。当ack确认后,由于本次投入货币可以购买货物,因此表示货物的led_choice4灯亮起,而表示找零的led_change闪烁1次表示找零。第三次则使用10元购买价值5元的商品,因此led_choice5亮起,led_change闪烁5次表示找零。每次交易退币操作完成后,choice、coin和change值清零为5'h00。结果与之前的设计要求完全一致。 |
|