专栏中心

EEPW首页 > 专栏 > 笔记2 键盘消抖

笔记2 键盘消抖

发布人:0750long 时间:2010-03-10 来源:工程师 发布文章

笔记键盘消抖

老实说,这个实验的开始之前和之后,都给我蛋疼了。时钟了解不到源码的思路,边看源码边睡着。醒来的时候既然 “惊” 一下,相通了......

 

module lesson02

 (

CLK, RST,

SW0, SW1, SW2,

LED0, LED1, LED2

);

input   CLK;

input   RST;

input  SW0, SW1, SW2;

output  LED0, LED1, LED2;

 

//---------------------------------------------------------------------------

//Detect the switch pressing

reg  [2:0] Press0;  

reg  [2:0] Press1; 

wire [2:0] isPress;

always @ (posedge CLK or negedge RST)

if(!RST)

   Press0 <= 3'b111;

else

   Press0 <= {SW0, SW1, SW2};  //read the pin result;

 

always @ (posedge CLK or negedge RST)

if(!RST) 

   Press1 <= 3'b111;

else

   Press1 <= Press0;  //read the previous Press0 result 

   

assign isPress = Press1 & (~Press0);   //detect the logic with bit is changed from logic 1 to 0

//---------------------------------------------------------------------------

//if pressing, counter start counting for 20ms

 

reg [19:0] Counter; //计数寄存器

 

always @ (posedge CLK or negedge RST)

if(!RST)

   Counter <= 20'd0;

else if(isPress)

   Counter <= 20'd0;

else

   Counter <= Counter + 1'b1; //increment for counter

 

//------------------------------------------------------------------------

//After 20ms read the key pin result

reg  [2:0] Press2;

reg  [2:0] Press3;

wire [2:0] Result;

 

always @ (posedge CLK or negedge RST)

if(!RST)

begin

   Press2 <= 3'b111;

   Press3 <= 3'b111;

end

else if(Counter == 20'hfffff)

   Press2 <= {SW0, SW1, SW2}; //read the pin result after 20ms

else

    always @ (posedge CLK or negedge RST)

if(!RST)

else 

   Press3 <= Press2; //read the previous pin result

 

assign Result = Press3 & (~Press2);  //detect the changing bit from logic 1 to 0

 

//------------------------------------------------------------------------

//turn on led with pin result

reg D1;

reg D2;

reg D3;

 

always @ (posedge CLK or negedge RST)

if(!RST)

begin

   D1 <= 1'b0;

   D2 <= 1'b0;

   D3 <= 1'b0;

end

else 

begin

   if( Result[0] ) D1 <= ~D1;

   if( Result[1] ) D2 <= ~D2;

   if( Result[2] ) D3 <= ~D3;

end

 

assign LED0 = D1 ? 1'b1 : 1'b0;

assign LED1 = D2 ? 1'b1 : 1'b0;

assign LED2 = D3 ? 1'b1 : 1'b0;

  

endmodule

这个实验主要有计数器和边缘检查来实现按键消抖,按键功能。该代码新手打从一开始看会觉得很难(我也却是如此)。不过只要一部一部的分析就会觉得很容易。

程式定义了SW0~2RSTCLK为输入,而LED0~2为输出,他们默认均是wire型。

 

                                                                                                                                   reg  [2:0] Press0;  

reg  [2:0] Press1; 

wire [2:0] isPress;

 

always @ (posedge CLK or negedge RST)

if(!RST)

   Press0 <= 3'b111;

else

   Press0 <= {SW0, SW1, SW2};  //read the pin result;

 

always @ (posedge CLK or negedge RST)

if(!RST) 

   Press1 <= 3'b111;

else

   Press1 <= Press0;  //read the previous Press0 result 

   

assign isPress = Press1 & (~Press0);   //detect the logic with bit is changed from logic 1 to 0

 

这一段代码主要是用来检测 “按键是否被按下”。程式依然建立了两个寄存器 press 0 和 press 1 ,和一个wire型的isPress 。(注意,全部都是3位)。Press0 每次时钟的上升沿都会读取 SW0SW1,和SW2的电平(回顾原理图,该3各按键都带上拉电阻)。而Press1 分别每一个时钟的上升沿读取 寄存器 Press0上一个时钟周期的值。 (注意<=非阻塞赋值,代码执行过后才赋值)。 

如上图假设,我们有五个时间周期,SW0为例子,SW0Reg0Reg1初始电平都是高电平。SW0的电平初始是高电平,在时间01的时候,Reg0读取到1,而Reg1读取Reg0上一个周期的值(00周期的值),也是1。当SW002周期之前发生电平变化,由高到低,而在02周期的时候,Reg0读取SW0的值,是0Reg1则读取Reg0上一个周期的值(01周期的值),依然是1.

02时间边缘检查就可以发生作用了。如以上的代码,Reg0Press0,而Reg1Press1

assign isPress = Press1 & (~Press0); 

02周期的时候,如以上的组合逻辑,Reg0的值会被取反,然后与计算Reg1的值。结果会是1

虽然以上给出的例子有点勉强。但是思维是一样的。如果SW0的电平持续1,那么 isPress的结果会一直是0,相反的,如果SW0的电平持续0或者发生过变化,那么isPress的结果会是1.

话题扯远了,回归正题。接下来是计数寄存器。

 

reg [19:0] Counter; //计数寄存器

 

always @ (posedge CLK or negedge RST)

if(!RST)

   Counter <= 20'd0;

else if(isPress)

   Counter <= 20'd0;

else

   Counter <= Counter + 1'b1; //increment for counter

如上代码的意思,计数器在每个时间的上升沿都会递增,只有两个情况会3个情况会清零,

1-计数超过10485752-复位信号,3-当检查到SW0~2的电平发生变化。很显然选线3是重点。该计数器主要是利用于,当SW0~2电平发生变化,执行长达20ms的计数,为了是实现软件消抖。

 

always @ (posedge CLK or negedge RST)

if(!RST)

begin

   Press2 <= 3'b111;

   Press3 <= 3'b111;

end

else if(Counter == 20'hfffff)

   Press2 <= {SW0, SW1, SW2}; //read the pin result after 20ms

else

    always @ (posedge CLK or negedge RST)

if(!RST)

else 

    Press3 <= Press2; //read the previous pin result

 

assign Result = Press3 & (~Press2);  //detect the changing bit from logic 1 to 0

以上的代码和第一个的代码的功能基本相通,第一个代码是20ms秒之前读取SW0~2的电平,而这个代码是20ms秒之后读取SW0~2的电平,亦即是按键按下之前和按键按下之后。

同样也是实现边缘检查。

 

 

                                                                                                                            reg D1;

reg D2;

reg D3;

 

always @ (posedge CLK or negedge RST)

 

if(!RST) begin

   D1 <= 1'b0;

   D2 <= 1'b0;

   D3 <= 1'b0;

end

else  begin

   if( Result[0] ) D1 <= ~D1;

   if( Result[1] ) D2 <= ~D2;

   if( Result[2] ) D3 <= ~D3;

end

 

assign LED0 = D1 ? 1'b1 : 1'b0;

assign LED1 = D2 ? 1'b1 : 1'b0;

assign LED2 = D3 ? 1'b1 : 1'b0;

 

最后这一段代码比较简单。就是分别将Result寄存器的结果,经if判断取反D1~D3的值。

最后利用3目表达式对LED0~2进行赋值。

 

简单归纳:

嗯,这一章笔记基本上拖了一段时间。主要的问题是边缘检测和还未习惯于RTL的思维。

这篇笔记很有很多漏洞之处,有望多多包含。本人依然是新手上路,在任何角度上还要多多请教。希望这一章笔记可以帮到你。

 

补上:这里有一个问题点?为什么检测IO的电平需要使用边缘检测法呢?而不是使用更简单的直接检查电平?这个问题先保留先吧。

专栏文章内容及配图由作者撰写发布,仅供工程师学习之用,如有侵权或者其他违规问题,请联系本站处理。 联系我们

关键词:

相关推荐

NEC与西门子合作开发工业机器人

TLC0820AC,TLC0820AI 采用改进快闪技术的先进的 LinCMOS 高速 8 位模数转换器

谷歌将于2027年发射搭载其TPU AI芯片的卫星

智能计算 2025-11-05

三星SDI正在与特斯拉就 $2.1b 电池供应交易进行谈判

英披露在研电磁装甲系统

视频 2010-01-14

英海军45型驱逐舰首舰“果敢”号下水

视频 2010-01-14

无线RF解决方案 - 结合 ZigBee, RF4CE, 智能能源及IP

视频 2010-01-14

TLC0831C_I,TLC0832C_I 通用串行输出8位A_D转换器

各省向使用中国制造芯片人工智能公司提供大幅电力折扣

AMD收入和利润再次跃升,但利润率令人失望致股价下跌

嵌入式系统 2025-11-05

纳芯微发布新一代车规级PWM控制器NSR2260x-Q1

TLC1542C_I_M_Q,TLC1543C_I_Q 10位开关电容逐次逼近模数转换器

大联大品佳集团荣获第七届“金辑奖之最佳技术实践应用”奖

印度准备接收俄“阿库拉”级核潜艇

视频 2010-01-14

TL750L TL751L TL751L05M,TL751L12M,TL750LxxY低落差电压稳压器

英国海军在研主战装备

视频 2010-01-14

EAS磷酸铁锂电池提供更多动力

华为推出配备国产CPU和操作系统的新型国产PC

NVIDIA Jetson Thor助力医疗、机器人、大模型领域迎接新机遇!

TLC2543C,TLC2543I 12位开关电容型逐次逼近模数转换器

更多 培训课堂
更多 焦点
更多 视频

技术专区