1.问题重述:
自动售饮料机是一个典型的利用状态机进行电路设计的例子。要求采用有限状态机设计,使用case语句来描述各个状态之间的转移关系。假定每瓶饮料售价为2.5元,可使用 2 种硬市,即5角(half_dollar)、1元(one_dollar),机器有找零功能。下图是该自动售饮料机的示意图。
在程序中,可以定义5个状态,代表不同时刻机器的不同状态。在系统复位后机器开始运行,在每一次出售饮料的过程中记录其状态,表示投币者已投入钱币数目的变化,在下一次售出前,首先reset将系统清零。
2.问题分析:
1)题目要求运用状态机来描述自动贩卖机,那么这时的输出(即找零和取饮料)是与用户的输入(投币)有关的,所以在这里应该运用mealy机。
2)对于工作模式的认识与建模:认为在这个机器中,有如下的工作模式:投入两元时,再投入五角,则出饮料,而不找零,进行清零;投入两元时,再投入一元,则出饮料,找零五角,进行清零。考虑到没有按键等交互功能,并且时钟频率较高的情况下,同时投下1元和五角的几率很低,这种情况可以忽略,即不会同时使元和角输入同时为1的可能。那么相应的,找零也不会出现找出1块钱的情况,只有要已经输入2元,在输入1元的情况下,会找出5角的零钱。这样可以大大简化状态机的设计。
3)在这里定义五个状态,由于输入可以为5角和1元,由yuan_in和jiao_in分别来表示,所以输入的状态定位0元,0.5元,1元,1.5元,2元五种,在yuan_in,jiao_in的控制下,在五种状态间进行状态转移。
4)输出包括取饮料和找零,当然也包括币值的显示和取饮料、找零的led显示。取饮料用一位二进制表示good_out,找零用jiao_out来表示。币值显示跟随状态机,用两个一位十进制数seg_shiyuan和seg_yiyuan来显示,之后用前面所做过的译码器来实现。另外是led_drink和led_exchange分别表示对应的led灯的亮灭,这和输入状态的good_out和jiao_out使绑定的。亮表示正在进行该动作。
5)根据上面描述,画出如下状态机转移图:
状态转移图对mealy机状态转移的描述不是十分清晰。下面再用状态转移表进行描述:
3.代码展现:
虽然通过上面的分析,为了代码的完备性,这里的代码还是考虑了同时投下一元和五角的情况,即每个状态机中对应的输入情况都有四种(00,01,10,11)。
.v文件:
`timescale 1ns / 1ps
//
// Company:
// Engineer: jeffery
module machine(
/*input*/ clk,rst,yuan_in,jiao_in,
/*output*/ good_out,yuan_out,jiao_out,
led_drink,led_exchange,//输出信号中显示出饮料、找零的指示灯
segment,chip //显示的led灯,使用第6题中的动态扫描输出
);
input wire clk,rst, yuan_in, jiao_in;
output reg good_out,yuan_out,jiao_out;
output wire led_drink,led_exchange;
output wire [6:0] segment;
output wire [1:0] chip;
parameter state00=3'd0,state05=3'd1,
state10=3'd2,state15=3'd3,
state20=3'd4;//连续定义parameter这里要是逗号隔开的!!
//这个assign块的含义是,这两个输出是互相绑定的
assign led_drink=good_out;
assign led_exchange=(jiao_out||yuan_out);
//这个always语句是对状态的转移进行定义
reg [2:0]state;
reg [7:0]number;//这个数字是用于产生
always @(posedge clk or negedge rst)
begin
if(!rst)
begin
state=state00;
good_out=0;
yuan_out=0;
jiao_out=0;
number=0;
end
else
begin
case(state)
state00:
begin
if(yuan_in==0 && jiao_in==0)
begin
state=state00;
good_out=0;
yuan_out=0;
jiao_out=0;
number[7:4]=0;
number[3:0]=0;
end
else if(yuan_in==0 && jiao_in==1)
begin
state=state05;
good_out=0;
yuan_out=0;
jiao_out=0;
number[7:4]=0;
number[3:0]=5;
end
else if(yuan_in==1 && jiao_in==0)
begin
state=state10;
good_out=0;
yuan_out=0;
jiao_out=0;
number[7:4]=1;
number[3:0]=0;
end
else if(yuan_in==1 && jiao_in==1)
begin
state=state15;
good_out=0;
yuan_out=0;
jiao_out=0;
number[7:4]=1;
number[3:0]=5;
end
end
state05:
begin
if(yuan_in==0 && jiao_in==0)
begin
state=state05;
good_out=0;
yuan_out=0;
jiao_out=0;
number[7:4]=0;
number[3:0]=5;
end
else if(yuan_in==0 && jiao_in==1)
begin
state=state10;
good_out=0;
yuan_out=0;
jiao_out=0;
number[7:4]=1;
number[3:0]=0;
end
else if(yuan_in==1 && jiao_in==0)
begin
state=state15;
good_out=0;
yuan_out=0;
jiao_out=0;
number[7:4]=1;
number[3:0]=5;
end
else if(yuan_in==1 && jiao_in==1)
begin
state=state20;
good_out=0;
yuan_out=0;
jiao_out=0;
number[7:4]=2;
number[3:0]=0;
end
end
state10:
begin
if(yuan_in==0 && jiao_in==0)
begin
state=state10;
good_out=0;
yuan_out=0;
jiao_out=0;
number[7:4]=1;
number[3:0]=0;
end
else if(yuan_in==0 && jiao_in==1)
begin
state=state15;
good_out=0;
yuan_out=0;
jiao_out=0;
number[7:4]=1;
number[3:0]=5;
end
else if(yuan_in==1 && jiao_in==0)
begin
state=state20;
good_out=0;
yuan_out=0;
jiao_out=0;
number[7:4]=2;
number[3:0]=0;
end
else if(yuan_in==1 && jiao_in==1)
begin
state=state00;
good_out=1;
yuan_out=0;
jiao_out=0;
number[7:4]=0;
number[3:0]=0;
end
end
state15:
begin
if(yuan_in==0 && jiao_in==0)
begin
state=state15;
good_out=0;
yuan_out=0;
jiao_out=0;
number[7:4]=1;
number[3:0]=5;
end
else if(yuan_in==0 && jiao_in==1)
begin
state=state20;
good_out=0;
yuan_out=0;
jiao_out=0;
number[7:4]=2;
number[3:0]=0;
end
else if(yuan_in==1 && jiao_in==0)
begin
state=state00;
good_out=1;
yuan_out=0;
jiao_out=0;
number[7:4]=0;
number[3:0]=0;
end
else if(yuan_in==1 && jiao_in==1)
begin
state=state00;
good_out=1;
yuan_out=0;
jiao_out=1;
number[7:4]=0;
number[3:0]=0;
end
end
state20:
begin
if(yuan_in==0 && jiao_in==0)
begin
state=state20;
good_out=0;
yuan_out=0;
jiao_out=0;
number[7:4]=2;
number[3:0]=0;
end
else if(yuan_in==0 && jiao_in==1)
begin
state=state00;
good_out=1;
yuan_out=0;
jiao_out=0;
number[7:4]=0;
number[3:0]=0;
end
else if(yuan_in==1 && jiao_in==0)
begin
state=state00;
good_out=1;
yuan_out=0;
jiao_out=1;
number[7:4]=0;
number[3:0]=0;
end
else if(yuan_in==1 && jiao_in==1)
begin
state=state00;
good_out=1;
yuan_out=1;
jiao_out=0;
number[7:4]=0;
number[3:0]=0;
end
end
default:
begin
state=state00;
good_out=0;
yuan_out=0;
jiao_out=0;
number[7:4]=0;
number[3:0]=0;
end
endcase
end
end
//这里将会是例化regment译码器
wire [7:0] number_show;
assign number_show=number;//由于reg类型变量无法直接作为例化的输入端口,
//所以这里要通过连续赋值语句将其赋给wire型变量
led myled(.number(number_show),.segment(segment),.chip(chip),.clk(clk),.rst(rst));
endmodule
led module:
`timescale 1ns / 1ps
//
// Company:
// Engineer: jeffery
module led(number,segment,chip,clk,rst);
input [7:0] number;
input clk,rst;
output reg [6:0] segment;
output reg [1:0] chip;
//这个always语句是完成了选通信号的逐个开启,0,1两个状态
reg cnt;
always @(posedge clk or negedge rst)//rst信号的下降沿将触发这个模块,是他们在任何条件都进行复位操作
begin
if(!rst)
cnt=0;
else
cnt=cnt+1;
end
//这个部分是对每次选择的数字,以及对应显示的片进行了选择
reg [3:0] number_reading;//number_reading是用来表示通过片选信号按顺序显示数字,这时正在读取的数字
always @(posedge clk or negedge rst)
begin
if(!rst)
begin
number_reading=1'd0;
chip=2'b00;
end
else
begin
case(cnt)
1'b0:
begin
number_reading=number[3:0];
chip=2'b01;
end
1'b1:
begin
number_reading=number[7:4];
chip=2'b10;
end
default:
begin
number_reading=4'd0;
chip=2'b00;
end
endcase
end
end
//这个always语句是对segment进行了数字编码
always @(posedge clk or negedge rst)
begin
if(!rst)
segment=7'b0;
else
begin
case(number_reading)
4'd0: segment=7'b1111110;
4'd1: segment=7'b0110000;
4'd2: segment=7'b1101101;
4'd3: segment=7'b1111001;
4'd4: segment=7'b0110011;
4'd5: segment=7'b1011011;
4'd6: segment=7'b1011111;
4'd7: segment=7'b1110000;
4'd8: segment=7'b1111111;
4'd9: segment=7'b1111011;
default: segment=7'b0;
endcase
end
end
endmodule
tb文件:文章来源:https://www.toymoban.com/news/detail-474722.html
`timescale 1ns / 1ps
module tb();
reg clk, rst, yuan_in, jiao_in;
wire good_out,yuan_out,jiao_out;
wire led_drink,led_exchange;
wire [6:0] segment;
wire [1:0] chip;
machine my_machine(
/*input*/ clk,rst,yuan_in,jiao_in,
/*output*/ good_out,yuan_out,jiao_out,
led_drink,led_exchange,//输出信号中显示出饮料、找零的指示灯
segment,chip //显示的led灯,使用第6题中的动态扫描输出
);
initial
begin
clk=1;
rst=1;
yuan_in=0;
jiao_in=0;
#8 rst=0;
#8 rst=1;//检测复位信号是否能够让输出不再为x
#4 yuan_in=1;jiao_in=0;
#4 yuan_in=0;jiao_in=0;
#4 yuan_in=1;jiao_in=0;
#4 yuan_in=0;jiao_in=0;
#4 yuan_in=1;jiao_in=0;//测试连续投三个1元
#4 yuan_in=0;jiao_in=0;//必须要留够一定时间,这样才能使扫描显示的led正常显示,方便测试
#4 yuan_in=0;jiao_in=1;
#4 yuan_in=0;jiao_in=0;
#4 yuan_in=0;jiao_in=1;
#4 yuan_in=0;jiao_in=0;
#4 yuan_in=0;jiao_in=1;
#4 yuan_in=0;jiao_in=0;
#4 yuan_in=0;jiao_in=1;
#4 yuan_in=0;jiao_in=0;
#4 yuan_in=0;jiao_in=1;//测试连续投五个五角
#4 yuan_in=0;jiao_in=0;
#4 yuan_in=0;jiao_in=1;
#4 yuan_in=0;jiao_in=0;
#4 yuan_in=1;jiao_in=0;
#4 yuan_in=0;jiao_in=0;
#4 yuan_in=0;jiao_in=1;
#4 yuan_in=0;jiao_in=0;
#4 yuan_in=1;jiao_in=0;//测试五角--一元--五角--一元
#4 yuan_in=0;jiao_in=0;
#4 yuan_in=0;jiao_in=1;
#4 yuan_in=0;jiao_in=0;
#4 yuan_in=1;jiao_in=1;
#4 yuan_in=0;jiao_in=0;
#4 yuan_in=0;jiao_in=0;
#4 yuan_in=0;jiao_in=0;
#4 yuan_in=0;jiao_in=1;//测试五角--一元-五角-不投--五角--一元
#4 yuan_in=0;jiao_in=0;
end
always
begin
#2 clk=~clk;//这里定义的时钟周期为4个时间单位
end
endmodule
4.实验结果:
从上到下分别为:
连续投3个一元,
连续投5个五角,
五角——一元——五角——一元,
五角——一元五角同时投——不投——五角文章来源地址https://www.toymoban.com/news/detail-474722.html
到了这里,关于数字系统设计实验七(完结):verilog实现简易饮料贩售机的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!