关于蓝桥杯单片机 官方例程 矩阵按键 消抖原理 ‘s 解释

  • Post author:
  • Post category:其他


关于蓝桥杯单片机官方例程矩阵按键消抖原理解释



项目场景:

芯片:IAP15F2K60S

蓝桥杯原书41页官方例程




问题描述

最开始我以为这款开发板有硬件消抖,对于下面这部分代码一直当作固定格式写,最近回看,发现其中另有“玄机”。

......
  ucKey_Val = Key_Read();
  ucKey_Down = ucKey_Val & (ucKey_Old ^ ucKey_Val);
  ucKey_Old = ucKey_Val;
......



原因分析:

这里默认大家看过并且会了 = = 之前的按键扫描例程了

众所周知,“ ^ ” 符号在C语言中是按位取 “ 异或 ” 的意思,并且,“ & ” 符号是按位取 “ 与 ”的意思。

这段代码的含义是获取扫描后的案件值然后进行消抖处理,我所截取的这一段代码是只保留了单边沿的。



详解:

首先,对于后面的异或,其作用到了ucKey_Old和ucKey_Val,其中ucKey_Old是上一次扫描按键获取的数值,包括获取到0,而ucKey_Val是这一次扫描按键获取的数值。如果二者不同,则会产生 “ 非零 ” 的结果,将代码改成如下。

......
  ucKey_Val = Key_Read();
  ucKey_Down = (ucKey_Old ^ ucKey_Val);
  ucKey_Old = ucKey_Val;
  
  if(ucKey_Down)
  {
       ......
  }
......

只要本次接收与上一次接收的按键值不同,ucKey_Down就会存储下“非零”的数值。回想一下,我们按键其实是有两个沿的,一次下降沿,一次上升沿。

更具体地针对官方例程来说,如果我按下4按键,那么他检测到的数值会出现两段变化,一次是ucKey_Val 从0到4的变化,另一次是其从4到0 的变化。

这样就会导致我的ucKey_Down在这两次变化过后都会有一次 “ 非零 ” 数值的出现,所以反应在我的输出上,就会将后面紧随的 if 代码段执行两次,这说明我们的 ” ^ ” 取异或只实现了部分的消抖功能,还需要保留单边沿,而非双边。

没错,我们的 “ & ” 取与符号就是实现的这个功能。我们分段讨论下0–4–0这个连续变化。

首先是 0–4,这段变化中,

我的 ucKey_Old = 0x00, 我的 ucKey_Val = 0x04;

因为这是从0到4的不同数值的变化,所以后面的取异或符号运算结束后一定是一个 “ 非零 ” 的量,并且结果一定是与 ucKey_Val 的数值相等!又加之与一个非零的 ucKey_Val 取与,那不就是 ucKey_Val 本身求与嘛!!!这就使得 ucKey_Down 最后的结果为 “ 非零 ” 的 ucKey_Val本身!!!这样解释了为什么后面会有

    switch(ucKey_Down)
    {
       ......
    }

的出现,原来我们仅凭借ucKey_Down的数值就可以判断我按下的是什么键。

————-分隔符————–

接下来是4–0这一段的变化,

我的 ucKey_Old = 0x40, 我的 ucKey_Val = 0x00;

之前说到如果是不同数值之间的变化必然会导致异或的结果为 “ 非零 ” 数值,所以这一段就很好明白了,我加上取与符号后,实现了ucKey_Val & “ 非零 ”,其中ucKey_Val为0,会将我的ucKey_Down,结果变成 0,这就实现了我取单边沿的效果。


总结


异或 “ ^ ” 是用来消抖的,只有扫描到不同的数值之后我才会发生变化。

取余 “ & ”是用来保留单边沿的,因为单单使用”^” 时,笨蛋机器不能判断是哪两个数值之间的变化,究竟是0–4还是4–0呢?当我加上 “ & ” 之后就可以消除一个沿。

PS:文中我们是以下降沿为例说明的,其实保留上升沿的话取个 “ ~ ” 就可以了,具体为啥,大家想想吧。



版权声明:本文为AFightingguy原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。