锐单电子商城 , 一站式电子元器件采购平台!
  • 电话:400-990-0325

FPGA按键去抖程序

时间:2024-04-23 04:07:09

代码是特权同学的,我将其理解后加上了注释。去抖的原理和单片机是一样的,即通过延时来过滤掉按键抖动产生的毛刺信号。不同的是判断按键按下的条件不同,单片机通常是已知按键不按时IO口的电平(如高电平),当IO口电平发生改变时(如低电平),则开启定时器进行延时,延时20ms后再次读取IO口的电平,若仍为低电平,则说明有按键按下;若为高电平,则说明是按键抖动,没有按键按下。的采样频率很高,它可以在每个时钟周期的上升沿到来时对IO口的电平进行一次读取。通过读取相邻2个时钟周期内IO口的电平值并进行比较,若电平值发生改变(此代码中是判断电平从0变为1),则计数器清零,若持续20ms后电平值没有发生改变,则读取按键的键值,同时将这一键值存储起来,当下一个20ms后再次读取键值,将2次键值进行比较,若键值发生改变,则说明按键有动作(要么按下,要么松手)。此代码中是判断键值从0变为1,即松手检测。

// 按键去抖 // 实现一个简单的三个按键分别控制三个 亮或暗的控制。 // 例如,按键1控制发光二极管1。上电初始发光二极管1不亮, // 当检测到按键1被按下后,发光二极管1则点亮, // 按键1再次被按下时,发光二极管1则不亮,如此反复。 // 该实验需要把握好按键消抖检测的设计技巧。 // 注:此代码的按键操作是包括松手检测的, // 即按键按下后要等到松手才算一次按键操作 module key_debounce( clk,rst_n, key1_n,key2_n,key3_n, led1_n,led2_n,led3_n ); input clk; input rst_n; input key1_n,key2_n,key3_n; output led1_n,led2_n,led3_n; reg [2:0] key_rst; always @(posedge clk or negedge rst_n) begin if(!rst_n) key_rst <= 3'b111; else key_rst <= {key3_n,key2_n,key1_n}; // 读取当前时刻的按键值 end reg [2:0] key_rst_r; always @(posedge clk or negedge rst_n) begin if(!rst_n) key_rst_r <= 3'b111; else key_rst_r <= key_rst; // 将上一时刻的按键值进行存储 end wire [2:0]key_an = key_rst_r & (~key_rst); // 当键值从0到1时key_an改变 //wire [2:0]key_an = key_rst_r ^ key_rst; // 注:也可以这样写 reg [19:0] cnt; // 延时用 always @(posedge clk or negedge rst_n) begin if(!rst_n) cnt <= 20'd0; else if(key_an) cnt <= 20'd0; else cnt <= cnt + 20'd1; end reg [2:0] key_value; always @(posedge clk or negedge rst_n) begin if(!rst_n) key_value <= 3'b111; else if(cnt == 20'hfffff) // 2^20*1/(50MHZ)=20ms key_value <= {key3_n,key2_n,key1_n}; // 去抖20ms后读取当前时刻的按键值 end reg [2:0] key_value_r; always @(posedge clk or negedge rst_n) begin if(!rst_n) key_value_r <= 3'b111; else key_value_r <= key_value; // 将去抖前一时刻的按键值进行存储 end wire [2:0] key_ctrl = key_value_r & (~key_value); // 当键值从0到1时key_ctrl改变 reg d1; reg d2; reg d3; always @(posedge clk or negedge rst_n) begin if(!rst_n) begin // 一个if内有多条语句时不要忘了begin end d1 <= 0; d2 <= 0; d3 <= 0; end else begin if(key_ctrl[0]) d1 <= ~d1; if(key_ctrl[1]) d2 <= ~d2; if(key_ctrl[2]) d3 <= ~d3; end end assign led1_n = d1? 1'b1:1'b0; // 此处只是为了将LED输出进行翻转,RTL级与下面注释代码无差别 assign led2_n = d2? 1'b1:1'b0; assign led3_n = d3? 1'b1:1'b0; endmodule
-电子元器件采购网(www.ruidan.com)是本土元器件目录分销商,采用“小批量、现货、样品”销售模式,致力于满足客户多型号、高质量、快速交付的采购需求。 自建高效智能仓储,拥有自营库存超过50,000种,提供一站式正品现货采购、个性化解决方案、选型替代等多元化服务。
锐单商城拥有海量元器件数据手册IC替代型号,打造电子元器件IC百科大全!

相关文章