//实验效果:依次按下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);
}