发 帖  
原厂入驻New
C语言编写的矩阵键盘程序为什么第一列的达成条件和后面三列不一样?
653 蓝桥杯 STC单片机 单片机编程 c语言
分享
本帖最后由 程鹏_3 于 2020-2-16 13:53 编辑

前序:
1.蓝桥杯相关。
2.上网查询了好几天,自己模仿写出来的矩阵键盘程序。
3.出现了和我想象中不一样的结果,原本第一列按键是无法按的,按照正确的代码(即“0x07fff”类型),后来我算错了,改成了“0x07777”类型,没想到居然可以实现!但是,后来又仔细思考了一下,发现我之前的算的结果错了。想了蛮久,,,,没想出为什么错误的代码可以得出正确的结果,,,于是发帖求助。




说明:
1.有原理图,原理图已上传,完整文件也已上传。
2.代码中有更为详细的说明。
3.num=0~num=3为第一列,num=4~num=7为第二列,num=8~num=11为第三列,num=12~num=15为第四列。

矩阵键盘扫描代码如下:
  1. //实验效果:依次按下S7~S19,倒数第四个数码管会依次显示0~F。
  2. //不足:所有按键在按下时那一刹那都会出现消隐的情况,若长按,数码管一直保持消隐状态,直至松手。
  3. #include<stc15f2k60s2.h>
  4. #include<intrins.h>
  5. #include<absacc.h>
  6. void Delay5ms();
  7. void Delay10us();
  8. unsigned char smg_Pxdata[8]={0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01};//数码管片选数据,共有八片,为共阳极数码管。
  9. unsigned char smg_Dxdata[16]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e};//数码管段选数据,依次为0~f。
  10. int buzz();
  11. int smg(tem);
  12. int button();
  13. unsigned char num;//全局变量,使用于按键函数和数码管显示函数中。
  14. int main()
  15. {
  16.         while(1)
  17.         {
  18.                 buzz();
  19.                 button();
  20.                 smg(num);
  21.         }
  22.         return 0;
  23. }
  24. int buzz()
  25. {
  26.         XBYTE[0xA000]=0;//关闭蜂鸣器
  27.         return 0;
  28. }
  29. int smg(tem)//数码管显示程序,和按键函数结合使用,用于判断按下哪个键。
  30. {
  31.         XBYTE[0xC000]=0;//片选信号——消隐。
  32.         Delay10us();
  33.         XBYTE[0xE000]=smg_Dxdata[tem];//段选信号。
  34.         XBYTE[0XC000]=smg_Pxdata[3];//片选信号——始终显示一片数码管。
  35.         Delay10us();
  36.         return 0;
  37. }
  38. int button()//P3.0~P3.3为行线,P3.4、P3.5、P4.2、P4.4为列线。
  39. {
  40.         unsigned int key;
  41.         P44=0,P42=1,P3=0x7f;//所有8个端口中,只令1个端口为低电平,若1个按键按下,那么肯定有另外1个端口会被拉低。因此,通过扫描就可以知道是哪个按键按下了。
  42.         key=P3&0x0f;//和0x0f相与,让高四位在任何情况下始终为0000,也就是让case后的值始终是0x0****形式。
  43.         P44=1,P42=0,P3=0xbf;
  44.         key=(key<<4)|(P3&0x0f);//为保留上一行扫描的数据,故将数据左移4位。此处“P3&0x0f”是为了将高四位清0,进而再进行位运算时不会清除之前的数据。
  45.         P44=1,P42=1,P3=0xdf;
  46.         key=(key<<4)|(P3&0x0f);
  47.         P44=1,P42=1,P3=0xef;
  48.         key=(key<<4)|(P3&0x0f);
  49.         IF(((key&0x0f000)!=0x0f000)|((key&0x00f00)!=0x00f00)|((key&0x000f0)!=0x000f0)|((key&0x0000f)!=0x0000f))//通过位运算,提取出按下不同按键时各自独有的数据部分,并加以判断。
  50.         {
  51.                 Delay5ms();//第一次消抖开始:消除按键前沿抖动,即按下抖动。
  52.                 P44=0,P42=1,P3=0x7f;
  53.                 key=P3&0x0f;
  54.                 P44=1,P42=0,P3=0xbf;
  55.                 key=(key<<4)|(P3&0x0f);
  56.                 P44=1,P42=1,P3=0xdf;
  57.                 key=(key<<4)|(P3&0x0f);
  58.                 P44=1,P42=1,P3=0xef;
  59.                 key=(key<<4)|(P3&0x0f);
  60.                 if(((key&0x0f000)!=0x0f000)|((key&0x00f00)!=0x00f00)|((key&0x000f0)!=0x000f0)|((key&0x0000f)!=0x0000f))
  61.                 {
  62.                         P44=0,P42=1,P3=0x7f;
  63.                         key=P3&0x0f;
  64.                         P44=1,P42=0,P3=0xbf;
  65.                         key=(key<<4)|(P3&0x0f);
  66.                         P44=1,P42=1,P3=0xdf;
  67.                         key=(key<<4)|(P3&0x0f);
  68.                         P44=1,P42=1,P3=0xef;
  69.                         key=(key<<4)|(P3&0x0f);//第一次消抖结束。
  70.                         switch(key)//开始判断key的值,并依此赋予num不同的值,然后将值传递给数码管显示函数。
  71.                         {
  72.                                 case 0x0fffe:num=15;break;
  73.                                 case 0x0fffd:num=14;break;
  74.                                 case 0x0fffb:num=13;break;
  75.                                 case 0x0fff7:num=12;break;
  76.                                 case 0x0ffef:num=11;break;
  77.                                 case 0x0ffdf:num=10;break;
  78.                                 case 0x0ffbf:num=9;break;
  79.                                 case 0x0ff7f:num=8;break;
  80.                                 case 0x0feff:num=7;break;
  81.                                 case 0x0fdff:num=6;break;
  82.                                 case 0x0fbff:num=5;break;
  83.                                 case 0x0f7ff:num=4;break;
  84.                                 case 0x0eeee:num=3;break;//正确的代码应该是0x0efff 。
  85.                                 case 0x0dddd:num=2;break;//正确的代码应该是0x0dfff。
  86.                                 case 0x0bbbb:num=1;break; //正确的代码应该是0x0bfff  。
  87.                                 case 0x07777:num=0;break;//正确的代码应该是0x07fff 。
  88.                                 default://倘若有的按键按下没有达到预期效果,根据这个来判断key的值是否正确。
  89.                                 {
  90.                                                 XBYTE[0x8000]=0xf5;//LED灯亮。
  91.                                                 Delay5ms();
  92.                                                 XBYTE[0x8000]=0xff;//LED灯灭。
  93.                                 }
  94.                         }
  95.                         while (((key&0x0f000)!=0x0f000)|((key&0x00f00)!=0x00f00)|((key&0x000f0)!=0x000f0)|((key&0x0000f)!=0x0000f))//第二次消抖开始:消除后沿抖动,即松手抖动。
  96.                         {
  97.                         P44=0,P42=1,P3=0x7f;
  98.                         key=P3&0x0f;
  99.                         P44=1,P42=0,P3=0xbf;
  100.                         key=(key<<4)|(P3&0x0f);
  101.                         P44=1,P42=1,P3=0xdf;
  102.                         key=(key<<4)|(P3&0x0f);
  103.                         P44=1,P42=1,P3=0xef;
  104.                         key=(key<<4)|(P3&0x0f);
  105.                         }//第二次消抖结束。
  106.                 }
  107.         }
  108.         return 0;
  109. }
  110.         void Delay5ms()                //单片机内部晶振频率@11.0592MHz
  111. {
  112.         unsigned char i, j;

  113.         i = 54;
  114.         j = 199;
  115.         do
  116.         {
  117.                 while (--j);
  118.         } while (--i);
  119. }
  120. void Delay10us()                //单片机内部晶振频率@11.0592MHz
  121. {
  122.         unsigned char i;

  123.         _nop_();
  124.         i = 25;
  125.         while (--i);
  126. }
复制代码


0

数码管原理图

数码管原理图

驱动部分原理图

驱动部分原理图

矩阵键盘原理图

矩阵键盘原理图

单片机原理图

单片机原理图

1.国信长天单片机竞赛平台V20原理图 - 副本.pdf

下载积分: 积分 -1 分

175.19 KB, 下载次数: 112, 下载积分: 积分 -1 分

奖励2积分
2020-2-15 23:51:54   评论 分享淘帖 邀请回答
2个回答
卧槽!!!解决了!!!原因是因为我J5短接帽接到独立键盘那里去了!!!!!刚刚调试单片机的时候无意中看到了!!卧槽!!!!!!我TM可是想了一天没想出来为什么!!!!!!卧槽!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
这个代码是没啥问题的。这个代码与网上大部分代码不一样的是,这个代码加了去抖动部分。大家只要把第一列的代码改成正确的代码,弄好短接帽,就可以正常运行了!
这个帖子就供大家参考吧。
2020-2-16 13:50:38 2 评论

举报

2 条评论
给你写了一个异组非顺序端口4*4矩阵按键示例,完全可以移植到你的程序中,可以消除按键干扰数码管显示,并大幅简化代码。仿真没有P4,用P2代替。
无标题.jpg
  1. #include <STC15F2K60S2.H>
  2. #define uint unsigned int
  3. #define uchar unsigned char
  4. #define PD ((P2<<3&0x80)|(P2<<4&0x40)|(P3&0x3f))//P4.4/P4.2

  5. sbit dula=P2^6;                        //573段选
  6. sbit wela=P2^7;                        //573位选

  7. uchar code table[]={                //数组
  8.         0x3f,0x06,0x5b,0x4f,
  9.         0x66,0x6d,0x7d,0x07,
  10.         0x7f,0x6f,0x77,0x7c,
  11.         0x39,0x5e,0x79,0x71};
  12. uchar data dis_buf[2];
  13. uchar key=0;
  14. bit wei=0;

  15. void PX(uchar x)
  16. {
  17.         P3&=0xc0;                //低6位清0,P36、37不变
  18.         P3|=(x&0x3f);        //P3低6位赋值
  19.         P2&=0xeb;                //P44、42清0,其它位不变
  20.         P2|=((x>>3&0x10)|(x>>4&0x04));//P44、42赋值
  21. }
  22. void keyscan()                                        //按键扫描程序
  23. {
  24.         static bit sign=0;                        //按键自锁标志
  25.         static uint count=0;                //消抖计数变量                       
  26.         uchar num=0;                                        //临时变量
  27.         PX(0xf0);                                        //赋值PX 1111 0000
  28.         if(PD!=0xf0)                                //检测有按键按下
  29.         {
  30.                 if((++count>=100)&&(sign==0))        //100~1000,根据主循环周期调整约10~20ms
  31.                 {                       
  32.                         sign=1;                                //按键自锁标志置1
  33.                         num=PD;                                //保存PD值xxxx 0000,x为0或1
  34.                         num|=0x0f;                        //保存num按位或0x0f值xxxx 1111
  35.                         PX(num);                                //赋值PX xxxx 1111
  36.                         num=PD;                                //保存PD xxxx xxxx
  37.                         switch(num)
  38.                         {
  39.                                 case 0xee: key= 1; break;
  40.                                 case 0xde: key= 2; break;
  41.                                 case 0xbe: key= 3; break;
  42.                                 case 0x7e: key= 4; break;
  43.                                 case 0xed: key= 5; break;
  44.                                 case 0xdd: key= 6; break;
  45.                                 case 0xbd: key= 7; break;
  46.                                 case 0x7d: key= 8; break;
  47.                                 case 0xeb: key= 9; break;
  48.                                 case 0xdb: key=10; break;
  49.                                 case 0xbb: key=11; break;
  50.                                 case 0x7b: key=12; break;
  51.                                 case 0xe7: key=13; break;
  52.                                 case 0xd7: key=14; break;
  53.                                 case 0xb7: key=15; break;
  54.                                 case 0x77: key=16; break;
  55.                         }
  56.                 }
  57.         }
  58.         else                                                //键抬起
  59.         {
  60.                 sign=0;                                //按键自锁标志清0
  61.                 count=0;                                //消抖计数清0
  62.         }
  63. }

  64. int main()
  65. {
  66.         while(1)
  67.         {
  68.                 keyscan();
  69.                 dis_buf[0]=table[key/10];
  70.                 dis_buf[1]=table[key%10];
  71.                 P0=0x00;//消隐
  72.                 dula=1;
  73.                 dula=0;
  74.                 if(wei==0)
  75.                 {
  76.                         P0=0xfe;//送位码
  77.                         wela=1;
  78.                         wela=0;
  79.                         P0=dis_buf[0];//送段码
  80.                         dula=1;
  81.                         dula=0;
  82.                         wei=1;
  83.                 }
  84.                 else
  85.                 {
  86.                         P0=0xfd;
  87.                         wela=1;
  88.                         wela=0;
  89.                         P0=dis_buf[1];
  90.                         dula=1;
  91.                         dula=0;
  92.                         wei=0;
  93.                 }
  94.         }
  95. }
复制代码


评分

参与人数 1积分 +2 收起 理由
程鹏_3 + 2 多谢哥们,这期间在上网课,代码我以后研究。

查看全部评分

2020-2-17 21:08:01 评论

举报

撰写答案

你正在撰写答案

如果你是对答案或其他答案精选点评或询问,请使用“评论”功能。

高级模式
您需要登录后才可以回帖 登录 | 注册

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容图片侵权或者其他问题,请联系本站作侵删。 侵权投诉
我要提问
关闭

站长推荐 上一条 /7 下一条

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