自动售货机控制模块-Verilog HDL

来源:互联网 发布:淘宝话费充值不到账 编辑:程序博客网 时间:2024/04/28 10:06

一、 问题描述

设计一个自动售货机控制模块,信息如下:

1. 售货机可提供8种可售商品,其中01号商品(代表第一种商品),价格为2元,02商品为4元,依次类推,08号商品售价为16元。

2. 售货机可接受1元,5元和10元的纸币收入。

3. 交易开始,用户需要先投入一定量的货币;在外部货币投入后,售货机累计输入货币总值;完成投币后,用户选择所有需要的商品;选择结束后,按下交易键;交易成功,售货机出货、找零,更新系统的存量货币信息和货物信息;交易不成功,退回用户投入货币。

4. 交易不成功可能可能因为投币不足;货物不足;零钱不足等原因造成;

5. 管理员可以通过外部设备访问和修改可售商品信息和存量货币信息。

 

二、 功能概括

自动售货机刚初始化时,需要管理员对其剩余钱数和商品数进行管理,之后用户可以进行商品购买。用户首先选择商品,无误后对商品进行确认,否则取消,在用户选择了某种商品后,售货机会对其存货进行确认,如果该商品已经售罄,则交易失败,回到空闲状态。该商品有存货时,售货机延时一段时间(30S)留给用户进行投币,用户只能投入1,5,10元的钱币,否则售货机会将其退出。用户在延时内投币后,售货机进行找零计算,如果售货机内现金不足找零,则退出所有钱币,售货机进入管理员管理状态,此时需要管理员管理现金。正确情况下,零钱足够多,则正常找零,如果找零数额为0直接出货,找零数不为0则是先找零再出货。出于实际情况的考虑,我认为自动售货机更适合使用先选择产品,再投入钱币的方式更为合理,因此在设计时使用的是先选择确认,再延时投币的流程。自动售货机的整个管理和售货流程如下图所示:

图1 自动售货机工作流程图

三、 接口定义

表1 系统接口与描述表

名称

I/O

描述

时钟与复位

clk

I

工作时钟

init

I

交易取消信号

rst

I

初始化与复位

管理员接口

manage

I

管理使能信号

manage_money

I

管理售货机内剩余钱数

load

I

外部串口接收(暂定)

left01

I

管理第01号商品数量

left02

I

管理第02号商品数量

left03

I

管理第03号商品数量

left04

I

管理第04号商品数量

left05

I

管理第05号商品数量

left06

I

管理第06号商品数量

left07

I

管理第07号商品数量

left08

I

管理第08号商品数量

用户接口

select

I

选择商品

confirm

I

确认购买商品

money_input

I

投入钱币

change

O

得到售货机找零

out

O

得到商品

 

四、 电路设计

系统设计:

根据题目要求,本项目关注点在于自动售货机控制的模块,因此对于一些软件、机械、电气方面的错误无法进行处理,如退钱时卡纸,突然停电等。出于集成化的考虑,采用了3个always块,always39为初始化状态模块,即将state的状态初始化为S_idle(可综合的Verilog不能使用initial进行初始化),always39为计时模块,在选定商品后,必须在规定的时间内投币。always63为自动售货机控制管理模块,是本设计主要电路。自动售货机控制模块的整体功能概括如下:

图2 自动售货机控制模块功能概括

         数据通路:

       考虑测试输入输出模块,数据流图和控制流图如下图所示,其中蓝线为数据线,红线为控制线。

 

图3 自动售货机控制模块数据通路

状态机:

自动售货机定义了10种状态,分别是选择(S_select),确认(S_confirm),是否售罄(S_allselled),延时(S_60s),投币是否足够(S_enough),是否需要找零(S_requirechange),找零(S_change),出货(S_out),空闲(S_idle),管理(S_management)。状态机如下图所示。

图4自动售货机控制模块状态机

时序设计:

首先要将售货机初始化,然后管理员进行第一次管理,在管理员管理阶段,需要设定各个商品的剩余数量,以及售货机里用于找零的现金。管理结束后进入用户使用阶段,用户首先选择商品号,在规定的延迟之内完成投币,之后在不缺货和现金的情况下,会进行找零和出货,售货机会更新商品数量和现金信息。如果出现缺货,现金不足,投币超时等情况会进行特殊处理,返回空闲或管理状态。

图5自动售货机控制模块时序图

内部信号定义:

自动售货机控制模块的内部信号主要用于保存信息和中间过程处理,管理员在初始化管理时会输入商品数量以及内部现金余量,这些都需要寄存器进行寄存,在进行正常售货时,因为有找零和出货,内部的信息也在不断的更新。

 

表2 内部信号描述表

名称

性质

描述

内部信号

cash

reg

内部剩余现金

left1

reg

第01号商品数量

left2

reg

第02号商品数量

left3

reg

第03号商品数量

left4

reg

第04号商品数量

left5

reg

第05号商品数量

left6

reg

第06号商品数量

left7

reg

第07号商品数量

left8

reg

第08号商品数量

select_sta

reg

选择了某个商品

state

reg

状态机状态

isSelled

reg

是否售罄

timeCnting

reg

是否开始计时

time_cnt

reg

延时期限

opt

reg

是否取消交易

//2017.1.5 葛兴
//全定制电路课程课程设计
//Verilog自动售货机控制模块
//Vending Machine
module VendingMac(clk,money_input,select,confirm,init,left01,left02,left03,left04,
left05,left06,left07,left08,change,out,manage,manage_money,rst);
input clk;//时钟信号
input rst;//使能信号
input confirm,init;//?idle=init
input [3:0] money_input;//1,5,10,最大为1010,4位input [1:8] select;//8种商品,选择上升沿触发
input [9:0] manage_money;//输入的钱数
input [5:0] left01,left02,left03,left04,left05,left06,left07,left08;//剩余商品数,认为不超过63input [1:0] manage;//这个是管理员功能 reg [9:0] cash;//自动售货机内部的钱数
reg [3:0] state;//状态机的各种状态
reg [5:0] left1,left2,left3,left4,left5,left6,left7,left8;output integer change;//找零,整数output reg [1:8] out;//出货,8种商品之一reg [1:8] select_sta;//选择某种商品reg isSelled;//判断是否售罄reg timeCnting;//延时计时
S_enough=4'b0100,S_requirechange=4'b0101,S_change=4'b0110,S_out=4'b0111,
reg [8:0] time_cnt;//500个时间单位,2^9=512reg [1:0] opt;//检查init是否启用integer money_sum;//剩余总钱数parameter S_select=4'b0000,S_confirm=4'b0001,S_allselled=4'b0010,S_60s=4'b0011,S_idle=4'b1000,S_management=4'b1001;//9种state的编号
start==4b'0000
/* initialbeginstate=S_idle;//所以应该在输入中输入?还是直接在45行那儿初始化?end */always@(posedge clk or posedge rst)beginif(rst)beginstate <= S_idle;endend/* always @(posedge clk)beginif (start==4b'1000)state=S_idle;end */
select_sta=8'b00000000;
always @(posedge clk)beginif(clk && timeCnting)//根据clk上跳延计时time_cnt=time_cnt+1;if(timeCnting==0)time_cnt=0;endalways @(posedge init or posedge clk or manage)beginif(clk)begincase(state)S_idle://初始化状态begintimeCnting=0;
left2 = left02;
money_sum=0;change=0;out=0;opt=0;if(manage==1)state=S_management;else beginstate=S_select;endendS_management://管理员可以通过外部设备访问和修改可售商品信息和存量货币信息beginleft1 = left01;left3 = left03;
if(confirm||init)//确认和初始化居其一(到下一步可以取消交易)
left4 = left04;left5 = left05;left6 = left06;left7 = left07;left8 = left08;cash = manage_money;////manage=0;state=S_idle;endS_select://选择某种商品beginselect_sta=select|select_sta;//按位或,应对选择和商品;begin
S_allselled://判断是否售罄
opt={confirm,init};state=S_confirm;endendS_confirm:beginif(opt==2'b10)state=S_allselled;//也就是说当confirm=1时,进入判判断货物状态?那init是做什么用的?else if(opt==2'b00||2'b01||2'b11)beginstate=S_idle;endendbegin
if(select_sta[6]==1 && left6<=0)
isSelled=0;//判断选择的商品是否售罄if(select_sta[1]==1 && left1<=0)isSelled=1;if(select_sta[2]==1 && left2<=0)isSelled=1;if(select_sta[3]==1 && left3<=0)isSelled=1;if(select_sta[4]==1 && left4<=0)isSelled=1;if(select_sta[5]==1 && left5<=0)isSelled=1;
timeCnting=1;//有商品则进入到计时付款阶段
isSelled=1;if(select_sta[7]==1 && left7<=0)isSelled=1;if(select_sta[8]==1 && left8<=0)isSelled=1;if(cash < 16)state=S_management;//没有足够零钱则进入管理员状态else if(isSelled)beginstate=S_idle;//没有商品,回到空闲状态endelsebeginstate=S_60s;end
state=S_idle;
endS_60s:beginif(time_cnt<25)beginif(money_input!=0)begin//只接收1,5,10元if(money_input==1||money_input==5||money_input==10||money_input==0)//检查是否为1,5,10元,不是则退钱并回到空闲状态//添加0是因为可能有连续的钱无法区分,实际上是投币间隔money_sum = money_sum + money_input;else
if(select_sta[3]==1)
endendelse if(time_cnt==25)if(money_sum!=0)state=S_enough;//在计时结束后有钱放入elsestate=S_idle;endS_enough:begin//其中01号商品价格为2元,02商品为4元,依次类推,08号商品售价为16元。if(select_sta[1]==1)money_sum=money_sum-2;if(select_sta[2]==1)money_sum=money_sum-4;
state=S_requirechange;//余额大于等于零,判断是否需要找钱
money_sum=money_sum-6;if(select_sta[4]==1)money_sum=money_sum-8;if(select_sta[5]==1)money_sum=money_sum-10;if(select_sta[6]==1)money_sum=money_sum-12;if(select_sta[7]==1)money_sum=money_sum-14;if(select_sta[8]==1)money_sum=money_sum-16;if(money_sum>=0)
S_out:
else//找零余额不够,退出所有钱,并进入管理状态state=S_management;endS_requirechange:beginif(money_sum==0)//余额为零,不用找零,直接出货state=S_out;else if(money_sum>0)//余额不为零,进入找零模式state=S_change;endS_change:beginchange = money_sum;//将余额找零cash = cash - money_sum;//减去找零state = S_out;end
if(select_sta[8]==1)
begin//对应的货物减1if(select_sta[1]==1)left1=left1-1;if(select_sta[2]==1)left2=left2-1;if(select_sta[3]==1)left3=left3-1;if(select_sta[4]==1)left4=left4-1;if(select_sta[5]==1)left5=left5-1;if(select_sta[6]==1)left6=left6-1;if(select_sta[7]==1)left7=left7-1;left8=left8-1;
out=select_sta;//出货state=S_idle;//进入空闲状态endendcaseendendendmodule
`timescale 1ns/1ns`include "./vending_machine_gx.v"module VendingMac_top;reg clk;reg rst;//复位reg manage;//管理员管理信号reg [9:0] manage_money;//管理售货机内现金reg [3:0] money_input;//用户输入钱reg [7:0] select;reg confirm,init;//确认取消reg [5:0] left01,left02,left03,left04,left05,left06,left07,left08;//剩余商品数,认为不超过63wire integer change;//找零wire [7:0] out;//出货initialbeginclk=0;select=8'b00000000;//初始并没有选择任何商品confirm=0;init=0;money_input=0;manage=0;endalways  begin#5 clk=~clk;//产生时钟#5 clk=~clk;  end   initialbegin#10 rst = 1;//进行初始化,使售货机初始状态为S_idle#10 rst = 0;#10manage=1;#10left01=63;//每种商品的数量left02=62;left03=61;left04=60;left05=59;left06=58;left07=57;left08=56;manage_money=1000;//开始售货机里放1000元#10 manage=0;//管理结束#30#10 select=8'b00000010;//posedge1#10 select=8'b00000000;#10 confirm=1;//确认购买#10 confirm=0;#50 money_input=10;//投币10元#10 money_input=0;//投币间隔#10 money_input=5;#10 money_input=0;#10 money_input=1;#10 money_input=0;  end    initial  begin    $monitor($time,,,"select=%b,money_input=%d,confirm=%d,init=%d,out=%b,change=%d",select,money_input,confirm,init,out,change);    #60000 $finish;  end    VendingMac v1(clk,money_input,select,confirm,init,left01,left02,left03,left04,left05,left06,left07,left08,change,out,manage,manage_money,rst);endmodule        



0 0
原创粉丝点击