问答 店铺
热搜: ZYNQ FPGA discuz

QQ登录

只需一步,快速开始

微信登录

微信扫码,快速开始

微信扫一扫 分享朋友圈

已有 17293 人浏览分享

开启左侧

按键去抖

  [复制链接]
17293 10
module Button(Clk,Rst,Sw,Led);// 模块接口
        input Clk;        //时钟信号
        input Rst;        //复位信号
        input [4 : 1] Sw;        //按钮SW输入,按下为0,抬起为1
        output [4 : 1] Led; // 4个led 输出
       
        reg [4 : 1] Led;
       
        reg [4 : 1] Sw1;
        reg [4 : 1] Sw1_r;
        wire [4 : 1] Sample1;
        reg [4 : 1] Sw2;
        reg [4 : 1] Sw2_r;
        wire [4 : 1] Sample2;
       
        reg [19 : 0] cnt;
       
        //第一次读取按键状态
        always @ (posedge Clk , negedge Rst)
                if(!Rst) Sw1 <= 4'b1111;
                else Sw1 <= Sw;
               
        //第一次读取的按键状态放入锁存器
        always @ (posedge Clk , negedge Rst)
                if(!Rst) Sw1_r <= 4'b1111;
                else Sw1_r <= Sw1;
               
        //Sample仅保持一个时钟周期
        assign Sample1 = Sw1_r & (!Sw1);
       
        //延时20MS后,第二次读取按键状态
        always @ (posedge Clk , negedge Rst)
                if(!Rst) Sw2 <= 4'b1111;
                else if (cnt == 20'hF_FFFF) Sw2 <= Sw;
                else Sw2 <= 4'b1111;
               
        //第二次读取的按键状态放入锁存器
        always @ (posedge Clk , negedge Rst)
                if(!Rst) Sw2_r <= 4'b1111;
                else Sw2_r <= Sw2;
       
        //Sample2仅保持一个时钟周期
        assign Sample2 = Sw2_r & (!Sw2);
       
        //计数器,定时20MS
        always @ (posedge Clk , negedge Rst)
                if(!Rst) cnt <= 0;
                else if (Sample1) cnt <= 0;
                else cnt <= cnt + 1'b1;
       
        //LED控制
        always @ (posedge Clk , negedge Rst)
                if(!Rst) Led <= 4'b0000;
                else if (Sample2) Led <= Sample2;
                else Led <= 4'b0000;
               
endmodule





求大神帮忙看看,我这个按键去抖有什么问题,我发现在sample1就出不来正确的波形。
另外,求大神讲下教程里的去抖程序,我有点看不懂。

评论 10

贾文洋  新手上路  发表于 2016-1-6 11:07:48 | 显示全部楼层
你程序是有问题的,sw你也没有用上,你两次采样之后必须判断。建议参考教程状态机那种写法!
贾文洋  新手上路  发表于 2016-1-6 11:18:51 | 显示全部楼层
教程上的意思是五个状态,每10ms检测一次,如果第一次检测是低电平,第二次检测还是低电平,则说明按键被按下,low_flg置1;然后继续检测当检测到一次高电平,又隔10ms检测到高电平,则说明按键被释放,high_flag置1。即完成一次按下与释放的过程。看懂这个程序,你得熟悉状态机的写法!
Damon  新手上路  发表于 2016-1-6 11:20:49 | 显示全部楼层
贾文洋 发表于 2016-1-6 11:07
你程序是有问题的,sw你也没有用上,你两次采样之后必须判断。建议参考教程状态机那种写法!

谢谢大神。
还有几个问题。
以下是第一次采样的程序。
关于你说的SW没有用的问题,这边SW用上了。

     //第一次读取按键状态
        always @ (posedge Clk , negedge Rst)
                if(!Rst) Sw1 <= 4'b1111;
                else Sw1 <= Sw;      //这边SW用上了呀。
               
        //第一次读取的按键状态放入锁存器
        always @ (posedge Clk , negedge Rst)
                if(!Rst) Sw1_r <= 4'b1111;
                else Sw1_r <= Sw1;
               
        //Sample仅保持一个时钟周期
        assign Sample1 = Sw1_r & (!Sw1);
仿真出来的波形,也是到sample1就没有了 ,貌似是   assign Sample1 = Sw1_r & (!Sw1);没有执行的样子。
   
Damon  新手上路  发表于 2016-1-6 11:21:21 | 显示全部楼层
这是仿真出来的波形,大神可以参考下。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
贾文洋  新手上路  发表于 2016-1-6 11:31:38 | 显示全部楼层
你这样写的话,也正确,但不可能没有sample1.你这程序我仔细看了一下没有问题,仿真没出波形?
Damon  新手上路  发表于 2016-1-6 11:34:45 | 显示全部楼层
贾文洋 发表于 2016-1-6 11:31
你这样写的话,也正确,但不可能没有sample1.你这程序我仔细看了一下没有问题,仿真没出波形?

对的,而且是前仿真,就是sample1出不来,好像assign不运行。
而且SW1,SW1_R都有,就是在他们2个有差异的时钟周期,没有sample1.
贾文洋  新手上路  发表于 2016-1-6 14:06:01 | 显示全部楼层
本帖最后由 贾文洋 于 2016-1-6 14:14 编辑

你试试把前两个always语句合并一下!
Damon  新手上路  发表于 2016-1-6 14:28:44 | 显示全部楼层
贾文洋 发表于 2016-1-6 14:06
你试试把前两个always语句合并一下!

还是不行,仿真出来的,跟之前的一样。
贾文洋  新手上路  发表于 2016-1-6 15:47:41 | 显示全部楼层
QQ上回复我,给你解决一下!
贾文洋  新手上路  发表于 2016-1-6 20:59:35 | 显示全部楼层
module sw_debounce(clk,rst_n,sw1_n,sw2_n,sw3_n,sw4_n,led_d1,led_d2,led_d3,led_d4);
input clk,rst_n;
input  wire sw1_n,sw2_n,sw3_n,sw4_n;
output wire led_d1,led_d2,led_d3,led_d4;

reg[3:0] key_rst;

always@(posedge clk or negedge rst_n)
  if(!rst_n) key_rst<=4'b1111;
  else
  key_rst<={sw4_n,sw3_n,sw2_n,sw1_n};
  
    reg[3:0] key_rst_r;

always@(posedge clk or negedge rst_n)
  if(!rst_n) key_rst_r<=4'b1111;
  else key_rst_r<=key_rst;
  
wire[3:0]key_an=key_rst_r&(~key_rst);

reg[19:0] cnt;
always@(posedge clk or negedge rst_n)
if(!rst_n) cnt<=20'd0;
else if (key_an) cnt<=20'd0;
   else cnt<=cnt+1'b1;
  
reg[3:0] low_sw;
always@(posedge clk or negedge rst_n)
if(!rst_n) low_sw<=4'b1111;
else if (cnt==20'hfffff)
low_sw<={sw4_n,sw3_n,sw2_n,sw1_n};
reg  [3:0] low_sw_r;       //每个时钟周期的上升沿将low_sw信号锁存到low_sw_r中

always @ ( posedge clk  or negedge rst_n )
    if (!rst_n) low_sw_r <= 4'b1111;
    else low_sw_r <= low_sw;
wire[3:0] led_ctrl=low_sw_r[3:0]&(~low_sw[3:0]);

reg d1,d2,d3,d4;
always @(posedge clk or negedge rst_n)
  if(!rst_n)begin
  d1<=1'b0;
  d2<=1'b0;
  d3<=1'b0;
  d4<=1'b0;
  end
  else begin
  if(led_ctrl[0]) d1<=~d1;
  if(led_ctrl[1]) d2<=~d2;
  if(led_ctrl[2]) d3<=~d3;
  if(led_ctrl[3]) d4<=~d4;
  end
  assign led_d4=d1?1'b1:1'b0;
  assign led_d3=d2?1'b1:1'b0;
  assign led_d2=d3?1'b1:1'b0;
  assign led_d1=d4?1'b1:1'b0;
  endmodule
可以参考这个写
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

0

关注

1

粉丝

4

主题
精彩推荐
热门资讯
网友晒图
图文推荐

  • 微信公众平台

  • 扫描访问手机版