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文件:

`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个五角, 五角——一元——五角——一元, 五角——一元五角同时投——不投——五角

精彩文章

评论可见,请评论后查看内容,谢谢!!!
 您阅读本篇文章共花了: