24.可乐机拓展练习--综合训练

(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)引脚绑定:

相关推荐
nanxl143 分钟前
FPGA-DDS信号发生器
fpga开发·verilog·vivado
黄埔数据分析3 小时前
RecoNIC 入门:SmartNIC 上支持 RDMA 的计算卸载-FPGA-智能网卡-AMD-Xilinx
fpga开发
nanxl15 小时前
FPGA-数字时钟
fpga开发·verilog·vivado
尤老师FPGA18 小时前
LVDS系列9:Xilinx 7系可编程输入延迟(二)
单片机·嵌入式硬件·fpga开发
内有小猪卖1 天前
时序约束 记录
fpga开发
Cao1234567893211 天前
FPGA时钟设计
fpga开发
JNTeresa1 天前
锁存器知识点详解
fpga开发
Cao1234567893211 天前
FPGA基础之基础语法
fpga开发
一大Cpp1 天前
通过Quartus II实现Nios II编程
fpga开发
7yewh1 天前
Verilog 语法 (二)
fpga开发