找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 1193|回复: 26
打印 上一主题 下一主题
收起左侧

单片机定时器按键扫描问题

[复制链接]
跳转到指定楼层
楼主
ID:1114858 发表于 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

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏2 分享淘帖 顶 踩
回复

使用道具 举报

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

使用道具 举报

板凳
ID:1114858 发表于 2024-4-7 22:46 | 只看该作者
我将  Temp=Keynum_return()    Delay(1)    if(Temp)中间加了一个延时函数代码就能正常跑起来,这个是什么原因,确实不大明白问题出在哪,我刚学不久,麻烦大佬们指点一二
回复

使用道具 举报

地板
ID:1114858 发表于 2024-4-8 09:57 来自手机 | 只看该作者
判断体可以进去,里面赋值也可以正常操作,但是里面调用按键就不行这是为啥啊,
回复

使用道具 举报

5#
ID:140489 发表于 2024-4-8 11:51 | 只看该作者
if(Temp)就等同于 if(Temp==1),只有if(Temp==1),按键才会动作
回复

使用道具 举报

6#
ID:1114858 发表于 2024-4-8 13:49 来自手机 | 只看该作者
lids 发表于 2024-4-8 11:51
if(Temp)就等同于 if(Temp==1),只有if(Temp==1),按键才会动作

谢谢您的回复,if判断条件只要不是0就应该为真,执行判断里面的语句,判断是可以进去的,就是按键判断不灵敏这个问题
回复

使用道具 举报

7#
ID:961114 发表于 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;        //按键释放
        }
    }

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

回复

使用道具 举报

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

看不懂,这是在硬件上测试的?我记得位变量反转用!的,字节才是~
回复

使用道具 举报

9#
ID:1114858 发表于 2024-4-8 17:01 来自手机 | 只看该作者
xiaobendan001 发表于 2024-4-8 16:05
看不懂,这是在硬件上测试的?我记得位变量反转用!的,字节才是~

谢谢您的回复,程序是在51单片机上面跑的,反转的操作这样写应该没问题,我在主函数里可以跑
回复

使用道具 举报

10#
ID:1114858 发表于 2024-4-8 17:03 来自手机 | 只看该作者
STC庄伟 发表于 2024-4-8 15:27
分享一个简单的按键扫描程序,方便有需要的用户搜索参考。
例程使用定时器分时调度,定时每毫秒检测一次按 ...

谢谢您的回复,我参考下
回复

使用道具 举报

11#
ID:1109793 发表于 2024-4-8 17:08 | 只看该作者
本质上 if(Temp)应该么有影响的啊
回复

使用道具 举报

12#
ID:1114858 发表于 2024-4-8 17:17 来自手机 | 只看该作者
xiaobendan001 发表于 2024-4-8 17:08
本质上 if(Temp)应该么有影响的啊

对啊,我想了一宿也没想明白啊,C语言语法书都翻几遍了,真想不出来哪里的问题
回复

使用道具 举报

13#
ID:1109793 发表于 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. }
复制代码
回复

使用道具 举报

14#
ID:1114858 发表于 2024-4-8 18:50 来自手机 | 只看该作者
xiaobendan001 发表于 2024-4-8 18:37
实在搞不清楚
这样改改试试

谢谢您的回复,我试试看
回复

使用道具 举报

15#
ID:161164 发表于 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. }
复制代码
回复

使用道具 举报

16#
ID:384109 发表于 2024-4-8 23:01 | 只看该作者
Key_num没在头文件里声明吧
回复

使用道具 举报

17#
ID:517951 发表于 2024-4-9 08:41 | 只看该作者
软件搞得复杂了, 定时器中断服务函数里面调用按键中断服务函数. 这思路还是有问题. 按键中断可以直接响应其服务函数了, 为什么还要在定时器中断里面去搞按键中断响应?
回复

使用道具 举报

18#
ID:192020 发表于 2024-4-9 09:19 | 只看该作者
下一站过后 发表于 2024-4-7 22:46
我将  Temp=Keynum_return()    Delay(1)    if(Temp)中间加了一个延时函数代码就能正常跑起来,这个是什么 ...

加delay正常的话有可能是中断已经将按键执行两次判定了,然后主函数刚好将引脚反转两次,肉眼看不出来就感觉是不灵敏,可以试下逻辑分析仪或者示波器量一下翻转的引脚
回复

使用道具 举报

19#
ID:1109793 发表于 2024-4-9 09:35 | 只看该作者
下一站过后 发表于 2024-4-8 18:50
谢谢您的回复,我试试看

抱歉,上面代码16行里面那个tointer输入错误,应该是t0inter
回复

使用道具 举报

20#
ID:1114858 发表于 2024-4-9 13:49 来自手机 | 只看该作者
lkc8210 发表于 2024-4-8 22:50
太累赘了

谢谢您的回复,您的解决方法确实简便很多,我在学习学习
回复

使用道具 举报

21#
ID:1114858 发表于 2024-4-9 13:49 来自手机 | 只看该作者
rayin 发表于 2024-4-9 08:41
软件搞得复杂了, 定时器中断服务函数里面调用按键中断服务函数. 这思路还是有问题. 按键中断可以直接响应其 ...

确实,您说的很有道理,我在思考下,谢谢您的回复
回复

使用道具 举报

22#
ID:1114858 发表于 2024-4-9 13:50 来自手机 | 只看该作者
xiaobendan001 发表于 2024-4-9 09:35
抱歉,上面代码16行里面那个tointer输入错误,应该是t0inter

谢谢您,我按照这个思路改了下确实可行,谢谢
回复

使用道具 举报

23#
ID:1114858 发表于 2024-4-9 13:51 来自手机 | 只看该作者
qq475878026 发表于 2024-4-9 09:19
加delay正常的话有可能是中断已经将按键执行两次判定了,然后主函数刚好将引脚反转两次,肉眼看不出来就 ...

这个问题我确实没考虑到,我回去试试看,谢谢您
回复

使用道具 举报

24#
ID:1109793 发表于 2024-4-9 14:06 | 只看该作者
下一站过后 发表于 2024-4-9 13:50
谢谢您,我按照这个思路改了下确实可行,谢谢

那么你根据这个改法,有没有思考到之前的代码的问题究竟出在哪儿?
回复

使用道具 举报

25#
ID:1114858 发表于 2024-4-9 22:32 | 只看该作者
xiaobendan001 发表于 2024-4-9 14:06
那么你根据这个改法,有没有思考到之前的代码的问题究竟出在哪儿?

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

使用道具 举报

26#
ID:1109793 发表于 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,或者液晶)放主循环自由运行,其他的都用状态或者直接放中断服务。
回复

使用道具 举报

27#
ID:1114858 发表于 2024-4-12 19:43 | 只看该作者
xiaobendan001 发表于 2024-4-10 07:44
我也只是分析,我觉得你增加delay或者使用4个if的结果是会影响到主循环的循环速度,当使用一个if包裹之后 ...

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

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表