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

相关推荐

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-12 12:56:03       67 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-12 12:56:03       71 阅读
  3. 在Django里面运行非项目文件

    2024-07-12 12:56:03       58 阅读
  4. Python语言-面向对象

    2024-07-12 12:56:03       69 阅读

热门阅读

  1. Vim 编辑文件时中文乱码的解决方法

    2024-07-12 12:56:03       18 阅读
  2. vim删除多行

    2024-07-12 12:56:03       24 阅读
  3. 嵌入式裸机开发与 Linux 开发

    2024-07-12 12:56:03       21 阅读
  4. 机器学习-分类器-总结

    2024-07-12 12:56:03       18 阅读
  5. Git-如何基于某个tag创建一个新分支

    2024-07-12 12:56:03       27 阅读
  6. 【Linux】Vim 使用教程

    2024-07-12 12:56:03       16 阅读
  7. Hive中的数据类型和存储格式总结

    2024-07-12 12:56:03       21 阅读
  8. modern C++:闭包与匿名函数

    2024-07-12 12:56:03       23 阅读
  9. 前缀,中缀,后缀表达式

    2024-07-12 12:56:03       22 阅读
  10. 笔记:如何使用Microsoft.Extensions.Options

    2024-07-12 12:56:03       30 阅读
  11. socket编程(1)

    2024-07-12 12:56:03       30 阅读
  12. stm32flash一键ISP烧录单片机

    2024-07-12 12:56:03       20 阅读