(1)设计要求:仍以可乐机为背景,一瓶可乐的价格是2.5 元,用按键控制投币(加入按键消抖功能),可以投 0.5 元硬币和 1元硬币,投入 0.5 元后亮一个灯,投入 1元后亮 2个灯,投入 1.5 元后亮 3个灯,投入 2元后亮 4 个灯。投入 2.5 元后出可乐不找零,此时 led 灯实现单向流水操作,流水 10s后自动停止;投入 3 元后出可乐找零,此时 led 灯实现双向流水操作,流水 3s 后自动停止。整个系统有复位键,其功能是终止本次投币操作,使可乐机立刻回到初始状态。
(2)Verilog代码:

module complex_cola(clk,reset_n,key_half_money,key_one_money,led_out);
input clk;
input reset_n;
input key_half_money;
input key_one_money;
output [3:0]led_out;
wire pi_money_half;
wire pi_money_one;
wire po_cola;
wire po_money;
wire en0;
wire en1;
wire [3:0]led_out0;
wire [3:0]led_out1;
wire [3:0]led_r;
//按键消抖模块
key_filter key_filter_inst0(
.clk(clk),
.reset_n(reset_n),
.key_in(key_half_money),
.key_p_flag(pi_money_half),
.key_r_flag(),
.key_state()
);
key_filter key_filter_inst1(
.clk(clk),
.reset_n(reset_n),
.key_in(key_one_money),
.key_p_flag(pi_money_one),
.key_r_flag(),
.key_state()
);
//可乐机主体程序
fsm_cola_plus fsm_cola_plus_inst(
.clk(clk),
.reset_n(reset_n),
.pi_money_one(pi_money_one),
.pi_money_half(pi_money_half),
.po_cola(po_cola),
.po_money(po_money),
.led(led_r)
);
//单向、双向流水灯模块
water_led_s water_led_s_inst(
.clk(clk),
.reset_n(reset_n),
.en(en0),
.led_out(led_out0)
);
water_led_d water_led_d_inst(
.clk(clk),
.reset_n(reset_n),
.en(en1),
.led_out(led_out1)
);
//en0、en1设计
assign {en1,en0} = ({po_cola,po_money} == 2'b11)? (2'b10):(({po_cola,po_money} == 2'b10)? 2'b01:2'b00);
//led_out设计
assign led_out = (led_r == 4'b0000)? ((en1)?led_out1:(en0?led_out0:4'b0000)):led_r;
endmodule
module key_filter(clk,reset_n,key_in,key_p_flag,key_r_flag,key_state);
input clk;
input reset_n;
input key_in;
output reg key_p_flag;
output reg key_r_flag;
output reg key_state;
reg key_in1;
reg key_in2;
reg key_in3;
reg [3:0]STATE;
//抖动时间往往小于20ms,20ms = 20_000_000ns = 20ns * 1_000_000; 需要一个20位的寄存器
reg [19:0]cnt;
reg en_cnt;
wire podge;
wire nedge;
wire arrive_time_20ms;
//状态设计
parameter IDLE = 4'b0001;
parameter P_SHAKE = 4'b0010;
parameter DOWN = 4'b0100;
parameter R_SHAKE = 4'b1000;
//异步输入key_in信号的同步化------------"打两拍"
always@(posedge clk)begin
key_in1 <= key_in;
key_in2 <= key_in1;
end
//上升沿、下降沿设计
always@(posedge clk)
key_in3 <= key_in2;
assign podge = key_in2 && (!key_in3);
assign nedge = (!key_in2) && key_in3;
//20ms计数器模块设计
always@(posedge clk or negedge reset_n)
if(!reset_n)
cnt <= 20'd0;
else if(en_cnt &&(cnt == 20'd999_999))
cnt <= 20'd0;
else if(en_cnt)
cnt <= cnt + 20'd1;
else
cnt <= 20'd0;
//计满20ms信号设计
assign arrive_time_20ms = (cnt == 20'd999_999);
//状态机主程序设计
always@(posedge clk or negedge reset_n)
if(!reset_n)begin
key_r_flag <= 1'd0;
key_p_flag <= 1'd0;
key_state <= 1'd1;
STATE <= IDLE;
en_cnt <= 1'd0;
end
else begin
case(STATE)
IDLE:begin
key_r_flag <= 1'd0;
key_state <= 1'd1;
if(nedge)begin
STATE <= P_SHAKE;
en_cnt <= 1'd1;
end
else
STATE <= STATE;
end
P_SHAKE:begin
if(arrive_time_20ms)begin
STATE <= DOWN;
en_cnt <= 1'd0;
key_p_flag <= 1'd1;
key_state <= 1'd0;
end
else if(podge)begin
STATE <= IDLE;
en_cnt <= 1'd0;
end
else
STATE <= STATE;
end
DOWN:begin
key_p_flag <= 1'd0;
key_state <= 1'd0;
if(podge)begin
STATE <= R_SHAKE;
en_cnt <= 1'd1;
end
else
STATE <= STATE;
end
R_SHAKE:begin
if(arrive_time_20ms)begin
STATE <= IDLE;
en_cnt <= 1'd0;
key_r_flag <= 1'd1;
key_state <= 1'd1;
end
else if(nedge)begin
STATE <= DOWN;
en_cnt <= 1'd0;
end
else
STATE <= STATE;
end
default:begin
key_r_flag <= 1'd0;
key_p_flag <= 1'd0;
key_state <= 1'd1;
STATE <= IDLE;
end
endcase
end
endmodule
module water_led_s(clk,reset_n,en,led_out);
input clk;
input en;
input reset_n;
output reg [3:0]led_out;
reg [29:0]cnt;
reg cnt_flag;
reg [4:0]flag_cnt;
parameter MCNT = 30'd24_999_999;
//0.5s计数器模块设计
always@(posedge clk or negedge reset_n)
if(!reset_n)
cnt <= 30'd0;
else if((cnt == MCNT) && (en))
cnt <= 30'd0;
else if(en)
cnt <= cnt + 30'd1;
else
cnt <= 30'd0;
//计数完成标志信号cnt_flag信号设计
always@(posedge clk or negedge reset_n)
if(!reset_n)
cnt_flag <= 1'd0;
else if(cnt == MCNT - 28'd1)
cnt_flag <= 1'd1;
else
cnt_flag <= 1'd0;
//flag_cnt信号设计
always@(posedge clk or negedge reset_n)
if(!reset_n)
flag_cnt <= 5'd0;
else if((cnt_flag)&&(flag_cnt == 5'd20))
flag_cnt <= 5'd0;
else if(cnt_flag)
flag_cnt <= flag_cnt + 5'd1;
else
flag_cnt <= flag_cnt;
//流水灯主程序设计
always@(posedge clk or negedge reset_n)
if(!reset_n)
led_out <= 4'b0001;
else if((cnt_flag)&&(flag_cnt == 5'd20))
led_out <= 4'b0000;
else if(cnt_flag)
led_out <= {led_out[2:0],led_out[3]};
else
led_out <= led_out;
endmodule
module fsm_cola_plus(clk,reset_n,pi_money_one,pi_money_half,po_cola,po_money,led);
input clk;
input reset_n;
input pi_money_one;
input pi_money_half;
output po_cola;
output po_money;
output reg [3:0]led;
reg [4:0] state;
wire [1:0]pi_money;
reg [1:0]po;
parameter IDLE = 5'b00001;
parameter HALF = 5'b00010;
parameter ONE = 5'b00100;
parameter ONE_HALF = 5'b01000;
parameter TWO = 5'b10000;
//输入、输出信号编码设计
assign pi_money = {pi_money_one,pi_money_half};
assign {po_cola,po_money} = po;
//状态机状态跳转设计
always@(posedge clk or negedge reset_n)
if(!reset_n)
state <= IDLE;
else begin
case(state)
IDLE:begin
if(pi_money == 2'b10)
state <= ONE;
else if(pi_money == 2'b01)
state <= HALF;
else
state <= state;
end
HALF:begin
if(pi_money == 2'b10)
state <= ONE_HALF;
else if(pi_money == 2'b01)
state <= ONE;
else
state <= state;
end
ONE:begin
if(pi_money == 2'b10)
state <= TWO;
else if(pi_money == 2'b01)
state <= ONE_HALF;
else
state <= state;
end
ONE_HALF:begin
if(pi_money == 2'b10)
state <= IDLE;
else if(pi_money == 2'b01)
state <= TWO;
else
state <= state;
end
TWO:begin
if((pi_money == 2'b10) || (pi_money == 2'b01))
state <= IDLE;
else
state <= state;
end
default:begin
state <= IDLE;
end
endcase
end
//状态机输出信号设计
always@(posedge clk or negedge reset_n)
if(!reset_n)
po <= 2'b00;
else if(((state == ONE_HALF) && (pi_money == 2'b10)) || ((state == TWO) && (pi_money == 2'b01)))
po <= 2'b10;
else if((state == TWO) && (pi_money == 2'b10))
po <= 2'b11;
else
po <= po;
//led灯设计
always@(posedge clk or negedge reset_n)
if(!reset_n)
led <= 4'b0000;
else begin
case(state)
IDLE:led <= 4'b0000;
HALF:led <= 4'b0001;
ONE:led <= 4'b0011;
ONE_HALF:led <= 4'b0111;
TWO:led <= 4'b1111;
default:led <= 4'b0000;
endcase
end
endmodule
module water_led_d(clk,reset_n,en,led_out);
input clk;
input en;
input reset_n;
output reg [3:0]led_out;
reg [29:0]cnt;
reg cnt_flag;
reg [4:0]flag_cnt;
parameter MCNT = 30'd24_999_999;
//0.5s计数器模块设计
always@(posedge clk or negedge reset_n)
if(!reset_n)
cnt <= 30'd0;
else if((cnt == MCNT) && (en))
cnt <= 30'd0;
else if(en)
cnt <= cnt + 30'd1;
else
cnt <= 30'd0;
//计数完成标志信号cnt_flag信号设计
always@(posedge clk or negedge reset_n)
if(!reset_n)
cnt_flag <= 1'd0;
else if(cnt == MCNT - 28'd1)
cnt_flag <= 1'd1;
else
cnt_flag <= 1'd0;
//flag_cnt信号设计
always@(posedge clk or negedge reset_n)
if(!reset_n)
flag_cnt <= 5'd0;
else if((cnt_flag)&&(flag_cnt == 5'd6))
flag_cnt <= 5'd0;
else if(cnt_flag)
flag_cnt <= flag_cnt + 5'd1;
else
flag_cnt <= flag_cnt;
//流水灯主程序设计
always@(posedge clk or negedge reset_n)
if(!reset_n)
led_out <= 4'b0001;
else if((cnt_flag)&&(flag_cnt == 5'd6))
led_out <= 4'b0000;
else if((cnt_flag)&&(flag_cnt <= 2))
led_out <= {led_out[2:0],led_out[3]};
else if(cnt_flag)
led_out <= {led_out[0],led_out[3:1]};
else
led_out <= led_out;
endmodule
(3)引脚绑定:
