打印
[FPGA]

自动售货机设计与仿真

[复制链接]
5023|0
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
zhaoqiansh|  楼主 | 2024-3-24 12:42 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
自动售货机设计与仿真
自动售货机销售价值分别为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。结果与之前的设计要求完全一致。

使用特权

评论回复

相关帖子

发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

6

主题

17

帖子

0

粉丝