找回密码
 立即注册

QQ登录

只需一步,快速开始

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

C51单片机键盘扫描程序异常,一次按下被判定为多次

[复制链接]
跳转到指定楼层
楼主
ID:1094415 发表于 2023-9-24 17:26 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
这是单片机实验,在这里我想用全局变量count来控制显示,但是一次按下后就被判定为按下了多次,而且行扫描停止了,大佬求教,代码还是电路哪里有问题,电路图用的是proteus。真心求教,看了一下午还是没找出问题。

单片机源程序如下:
  1. #include <reg51.h>
  2. #include <intrins.h>

  3. sbit P2_1=P2^1;
  4. sbit P2_0=P2^0;
  5. unsigned char discontrol[]={0xfe,0xfd,0xfb,0xf7};
  6. unsigned int buffer[]={-1,-1,-1,-1};
  7. unsigned code table[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};
  8. int count=0;

  9. void Delay(unsigned int x){
  10.         unsigned char t;
  11.         while(x--){
  12.         for(t=0;t<60;t++);
  13.         }
  14.         
  15. }





  16. unsigned char Keyscan(void){
  17.   int i,tmp,num=16;
  18.         unsigned char cflag=1;//cycling flag
  19.         for(i=0;i<4;i++){
  20.                 if(!cflag)
  21.                         break;
  22.          P1=_crol_(0xfe,i);
  23.          tmp=P1;
  24.          tmp=tmp&0xf0;
  25.                 if(tmp!=0xf0){
  26.                                 Delay(50);//prevent keyboard quiver
  27.                                 tmp=P1;
  28.                           tmp=tmp&0xf0;
  29.                                 if(tmp!=0xf0){//check angin
  30.                                         tmp=P1;
  31.                                         switch(tmp){
  32.                                                 case 0xee:num=0;break;
  33.                                                 case 0xde:num=1;break;
  34.                                                 case 0xbe:num=2;break;
  35.                                                 case 0x7e:num=3;break;
  36.                                                 case 0xed:num=4;break;
  37.                                                 case 0xdd:num=5;break;
  38.                                                 case 0xbd:num=6;break;
  39.                                                 case 0x7d:num=7;break;
  40.                                                 case 0xeb:num=8;break;
  41.                                                 case 0xdb:num=9;break;
  42.                                                 case 0xbb:num=10;break;
  43.                                                 case 0x7b:num=11;break;
  44.                                                 case 0xe7:num=12;break;
  45.                                                 case 0xd7:num=13;break;
  46.                                                 case 0xb7:num=14;break;
  47.                                                 case 0x77:num=15;break;
  48.                                                 default:break;
  49.                                 }
  50.                                         cflag=0;
  51.                                         while((tmp&0xf0)!=0xf0){//judge the up
  52.                                                 tmp=P1;
  53.                                         }
  54.                                 }
  55.                         
  56.                 }
  57.         }
  58. return num;
  59. }



  60. void main(){

  61.    int num,i;        
  62.         while(1){
  63.                 num=keyscan();
  64.                 if(num<16){
  65.                    if(count<4)//update count number
  66.                      count++;
  67.                         for( i=count-1;i>0;i--){//update buffer
  68.                                         buffer[i]=buffer[i-1];
  69.                                 }
  70.                    buffer[0]=num;
  71.                 }
  72.                 for( i=0;i<count;i++){//display
  73.                   P2=discontrol[i];//the outport set 0,other set 1
  74.                         P0=table[0];
  75.                         Delay(500);
  76.                 }

  77.         }
  78.         

  79. }

复制代码


exp2.rar

18.28 KB, 下载次数: 3

电路图,Proteus

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

使用道具 举报

沙发
ID:1094415 发表于 2023-9-24 19:00 | 只看该作者
本来在main函数中,调用keyscan后返回一次有效值,也就是按下一次按键后,count才会加一,但实际情况却是,按下一次后,count直接加1,加1,加1,变成了4
回复

使用道具 举报

板凳
ID:1094415 发表于 2023-9-24 19:03 | 只看该作者
异常情况描述,本来在main函数中,调用一次keyscan,只有当返回有效值,也就是按键按下后松开,count才会加1,但实际情况却是按下一次按键后,main函数中的while(1)循环进行了4次。keyscan中有通过延时进行键盘防抖,也有一个循环进行按键松开的检测,但就是不正常,我才疏学浅,找不出问题,请各位指教
回复

使用道具 举报

地板
ID:235200 发表于 2023-9-24 19:14 | 只看该作者
最好是把电路图和工程文件全部打包发上来,并说明PROTEUS使用的是哪个版本
回复

使用道具 举报

5#
ID:1094415 发表于 2023-9-24 20:08 | 只看该作者
这是全部文件,使用的是Proteus 8 Professional和Keil uVision5。

EXP2.rar

81.87 KB, 下载次数: 1

回复

使用道具 举报

6#
ID:1094415 发表于 2023-9-24 20:13 | 只看该作者
csmyldl 发表于 2023-9-24 19:14
最好是把电路图和工程文件全部打包发上来,并说明PROTEUS使用的是哪个版本

发在楼下了,  如果您有时间,能劳烦你指教
回复

使用道具 举报

7#
ID:1045456 发表于 2023-9-24 21:31 | 只看该作者
  P3=0xf0;
   time(10);
   if (P3==0xf0) SB=0;
   else
   {
    time(5);
    Beep = 0;
        SB=P3;
    P3=0x0f;
        time(5);
    if (P3==0x0f) SB=0;
    else
        {
    time(5);
    SB=SB|P3;
    time(5);
        }
        P3=0xf0;
     
         time(5);
        while (P3!=0xf0);
                switch (SB)
        {
     case 0xee : SB=1; break;
         case 0xde : SB=2; break;
         case 0xbe : SB=3; break;
     case 0x7e : SB=4; break;
         case 0xed : SB=5; break;
         case 0xdd : SB=6; break;
         case 0xbd : SB=7; break;
         case 0x7d : SB=8; break;
         case 0xeb : SB=9; break;
         case 0xdb : SB=10; break;
         case 0xbb : SB=11; break;
         case 0x7b : SB=12; break;
         case 0xe7 : SB=13; break;
         case 0xd7 : SB=14; break;
         case 0xb7 : SB=15; break;
         case 0x77 : SB=16; break;
     default:  ;
           }       


试一试以上代码
回复

使用道具 举报

8#
ID:1094415 发表于 2023-9-24 21:39 | 只看该作者
吴征 发表于 2023-9-24 21:31
P3=0xf0;
   time(10);
   if (P3==0xf0) SB=0;

请问不去要对按键抬起做判断吗,这样的话不会一次按下被多次判定吗
回复

使用道具 举报

9#
ID:1045456 发表于 2023-9-24 21:44 | 只看该作者
这个就是按键抬起做判断
回复

使用道具 举报

10#
ID:1045456 发表于 2023-9-24 21:46 | 只看该作者
        time(5);
        while (P3!=0xf0);


这个就是按键抬起做判断
回复

使用道具 举报

11#
ID:1045456 发表于 2023-9-24 21:49 | 只看该作者
半步成 发表于 2023-9-24 21:39
请问不去要对按键抬起做判断吗,这样的话不会一次按下被多次判定吗

       P3=0xf0;
     
         time(5);
        while (P3!=0xf0);
     
这个就是抬起判断

回复

使用道具 举报

12#
ID:1094415 发表于 2023-9-24 22:07 | 只看该作者
吴征 发表于 2023-9-24 21:49
P3=0xf0;
     
         time(5);

我试着替换了我的扫描函数,但还是不行,一次按键按下后,count就加到了4,我觉得应该不是扫描函数的问题,我这部分代码的逻辑和你差不多。最后还是谢谢你的帮助
回复

使用道具 举报

13#
ID:1094415 发表于 2023-9-24 22:20 | 只看该作者
吴征 发表于 2023-9-24 21:49
P3=0xf0;
     
         time(5);

问题解决了,键盘抬起也需要延时防抖,在抬起判断中,加入延时后就正常了
回复

使用道具 举报

14#
ID:1094415 发表于 2023-9-24 22:20 | 只看该作者
csmyldl 发表于 2023-9-24 19:14
最好是把电路图和工程文件全部打包发上来,并说明PROTEUS使用的是哪个版本

谢谢您的帮助,问题解决了,键盘抬起也需要延时防抖,在抬起判断中,加入延时后就正常了
回复

使用道具 举报

15#
ID:1094415 发表于 2023-9-24 22:20 | 只看该作者
吴征 发表于 2023-9-24 21:49
P3=0xf0;
     
         time(5);

还有,谢谢您的帮助
回复

使用道具 举报

16#
ID:1045456 发表于 2023-9-24 22:39 | 只看该作者
半步成 发表于 2023-9-24 22:20
还有,谢谢您的帮助

unsigned char Keyscan(void)
{
        unsigned char tmp,num=16;//cycling flag
         P1=_0xf0;
         Delay(50);//prevent keyboard quiver
         if(P1!=0xf0)
                 {
             tmp=P1;
             P1=_0x0f;
             Delay(50);//prevent keyboard quiver
             if(P1!=0x0f)   tmp |= P1;
             P1=_0xf0;
             Delay(50);//prevent keyboard quiver
             while (P1!=0xf0);
             switch(tmp)
                         {
                     case 0xee:num=0;break;
                     case 0xde:num=1;break;
                     case 0xbe:num=2;break;
                     case 0x7e:num=3;break;
                     case 0xed:num=4;break;
                     case 0xdd:num=5;break;
                     case 0xbd:num=6;break;
                     case 0x7d:num=7;break;
                     case 0xeb:num=8;break;
                     case 0xdb:num=9;break;
                     case 0xbb:num=10;break;
                     case 0x7b:num=11;break;
                     case 0xe7:num=12;break;
                     case 0xd7:num=13;break;
                     case 0xb7:num=14;break;
                     case 0x77:num=15;break;
                     default:break;
              }
        }
return num;
}


你试一试这个用你的原程诚序改的
回复

使用道具 举报

17#
ID:1094811 发表于 2023-9-29 11:50 | 只看该作者
建议用状态机的方式检测按键:(switch)
状态1-----有按键,转到2,无按键,等待
状态2-----判断按键是否稳定,稳定,到3,不稳定,回到1
状态3-----记录按下的时间,并检测松手,如果时间小于2-3秒检测到松手,到4,如果大于2-3秒,输出长按按键值,到4
状态4-----按键稳定松手,如果时间是短按的时间,清除记录的时间,输出短按按键值,回到1。如果是长按时间,回到1。按键如果是抖动,回到3.
回复

使用道具 举报

18#
ID:1097455 发表于 2023-10-27 13:42 | 只看该作者
按键消抖方式不对
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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