cyclone IV板子做一个自动售货机

目录

1.实验目的

2.需求分析

3.状态转移图

4.结构框图

5.代码片段

5.1   seller_ctrl模块(中心控制)

5.2  led_ctrl(led控制模块)

5.3 beep_ctrl模块(蜂鸣器控制模块)

 5.4 seg_ctrl模块(数码管控制模块)

 5.5 key_filter模块

5.6 top_seller(顶层文件)

6. 仿真文件书写

6.1 仿真代码

6.2仿真效果实现

 7.0上板验证

1.实验目的

1.使用状态机的方法实现按键消抖;

2.简易售货机

                货物(唯一)价值5元

                货币(0.5 ,1.0 ,2.0)

                显示模块(投入货币总值,并显示找零)

                LED(表示状态)

        设置确认付款按钮,(我这里只有四个按键,所以不设复位,但还是要写代码,

                Key1: 确认付款按键

                Key2:货币0.5信号

                Key3:货币1.0信号

                Key4:货币2.0信号

1.满足货物价值,出货开关打开,并显示找零,led流水,蜂鸣器播放音乐(两只老虎);

2.不满足货物价值,退钱,led灯高速闪烁,蜂鸣器鸣叫(我这里播放 《我没有钱,我不要脸》)

2.需求分析

这里要求我们的是一个简易的售货机,自动默认已经选好商品,且价值也唯一(这些有需要可以自己加),相当于我们只需要直接投入货币,然后计算投入总值,再与商品价值作比较,如果投入金额大于等于商品价值,出货成功,并有一系列器件反映(目的处有),如果小于商品价值,退钱,并且嘲讽他穷。

3.状态转移图

4.结构框图

5.代码片段

5.1   seller_ctrl模块(中心控制)

        这个模块实现的就是实现投币,判断投币值是否大于等于商品价值,并实现计算找零,最后将是否成功购买的信号传递到其他模块,将其作为其他元器件反映的输入信号,其他的反应可随自己意添加和修改。

module seller_ctrl (
    input               clk     ,    
    input               rst_n   ,
    input               key1    , //确认付款
    input               key2    , //投币0.5 
    input               key3    , //投币1
    input               key4    , //投币2

    output  reg [2:0]   flag_sell     ,//是否成功支付,需要传递到led,蜂鸣器模块
    output  reg [7:0]   num_money     ,//投入货币的总额,需要传递到数码管模块。最高6.5,即显示65  
    output  reg [7:0]   surplus_money //应该找零的余额,也传递到数码管。
);

parameter MAX_money = 6'd50 ; //商品总价值5元

parameter IDLE = 4'b0001; //空闲状态
parameter BUY  = 4'b0010;// 货币投入
parameter JUD  = 4'b0100;//判断投入货币总值
parameter RES  = 4'b1000;//判断结果

parameter NUM_5s = 28'd25000_0000; //5s计数;
reg [27:0] cnt_5s;

reg [3:0] cstate; //现态
reg [3:0] nstate; //次态

//100ms计时器,当判断投入货币总值状态过了100ms后进入判断结果状态,再过100ms进入判断结果状态。
always @(posedge clk or negedge rst_n) begin
    if(!rst_n)begin
        cnt_5s <= 28'd0;
    end
    else if(cnt_5s == NUM_5s - 1'd1)begin
        cnt_5s <= 28'd0;
    end
    else begin
        cnt_5s <= cnt_5s + 1'd1;
    end
end

//状态转移
always @(posedge clk or negedge rst_n) begin
    if(!rst_n)begin
       cstate <= IDLE; 
    end
    else begin
        cstate <= nstate;
    end
end

//状态转移判断
always @(*) begin
    if(!rst_n)begin
        nstate <= IDLE;
    end
    else begin
        case (cstate)
                IDLE: begin
                    if(key1)begin
                        nstate = BUY;
                    end
                    else begin
                        nstate = IDLE;
                    end
                end          
                BUY : begin
                    if(key1)begin
                        nstate = JUD;
                    end
                    else begin
                        nstate = BUY;
                    end
                end          
                JUD : begin
                    if(cnt_5s == (NUM_5s / 5) - 1'd1)begin //一秒后进入状态四,
                        nstate = RES;
                    end
                    else begin
                        nstate = JUD;
                    end
                end          
                RES : begin
                    if(cnt_5s == NUM_5s - 1'd1)begin  // 5s后进入状态一,元器件反映的时间就在这状态
                        nstate = IDLE;
                    end
                    else begin
                        nstate = RES;
                    end
                end           
            default: nstate = IDLE;
        endcase
    end
end

//对每个状态下的值进行分支并且将输出赋值

always @(posedge clk or negedge rst_n) begin
    if(!rst_n)begin
        flag_sell       <= 3'b001 ;  
        num_money       <= 8'd0 ;
        surplus_money   <= 8'd0 ;
    end
    else begin
        case (cstate)
            IDLE:begin 
                flag_sell       <= 3'b001 ;  
                num_money       <= 8'd0 ;
                surplus_money   <= 8'd0 ;

            end
            BUY: begin
                if(key2)begin //按下按键2,投入总额增加0.5
                    num_money <= num_money + 8'd5;
                end
                else if(key3)begin //按下按键3,投入总额增加1
                    num_money <= num_money + 8'd10;
                end
                else if(key4)begin //按下按键4,投入增加2
                    num_money <= num_money + 8'd20;
                end
                else begin
                    num_money <= num_money;
                end
            end
            JUD:begin
                if(num_money >= MAX_money)begin //当投入总额大于总价值时,找零。
                    surplus_money <= num_money - MAX_money;
                end
                else begin  //当投入总额小于总价值时,退还投入的钱。
                    surplus_money <= num_money;
                end
            end
            RES:begin
                if(num_money >= MAX_money)begin //当投入总额大于总价值时,购买成功。
                    flag_sell <= 3'b010;
                end
                else begin  //当投入总额小于总价值时,购买失败。
                    flag_sell <= 3'b100;
                end
            end
            default: ;
        endcase
    end
end
    
endmodule

5.2  led_ctrl(led控制模块)

这个模块是根据seller_ctrl模块传过来的是否成功购买的参数,来判断led应该显示什么状态

module led_ctrl(
    input clk,
    input rst_n,
    input [2:0]flag_sell,
    output reg[3:0] led
);

reg [25:0] cnt; // 振动次数寄存器
parameter  MAX_NUM =  26'd250_0000; //50ms 

reg flag ;// 闪烁信号

always @(posedge clk or negedge rst_n) begin
    if(!rst_n)begin
        cnt <= 26'd0;
        flag <= 1'b0;

    end
    else if(cnt == MAX_NUM -1'd1)begin
        cnt <= 26'd0;
        flag <= ~flag;
    end
    else begin
        cnt <= cnt +1'd1;
        flag <= flag;
    end
end
    
always @(posedge clk or negedge rst_n) begin
    if(!rst_n)begin
        led <= 4'b0001;
    end
    else if(cnt == MAX_NUM -1'd1 && flag_sell==3'b010)begin
        led <= {led[2:0],led[3]};
    end
    else if(flag_sell == 3'b100)begin
        case (flag)
            1'b0:  led <= 4'b0000;
            1'b1:  led <= 4'b1111;
            default: ;
        endcase
    end
    else begin
        led <= led;
    end
end
endmodule

5.3 beep_ctrl模块(蜂鸣器控制模块)

这个也是随自己心意设计,我设计当成功购买,蜂鸣器播放《两只老虎》5s,失败后,播放5s

《我没有钱,我不要脸》。

module beep_ctrl (
    input       clk,
    input       rst_n,
    input  [2:0] flag_sell,  // 消抖的按键信号,控制系统暂停播放。
    output reg  pwm_o
);
parameter CLK_FRE = 5000_0000;
    parameter
        L_DO = CLK_FRE / 262,
        L_RE = CLK_FRE / 294,
        L_MI = CLK_FRE / 330,
        L_FA = CLK_FRE / 349,
        L_SO = CLK_FRE / 392,
        L_LA = CLK_FRE / 440,
        L_SI = CLK_FRE / 494,

        M_DO = CLK_FRE / 523,
        M_RE = CLK_FRE / 587,
        M_MI = CLK_FRE / 659,
        M_FA = CLK_FRE / 698,
        M_SO = CLK_FRE / 784,
        M_LA = CLK_FRE / 880,
        M_SI = CLK_FRE / 998,
    
        H_DO = CLK_FRE / 1047,
        H_RE = CLK_FRE / 1175,
        H_MI = CLK_FRE / 1319,
        H_FA = CLK_FRE / 1397,
        H_SO = CLK_FRE / 1568,
        H_LA = CLK_FRE / 1760,
        H_SI = CLK_FRE / 1967;



reg [17:0] cnt_charac; //单个音符的计数器,单个音符振动次数
wire  add_charac;// 开始音符计数使能信号
wire  end_charac;//结束音符计数使能信号
reg [17:0] max_charac;

reg [9:0] cnt_200; //单个音符持续时间,
wire  add_200; //开始250ms计时信号
wire  end_200; //结束250ms计时信号,

reg [7:0] cnt_num; //音谱里的音符数
wire add_num; //音谱计数使能信号
wire end_num; //音谱结束信号
reg [17:0] max_num;

parameter MAX_250ms = 24'd1500_0000 ; //音符持续时间,250ms
parameter MAX_NUM = 8'd49; //乐谱中音符数。


//单个音符计周期模块
always @(posedge clk or negedge rst_n) begin
    if(!rst_n)begin
       cnt_charac <= 18'd0; 
    end
    else if(add_charac)begin
        if(end_charac)begin
            cnt_charac <= 18'd0;
        end
        else begin
            cnt_charac <= cnt_charac + 1'd1;
        end
    end
    else begin
        cnt_charac <= cnt_charac;
    end
end
assign add_charac =  flag_sell == 3'b010 || flag_sell == 3'b100;
assign end_charac = add_charac && cnt_charac >= max_charac - 18'd1;

//音符计数模块,选择每个音符持续200个周期
always @(posedge clk or negedge rst_n) begin
    if(!rst_n)begin
        cnt_200 <= 10'd0;
    end
    else if(add_200)begin
        if(end_200)begin
            cnt_200 <= 10'd0;
        end
        else begin
            cnt_200 <= cnt_200 + 1'd1;
        end
    end
    else begin
        cnt_200 <= cnt_200;
    end
end
assign add_200 = end_charac;
assign end_200 = add_200 && cnt_200 == 200 - 1'd1;
//音符选择模块
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        cnt_num <= 8'd0;
    end
    else if (add_num)begin
        if(end_num)begin
            cnt_num <= 8'd0;
        end
        else begin
            cnt_num <= cnt_num + 8'd1;
        end
    end
    else begin
        cnt_num <= cnt_num;
    end
end
assign add_num = end_200;
assign end_num = add_num && cnt_num ==MAX_NUM - 1'd1;

always @(*) begin
    case (flag_sell)
        3'b010: begin
            case(cnt_num)
                    8'd0   : max_charac = M_DO; //两
                    8'd1   : max_charac = M_RE;//只
                    8'd2   : max_charac = M_MI;//老
                    8'd3   : max_charac = M_DO;//虎
                    8'd4   : max_charac = M_DO;//两
                    8'd5   : max_charac = M_RE;//只
                    8'd6   : max_charac = M_MI;//老
                    8'd7   : max_charac = M_DO;//虎
                    8'd8   : max_charac = M_MI;//跑
                    8'd9   : max_charac = M_FA;//得
                    8'd10  : max_charac = M_SO;//快
                    8'd11  : max_charac = M_SO;//快
                    8'd12  : max_charac = M_MI;//跑
                    8'd13  : max_charac = M_FA;//得
                    8'd14  : max_charac = M_SO;//快
                    8'd15  : max_charac = M_SO;//快

                    8'd16   : max_charac = 1;
                    8'd17  : max_charac = M_SO;//一
                    8'd18  : max_charac = M_LA;//只
                    8'd19  : max_charac = M_SO;//没
                    8'd20  : max_charac = M_FA;//有
                    8'd21  : max_charac = M_MI;//眼
                    8'd22  : max_charac = M_MI;//
                    8'd23  : max_charac = M_DO;//睛
                    8'd24  : max_charac = M_DO;//
                    8'd25  : max_charac = M_SO;//一
                    8'd26  : max_charac = M_LA;//只
                    8'd27  : max_charac = M_SO;//没
                    8'd28  : max_charac = M_FA;//有
                    8'd29  : max_charac = M_MI;//尾
                    8'd30  : max_charac = M_MI;//
                    8'd31  : max_charac = M_DO;//巴
                    8'd32  : max_charac = M_DO;//
                    8'd33  : max_charac = M_RE;//真
                    8'd34 : max_charac = M_RE;//
                    8'd35  : max_charac = L_SO;//奇
                    8'd36  : max_charac = L_SO;//
                    8'd37  : max_charac = M_DO;//怪
                    8'd38  : max_charac = M_DO;//
                    8'd39  : max_charac = 1;
                    8'd40  : max_charac = 1;
                    8'd41  : max_charac = M_RE;//真
                    8'd42  : max_charac = M_RE;//
                    8'd43  : max_charac = L_SO;//奇
                    8'd44  : max_charac = L_SO;//
                    8'd45  : max_charac = M_DO;//怪
                    8'd46  : max_charac = M_DO;//
                    8'd47  : max_charac = 1;
                    8'd48  : max_charac = 1;
                    default: max_charac = 1;
            endcase
        end
        3'b100:begin
            case (cnt_num)
                    8'd0   : max_charac = L_MI;
                    8'd1   : max_charac = M_DO;
                    8'd2   : max_charac = L_SO;
                    8'd3   : max_charac = L_LA;
                    8'd4   : max_charac = M_LA;
                    8'd5   : max_charac = 1;
                    8'd6   : max_charac = 1;
                    8'd7   : max_charac = 1;
                    8'd8   : max_charac = 1;
                    8'd9   : max_charac = L_SO;
                    8'd10  : max_charac = M_DO;
                    8'd11  : max_charac = M_DO;
                    8'd12  : max_charac = L_MI;
                    8'd13  : max_charac = M_DO;
                    8'd14  : max_charac = L_SO;
                    8'd15  : max_charac = L_LA;
                    8'd16   : max_charac =M_LA;
                    8'd17  : max_charac = 1;
                    8'd18  : max_charac = 1;
                    8'd19  : max_charac = 1;
                    8'd20  : max_charac = 1;
                    8'd21  : max_charac = L_SO;
                    8'd22  : max_charac = M_DO;
                    8'd23  : max_charac = L_MI;
                    8'd24  : max_charac = M_DO;
                    8'd25  : max_charac = L_SO;
                    8'd26  : max_charac = L_LA;
                    8'd27  : max_charac = M_LA;
                    8'd28  : max_charac = 1;
                    8'd29  : max_charac = 1;
                    8'd30  : max_charac = 1;
                    8'd31  : max_charac = 1;
                    8'd32  : max_charac = L_SO;
                    8'd33  : max_charac = M_DO;
                    8'd34 :  max_charac = L_MI;
                    8'd35  : max_charac = M_DO;
                    8'd36  : max_charac = L_SO;
                    8'd37  : max_charac = L_LA;
                    8'd38  : max_charac = M_LA;
                    8'd39  : max_charac = 1;
                    8'd40  : max_charac = 1;
                    8'd41  : max_charac = 1;
                    8'd42  : max_charac = 1;
                    8'd43  : max_charac = L_SO;
                    8'd44  : max_charac = M_DO;
                    8'd45  : max_charac = L_MI;
                    8'd46  : max_charac = M_DO;
                    8'd47  : max_charac = L_SO;
                    8'd48  : max_charac = L_LA;
                default: ; 
            endcase
        end
        default: ;
    endcase
    

end
//设置占空比可调
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        pwm_o <= 1'b1;//复位,静音
    end
    else if (cnt_charac < (max_charac >> 2 )&& (flag_sell == 3'b010 || flag_sell == 3'b100)) begin//占空比设置为25%
        pwm_o <= 1'b0;
    end
    else begin
        pwm_o <= 1'b1;
    end
end

endmodule

 5.4 seg_ctrl模块(数码管控制模块)

数码管显示模块,左边两位显示投币金额,右边两位显示找零金额

module seg_ctrl (
    input               clk  ,
    input               rst_n,
    input wire [7:0]   num_money     ,  //投入总金额,放在sel[1:0]
    input wire [7:0]   surplus_money ,  //找零金额,放在sel[5:4]
    output    reg[7:0]  seg  ,
    output    reg[5:0]  sel
);

parameter MIN_NUM = 20'd15_0000; //3ms计数器
reg [19:0] cnt_3ms; //3ms计数器,用于位选信号切换计时
reg [3:0]flag; //位选信号状态设置。

wire [3:0]  num_money_low  ;
wire [3:0]  num_money_high  ;
wire [3:0]  surplus_money_low  ;
wire [3:0]  surplus_money_high  ;

assign  num_money_high = num_money / 10;
assign  num_money_low = num_money % 10;
assign  surplus_money_high = surplus_money / 10;
assign  surplus_money_low = surplus_money % 10;

//3ms计时模块,计满位选信号取反
always @(posedge clk or negedge rst_n) begin
    if(!rst_n)begin
        cnt_3ms <= 20'd0;
        flag <= 4'd0;
    end
    else if(cnt_3ms == MIN_NUM - 1'd1 && flag <=5)begin
        cnt_3ms <= 20'd0;
        flag <= flag + 1'd1;
    end
    else if(cnt_3ms == MIN_NUM - 1'd1)begin
        cnt_3ms <= 20'd0;
        flag <= 4'd0;
    end
    else begin
        cnt_3ms <= cnt_3ms + 1'd1;
        flag <= flag;
    end
end


always @(*) begin //位选信号设置
    case (flag)
        4'd0: sel = 6'b011_111;
        4'd1: sel = 6'b101_111;
        4'd2: sel = 6'b111_111;
        4'd3: sel = 6'b111_111;
        4'd4: sel = 6'b111_101;
        4'd5: sel = 6'b111_110; 
        default: sel = 6'b111_111;
    endcase
end

reg [3:0] number; //寄存数字。
always @(*) begin //对每个数码管进行赋值。
   case (flag)
       4'd0:number  = surplus_money_low;
       4'd1:number  = surplus_money_high;
       4'd4:number  = num_money_low;
       4'd5:number  = num_money_high;
       default: ;
   endcase 
end

always @(*) begin
    if(sel == 6'b101_111 ||sel == 6'b111_110)begin
        case(number)//匹配16进制数
			4'h0:    seg = 8'b0100_0000;//匹配到后参考共阳极真值表
	        4'h1:    seg = 8'b0111_1001;
	        4'h2:    seg = 8'b0010_0100;
	        4'h3:    seg = 8'b0011_0000;
	        4'h4:    seg = 8'b0001_1001;
	        4'h5:    seg = 8'b0001_0010;
	        4'h6:    seg = 8'b0000_0010;
	        4'h7:    seg = 8'b0111_1000;
	        4'h8:    seg = 8'b0000_0000;
	        4'h9:    seg = 8'b0001_0000;
	      	default : seg = 8'b1100_0000;
	    endcase
    end
    else begin
         case(number)//匹配16进制数
			4'h0:    seg = 8'b1100_0000;//匹配到后参考共阳极真值表
	        4'h1:    seg = 8'b1111_1001;
	        4'h2:    seg = 8'b1010_0100;
	        4'h3:    seg = 8'b1011_0000;
	        4'h4:    seg = 8'b1001_1001;
	        4'h5:    seg = 8'b1001_0010;
	        4'h6:    seg = 8'b1000_0010;
	        4'h7:    seg = 8'b1111_1000;
	        4'h8:    seg = 8'b1000_0000;
	        4'h9:    seg = 8'b1001_0000;
	      	default : seg = 8'b1100_0000;
	    endcase
    end
end

endmodule

 5.5 key_filter模块

这里使用的是状态机的按键消抖模块,并且是一个一个消抖,也可以用多个按键同时消抖

//通过状态机实现消抖
module key_filter(
    input           clk,
    input           rst_n,
    input           key_in,
    output   reg    key_out
    
);

//三段式状态机描述按键消抖。
//状态参数使用独热码进行定义
parameter state1 = 4'b0001, //空闲状态
          state2 = 4'b0010,// 按下抖动状态
          state3 = 4'b0100, //保持按下状态
          state4 = 4'b1000; // 按键松开抖动状态

parameter MAX_NUM = 20'd100_0000; //20ms
reg [19:0] cnt;//20位的20ms计数器
reg [3:0] cstate, nstate; //当前状态和下一状态。
wire add_cnt;
wire end_cnt;

always @(posedge clk or negedge rst_n) begin // 20ms计时模块
    if(!rst_n)begin
        cnt <= 20'd0;
    end
    else if(add_cnt)begin
        if(end_cnt)begin
            cnt <= cnt;
        end
        else begin
            cnt <= cnt +1'd1;
        end
    end
    else begin
        cnt <= 20'd0;
    end
end
assign add_cnt = (cstate == state2 && !key_in ) || (cstate == state4 && key_in);
assign end_cnt = (cnt == MAX_NUM -1'd1 && add_cnt);

always @(posedge clk or negedge rst_n) begin //第一段,时序逻辑,状态空间切换
    if(!rst_n) begin
        cstate <= state1;
    end
    else begin
        cstate <= nstate;
    end
end

always @(*) begin //第二段,组合逻辑描述状态转移
    case (cstate)
        state1:begin
            if(!key_in)begin //空闲状态时,当按下按键,进入按下抖动状态。
                nstate <= state2;
            end
            else begin
                nstate <= state1;
            end
        end

        state2:begin
            if(end_cnt)begin //按下抖动状态下,计满20ms后,进入状态三,稳定状态
                nstate <= state3;
            end
            else if(key_in) begin
                nstate <= state1;
            end
            else begin
                nstate <= state2;
            end
        end 

        state3:begin //稳定状态下,检测到按键高电平,即松开按键,进入按键松开抖动状态。
            if(key_in)begin
                nstate <= state4;
            end
            else begin
                nstate <= state3;
            end
        end

        state4:begin
            if(end_cnt)begin //松开抖动状态下,当计时满了20ms后,进入空闲状态。
                nstate <= state1;
            end
            else begin
                nstate <= state4;
            end
        end

        default: nstate <= state1; //其他状态下,回到空闲状态
    endcase
end

always @(*) begin //第三段,组合逻辑描述输出。
    if(!rst_n)begin
        key_out = 1'b0;
    end
    else begin
        case (cstate) // 对当前状态的输出进行赋值。
            state2:begin
                if(end_cnt)begin
                    key_out = 1'b1;
                end
                else begin
                    key_out = 1'b0;
                end
            end
            default: key_out = 1'b0;
        endcase
    end
end
    
endmodule

5.6 top_seller(顶层文件)

module top_seller (
input               clk          , 
input               rst_n        ,
input               key1         ,
input               key2         ,
input               key3         ,
input               key4         ,
output   wire[5:0]   sel          ,   
output   wire[7:0]   seg          ,
output   wire[3:0]   led          ,
output   wire        beep
);
wire    add_key1;
wire    add_key2;
wire    add_key3;
wire    add_key4;

wire [2:0]   flag_sell     ;
wire [7:0]   num_money     ;
wire [7:0]   surplus_money ;


beep_ctrl  u_beep_ctrl(
.clk      (clk      ) ,
.rst_n    (rst_n    ) ,
.flag_sell(flag_sell) ,  // 消抖的按键信号,控制系统暂停播放。
.pwm_o     (beep)
);


seg_ctrl  u_seg_ctrl(
.clk           (clk          ) ,
.rst_n         (rst_n        ) ,
.num_money     (num_money    ) ,  //投入总金额,放在sel[1:0]
.surplus_money (surplus_money) ,  //找零金额,放在sel[5:4]
.seg           (seg          ) ,
.sel           (sel)
);

led_ctrl u_led_ctrl(
.clk      (clk      ) ,
.rst_n    (rst_n    ) ,
.flag_sell(flag_sell) ,
.led(led)
);

seller_ctrl u_seller_ctrl(
.clk  (clk  )   ,    
.rst_n(rst_n)   ,
.key1 (add_key1)   , //确认付款
.key2 (add_key2)   , //投币0.5 
.key3 (add_key3)   , //投币1
.key4 (add_key4)   , //投币2

.flag_sell    (flag_sell    ) ,//是否成功支付,需要传递到led,蜂鸣器模块
.num_money    (num_money    ) ,//投入货币的总额,需要传递到数码管模块。最高6.5,即显示65  
.surplus_money(surplus_money) //应该找零的余额,也传递到数码管。
);

key_filter u1_key_filter(
.clk    (clk    ) ,
.rst_n  (rst_n  ) ,
.key_in (key1 ) ,
.key_out(add_key1)
);

key_filter u2_key_filter(
.clk    (clk    ) ,
.rst_n  (rst_n  ) ,
.key_in (key2 ) ,
.key_out(add_key2)
);

key_filter u3_key_filter(
.clk    (clk    ) ,
.rst_n  (rst_n  ) ,
.key_in (key3 ) ,
.key_out(add_key3)
);

key_filter u4_key_filter(
.clk    (clk    ) ,
.rst_n  (rst_n  ) ,
.key_in (key4 ) ,
.key_out(add_key4)
);
endmodule

6. 仿真文件书写

6.1 仿真代码

`timescale 1ns/1ps
module tb_seller();
reg                 clk;
reg                 rst_n;
reg                 key1;
reg                 key2;
reg                 key3;
reg                 key4;
wire[5:0]   sel          ; 
wire[7:0]   seg          ;
wire[3:0]   led          ;
wire        beep;
defparam u_top_seller.u1_key_filter.MAX_NUM = 20'd10; //按键消抖时间20ms
defparam u_top_seller.u2_key_filter.MAX_NUM = 20'd10; //按键消抖时间20ms
defparam u_top_seller.u3_key_filter.MAX_NUM = 20'd10; //按键消抖时间20ms
defparam u_top_seller.u4_key_filter.MAX_NUM = 20'd10; //按键消抖时间20ms
defparam u_top_seller.u_seller_ctrl.NUM_5s = 20'd250;
defparam u_top_seller.u_led_ctrl.MAX_NUM = 20'd50;
defparam u_top_seller.u_seg_ctrl.MIN_NUM = 20'd15;
always #10 clk = ~clk ;
initial begin
    clk = 1'b0;
    rst_n = 1'b0;
    key1 = 1'b1;
    key2 = 1'b1;
    key3 = 1'b1;
    key4 = 1'b1;

    #100 rst_n = 1'b1;
    #100 key1 = 1'b0; //选择投币
    #8000 key1 = 1'b1;
    #100 key2 = 1'b0;
    #8000 key2 = 1'b1; // 0.5
    #8000 key3 = 1'b0;
    #8000 key3 = 1'b1; // 1
    #8000 key4 = 1'b0;
    #8000 key4 = 1'b1; //2
    #8000 key4 = 1'b0;
    #8000 key4 = 1'b1;  //2
    #8000 key4 = 1'b0;
    #8000 key4 = 1'b1;  //2
    #8000 key1 = 1'b0; //确认付款
    #8000 key1 = 1'b1;

end

top_seller  u_top_seller(
/*input              */.clk  (clk  )        , 
/*input              */.rst_n(rst_n)        ,
/*input              */.key1 (key1 )        ,
/*input              */.key2 (key2 )        ,
/*input              */.key3 (key3 )        ,
/*input              */.key4 (key4 )        ,
/*output   wire[5:0] */. sel ( sel )         ,   
/*output   wire[7:0] */. seg ( seg )         ,
/*output   wire[3:0] */. led ( led )         ,
/*output             */.beep(beep)
);

endmodule

6.2仿真效果实现

 7.0上板验证

自动售货机

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值