打印
[51单片机]

单片机独立按键双击偶尔变单击,why???

[复制链接]
2338|12
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
k1990|  楼主 | 2015-4-29 00:56 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 k1990 于 2015-4-29 00:58 编辑

自己模仿别人程序改写的单片机独立按键同时实现单击,双击,双击蜂鸣器操作,单击led灯点亮。反复运行几次就会出现双击变成单击。用的是郭天祥的51开发板。不知道程序哪里出现问题。还是按键有问题。

/*独立按键实现单双击功能*/
#include <reg52.h>
#define const_Voice_short 40 //设定蜂鸣器短鸣累计次数
#define const_Voice_long 80 //设定蜂鸣器长鸣累计次数

#define const_KeyTime1         30//按键延时计数器实现延时去抖
#define const_KeyTime2         30//可以设置按键响应时间

#define const_Key_interval_Time1 200
#define const_Key_interval_Time2 200

void initial_Myself();//初始化
void initial_Peripheral();//初始化外部器件

void Delay_long(unsigned int uiDelaylong);

void Key_scan();//
void Key_service();

void T0_time();

sbit beep_dr=P2^3;
sbit led0_dr=P1^0;
sbit led1_dr=P1^1;

sbit Key1_sr=P3^6;//s4键
sbit Key2_sr=P3^7;//s5键

unsigned char ucKeynum=0;//判断按键
unsigned int  uiVoiceCnt=0;//蜂鸣器延时计数器

unsigned char ucKeycnt1=0;//按键次数计数器
unsigned int  uiKeyTimeCnt1=0;//按键延时计数器
unsigned char ucKeylock1=0;//按键s2自锁标志
unsigned int  uiKeyintervalCnt1=0;//按键时间间隔计数器

unsigned char  ucKeycnt2=0;//按键次数计数器
unsigned int  uiKeyTimeCnt2=0;
unsigned char ucKeylock2=0;
unsigned int  uiKeyintervalCnt2=0;//按键时间间隔计数器

void main()
{
        initial_Myself();
        Delay_long(100);
        initial_Peripheral();
        while(1)
        {
    Key_service();
        }
        
}
void Key_scan()
{        
        if(Key1_sr==1)//判断按键1是否按下,没有按下清空按键延时计数器和按键自锁标志
                {
                        ucKeylock1=0;
                        uiKeyTimeCnt1=0;//累计中断次数计数器清零
                        if(ucKeycnt1>0)//已经按键一次,可能触发双击
                        {
                                uiKeyintervalCnt1++;//按键时间间隔计数器开始累加
                                if(uiKeyintervalCnt1>const_Key_interval_Time1)//超过有效间隔时间
                                        {
                                        uiKeyintervalCnt1=0;//时间间隔计数器清零
                                        ucKeycnt1=0;//按键次数清零
                                        ucKeynum=3;
                                        }
                        }
                }
                else if(ucKeylock1==0)
                        {
                        ++uiKeyTimeCnt1;
                                if(uiKeyTimeCnt1>const_KeyTime1)//延时去抖
                                        {
                                                uiKeyTimeCnt1=0;
                                                ucKeylock1=1;
                                                ucKeycnt1++;//按键次数加1
                                                        if(ucKeycnt1>1)
                                                                {
                                                                ucKeycnt1=0;
                                                                ucKeynum=1;
                                                                }
                                        }
                        }        
               
        if(Key2_sr==1)//判断按键2是否按下,没有按下清空按键延时计数器和按键自锁标志
                {
                        ucKeylock2=0;
                        uiKeyTimeCnt2=0;
                        if(ucKeycnt2>0)//已经按键一次,可能触发双击
                        {
                                uiKeyintervalCnt2++;//按键时间间隔计数器开始累加
                                if(uiKeyintervalCnt2>const_Key_interval_Time2)//超过有效间隔时间
                                 
                                {
                                                
                                        uiKeyintervalCnt2=0;//时间间隔计数器清零
                                        ucKeycnt2=0;//按键次数清零
                                        ucKeynum=4;
                                       
                                }
                                
                        }
                }
                else if(ucKeylock2==0)
                        {
                        ++uiKeyTimeCnt2;
                                if(uiKeyTimeCnt2>const_KeyTime2)//延时去抖
                                        {
                                                uiKeyTimeCnt2=0;
                                                ucKeylock2=1;
                                                ucKeycnt2++;//按键次数加1
                                                        if(ucKeycnt2>1)
                                                                {
                                                                ucKeycnt2=0;
                                                                ucKeynum=2;
                                                                }
                                                
                                                
                                        }
                        }        
               
}

void Key_service()
{
        switch(ucKeynum)
        {
        case 1:
                uiVoiceCnt=const_Voice_short;
                ucKeynum=0;
                break;
        case 2:
                uiVoiceCnt=const_Voice_long;
                //uiVoiceCnt=const_Voice_short;
                ucKeynum=0;
                break;
        case 3:
                //uiVoiceCnt=const_Voice_long;
                //uiVoiceCnt=const_Voice_short;
                led0_dr=~led0_dr;
                ucKeynum=0;
                break;        
        case 4:
                //uiVoiceCnt=const_Voice_long;
                //uiVoiceCnt=const_Voice_short;
                led1_dr=~led1_dr;
                ucKeynum=0;
                break;               
        }
}
void T0_time() interrupt 1
{
                TF0=0;
                TR0=0;
                Key_scan();
        if(uiVoiceCnt!=0)
         {
                 uiVoiceCnt--;
                 beep_dr=0;
         }
        else
        {
                beep_dr=1;
        }
                TH0=0xf8;   //重装初始值(65535-2000)=63535=0xf82f
                TL0=0x2f;
                TR0=1;  //开中断
}

/* 注释:
* C51的中断函数格式如下:
* void 函数名() interrupt 中断号
* {
*    中断程序内容
* }
* 函数名可以随便取,只要不是编译器已经征用的关键字。
* 这里最关键的是中断号,不同的中断号代表不同类型的中断。
* 定时中断的中断号是 1.至于其它中断的中断号,大家可以查找
* 相关书籍和资料。大家进入中断时,必须先清除中断标志,并且
* 关闭中断,然后再写代码,最后出来时,记得重装初始值,并且
* 打开中断。
*/

void Delay_long(unsigned int uiDelaylong)
{
        unsigned int i;
        unsigned int j;
        for(i=0;i<uiDelaylong;i++)
        {
                for(j=0;j<500;j++)
                {
                ;//空指令延时
                }
        }
}
void initial_Myself()
{        
        beep_dr=1;//关闭蜂鸣器

        led0_dr=1;
        led1_dr=1;
        
        //Key_gnd_sr=0;
        
        TMOD=0X01;
        TH0=0xf8;   //重装初始值(65535-2000)=63535=0xf82f
        TL0=0x2f;
}

void initial_Peripheral()
{
  EA=1;     //开总中断
  ET0=1;    //允许定时中断
  TR0=1;    //启动定时中断
}

相关帖子

来自 2楼
k1990|  楼主 | 2015-4-29 23:55 | 只看该作者
之前没有在双击判断和单击判断之后,将时间间隔清零

void Key_scan()
{       
        if(Key1_sr)//判断按键1是否按下,没有按下清空按键延时计数器和按键自锁标志
                {
                        ucKeylock1=0;
                        uiKeyTimeCnt1=0;//累计中断次数计数器清零
                        if(ucKeycnt1>0)//已经按键一次,可能触发双击
                        {
                                uiKeyintervalCnt1++;//按键时间间隔计数器开始累加
                                if(uiKeyintervalCnt1>=const_Key_interval_Time1)//超过有效间隔时间
                                        {
                                        ucKeynum=3;       
                                        uiKeyintervalCnt1=0;//时间间隔计数器清零
                                        ucKeycnt1=0;//按键次数清零
                                       
                                        }
                        }
                }
                else if(ucKeylock1==0)
                        {
                        ++uiKeyTimeCnt1;
                                if(uiKeyTimeCnt1>const_KeyTime1)//延时去抖
                                        {
                                                uiKeyTimeCnt1=0;
                                                ucKeylock1=1;
                                                ucKeycnt1++;//按键次数加1
                                                        if(ucKeycnt1>1)
                                                                {
                                                                ucKeycnt1=0;
                                                                uiKeyintervalCnt1=0;
                                                                ucKeynum=1;
                                                               
                                                                }
                                        }
                        }       
               
        if(Key2_sr==1)//判断按键2是否按下,没有按下清空按键延时计数器和按键自锁标志
                {
                        ucKeylock2=0;
                        uiKeyTimeCnt2=0;
                        if(ucKeycnt2>0)//已经按键一次,可能触发双击
                        {
                                ++uiKeyintervalCnt2;//按键时间间隔计数器开始累加
                                if(uiKeyintervalCnt2>=const_Key_interval_Time2)//超过有效间隔时间
                                 
                                {       
                                        uiKeyintervalCnt2=0;//时间间隔计数器清零
                                        ucKeycnt2=0;//按键次数清零
                                        ucKeynum=4;
                                       
                                }
                               
                        }
                }
                else if(ucKeylock2==0)
                        {
                        ++uiKeyTimeCnt2;
                                if(uiKeyTimeCnt2>const_KeyTime2)//延时去抖
                                        {
                                                uiKeyTimeCnt2=0;
                                                ucKeylock2=1;
                                                ucKeycnt2++;//按键次数加1
                                                //uiKeyintervalCnt2=0;
                                                        if(ucKeycnt2>1)
                                                                {
                                                                uiKeyintervalCnt2=0;//时间间隔计数器清零       
                                                                ucKeycnt2=0;
                                                                ucKeynum=2;
                                                                }
                                               
                                               
                                        }
                        }       
               
}

使用特权

评论回复
板凳
huaziforever| | 2015-4-29 16:03 | 只看该作者
将timer中断的时间做小一些。比如将之前的50ms定时修改成5ms定时中断,按键的扫描精度就提高了。

使用特权

评论回复
地板
k1990|  楼主 | 2015-4-29 20:34 | 只看该作者
huaziforever 发表于 2015-4-29 16:03
将timer中断的时间做小一些。比如将之前的50ms定时修改成5ms定时中断,按键的扫描精度就提高了。 ...

定时器2ms中断一次,扫描一次按键,程序还是会出现第3次双击变单击,将两次按键有效间隔时间会变长双击变单击出现会推迟。搞不明白

使用特权

评论回复
5
dirtwillfly| | 2015-4-29 21:59 | 只看该作者
因为间隔时间太长,而你双击的比较快,单片机容易识别不出来

使用特权

评论回复
6
k1990|  楼主 | 2015-4-29 22:09 | 只看该作者
本帖最后由 k1990 于 2015-4-29 22:12 编辑
dirtwillfly 发表于 2015-4-29 21:59
因为间隔时间太长,而你双击的比较快,单片机容易识别不出来

它总是在双击3次之后,第四次出现。出现一次之后,在双击3次,又会出现。。。。怎么改进更好呢,。。。。

使用特权

评论回复
7
wyq165| | 2015-4-30 08:54 | 只看该作者
无法验证,看着好像也发现不出问题。
但是我觉得连续几次都可以,说明思路是对的。至于有不可以的,是不是某个值没有及时清0呢?
比如:
if(Key1_sr==1)//判断按键1是否按下,没有按下清空按键延时计数器和按键自锁标志
         {
                        ucKeylock1=0;
                        uiKeyTimeCnt1=0;//累计中断次数计数器清零
                        if(ucKeycnt1>0)//已经按键一次,可能触发双击
                        {
                                uiKeyintervalCnt1++;//按键时间间隔计数器开始累加
                                if(uiKeyintervalCnt1>const_Key_interval_Time1)//超过有效间隔时间
                                        {
                                        uiKeyintervalCnt1=0;//时间间隔计数器清零
                                        ucKeycnt1=0;//按键次数清零
                                        ucKeynum=3;
                                        }
                        }
          }else if(ucKeylock1==0)
          {
                        ++uiKeyTimeCnt1;
                          uiKeyintervalCnt1=0;//时间间隔计数器清零  ---------------------我觉得这里时间计数器需要清0
                                if(uiKeyTimeCnt1>const_KeyTime1)//延时去抖
                                        {
                                                uiKeyTimeCnt1=0;
                                                ucKeylock1=1;
                                                ucKeycnt1++;//按键次数加1
                                                        if(ucKeycnt1>1)
                                                                {
                                                                ucKeycnt1=0;
                                                                ucKeynum=1;
                                                                }
                                        }
           }        
不知道是不是这个问题。

使用特权

评论回复
8
flove00| | 2015-4-30 10:43 | 只看该作者
楼主这个是单击吧   ucKeynum=3  我觉得应该做松手检测 ,
if(uiKeyintervalCnt1>const_Key_interval_Time1)//超过有效间隔时间
                                        {
                                        uiKeyintervalCnt1=0;//时间间隔计数器清零
                                        ucKeycnt1=0;//按键次数清零
                                        ucKeynum=3;
                                        }
这个情况下手还是按着的,可能会导致第二次误触发单击
所以应该做松手检测

使用特权

评论回复
9
flove00| | 2015-4-30 10:44 | 只看该作者
另外鸿哥的程序我看过,他本人也很热心,你可以直接论坛问他

使用特权

评论回复
10
k1990|  楼主 | 2015-4-30 23:16 | 只看该作者
wyq165 发表于 2015-4-30 08:54
无法验证,看着好像也发现不出问题。
但是我觉得连续几次都可以,说明思路是对的。至于有不可以的,是不是 ...

我的思路和你差不多,应该是忘记将时间间隔计数器清零,改过之后按键变正常了,不过,我的时间间隔清零放在判断确定是双击之后才清零,按照你的方法修改,按键也是正常,两种应该都可以。

else if(ucKeylock1==0)
                        {
                        ++uiKeyTimeCnt1;
                       
                                if(uiKeyTimeCnt1>const_KeyTime1)//延时去抖
                                        {
                                                uiKeyTimeCnt1=0;
                                                ucKeylock1=1;
                                                ucKeycnt1++;//按键次数加1
                                                        if(ucKeycnt1>1)
                                                                {
                                                                ucKeycnt1=0;
                                                                uiKeyintervalCnt1=0;//时间间隔计数器清零
                                                                ucKeynum=1;
                                                               
                                                                }
                                        }
                        }       

使用特权

评论回复
11
k1990|  楼主 | 2015-4-30 23:28 | 只看该作者
本帖最后由 k1990 于 2015-4-30 23:34 编辑
flove00 发表于 2015-4-30 10:43
楼主这个是单击吧   ucKeynum=3  我觉得应该做松手检测 ,
if(uiKeyintervalCnt1>const_Key_interval_Time1 ...

我不知道怎么加松手检测更好,不过按照鸿哥的程序框架来看,第一次判断按键按下的时候已经做了防止按键按住不放,将ucKeylock1=1;防止误操作。

使用特权

评论回复
12
神的兄弟| | 2015-5-4 11:45 | 只看该作者
也许你手指头没有离开就按下第二次了~~~

使用特权

评论回复
13
huaziforever| | 2015-5-18 15:37 | 只看该作者
k1990 发表于 2015-4-29 20:34
定时器2ms中断一次,扫描一次按键,程序还是会出现第3次双击变单击,将两次按键有效间隔时间会变长双击变 ...

你双击之后是不是去做了别的事情,耽误了时间?你可以尝试不做其他任何事情只检测双击事件。

使用特权

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

本版积分规则

1

主题

7

帖子

0

粉丝