标题: 单片机定时器按键扫描问题 [打印本页]

作者: 下一站过后    时间: 2024-4-7 20:54
标题: 单片机定时器按键扫描问题
大佬们我想问一下加了if(Temp)这里为什么按键就非常不灵敏了,不加判断返回值是否为0代码就能正确检测到按键,这个if(Temp)判断返回值是否为0为什么会导致按键操作不灵敏,这个是测试的,后面必须要用到判断是否为0,不是很理解,求大佬能指点一二

单片机源程序如下:
#include <REGX52.H>
#include "LCD1602.H"
#include "AT24C02.H"
#include "Delay.H"
#include "Timer0Init.H"
#include "Key.H"
void main()
{
        unsigned char Temp=0;
        Timer0Init();
        while(1)
        {
                Temp=Keynum_return();
                if(Temp)//加了判断按键就不灵敏,不加就很正常
                {
                        
                                if(Temp==1)
                                        P2_0=~P2_0;
                                if(Temp==2)
                                        P2_1=~P2_1;
                                if(Temp==3)
                                        P2_2=~P2_2;
                                if(Temp==4)
                                        P2_3=~P2_3;
                        
                                
                }
        }
}



void Timer0_Rountine(void) interrupt 1//中断函数
{
        static unsigned char count;//计数范围为0-256
        TL0 = 0x66;
        TH0 = 0xFC;        
        count++;
        if(count>=20)
        {
                count=0;
                key_Interrupt();//按键中断
               
        }
        
}



这是Key里面的函数
#include <REGX52.H>

unsigned char Key_num;


unsigned char Keynum_return()
{
        unsigned char Temp=0;
        
        Temp=Key_num;
        
        Key_num=0;
        
        return Temp;


}


unsigned char Key_Timer0()
{
        
        unsigned char KeyNumber=0;
        
        
        if(P3_1==0){KeyNumber=1;}                        
        if(P3_0==0){KeyNumber=2;}
        if(P3_2==0){KeyNumber=3;}
        if(P3_3==0){KeyNumber=4;}
        
        return KeyNumber;
        
}
        


void key_Interrupt()//按键中断函数
{
        
        static unsigned char Last_Status=0,Now_Status=0;
        Last_Status=Now_Status;
        Now_Status=Key_Timer0();//现态次态检测
        if(        Last_Status==1 && Now_Status==0)
        {
                        Key_num=1;
        
        }
        if(        Last_Status==2 && Now_Status==0)
        {
                        Key_num=2;
        
        }
               
        if(        Last_Status==3 && Now_Status==0)
        {
                        Key_num=3;
        
        }
               
        if(        Last_Status==4 && Now_Status==0)
        {
                        Key_num=4;
        
        }
        
        
}

秒表设计.rar

55.56 KB, 下载次数: 4


作者: 下一站过后    时间: 2024-4-7 22:04
麻烦各位大佬帮忙看一下,这个问题确实很奇怪,if判断体里面是可以正常进入的,在里面计数都可以,但是一旦使用按键相关的操作,按键就变得十分不灵敏,有点想不明白

作者: 下一站过后    时间: 2024-4-7 22:46
我将  Temp=Keynum_return()    Delay(1)    if(Temp)中间加了一个延时函数代码就能正常跑起来,这个是什么原因,确实不大明白问题出在哪,我刚学不久,麻烦大佬们指点一二
作者: 下一站过后    时间: 2024-4-8 09:57
判断体可以进去,里面赋值也可以正常操作,但是里面调用按键就不行这是为啥啊,
作者: lids    时间: 2024-4-8 11:51
if(Temp)就等同于 if(Temp==1),只有if(Temp==1),按键才会动作
作者: 下一站过后    时间: 2024-4-8 13:49
lids 发表于 2024-4-8 11:51
if(Temp)就等同于 if(Temp==1),只有if(Temp==1),按键才会动作

谢谢您的回复,if判断条件只要不是0就应该为真,执行判断里面的语句,判断是可以进去的,就是按键判断不灵敏这个问题
作者: STC庄伟    时间: 2024-4-8 15:27
分享一个简单的按键扫描程序,方便有需要的用户搜索参考。
例程使用定时器分时调度,定时每毫秒检测一次按键状态,有按键时累加计数器,没有按键时清除计数器。
连续计数50次表明按键按下并持续50ms(防抖),设置按键有效状态标志:

        if(!KEY1)
        {
            if(!Key1_Flag)
            {
                Key1_cnt++;
                if(Key1_cnt >= 50)                //50ms防抖
                {
                    Key1_Flag = 1;                        //设置按键状态,防止重复触发
                    Key1_Function = 1;
                }
            }
        }
        else
        {
            Key1_cnt = 0;
            Key1_Flag = 0;
        }

检测连续1s为低电平则判定按键长按有效;连续低电平时间大于50ms并小于1s则判定为按键短按有效:

        if(!KEY2)
        {
            if(!Key2_Flag)
            {
                Key2_cnt++;
                if(Key2_cnt >= 1000)                //长按1s
                {
                    Key2_Short_Flag = 0;        //清除短按标志
                    Key2_Long_Flag = 1;                //设置长按标志
                    Key2_Flag = 1;                                //设置按键状态,防止重复触发
                    Key2_Long_Function = 1;
                }
                else if(Key2_cnt >= 50)                //50ms防抖
                {
                    Key2_Short_Flag = 1;                //设置短按标志
                }
            }
        }
        else
        {
            if(Key2_Short_Flag)                        //判断是否短按
            {
                Key2_Short_Flag = 0;        //清除短按标志
                Key2_Short_Function = 1;
            }
            Key2_cnt = 0;
            Key2_Flag = 0;        //按键释放
        }
    }

此外,推荐一份社区大神分享的按键扫描方法介绍的帖子:
分享 按键程序,大道至简,按键扫描 + 累计主循环次数去抖动/不占用定时器


作者: xiaobendan001    时间: 2024-4-8 16:05
下一站过后 发表于 2024-4-8 13:49
谢谢您的回复,if判断条件只要不是0就应该为真,执行判断里面的语句,判断是可以进去的,就是按键判断不 ...

看不懂,这是在硬件上测试的?我记得位变量反转用!的,字节才是~
作者: 下一站过后    时间: 2024-4-8 17:01
xiaobendan001 发表于 2024-4-8 16:05
看不懂,这是在硬件上测试的?我记得位变量反转用!的,字节才是~

谢谢您的回复,程序是在51单片机上面跑的,反转的操作这样写应该没问题,我在主函数里可以跑
作者: 下一站过后    时间: 2024-4-8 17:03
STC庄伟 发表于 2024-4-8 15:27
分享一个简单的按键扫描程序,方便有需要的用户搜索参考。
例程使用定时器分时调度,定时每毫秒检测一次按 ...

谢谢您的回复,我参考下
作者: xiaobendan001    时间: 2024-4-8 17:08
本质上 if(Temp)应该么有影响的啊
作者: 下一站过后    时间: 2024-4-8 17:17
xiaobendan001 发表于 2024-4-8 17:08
本质上 if(Temp)应该么有影响的啊

对啊,我想了一宿也没想明白啊,C语言语法书都翻几遍了,真想不出来哪里的问题
作者: xiaobendan001    时间: 2024-4-8 18:37
实在搞不清楚
这样改改试试
  1. #include <REGX52.H>
  2. #include "LCD1602.H"
  3. #include "AT24C02.H"
  4. #include "Delay.H"
  5. #include "Timer0Init.H"
  6. #include "Key.H"
  7. #include "Nixie_tube.H"
  8. bit t0inter;                                                //加一个BIT
  9. void main()
  10. {
  11.         unsigned char i=0;
  12.         unsigned char Temp=0,Temp_1;
  13.         Timer0Init();
  14.         while(1)
  15.         {
  16.                 if(tointer){                                                //这里增加
  17.                         Temp=Keynum_return();
  18.                         t0inter = 0;
  19.                 }
  20.                 if(Temp)
  21.                 {
  22.                         //按键操作放在这个循环里就会不灵敏
  23.                         if(Temp==1)
  24.                                                         P2_0=~P2_0;
  25.                         if(Temp==2)
  26.                                                         P2_1=~P2_1;
  27.                         if(Temp==3)
  28.                                                         P2_2=~P2_2;
  29.                         if(Temp==4)
  30.                                                         P2_3=~P2_3;
  31.                 i++;
  32.                        
  33.                 }
  34.                 P2=~(0x80>>i);       

  35.                
  36.                
  37.         }
  38. }



  39. void Timer0_Rountine(void) interrupt 1//中断函数
  40. {
  41.         static unsigned char count;//计数范围为0-256
  42.         TL0 = 0x66;
  43.         TH0 = 0xFC;       
  44.         t0inter = 1;                                                //这里增加
  45.         count++;
  46.         if(count>=10)
  47.         {
  48.                 count=0;
  49.                 key_Interrupt();//按键中断
  50.                
  51.         }
  52.        
  53. }
复制代码

作者: 下一站过后    时间: 2024-4-8 18:50
xiaobendan001 发表于 2024-4-8 18:37
实在搞不清楚
这样改改试试

谢谢您的回复,我试试看
作者: lkc8210    时间: 2024-4-8 22:50
太累赘了
  1. void main()
  2. {
  3.         Timer0Init();
  4.         while(1)
  5.         {
  6.                 if(Key_num)//加了判断按键就不灵敏,不加就很正常
  7.                 {
  8.                         if(Key_num==1)
  9.                                 P2_0=~P2_0;
  10.                         if(Key_num==2)
  11.                                 P2_1=~P2_1;
  12.                         if(Key_num==3)
  13.                                 P2_2=~P2_2;
  14.                         if(Key_num==4)
  15.                                 P2_3=~P2_3;
  16.                         Key_num = 0;
  17.                 }
  18.         }
  19. }
复制代码

作者: 人中狼    时间: 2024-4-8 23:01
Key_num没在头文件里声明吧
作者: rayin    时间: 2024-4-9 08:41
软件搞得复杂了, 定时器中断服务函数里面调用按键中断服务函数. 这思路还是有问题. 按键中断可以直接响应其服务函数了, 为什么还要在定时器中断里面去搞按键中断响应?
作者: Graves    时间: 2024-4-9 09:19
下一站过后 发表于 2024-4-7 22:46
我将  Temp=Keynum_return()    Delay(1)    if(Temp)中间加了一个延时函数代码就能正常跑起来,这个是什么 ...

加delay正常的话有可能是中断已经将按键执行两次判定了,然后主函数刚好将引脚反转两次,肉眼看不出来就感觉是不灵敏,可以试下逻辑分析仪或者示波器量一下翻转的引脚
作者: xiaobendan001    时间: 2024-4-9 09:35
下一站过后 发表于 2024-4-8 18:50
谢谢您的回复,我试试看

抱歉,上面代码16行里面那个tointer输入错误,应该是t0inter
作者: 下一站过后    时间: 2024-4-9 13:49
lkc8210 发表于 2024-4-8 22:50
太累赘了

谢谢您的回复,您的解决方法确实简便很多,我在学习学习
作者: 下一站过后    时间: 2024-4-9 13:49
rayin 发表于 2024-4-9 08:41
软件搞得复杂了, 定时器中断服务函数里面调用按键中断服务函数. 这思路还是有问题. 按键中断可以直接响应其 ...

确实,您说的很有道理,我在思考下,谢谢您的回复
作者: 下一站过后    时间: 2024-4-9 13:50
xiaobendan001 发表于 2024-4-9 09:35
抱歉,上面代码16行里面那个tointer输入错误,应该是t0inter

谢谢您,我按照这个思路改了下确实可行,谢谢
作者: 下一站过后    时间: 2024-4-9 13:51
qq475878026 发表于 2024-4-9 09:19
加delay正常的话有可能是中断已经将按键执行两次判定了,然后主函数刚好将引脚反转两次,肉眼看不出来就 ...

这个问题我确实没考虑到,我回去试试看,谢谢您
作者: xiaobendan001    时间: 2024-4-9 14:06
下一站过后 发表于 2024-4-9 13:50
谢谢您,我按照这个思路改了下确实可行,谢谢

那么你根据这个改法,有没有思考到之前的代码的问题究竟出在哪儿?
作者: 下一站过后    时间: 2024-4-9 22:32
xiaobendan001 发表于 2024-4-9 14:06
那么你根据这个改法,有没有思考到之前的代码的问题究竟出在哪儿?

  这个问题我也想了很久,改过之后的代码逻辑变为只有进入中断,扫描了按键才会在主函数里进行判断,逻辑上确实更清晰,我的代码是会一直接收返回值进行判断,这个我确实没想明白我的代码是哪里的原因,我觉得这两种方法逻辑上都能跑的通的,我想是因为我对机器了解程度还不够,还望大佬能指点一下是哪里出现的问题。万分感谢。
作者: xiaobendan001    时间: 2024-4-10 07:44
下一站过后 发表于 2024-4-9 22:32
这个问题我也想了很久,改过之后的代码逻辑变为只有进入中断,扫描了按键才会在主函数里进行判断,逻辑 ...

我也只是分析,我觉得你增加delay或者使用4个if的结果是会影响到主循环的循环速度,当使用一个if包裹之后使得Keynum_return()被调用的频率明显的增加,这使中断发生在函数内部的可能性增加很多。比如temp在取得key_num的时候中断尚未把key_num更新,在更新了以后立刻又被你下一行清零了。这种虽然比较牵强,但是可能性还是有的。配合的好就行。
我的习惯就是要么搞一个bit,要么把按键识别直接放中断服务,反正1ms甚至2ms时间能做很多事情。除了显示(利用芯片比如1638,或者液晶)放主循环自由运行,其他的都用状态或者直接放中断服务。
作者: 下一站过后    时间: 2024-4-12 19:43
xiaobendan001 发表于 2024-4-10 07:44
我也只是分析,我觉得你增加delay或者使用4个if的结果是会影响到主循环的循环速度,当使用一个if包裹之后 ...

你讲的确实是我没有考虑到的问题,确实是有这个可能性,我都没忘这方面去考虑,谢谢




欢迎光临 (http://www.51hei.com/bbs/) Powered by Discuz! X3.1