本帖最后由 程鹏_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为第四列。
矩阵键盘扫描代码如下:
- //实验效果:依次按下S7~S19,倒数第四个数码管会依次显示0~F。
- //不足:所有按键在按下时那一刹那都会出现消隐的情况,若长按,数码管一直保持消隐状态,直至松手。
- #include
- #include
- #include
- void Delay5ms();
- void Delay10us();
- unsigned char smg_Pxdata[8]={0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01};//数码管片选数据,共有八片,为共阳极数码管。
- unsigned char smg_Dxdata[16]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e};//数码管段选数据,依次为0~f。
- int buzz();
- int smg(tem);
- int button();
- unsigned char num;//全局变量,使用于按键函数和数码管显示函数中。
- int main()
- {
- while(1)
- {
- buzz();
- button();
- smg(num);
- }
- return 0;
- }
- int buzz()
- {
- XBYTE[0xA000]=0;//关闭蜂鸣器。
- return 0;
- }
- int smg(tem)//数码管显示程序,和按键函数结合使用,用于判断按下哪个键。
- {
- XBYTE[0xC000]=0;//片选信号——消隐。
- Delay10us();
- XBYTE[0xE000]=smg_Dxdata[tem];//段选信号。
- XBYTE[0XC000]=smg_Pxdata[3];//片选信号——始终显示一片数码管。
- Delay10us();
- return 0;
- }
- int button()//P3.0~P3.3为行线,P3.4、P3.5、P4.2、P4.4为列线。
- {
- unsigned int key;
- P44=0,P42=1,P3=0x7f;//所有8个端口中,只令1个端口为低电平,若1个按键按下,那么肯定有另外1个端口会被拉低。因此,通过扫描就可以知道是哪个按键按下了。
- key=P3&0x0f;//和0x0f相与,让高四位在任何情况下始终为0000,也就是让case后的值始终是0x0****形式。
- P44=1,P42=0,P3=0xbf;
- key=(key<<4)|(P3&0x0f);//为保留上一行扫描的数据,故将数据左移4位。此处“P3&0x0f”是为了将高四位清0,进而再进行位运算时不会清除之前的数据。
- P44=1,P42=1,P3=0xdf;
- key=(key<<4)|(P3&0x0f);
- P44=1,P42=1,P3=0xef;
- key=(key<<4)|(P3&0x0f);
- if(((key&0x0f000)!=0x0f000)|((key&0x00f00)!=0x00f00)|((key&0x000f0)!=0x000f0)|((key&0x0000f)!=0x0000f))//通过位运算,提取出按下不同按键时各自独有的数据部分,并加以判断。
- {
- Delay5ms();//第一次消抖开始:消除按键前沿抖动,即按下抖动。
- P44=0,P42=1,P3=0x7f;
- key=P3&0x0f;
- P44=1,P42=0,P3=0xbf;
- key=(key<<4)|(P3&0x0f);
- P44=1,P42=1,P3=0xdf;
- key=(key<<4)|(P3&0x0f);
- P44=1,P42=1,P3=0xef;
- key=(key<<4)|(P3&0x0f);
- if(((key&0x0f000)!=0x0f000)|((key&0x00f00)!=0x00f00)|((key&0x000f0)!=0x000f0)|((key&0x0000f)!=0x0000f))
- {
- P44=0,P42=1,P3=0x7f;
- key=P3&0x0f;
- P44=1,P42=0,P3=0xbf;
- key=(key<<4)|(P3&0x0f);
- P44=1,P42=1,P3=0xdf;
- key=(key<<4)|(P3&0x0f);
- P44=1,P42=1,P3=0xef;
- key=(key<<4)|(P3&0x0f);//第一次消抖结束。
- switch(key)//开始判断key的值,并依此赋予num不同的值,然后将值传递给数码管显示函数。
- {
- case 0x0fffe:num=15;break;
- case 0x0fffd:num=14;break;
- case 0x0fffb:num=13;break;
- case 0x0fff7:num=12;break;
- case 0x0ffef:num=11;break;
- case 0x0ffdf:num=10;break;
- case 0x0ffbf:num=9;break;
- case 0x0ff7f:num=8;break;
- case 0x0feff:num=7;break;
- case 0x0fdff:num=6;break;
- case 0x0fbff:num=5;break;
- case 0x0f7ff:num=4;break;
- case 0x0eeee:num=3;break;//正确的代码应该是0x0efff 。
- case 0x0dddd:num=2;break;//正确的代码应该是0x0dfff。
- case 0x0bbbb:num=1;break; //正确的代码应该是0x0bfff 。
- case 0x07777:num=0;break;//正确的代码应该是0x07fff 。
- default://倘若有的按键按下没有达到预期效果,根据这个来判断key的值是否正确。
- {
- XBYTE[0x8000]=0xf5;//LED灯亮。
- Delay5ms();
- XBYTE[0x8000]=0xff;//LED灯灭。
- }
- }
- while (((key&0x0f000)!=0x0f000)|((key&0x00f00)!=0x00f00)|((key&0x000f0)!=0x000f0)|((key&0x0000f)!=0x0000f))//第二次消抖开始:消除后沿抖动,即松手抖动。
- {
- P44=0,P42=1,P3=0x7f;
- key=P3&0x0f;
- P44=1,P42=0,P3=0xbf;
- key=(key<<4)|(P3&0x0f);
- P44=1,P42=1,P3=0xdf;
- key=(key<<4)|(P3&0x0f);
- P44=1,P42=1,P3=0xef;
- key=(key<<4)|(P3&0x0f);
- }//第二次消抖结束。
- }
- }
- return 0;
- }
- void Delay5ms() //单片机内部晶振频率@11.0592MHz
- {
- unsigned char i, j;
- i = 54;
- j = 199;
- do
- {
- while (--j);
- } while (--i);
- }
- void Delay10us() //单片机内部晶振频率@11.0592MHz
- {
- unsigned char i;
- _nop_();
- i = 25;
- while (--i);
- }
复制代码
0
已退回2积分
|
2个回答
|
|
|