按键模拟控制售货机实验
一、实验目标
现有自动售货机,自动售货机只能出售可乐,可乐为2.5元,投入的币种只有0.5元和1元的,投入总金额为2.5元时出可乐,投入金额为3元时,出可乐并且找零0.5元。现在使用开发板模拟自动售货机,使用两个按键模拟投币0.5元和1元,开发板上有四个led灯,当投入总金额为0.5元时,亮一个灯;投入总金额为1元时,亮两个灯;投入总金额为1.5元时,亮三个灯;投入总金额为2元时,亮四个灯。当只出可乐时,led灯为单向流水灯效果;当即出可乐又找零时,led灯为双向流水灯效果,并且流水灯的持续时间为10秒。
二、实验原理框图

三、框图分析
因为有两个按键输入,所以要有按键消抖模块,且要例化两次。将消抖之后的按键信号输入给状态机模块,状态机模块内部进行一系列操作,并且把实时的状态变量输出给led显示模块,以显示总金额所代表的led灯点亮数。状态机也输出两个变量给led流水灯显示模块,以表示是否需要找零或者出可乐,led流水灯模块判断这两个信号,然后选择是单向流水灯显示还是双向流水灯显示。最后led流水灯和led显示的输出给led输出选择模块,因为只有一组四个led灯,所以需要分时使用这四个led灯。
四、实验程序
1.按键消抖模块
//============================================================= // ---名 称:key_debounce // ---作 者:橘子哥哥 // ---Q Q :1073273114 // ---we chat:15870894502 // ---日 期:2021-1-21 // ---描 述:按键消抖模块 //============================================================= module key_debounce( input wire Clk, input wire Rst_n, input wire key, output reg key_flag ); wire Rst; assign Rst=~Rst_n; //定时5ms parameter T5ms = 249_999; //定时5ms所需要时钟周期的个数,时钟频率为50mhz reg [17:0]T20ns_count; //计数器,用于计算20ns的个数,其实就是计算时钟周期的个数 always@(posedge Clk or posedge Rst) if(Rst) T20ns_count<='d0; else if(!key) //按键为低电平才计时,即有5ms按键为低电平,才表示按键按下了 T20ns_count<=T20ns_count+1'b1; else T20ns_count<='d0; //一次按键有效标示位 reg key_vaild; always@(posedge Clk or posedge Rst) if(Rst) key_vaild<=1'b0; else if(key) key_vaild<=1'b0; else if(T20ns_count==T5ms) //标志位,防止一次按键时间过长,在一次按键内产生多个keY_flag key_vaild<=1'b1; //按键标志位 always@(posedge Clk or posedge Rst) if(Rst) key_flag<=1'b0; else if((T20ns_count==T5ms)&&(!key_vaild)) //按键稳定区定时超过5ms即表示一次按键有效,因为有key_vaild标志位 key_flag<=1'b1; //此次按键不会再产生一次key_flag高脉冲,既保证一次按键只会输出一个 else //时钟高脉冲的key_flag信号 key_flag<=1'b0; endmodule
2.状态机模块
2.1状态转移图

2.2程序
//============================================================= // ---名 称:fsm // ---作 者:橘子哥哥 // ---Q Q :1073273114 // ---we chat:15870894502 // ---日 期:2021-1-20 // ---描 述:两段式状态机练习 //============================================================= module fsm( input wire Clk, input wire Rst_n, input wire in_0p5, input wire in_1, output wire [4:0] state_out, output reg out_0p5, output reg out_cola ); parameter IDLE = 5'b00001; parameter State_0p5 = 5'b00010; parameter State_1 = 5'b00100; parameter State_1p5 = 5'b01000; parameter State_2 = 5'b10000; wire Rst; assign Rst=~Rst_n; reg [4:0]state; always@(posedge Clk or posedge Rst) if(Rst) begin state<=5'd0; end else begin case(state) IDLE:if(in_0p5) state<=State_0p5; else if(in_1) state<=State_1; State_0p5:if(in_0p5) state<=State_1; else if(in_1) state<=State_1p5; State_1:if(in_0p5) state<=State_1p5; else if(in_1) state<=State_2; State_1p5:if(in_0p5) state<=State_2; else if(in_1) state<=IDLE; State_2:if(in_0p5||in_1) state<=IDLE; default:state<=IDLE; endcase end //出可乐 always@(posedge Clk or posedge Rst) if(Rst) begin out_cola<=1'b0; end else if(((state==State_1p5)&&(in_1))||((state==State_2)&&((in_0p5)||(in_1)))) begin out_cola<=1'b1; end else begin out_cola<=1'b0; end //找钱 always@(posedge Clk or posedge Rst) if(Rst) begin out_0p5<=1'b0; end else if((state==State_2)&&(in_1)) begin out_0p5<=1'b1; end else begin out_0p5<=1'b0; end assign state_out=state; endmodule
3.led显示模块
//============================================================= // ---名 称:led_display // ---作 者:橘子哥哥 // ---Q Q :1073273114 // ---we chat:15870894502 // ---日 期:2021-1-21 // ---描 述:显示当前售货机投入的总金额 //============================================================= module led_display( input wire Clk, input wire Rst_n, input wire [4:0] state, output reg [3:0] led_out ); wire Rst; assign Rst=~Rst_n; parameter IDLE = 5'b00001; parameter State_0p5 = 5'b00010; parameter State_1 = 5'b00100; parameter State_1p5 = 5'b01000; parameter State_2 = 5'b10000; always@(posedge Clk or posedge Rst) if(Rst) begin led_out<=4'd0; end else begin case (state) IDLE : led_out <= 4'd0; State_0p5 : led_out <= 4'b0001; State_1 : led_out <= 4'b0011; State_1p5 : led_out <= 4'b0111; State_2 : led_out <= 4'b1111; default : led_out <= 4'd0; endcase end endmodule
4.led流水灯模块
//============================================================= // ---名 称:led_shift // ---作 者:橘子哥哥 // ---Q Q :1073273114 // ---we chat:15870894502 // ---日 期:2021-1-21 // ---描 述:流水灯 //============================================================= module led_shift( input wire Clk, input wire Rst_n, input wire vaild_cola, input wire vaild_0p5, output wire [3:0] led_out, output wire start_cnt ); wire Rst; assign Rst=~Rst_n; wire flag_out_cola; wire flag_out_cola_money; assign flag_out_cola=(vaild_cola)&(!vaild_0p5); //只出可乐,不找钱,流水灯单向移动 assign flag_out_cola_money=(vaild_cola)&(vaild_0p5);//即出可乐,也找钱,流水灯双向流动 reg start_count; //定时器,计时0.1s parameter T100ms = 23'd4_999_999; reg [22:0] T20ns_count; always@(posedge Clk or posedge Rst) if(Rst) begin T20ns_count<='d0; end else if(T20ns_count==T100ms) begin T20ns_count<='d0; end else if(start_count) //使能有效才开始计时 begin T20ns_count<=T20ns_count+1'b1; end else begin T20ns_count<='d0; end //定时器,计时10s parameter T10s = 7'd99;//100*100ms等于10s reg [6:0] T100ms_count;//计算100ms的个数 always@(posedge Clk or posedge Rst) if(Rst) begin T100ms_count<='d0; end else if(T100ms_count==T10s) //定时时间到10s,自动清零 begin T100ms_count<='d0; end else if(T20ns_count==T100ms) //定时时间到100ms,计数器加一 begin T100ms_count<=T100ms_count+1'b1; end //计数使能信号start_count reg [3:0]led_shift; always@(posedge Clk or posedge Rst) if(Rst) begin start_count<=1'b0; end else if(flag_out_cola||flag_out_cola_money)//计数开启条件 begin start_count<=1'b1; end else if(T100ms_count==T10s)//计数停止条件 begin start_count<=1'b0; end //流水灯显示控制 reg led_single_shift;//流水灯单向流动标志位 reg led_double_shift;//流水灯双向流动标志位 always@(posedge Clk or posedge Rst) if(Rst) begin led_single_shift<=1'b0; end else if(flag_out_cola) //只出可乐,流水灯单向流动 begin led_single_shift<=1'b1; end else if(T100ms_count==T10s)//定时10s到,关闭流水灯显示 begin led_single_shift<=1'b0; end always@(posedge Clk or posedge Rst) if(Rst) begin led_double_shift<=1'b0; end else if(flag_out_cola_money)//即出可乐也找零,流水灯双向流动 begin led_double_shift<=1'b1; end else if(T100ms_count==T10s)//定时10s到,关闭流水灯显示 begin led_double_shift<=1'b0; end reg L_R_flag;//LED灯左右移位标志位 always@(posedge Clk or posedge Rst) if(Rst) begin led_shift<=4'b0001; L_R_flag<=1'b0; end else if(led_single_shift) begin if(T20ns_count==T100ms) begin led_shift<={led_shift[2:0],led_shift[3]}; end end else if(led_double_shift) begin if(T20ns_count==T100ms) begin if(!L_R_flag) //左移位 begin if(led_shift==4'b1000)//左移位到最左边的一位,改变标志位,转为向右移动 L_R_flag<=1'b1; else led_shift<={led_shift[2:0],led_shift[3]}; end else begin //右移位 if(led_shift==4'b0001)//右移位到最右边的一位,改变标志位,转为向左移动 L_R_flag<=1'b0; else led_shift<={led_shift[0],led_shift[3:1]}; end end end assign led_out=led_shift; assign start_cnt=start_count;//输出给led选择模块,当10s时间到,start_cnt为零,即不再输出流水灯效果 endmodule
5.led选择模块
//============================================================= // ---名 称:led_select // ---作 者:橘子哥哥 // ---Q Q :1073273114 // ---we chat:15870894502 // ---日 期:2021-1-21 // ---描 述:控制led的显示,是显示投入总金额,还是流水灯显示 //============================================================= module led_select( input wire [3:0] led_dsp, input wire [3:0] led_sft, input wire led_control, output wire [3:0] led ); assign led=(led_control)?led_sft:led_dsp;//led_control即接流水灯的start_cnt,10s时间到,start_cnt就为零,不在需要流水灯显示 endmodule //就转为led显示的led为输出
浙公网安备 33010602011771号