打印

不需要延时去抖的按键程序

[复制链接]
8753|25
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
shuijinliuxi|  楼主 | 2013-8-10 13:46 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
file:///C:\Users\ADMINI~1.WJ-\AppData\Local\Temp\%W@GJ$ACOF(TYDYECOKVDYB.pnghttp://blog.sina.com.cn/s/blog_a00aafb40101dxtu.html
在写按键处理函数时最常用的应该是延时去抖吧,顶多在加上个按键等待什么的,这个写法非常传统也用的比较普遍,但是相较而言它执行效率不高比较浪费时钟周期,那有没有一个执行效率比较高占用时钟周期短的写法呢?亲,这个是有的!
     这个也是我在网上无意间看到的,感觉比较有用就分享给大家。分享之前先说明这个写法比较有意义的几个方面:第一,执行效率比较高占用时钟周期少;第二,可以方便实现单按跟常按按键的功能;第三,自己发现。。。。。。。。
    核心部分:
     unsigned char Trg,Cont;  //Trg触发有效,Cont连续有效
     void keyread(void)
    {
         unsigned char ReadData = P1IN^0XFF;   //读PORTB的端口数据,取反,然后送到ReadData 临时变量里面保存起来
         Trg = ReadData&(ReadData^Cont);       //用来计算触发变量的
         Cont = ReadData;                                 //用来计算连续变量

     }

(1)       没有按键的时候
                P1IN = 0XFF;
                ReadData = 0;
                Trg = 0;
                Cont = 0;


(2)       第一次PB0按下的情况
                P1IN = 0XF7;     //这里用的是P1.3端口
                ReadData = 0X08;
                Trg = 0X08;
                Cont = 0X08;


(3)       PB0按着不松(长按键)的情况
                P1IN = 0XF7;     //这里用的是P1.3端口
                ReadData = 0X08;
                Trg = 0;
                Cont = 0X08;


(4)       按键松开的情况
                P1IN = 0XF7;     //这里用的是P1.3端口
                ReadData = 0;
                Trg = 0;
                Cont = 0;

  看到这应该差不多明白了吧。那就举个例子验证一下:

   程序中最开始用的延时去抖的写法没有删掉,想让大家看着比较一下两种写法

#include
unsigned char Trg,Cont;  //Trg触发有效,Con连续有效

void keyread(void)
{
    unsigned char ReadData = P1IN^0XFF;
    Trg = ReadData&(ReadData^Cont);
    Cont = ReadData;

}

void main( void )
{
  // Stop watchdog timer to prevent time out reset
  WDTCTL = WDTPW + WDTHOLD;
  P1DIR = 0X41;           //设置P1.6、P1.6输出

  P1OUT = 0X09;          //点亮LED1,并设置P1.3上拉
  P1REN = 0X08;          //设置P1.3上使能,代替硬件上拉电阻

while(1)
{
   keyread();
   if(Trg&0x08)
   {
        P1OUT^= 0X41;
   }
//    if(!(P1IN&0X08))
//    {
//        __delay_cycles(50000);    //延时去抖
//        if(!(P1IN&0X08))
//        {
//            while(!(P1IN&0X08)); //释放有效
//            
//                P1OUT^= 0X41;   //LED取反
//            
//            
//        }
//    }
//
}
}


  看完这个程序或许感觉这种写法没什么,都不如延时去抖写着方便,其实节约时钟中期这点你不能否认,那就让我们看看它很能干什么,在举一个长按效果的程序.

    if (Cont & 0x08) // 如果“加”按键被按着不放
    {
         cnt_plus++;       // 计时
         if (cnt_plus > 100) // 20ms*100 = 2S 如果时间到
         {
              Func();      // 你需要的执行的程序
         }           
    }

这里是一个不需要延时去抖的按键程序
想问一下,里面是如何做到消除抖动的


沙发
keasen| | 2013-8-10 15:16 | 只看该作者
留名,有空试试

使用特权

评论回复
板凳
shuijinliuxi|  楼主 | 2013-8-10 15:23 | 只看该作者
keasen 发表于 2013-8-10 15:16
留名,有空试试

问题找到了,当按下按键时 P1IN = 0XF7; ReadData = 0X08; Trg = 0X08; Cont = 0X08;LED取反,再一次检测,不管抖动的状态是什么,这些的值为P1IN = 0Xxx; ReadData = 0Xxx; Trg = 0; Cont = 0Xxx;因此不进入取反,但是如果再一次检测时还存在抖动,那会就出现问题了

使用特权

评论回复
地板
重邮king| | 2013-8-10 21:45 | 只看该作者
试过程序了,效果挺好的,比延时消抖神马的都节约资源!我之前还收集过一个类似的程序,跟大伙分享下!
/**************************************************
*          大量宏定义,便于代码移植和阅读
**************************************************/
#define KeyPort          P1IN          // 按键占用的IO口
#define KeyMask          0x0F     // 按键掩码

#define KeySearchStatus  0          // 查询按键状态
#define KeyAckStatus     1          // 确认按键状态
#define KeyReleaseStatus 2          // 释放按键状态

#define Key1             1          // 按键1键值

/*************************************************
* 函数名称:KeyRead
* 输    入:无
* 输    出:当前按下的键值
* 功能描述:读取按下的键值
*************************************************/
uint8 KeyRead(void)
{
  static uint8 KeyStatus   = KeySearchStatus; // 静态变量,保存按键状态
  static uint8 KeyCurPress = 0;                      // 静态变量,保存当前按键的键值
  uint8 KeyValue           = 0;
  uint8 i                  = 0;
  
  KeyValue = (~KeyPort) & KeyMask;   // 检测哪一个按键按下
  
  switch (KeyStatus)
  {
    case KeySearchStatus:            // 按键查询状态
    {
      if (KeyValue)
      {
        KeyStatus = KeyAckStatus;    // 按键下一个状态为确认状态
      }
      return 0;
    } break;
   
    case KeyAckStatus:               // 按键确认状态
    {
      if (!KeyValue)
      {
        KeyStatus = KeySearchStatus;
      }
      else
      {
        for (i=0; i<4; i++)               // 搜索按下的是哪个按键
        {
          if (KeyValue & (0x01<<i))       
          {
            KeyCurPress = Key1 + i;
            break;
          }
        }
        KeyStatus = KeyReleaseStatus;  // 按键下一个状态为释放状态
      }
      return 0;
    } break;       
                    
    case KeyReleaseStatus:             // 按键释放状态
    {
      if (!KeyValue)                   // 按键释放
      {
        KeyStatus = KeySearchStatus;   // 按键下一个状态为查询状态
                                         
        return KeyCurPress;            // 返回当前按键值               
      }
      return 0;
    }
   
    default : return 0;break;
  }
}

使用特权

评论回复
5
重邮king| | 2013-8-10 21:50 | 只看该作者
顺便问下楼主:
if (Cont & 0x08) // 如果“加”按键被按着不放
    {
         cnt_plus++;       // 计时
         if (cnt_plus > 100) // 20ms*100 = 2S 如果时间到
         {
              Func();      // 你需要的执行的程序
         }           
    }
这段代码中cnt_plus每加一次时间增加20ms是怎么回事,处理器速度不可能那么慢的啊,执行一次cnt_plus++不是需要us级别的时间吗,20ms*100 = 2s是怎么个意思呢?

使用特权

评论回复
6
shuijinliuxi|  楼主 | 2013-8-11 10:12 | 只看该作者
重邮king 发表于 2013-8-10 21:50
顺便问下楼主:
if (Cont & 0x08) // 如果“加”按键被按着不放
    {

这个加20ms可以是用定时器每20ms进入一次中断,当然也可以1ms或者其他的时间

使用特权

评论回复
7
重邮king| | 2013-8-11 10:20 | 只看该作者
shuijinliuxi 发表于 2013-8-11 10:12
这个加20ms可以是用定时器每20ms进入一次中断,当然也可以1ms或者其他的时间 ...

嗯嗯,那样的话就是在定时器中完成自加或是查询的方式自加了~

使用特权

评论回复
8
ZUI135| | 2013-8-11 11:59 | 只看该作者
if(key_down() == true)
{
   ostimedly(os_time_tick/50)
   if(key_down() == true)
  {
    //确实按下了按键...................
  }
}
没觉得这样有很消耗系统资源...........................

使用特权

评论回复
9
shuijinliuxi|  楼主 | 2013-8-11 12:41 | 只看该作者
ZUI135 发表于 2013-8-11 11:59
if(key_down() == true)
{
   ostimedly(os_time_tick/50)

ostimedly(os_time_tick/50)

你这个是利用死循环不断计数来达到延时的作用的吗

使用特权

评论回复
10
hithms| | 2013-8-12 12:25 | 只看该作者
(4)       按键松开的情况
                P1IN = 0XF7;     //这里用的是P1.3端口
                ReadData = 0;
                Trg = 0;
                Cont = 0;


这个是什么状态?不就是(1)没有按下的状态吗?求解

使用特权

评论回复
11
puchuang| | 2013-8-12 19:21 | 只看该作者
这样也不错   谢谢了  楼主   比较给力  学一学   原来   不通过消抖  也能解决问题   顶一个  

使用特权

评论回复
12
hithms| | 2013-8-12 20:04 | 只看该作者
重邮king 发表于 2013-8-10 21:45
试过程序了,效果挺好的,比延时消抖神马的都节约资源!我之前还收集过一个类似的程序,跟大伙分享下!
/** ...

我也试过了,但感觉效果很不好。:(

使用特权

评论回复
13
twt329270073| | 2013-8-12 21:29 | 只看该作者
网上的程序不要指望直接可用。具体还是需要自己消化后才行。

使用特权

评论回复
14
shuijinliuxi|  楼主 | 2013-8-13 12:59 | 只看该作者
hithms 发表于 2013-8-12 12:25
(4)       按键松开的情况
                P1IN = 0XF7;     //这里用的是P1.3端口
                Re ...

这里是和1一样,P1IN=0xf7错了

使用特权

评论回复
15
shuijinliuxi|  楼主 | 2013-8-13 13:01 | 只看该作者
puchuang 发表于 2013-8-12 19:21
这样也不错   谢谢了  楼主   比较给力  学一学   原来   不通过消抖  也能解决问题   顶一个   ...

如果按上面来虽然可行,但还要考虑特定情况,并不是一定行,有一定的问题,和我在3楼说的存在那个问题

使用特权

评论回复
16
shuijinliuxi|  楼主 | 2013-8-13 13:18 | 只看该作者
hithms 发表于 2013-8-12 20:04
我也试过了,但感觉效果很不好。

你是以哪一个试的呢

使用特权

评论回复
17
重邮king| | 2013-8-13 14:25 | 只看该作者
hithms 发表于 2013-8-12 20:04
我也试过了,但感觉效果很不好。

你试的哪一个?还有你用什么的控制器呢?

使用特权

评论回复
18
speme| | 2013-8-13 16:58 | 只看该作者
这类检测的以前用过,不过我的需求是按第一下打开,再按一下关闭,所以当时用的上升沿的检测。效果算是还行。

使用特权

评论回复
19
hawksabre| | 2013-8-13 20:20 | 只看该作者
不使用延时   可以将单片机的性能最大话的优化   不错   谢谢哦了  楼主

使用特权

评论回复
20
hawksabre| | 2013-8-13 20:21 | 只看该作者
感觉延时程序  比较浪费时间  这是我的感觉  

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

22

主题

51

帖子

0

粉丝