(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)beginkey_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)beginkey_r_flag <= 1'd0;key_p_flag <= 1'd0;key_state <= 1'd1;STATE <= IDLE;en_cnt <= 1'd0;endelse begincase(STATE)IDLE:beginkey_r_flag <= 1'd0;key_state <= 1'd1;if(nedge)beginSTATE <= P_SHAKE;en_cnt <= 1'd1;endelse STATE <= STATE;endP_SHAKE:beginif(arrive_time_20ms)beginSTATE <= DOWN;en_cnt <= 1'd0;key_p_flag <= 1'd1;key_state <= 1'd0;endelse if(podge)beginSTATE <= IDLE;en_cnt <= 1'd0;endelse STATE <= STATE; endDOWN:beginkey_p_flag <= 1'd0;key_state <= 1'd0;if(podge)beginSTATE <= R_SHAKE;en_cnt <= 1'd1;endelse STATE <= STATE; endR_SHAKE:beginif(arrive_time_20ms)beginSTATE <= IDLE;en_cnt <= 1'd0;key_r_flag <= 1'd1;key_state <= 1'd1;endelse if(nedge)beginSTATE <= DOWN;en_cnt <= 1'd0;endelse STATE <= STATE; enddefault:beginkey_r_flag <= 1'd0;key_p_flag <= 1'd0;key_state <= 1'd1;STATE <= IDLE;endendcaseendendmodule
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 begincase(state)IDLE:beginif(pi_money == 2'b10)state <= ONE;else if(pi_money == 2'b01)state <= HALF;else state <= state;endHALF:beginif(pi_money == 2'b10)state <= ONE_HALF;else if(pi_money == 2'b01)state <= ONE;else state <= state;endONE:beginif(pi_money == 2'b10)state <= TWO;else if(pi_money == 2'b01)state <= ONE_HALF;else state <= state;endONE_HALF:beginif(pi_money == 2'b10)state <= IDLE;else if(pi_money == 2'b01)state <= TWO;else state <= state;endTWO:beginif((pi_money == 2'b10) || (pi_money == 2'b01))state <= IDLE;else state <= state;enddefault:beginstate <= IDLE;endendcaseend//状态机输出信号设计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;elsepo <= po;//led灯设计always@(posedge clk or negedge reset_n)if(!reset_n)led <= 4'b0000;else begincase(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;endcaseendendmodule
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)引脚绑定: