cnqdxiaoyu 发表于 2010-3-25 00:43:10

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

module key2(key,led,clk,rst);

input key,clk,rst;
output led;


reg 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


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

cnqdxiaoyu 发表于 2010-3-25 00:45:10

问题1:我采用的是50M的晶振,想用的防抖原理是把相隔5MS采集到的键值相&,从而判断出是否真的有键按下。always@(posedge clk)
key_r_sw<=key_r;只是把键盘值锁存了一个时钟周期,为什么不是锁存5MS?

cnqdxiaoyu 发表于 2010-3-25 00:46:09

问题2:reg 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

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

tear086 发表于 2010-3-25 07:07:21

呵呵,程序是周杰写的,具体思路我也不甚清楚哟,呵呵。

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

//++++++++++++++++++++++++++++++++++++++
// 分频器 开始
//++++++++++++++++++++++++++++++++++++++
reg 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
———————————————————————————————————

tear086 发表于 2010-3-25 07:37:36

我写的在这里。

这个是我写的。

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

//++++++++++++++++++++++++++++++++++++++
reg 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 key_changed1;

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


//++++++++++++++++++++++++++++++++++++++
reg 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 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 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
———————————————————————————————————

cnqdxiaoyu 发表于 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后的了。。。

1181zjf 发表于 2010-3-25 10:30:27

mark

tear086 发表于 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采集一次,滤除高频抖动。

cnqdxiaoyu 发表于 2010-3-25 12:24:32

回复【7楼】tear086 .COM缺氧
-----------------------------------------------------------------------

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

tear086 发表于 2010-3-25 12:27:20

你看波形。
//                   _
// ~key_r    _______| |____
//            ________   ___
//key_r_sw          |_|

滞后一个时钟周期。

ninjalp 发表于 2010-3-27 00:44:42

mark

perofhap 发表于 2011-3-20 14:24:23

顶tear086.com

hevry 发表于 2011-3-23 14:48:51

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

CHA168 发表于 2011-6-6 11:54:28

//++++++++++++++++++++++++++++++++++++++
// 分频器 开始
//++++++++++++++++++++++++++++++++++++++
reg 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;

6091820503 发表于 2013-4-23 08:31:51

CHA168 发表于 2011-6-6 11:54 static/image/common/back.gif
//++++++++++++++++++++++++++++++++++++++
// 分频器 开始
//++++++++++++++++++++++++++++++++++++++


最后一句是缩位操作符,就是一个数的所有位进行与操作,当所有的位全为时结果为1,否则为0
页: [1]
查看完整版本: 不懂就问!verilog键盘防抖程序