功能要求:

1.只售咖啡; 2.三元/杯,接收一元/五角硬币; 3.不找零钱; 4.售货机中的杯子永远用不完。         从投币口投入1元或5角硬币后,系统对钱币进行计数,当计够3元钱,便自动出咖啡一杯。如果投人的钱币大于3元,如 3.5 元,不进行找零,并且在卖出一次咖啡后,系统钱数清零。

系统定义:

        通过分析咖啡机的功能需求,可以提取出系统的最外层输入输出接口,包括时钟输人、复位输人、投币信号、注咖啡信号、咖啡注完信号、放杯信号、杯子准备就绪信号等。

状态机设计:

        按照流程图的条件转换关系,就可以对应的画出状态转换图,该图如图所示。在设计中,有的状态需要向外部发出控制信号,有的状态不需要发出控制信号,有控制信号输出的状态,需要将控制信号表明在对应的状态图旁边。在该状态转换图中 Add a 和 Add_b分别是计数器一次计数加1行为。当投币是1元钱的时候,计数行为先经过 Add a 接着经过 Addb完成两次计数工作。当投币是5角钱的时候,计数行为只经过 Add_b只完成一次计数工作。Comp 状态是一个空状态,在这里就是为了再等一个时钟周期。因为前面的 Add b是一个计数器的时序动作,在时钟上沿来到的时候才有效,因此只在下一个时钟周期才会完成计数动作,因此在这里需要等待一个时钟周期再判断计数值才有效。具体时序图关系如图所示。分别是计数器一次计数加1行为。当投币是1元钱的时候,计数行为先经过 Add a接着经过Addb完成两次计数工作当投币是5角钱的时候,计数行为只经过 Add b 只完成一次计数工作。comp 状态是一个空态,在这里就是为了再等一个时钟周期。因为前面的 Add_b是一个计数器的时序动作,在时钟上升沿来到的时候才有效,因此只在下一个时钟周期才会完成计数动作,因此在这里需要等待一个时钟周期再判断计数值才有效。具体时序图关系如图所示。

//状态机模块

module coffee_ztj(

clk,//时钟

RSTN,//复位

cup_rdy,//杯子就绪

cof_rdy,//咖啡机就绪

place_cup,//放杯子

Release_cof,//注入咖啡

half_yuan,//半元

one_yuan,//一元

present_state,//当前状态

cnt,//计数值

cnt_en,

cnt_clr,

Eql_grt

);

input clk,RSTN,cup_rdy,cof_rdy,half_yuan,one_yuan,Eql_grt;

output place_cup,Release_cof,present_state,cnt_en,cnt_clr;

output [3:0]cnt;

//reg place_cup,inject_cof;

reg cnt_clr,a,b,c,d,e,f;

reg cnt_en, place_cup,Release_cof;

reg [3:0]present_state,next_state;//当前状态和下一状态

parameter Init=3'b000,//初始状态

Wait=3'b010,//等待状态

Add_a=3'b110,//加一元状态

Add_b=3'b100,//加半元状态

comp=3'b111,//比较状态

Place=3'b001,//放杯子状态

Release=3'b011;//释放咖啡状态

always @ (posedge clk)

begin

a<=~one_yuan;

b<=a;

c<=a&&(~b);

end

always @ (posedge clk)

begin

d<=~half_yuan;

e<=d;

f<=d&&(~e);

end

always @ (negedge clk or negedge RSTN)

if(!RSTN)//复位

present_state<=Init;

else

present_state<=next_state;

always @ (*)

begin

case(present_state)

Init: begin//初始状态

{cnt_en,cnt_clr,place_cup,Release_cof}=4'b0000;

next_state<=Wait;//等待状态

end

Wait : begin//等待状态

{cnt_en,cnt_clr,place_cup,Release_cof}=4'b0100;

if(f)//半元

next_state<=Add_b;//加半元状态

else

if(c)//一元

next_state<=Add_a;//加一元状态

else

next_state<=Wait;//等待状态

end

Add_a: begin//加一元状态

{cnt_en,cnt_clr,place_cup,Release_cof}=4'b1100;

next_state<=Add_b;//加半元状态

end

Add_b: begin//加半元状态

{cnt_en,cnt_clr,place_cup,Release_cof}=4'b1100;

next_state<=comp;//比较状态

end

comp: begin//比较状态

{cnt_en,cnt_clr,place_cup,Release_cof}=4'b0100;

if(Eql_grt)//计数到6

next_state<=Place;//放杯子状态

else

next_state<=Wait;//等待状态

end

Place: begin//放杯子状态

{cnt_en,cnt_clr,place_cup,Release_cof}=4'b0110;

if(!cup_rdy)//杯子未就绪

next_state<=Place;//放杯子状态

else

next_state<=Release;//释放咖啡状态

end

Release: begin//释放咖啡状态

{cnt_en,cnt_clr,place_cup,Release_cof}=4'b0101;

if(!cof_rdy)//咖啡机未就绪

next_state<=Release;//释放咖啡状态

else

next_state<=Init;// 初始化状态

end

endcase

end

endmodule

数据通道设计:

        根据流程图来分析数据通道模块,流程图中有加一动作,因此采用计数器来实现该功能。不过这里因为以5角钱作为基本计数单位,那么有可能投币情况会出现 3元与3元5角两种情况。以5角为单位,也就是说计数器最大计数值是 7,所以在数据通道中采用位宽为3位的二进制计数器来实现投币额度的计算。又由于咖啡机不找零,计数额大于等于 6 的时候就开始放杯倒咖啡,这时候计数器输出之和Sum[2:7的最高位Sum[2]一定是1,因此用Sum[2]信号引出给外部状态机电路作为计数额大于等于6有效地判断信号,该信号取名为 Eql_grt_6。

//数据通道模块

module DataPath(

cnt_clr,//复位

clk,//时钟

cnt_en,

Eql_grt,//等于大于信号

Sum//计数值

);

input cnt_clr,clk,cnt_en;

output Eql_grt;

output [3:0]Sum;

wire cnt_en;

//实例化计数器模块

counter cnt1(

.cnt_clr(cnt_clr),

.clk(clk),

.cnt(Sum),

.cnt_en(cnt_en)

);

//实例化比较器模块

comparator cmp1(

.clk(clk),

.cnt(Sum),

.Eql_grt(Eql_grt)

);

endmodule

整体电路设计:

//顶层设计

module coffee(

clk,//时钟

RSTN,//复位

cup_rdy,//杯子就绪

cof_rdy,//咖啡机就绪

half_yuan,//半元

one_yuan,//一元

place_cup,//放杯子

Release_cof,//注入咖啡

present_state,//当前状态

cnt_en,

cnt_clr

);

input clk,RSTN,cup_rdy,cof_rdy,half_yuan,one_yuan;

output place_cup,Release_cof,present_state,cnt_en,cnt_clr;

wire place_cup,Release_cof,cnt_en,cnt_clr;

wire Eql_grt;

wire [3:0]cnt,present_state;

//实例化状态机

coffee_ztj coffee_ztj(

.clk(clk),

.RSTN(RSTN),

.cup_rdy(cup_rdy),

.cof_rdy(cof_rdy),

.half_yuan(half_yuan),

.one_yuan(one_yuan),

.place_cup(place_cup),

.Release_cof(Release_cof),

.present_state(present_state),

.cnt_en(cnt_en),

.cnt_clr(cnt_clr),

.Eql_grt(Eql_grt)

);

//实例化数据通道模块

DataPath DataPath(

.cnt_clr(cnt_clr),

.clk(clk),

.cnt_en(cnt_en),

.Eql_grt(Eql_grt),

.Sum(cnt)

);

endmodule

 其他子模块:

//比较器模块

module comparator(

clk,//时钟

cnt,

Eql_grt,//等于大于信号

);

input clk;

input [3:0]cnt;

output Eql_grt;

reg Eql_grt;

always @( posedge clk ) begin

if(cnt >= 4'b0110)

Eql_grt<=1'b1;

else

Eql_grt<=1'b0;

end

endmodule

//计数器模块

module counter(

cnt_clr,//复位

clk,//时钟

cnt,//计数信号

cnt_en,//计数使能

);

input cnt_en,cnt_clr,clk;

output [3:0]cnt;

reg [3:0]cnt;

always @ (negedge cnt_clr or posedge clk)

begin

if(!cnt_clr)//复位

cnt<=4'b0000;

else

if(cnt_en)//计数使能

cnt<=cnt+3'b1;

else

if(cnt==4'b0111)//计数到15

cnt<=4'b0000;

else

cnt<=cnt;

end

endmodule

推荐文章

评论可见,请评论后查看内容,谢谢!!!评论后请刷新页面。