搜索
bottom↓
回复: 14

不懂就问!verilog键盘防抖程序

[复制链接]

出0入0汤圆

发表于 2010-3-25 00:43:10 | 显示全部楼层 |阅读模式
module key2(key,led,clk,rst);

input key,clk,rst;
output led;


reg[17:0] cout;
always@(posedge clk)
begin
        if(!rst)
                cout<=12'b0;
        else cout<=cout+1;
end

        wire clk_5ms=&cout;
       
reg key_r;
always@(posedge clk)
begin
        if(!rst)
         key_r<=1'b1;
        else if (clk_5ms)
         key_r<=key;         
end

reg key_r_sw;
always@(posedge clk)
key_r_sw<=key_r;

wire ledctrl=key_r_sw&(!key_r);

reg led;
always@(posedge clk or negedge rst )
begin
        if(!rst)
                led<=1'b0;
        else if (ledctrl)
            led<=~led;
       
end

endmodule


本来看艾米的程序,觉得自己看懂了,但是自己编完上面的程序之后,又迷茫了,觉得这样是错的,但是下载到板子上,居然能防抖。。。

阿莫论坛20周年了!感谢大家的支持与爱护!!

知道什么是神吗?其实神本来也是人,只不过神做了人做不到的事情 所以才成了神。 (头文字D, 杜汶泽)

出0入0汤圆

 楼主| 发表于 2010-3-25 00:45:10 | 显示全部楼层
问题1:我采用的是50M的晶振,想用的防抖原理是把相隔5MS采集到的键值相&,从而判断出是否真的有键按下。always@(posedge clk)
key_r_sw<=key_r;  只是把键盘值锁存了一个时钟周期,为什么不是锁存5MS?

出0入0汤圆

 楼主| 发表于 2010-3-25 00:46:09 | 显示全部楼层
问题2:reg[17:0] cout;
always@(posedge clk)
begin
if(!rst)
cout<=12'b0;
else cout<=cout+1;
end

wire clk_5ms=&cout;

reg key_r;
always@(posedge clk)
begin
if(!rst)
key_r<=1'b1;
else if (clk_5ms)
key_r<=key;   
end

这段语句不会产生竞争吗?

出0入0汤圆

发表于 2010-3-25 07:07:21 | 显示全部楼层
呵呵,程序是周杰写的,具体思路我也不甚清楚哟,呵呵。

key2.v
———————————————————————————————————
module key2(
  input   clk,
          rst,
          key,
  output  led
);  

//++++++++++++++++++++++++++++++++++++++
// 分频器 开始
//++++++++++++++++++++++++++++++++++++++
reg [17:0] cout;

always@(posedge clk)
  if(!rst)
    cout <= 0;
  else
    cout <= cout + 1'b1;

wire clk_5ms = &cout;                   // 相当诡异的用法
//--------------------------------------
// 分频器 结束
//--------------------------------------


//++++++++++++++++++++++++++++++++++++++
// 5ms采集一次键值 开始
//++++++++++++++++++++++++++++++++++++++
reg key_r;

always@(posedge clk)
  if(!rst)
    key_r<=1'b1;
  else if (clk_5ms)
    key_r<=key;   
//--------------------------------------
// 5ms采集一次键值 结束
//--------------------------------------


//++++++++++++++++++++++++++++++++++++++
// 锁存采集到的键值 开始
//++++++++++++++++++++++++++++++++++++++
reg key_r_sw;

always@(posedge clk)
  key_r_sw<=key_r;
//--------------------------------------
// 锁存采集到的键值 结束
//--------------------------------------


//+++++++++++++++++++++++++++++++++++++
// 检测键值变动 开始
//+++++++++++++++++++++++++++++++++++++
//           _______   ____
//  key_r           |_|
//                   _
// ~key_r    _______| |____
//            ________   ___
//  key_r_sw          |_|
wire ledctrl = key_r_sw & (~key_r);
//--------------------------------------
// 检测键值变动 结束
//--------------------------------------


//+++++++++++++++++++++++++++++++++++++
// 做出相应动作 开始
//+++++++++++++++++++++++++++++++++++++
reg led;

always@(posedge clk or negedge rst )
  if(!rst)
    led <= 0;
  else if (ledctrl)
  led <= ~led;
//-------------------------------------
// 做出相应动作 结束
//-------------------------------------

endmodule
———————————————————————————————————

出0入0汤圆

发表于 2010-3-25 07:37:36 | 显示全部楼层
我写的在这里。

这个是我写的。

key_debounce.v
———————————————————————————————————
module key_debounce(
  input            i_clk,
  input            i_rst_n,
  input      [4:1] i_key,               // 按下为0,松开为1
  output reg [4:1] o_key_val            // 键值
);  

//++++++++++++++++++++++++++++++++++++++
reg [4:1] key_samp1, key_samp1_locked;

// 将i_key采集至key_samp1
always @ (posedge i_clk, negedge i_rst_n)
  if(!i_rst_n)
    key_samp1 <= 4'hF;
  else         
    key_samp1 <= i_key;

// 将key_samp1锁存至key_samp1_locked
always @ (posedge i_clk, negedge i_rst_n)
  if(!i_rst_n)
    key_samp1_locked <= 4'hF;
  else         
    key_samp1_locked <= key_samp1;
//--------------------------------------

//++++++++++++++++++++++++++++++++++++++
wire [4:1] key_changed1;

// 当key_samp1由1变为0时
// key_changed1由0变为1,只维持一个时钟周期
assign key_changed1 = key_samp1_locked & (~key_samp1);
//--------------------------------------


//++++++++++++++++++++++++++++++++++++++
reg [19:0] cnt;

// 一旦有按键按下,cnt立即被清零
always @ (posedge i_clk, negedge i_rst_n)
  if(!i_rst_n)
    cnt <= 20'h0;
  else if(key_changed1)
    cnt <= 20'h0;
  else
    cnt <= cnt + 1'b1;
//--------------------------------------


//++++++++++++++++++++++++++++++++++++++
reg [4:1] key_samp2, key_samp2_locked;

// 只有当按键不变化(不抖动),且维持20ms以上时
// 才将i_key采集至key_samp2
always @ (posedge i_clk, negedge i_rst_n)
  if(!i_rst_n)
    key_samp2 <= 4'hF;
  else if(cnt == 20'hF_FFFF)            // 0xFFFFF/50M = 20.9715ms
    key_samp2 <= i_key;

// 将key_samp2锁存至key_samp2_locked
always @ (posedge i_clk, negedge i_rst_n)
  if(!i_rst_n)
    key_samp2_locked <= 4'hF;
  else
    key_samp2_locked <= key_samp2;
//--------------------------------------

//++++++++++++++++++++++++++++++++++++++
wire [4:1] key_changed2;

// 当key_samp2由1变为0时
// key_changed2由0变为1,只维持一个时钟周期
assign key_changed2 = key_samp2_locked & (~key_samp2);
//--------------------------------------


//++++++++++++++++++++++++++++++++++++++
// 每次按键稳定后,输出键值
// 按下为0,松开为1
always @ (posedge i_clk, negedge i_rst_n)
  if(!i_rst_n)
    o_key_val <= 4'hF;
  else
    o_key_val <= ~key_changed2;
//--------------------------------------

endmodule
———————————————————————————————————

出0入0汤圆

 楼主| 发表于 2010-3-25 09:33:42 | 显示全部楼层
谢谢tear086,谢谢您的仔细标注,但还是不懂得地方
//+++++++++++++++++++++++++++++++++++++
// 检测键值变动 开始
//+++++++++++++++++++++++++++++++++++++
//           _______   ____
//  key_r           |_|
//                   _
// ~key_r    _______| |____
//            ________   ___
//  key_r_sw          |_|
wire ledctrl = key_r_sw & (~key_r);  

1.由波形所示,这样怎么能使ledctrl=1?
2.我总是觉得这样做只是把一个CLK前后的两次采样结果相比较,为什么是5ms前后的?

我没深刻理解的地方是不是在这里:
//++++++++++++++++++++++++++++++++++++++
// 5ms采集一次键值 开始
//++++++++++++++++++++++++++++++++++++++
reg key_r;  

always@(posedge clk)  
  if(!rst)  
    key_r<=1'b1;  
  else if (clk_5ms)  
    key_r<=key;     
//--------------------------------------
// 5ms采集一次键值 结束
//--------------------------------------


当清零按下式,当key_r=1,要不当clk_5ms为高时,key_r<=key,但是当rst为1,也就是不按下,clk_5ms又等于0的时候,输出是什么样子的呢?还是等于上次采集到的键值吗?如果等于上次采集到的键值,那就是0,然后被key_r_sw锁存住,这样更看不出是5MS后的了。。。

出0入0汤圆

发表于 2010-3-25 10:30:27 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-3-25 10:50:05 | 显示全部楼层
回复【5楼】cnqdxiaoyu  鸿宇
-----------------------------------------------------------------------

A1:
// ~key_r    _______| |____  
//            ________   ___  
//  key_r_sw          |_|  
wire ledctrl = key_r_sw & (~key_r);  
一旦有按键被按下,~key_r和key_r_sw按位与,就会产生一个高电平;其他情况都是低电平。
然后以ledctrl作为触发信号,触发led的亮灭动作。

A2:
key_r_sw比key_r延迟一个时钟周期,由于flip-flop的缘故。5ms采集一次,滤除高频抖动。

出0入0汤圆

 楼主| 发表于 2010-3-25 12:24:32 | 显示全部楼层
回复【7楼】tear086 .COM缺氧
-----------------------------------------------------------------------

一旦有键按下,~key_r为1,key_r_sw为0,相&之后怎么会是1?1&0=1?

出0入0汤圆

发表于 2010-3-25 12:27:20 | 显示全部楼层
你看波形。
//                   _  
// ~key_r    _______| |____  
//            ________   ___  
//  key_r_sw          |_|  

滞后一个时钟周期。

出0入0汤圆

发表于 2010-3-27 00:44:42 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-3-20 14:24:23 | 显示全部楼层
顶tear086.com

出0入0汤圆

发表于 2011-3-23 14:48:51 | 显示全部楼层
深刻怀疑这东西能去抖。
这个东西难道不是只实现了5mS间隔采样和键值变化的检测吗?
如果5mS刚好采在抖动上不是把抖动采进去了吗?
大家搞搞清楚什么是去抖再说。给篇文件做参考吧 http://www.fpga4fun.com/Debouncer.html

出0入0汤圆

发表于 2011-6-6 11:54:28 | 显示全部楼层
//++++++++++++++++++++++++++++++++++++++
// 分频器 开始
//++++++++++++++++++++++++++++++++++++++
reg [17:0] cout;
always@(posedge clk)  
  if(!rst)  
    cout <= 0;  
  else  
    cout <= cout + 1'b1;  
wire clk_5ms = &cout;       // 相当诡异的用法  
最后一句是怎么去理解的,望有心人解答。

它是如何展开的clk_5ms = cout & cout; 这样写对吗?
如果是这样那有何如理解他的作用呢?
不会是下面这种展开吧:clk_5ms = clk_5ms & cout;
那他的缩写应该是这样吧 ?wire clk_5ms &= cout;

出0入0汤圆

发表于 2013-4-23 08:31:51 | 显示全部楼层
CHA168 发表于 2011-6-6 11:54
//++++++++++++++++++++++++++++++++++++++
// 分频器 开始
//++++++++++++++++++++++++++++++++++++++

最后一句是缩位操作符,就是一个数的所有位进行与操作,当所有的位全为时结果为1,否则为0
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片。注意:要连续压缩2次才能满足要求!!】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-7-24 07:23

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表