热度 30
2011-4-22 13:35
3846 次阅读|
13 个评论
在特权同学的博文《别忘了随手关上“门”》中卖了个关子,现在就要来讲讲用硬件做消抖的方法,当然其实这个任务并没有太多新意,也没有太多“技术含量”可言,但是在某些应用场合,这个硬消抖却对系统性能的提升有着非常大的助益。 我们先来了解一下一般的软件消抖(本文主要以按键的消抖为例)方式。有如下一段序: If(value == 0) //一旦检测到键值 { Delay(); //延时20ms,有效滤除按键的抖动 If(value == 0) //再次确定键值是否有效 { …… //执行相应处理 } } 这段软消抖程序从机理上看不会有什么问题,通常在软件程序不太“繁忙”的情况下也能够很好的消抖并做相应处理。也许value值的产生也是系统的一个中断(如PIO边沿检测产生的中断),通常系统中也不会就此一个中断,那么在多个中断共存的情况下,该程序的消抖延时就很可能成为系统性能提升的一个瓶颈。为什么这么说呢?举个简单的实例。在这个实例中,系统中除了按键检测外,还有一个中断A以及相应的中断处理函数。在主函数中,我们通常会这么编写程序: Void main(void) { If(中断A标志位有效) { Clear_A; //清除A标志位 Processing_A(); //中断A处理函数 } If(value == 0) //一旦检测到键值 { Delay(); //延时20ms,有效滤除按键的抖动 If(value == 0) //再次确定键值是否有效 { …… //执行相应处理 } } } 假设这个系统两次产生中断A的最小间隔时间是5ms,A中断处理函数需要1ms,按键中断处理需要1ms。那么,系统中断A有可能出现产生了中断却无法得到相应。在下面的状况中就可能出现如图1所示的问题。 图1 在这种情况下,中断A产生若干次后却只有最后一次能够得到响应处理,这是由于软件消抖延时影响了系统响应的实时性。当然了,如果非得用软件来解决这个问题,也许办法还是有的(不过特权同学没有深究,也不是很精于此道,欢迎软件高手们指点;当时遇到类似问题时朋友提过用状态机的思想来做消抖,不过特权同学潜意识里感觉状态机处理消抖可能会让整个软件编程思路混乱,所以也没有深入去思考过)。但是既然特权同学的系统是软硬协同架构,那么软硬都是可以互补的,也就是说有些工作的分工是可以重新调配的,因此就提出了用硬件来减轻软件工作量,从而提升软件的实时性。 硬件分担软件的任务我们通常称之为“硬件加速”,这个实例中的硬消抖替代软消抖归根结底也是“硬件加速”。在按键信号输入到软件系统前用逻辑对其进行一下简单的处理即可实现所谓的“硬件消抖”,verilog代码如下: //---------------------------------------------------------------------- //对输入信号inpio硬件滤波,每20ms采样一次当前值 reg cnt; //20ms计数器 always @(posedge clk_25m or negedge rst_n) if(!rst_n) cnt = 19'd0; else if(cnt 19’d500000) cnt = cnt+1'b1; else cnt = 19’d0; reg inpior; //当前inpio信号锁存,每20ms锁存一拍 always @(posedge clk_25m or negedge rst_n) if(!rst_n) inpior = 2'b11; else if(cnt == 19'h7ffff) inpior = {inpior ,inpior}; wire inpio_swin =inpior | inpior ; //前后20ms两次锁存值都为0时才为0 原先直接给软件处理的信号是inpio,它的抖动必须用delay()来滤除。而用硬件逻辑处理后得到的inpio_swin信号则是消抖处理过的信号。软件程序就不再需要delay()来滤波了。软件程序简化可以如下: Void main(void) { If(中断A标志位有效) { Clear_A; //清除A标志位 Processing_A(); //中断A处理函数 } If(value == 0) //一旦检测到键值 { If(value == 0) //再次确定键值是否有效 { …… //执行相应处理 } } } 重新回到图1所示的状况,其实已经不再会出现中断A被“丢帧”的尴尬了。这就是“硬件加速”的效果,虽然这只是很简单的一个技巧,但也不禁让特权同学感慨:有逻辑(资源)真好!