正点原子视频学习笔记—Verilog下按键消抖, 实现LED灯的点亮和熄灭

    科技2023-06-28  109

    正点原子视频学习笔记—Verilog下按键消抖, 实现LED灯的点亮和熄灭

    在学习FPGA的基础阶段会有按键控制LED灯亮灭的实验,其中避免不了要对按键进行消抖处理,以及LED的控制模块,和顶层例化模块。本文包括详细的源代码和注释。

    1.按键消抖部分的代码如下所示:

    //key_debounce module key_d( input clk,//时钟 input rst_n,//复位 input key,//按键输入 output key_value,//定义key_value,来接收消抖后的按键值 output key_flag//按键消抖的标志,0表示未消抖,1表示已消抖 ); reg key_reg;//判断按键是否稳定的中间寄存器 reg [19:0] cnt; always@(posedge clk or negedge rst_n) begin if(!rst_n)//复位状态 begin key_reg<=1'b1;//按键未按下为1 cnt<=20'd0; end else begin key_reg<=key; if(key_reg!=key) cnt<=20'd1000_000;//按键抖动一般在20ms内结束 else begin if(cnt>20'd0) cnt<=cnt-1,b1; else cnt<=20'd0’;//倒计时结束,cnt重新赋值为0 end end end always@(posedge clk or negedge rst_n) begin if(!rst_n)//复位状态 begin key_value<=1'b1;//复位下,按键未按下 key_flag<=1'b0;//标志位在消抖之前置0 end else begin if(cnt==20'd1) begin key_value<=key;//按键按下,键值为0 key_flag<=1'b1;//按键按下标志位置1 end else begin key_value<=key_value; key_flag<=1'b0; end end end endmodule

    主要思路:

    第一个always块: 1.复位状态下,计数器cnt初值为0,键值中间寄存器key_reg为1(按键未按下); 2.非复位状态下,将按键的值key赋给key_reg,并在下一时刻检验二者是否还相等。如果不相等,给计数器赋最大值1000_000,准备倒计时;如果相等,计数器的值开始由1000_000做减一操作,直到计数器倒计时到0。此时的键值已是消抖完毕后稳定的键值。

    第二个always块: 1.复位状态下,消抖完毕的键值接收变量key_value为1,按键标志位key_flag为0; 2.非复位状态下,如果cnt=1,说明计数器的值已经由1000_000倒计时到1,即按键消抖完毕,此时将稳定的键值key赋给key_value,按键消抖标志位key_flag置1;如果cnt的值不等于1,说明倒计时还未结束,消抖还未完毕,key_value、key_flag保持原来的值。

    关于cnt最大值得解释: 我们知道,现在市场上出售的机械按键,抖动的时间一般不超过20ms,对于50Mhz晶振而言,一个周期为1/50M等于20ns,所以要想实现20ms的计数,需要1000_000次计数周期。简单点说,对于50Mhz的晶振而言,计1000_000个数的时间为20ms,所以cnt的最大值为1000_000。

    2.LED灯控制模块程序如下所示:

    //LED module led_c( input clk,//时钟 input rst_n,//复位 output key_value,//定义key_value,来作为消抖后的按键值 output key_flag,//按键消抖的标志,0表示未消抖,1表示已消抖 output led ); always@(posedge clk or negedge rst_n) begin if(!rst_n) led<=1'b1;//灯低电平点亮,复位时让灯熄灭 else if((key_value==1'b0)&&key_flag)//按键按下且按下标志为1, //两个条件缺一不可 led=~led;//按键按下,LED灯状态取反,从而实现闪烁 end endmodule

    对于语句

    else if((key_value==1'b0)&&key_flag)//按键按下且按下标志为1, //两个条件缺一不可 led=~led;//按键按下,LED灯状态取反,从而实现闪烁

    做以下解释: 1.按键按下和松开的时候都会产生一个flag,按下稳定后key_value为0,松开稳定后key_value为1,(没有按下的时候按键值为1),而是否稳定的条件就是flag是否为1,所以flag为1且key_value为0,两个条件缺一不可。 2.key_value=0的原因:在上一个按键消抖模块中,将稳定后的键值key赋给了key_value,所以要想让key_value等于0,key就必须为0,key为0的条件就是按键按下,而key_value=key又是在按键按下并且键值稳定后才开始执行的,所以key_value=0代表的条件就是,按键key按下并且键值稳定后。

    3.例化模块程序如下所示:

    //top_k_l module top_k_l( input clk, input rst_n, input key, output led ); wire key_value; wire key_flag; key_d u_key_d( .key (key), .clk (clk), .rst_n (rst_n), .key_value (key_value), .key_flag (key_flag) ); led_c u_led_c( .key_value (key_value), .key_flag (key_flag), .clk (clk), .rst_n (rst_n), .led (led) ); endmodule

    本次实验笔记到此结束。

    Processed: 0.016, SQL: 8