/***12个按键,每一个按键都会让蜂鸣器发出“嘀”的一声***/
#include "REG52.H"
#define const_voice_short 40
#define const_key_time 20
#define const_voice_short 40
#define const_key_time 20
void initial_myself();
void initial_peripheral();
void delay_long(unsigned int uiDelaylong);
void T0_time();
void key_service();
void key_scan();
sbit key_sr1=P0^1; //第一行输入
sbit key_sr2=P0^2; //第二行输入
sbit key_sr3=P0^3; //第三行输入
void initial_peripheral();
void delay_long(unsigned int uiDelaylong);
void T0_time();
void key_service();
void key_scan();
sbit key_sr1=P0^1; //第一行输入
sbit key_sr2=P0^2; //第二行输入
sbit key_sr3=P0^3; //第三行输入
sbit key_dr1=P0^4; //第一列输出
sbit key_dr2=P0^5; //第二列输出
sbit key_dr3=P0^6; //第三列输出
sbit key_dr4=P0^7; //第四列输出
sbit key_dr2=P0^5; //第二列输出
sbit key_dr3=P0^6; //第三列输出
sbit key_dr4=P0^7; //第四列输出
sbit beep_dr=P1^5;
unsigned char ucKeyStep=1; //按键扫描步骤变量
unsigned char ucKeySec=0; //被触发的按键编号
unsigned int uiKeyTimeCnt=0; //按键去抖动延时计数器
unsigned char ucKeyLock=0; //按键触发后自锁的变量标志
unsigned int uiVoiceCnt=0; //蜂鸣器鸣叫的时间计数器
unsigned char ucKeySec=0; //被触发的按键编号
unsigned int uiKeyTimeCnt=0; //按键去抖动延时计数器
unsigned char ucKeyLock=0; //按键触发后自锁的变量标志
unsigned int uiVoiceCnt=0; //蜂鸣器鸣叫的时间计数器
void main()
{
initial_myself();
delay_long(100);
initial_peripheral();
while(1)
{
key_service();
}
}
{
initial_myself();
delay_long(100);
initial_peripheral();
while(1)
{
key_service();
}
}
void key_scan() //按键扫描函数,放到定时中断里
{
/*
按键扫描的详细过程:
先输出某一列低电平,其他三列输出高电平,这个时候再分别判断输入的三行,
如果发现哪一行是低电平,就说明对应的某个按键被触发。
依次分别输出另外三列中的某一列为低电平,再分别判断输入的三行,就可以检测完12个按键。
*/
switch(ucKeyStep)
{
case 1: //按键扫描,输出的第一列为低电平
key_dr1=0;
key_dr2=1;
key_dr3=1;
key_dr4=1;
uiKeyTimeCnt=0; //延时计数器清零
ucKeyStep++; //切换到下一个运行步骤
break;
case 2: //此处的小延时用来等待刚才列输出信号稳定,再判断输入信号。不是去抖动延时
uiKeyTimeCnt++;
if(uiKeyTimeCnt>1)
{
uiKeyTimeCnt=0;
ucKeyStep++; //切换到下一个运行步骤
}
break;
case 3:
if(key_sr1==1&&key_sr2==1&&key_sr3==1)
{
ucKeyStep++; //如果没有按键按下,切换到下一个运行步骤
ucKeyLock=0; //按键自锁标志清零
uiKeyTimeCnt=0; //按键去抖动延时清零,此行非常巧妙
}
else if(ucKeyLock==0) //如果有按键按下,且是第一次触发
{
if(key_sr1==0&&key_sr2==1&&key_sr3==1)
{
uiKeyTimeCnt++; //去抖动延时
if(uiKeyTimeCnt>const_key_time)
{
uiKeyTimeCnt=0;
ucKeyLock=1; //自锁标志置位,以免一直触发,只有松开按键,此标志位才会被清零
ucKeySec=1; //触发1号键
}
}
else if(key_sr1==1&&key_sr2==0&&key_sr3==1)
{
uiKeyTimeCnt++; //去抖动延时
if(uiKeyTimeCnt>const_key_time)
{
uiKeyTimeCnt=0;
ucKeyLock=1; //自锁标志置位,以免一直触发,只有松开按键,此标志位才会被清零
ucKeySec=5; //触发5号键
}
}
else if(key_sr1==1&&key_sr2==1&&key_sr3==0)
{
uiKeyTimeCnt++; //去抖动延时
if(uiKeyTimeCnt>const_key_time)
{
uiKeyTimeCnt=0;
ucKeyLock=1; //自锁标志置位,以免一直触发,只有松开按键,此标志位才会被清零
ucKeySec=9; //触发9号键
}
}
}
break;
case 4: //按键扫描输出第二列低电平
key_dr1=1;
key_dr2=0;
key_dr3=1;
key_dr4=1;
uiKeyTimeCnt=0;
ucKeyStep++;
break;
case 5:
uiKeyTimeCnt++;
if(uiKeyTimeCnt>1)
{
uiKeyTimeCnt=0;
ucKeyStep++;
}
break;
case 6:
if(key_sr1==1&&key_sr2==1&&key_sr3==1)
{
ucKeyStep++;
ucKeyLock=0;
uiKeyTimeCnt=0;
}
else if(ucKeyLock==0)
{
if(key_sr1==0&&key_sr2==1&&key_sr3==1)
{
uiKeyTimeCnt++;
if(uiKeyTimeCnt>const_key_time)
{
uiKeyTimeCnt=0;
ucKeyLock=1;
ucKeySec=2;
}
}
else if(key_sr1==1&&key_sr2==0&&key_sr3==1)
{
uiKeyTimeCnt++;
if(uiKeyTimeCnt>const_key_time)
{
uiKeyTimeCnt=0;
ucKeyLock=1;
ucKeySec=6;
}
}
if(key_sr1==1&&key_sr2==1&&key_sr3==0)
{
uiKeyTimeCnt++;
if(uiKeyTimeCnt>const_key_time)
{
uiKeyTimeCnt=0;
ucKeyLock=1;
ucKeySec=10;
}
}
}
break;
case 7: //按键扫描输出第三列低电平
key_dr1=1;
key_dr2=1;
key_dr3=0;
key_dr4=1;
uiKeyTimeCnt=0;
ucKeyStep++;
break;
case 8:
uiKeyTimeCnt++;
if(uiKeyTimeCnt>1)
{
uiKeyTimeCnt=0;
ucKeyStep++;
}
break;
case 9:
if(key_sr1==1&&key_sr2==1&&key_sr3==1)
{
ucKeyStep++;
ucKeyLock=0;
uiKeyTimeCnt=0;
}
else if(ucKeyLock==0)
{
if(key_sr1==0&&key_sr2==1&&key_sr3==1)
{
uiKeyTimeCnt++;
if(uiKeyTimeCnt>const_key_time)
{
uiKeyTimeCnt=0;
ucKeyLock=1;
ucKeySec=3;
}
}
else if(key_sr1==1&&key_sr2==0&&key_sr3==1)
{
uiKeyTimeCnt++;
if(uiKeyTimeCnt>const_key_time)
{
uiKeyTimeCnt=0;
ucKeyLock=1;
ucKeySec=7;
}
}
else if(key_sr1==1&&key_sr2==1&&key_sr3==0)
{
uiKeyTimeCnt++;
if(uiKeyTimeCnt>const_key_time)
{
uiKeyTimeCnt=0;
ucKeyLock=1;
ucKeySec=11;
}
}
}
break;
case 10: //按键扫描输出第四列低电平
key_dr1=1;
key_dr2=1;
key_dr3=1;
key_dr4=0;
uiKeyTimeCnt=0;
ucKeyStep++;
break;
case 11:
uiKeyTimeCnt++;
if(uiKeyTimeCnt>1)
{
uiKeyTimeCnt=0;
ucKeyStep++;
}
break;
case 12:
if(key_sr1==1&&key_sr2==1&&key_sr3==1)
{
ucKeyStep=1; //如果没有按键按下,返回到第一步,重新开始扫描
ucKeyLock=0; //按键自锁标志清零
uiKeyTimeCnt=0;
}
else if(ucKeyLock==0)
{
if(key_sr1==0&&key_sr2==1&&key_sr3==1)
{
uiKeyTimeCnt++;
if(uiKeyTimeCnt>const_key_time)
{
uiKeyTimeCnt=0;
ucKeyLock=1;
ucKeySec=4;
}
}
else if(key_sr1==1&&key_sr2==0&&key_sr3==1)
{
uiKeyTimeCnt++;
if(uiKeyTimeCnt>const_key_time)
{
uiKeyTimeCnt=0;
ucKeyLock=1;
ucKeySec=8;
}
}
else if(key_sr1==1&&key_sr2==1&&key_sr3==0)
{
uiKeyTimeCnt++;
if(uiKeyTimeCnt>const_key_time)
{
uiKeyTimeCnt=0;
ucKeyLock=1;
ucKeySec=12;
}
}
}
break;
}
}
{
/*
按键扫描的详细过程:
先输出某一列低电平,其他三列输出高电平,这个时候再分别判断输入的三行,
如果发现哪一行是低电平,就说明对应的某个按键被触发。
依次分别输出另外三列中的某一列为低电平,再分别判断输入的三行,就可以检测完12个按键。
*/
switch(ucKeyStep)
{
case 1: //按键扫描,输出的第一列为低电平
key_dr1=0;
key_dr2=1;
key_dr3=1;
key_dr4=1;
uiKeyTimeCnt=0; //延时计数器清零
ucKeyStep++; //切换到下一个运行步骤
break;
case 2: //此处的小延时用来等待刚才列输出信号稳定,再判断输入信号。不是去抖动延时
uiKeyTimeCnt++;
if(uiKeyTimeCnt>1)
{
uiKeyTimeCnt=0;
ucKeyStep++; //切换到下一个运行步骤
}
break;
case 3:
if(key_sr1==1&&key_sr2==1&&key_sr3==1)
{
ucKeyStep++; //如果没有按键按下,切换到下一个运行步骤
ucKeyLock=0; //按键自锁标志清零
uiKeyTimeCnt=0; //按键去抖动延时清零,此行非常巧妙
}
else if(ucKeyLock==0) //如果有按键按下,且是第一次触发
{
if(key_sr1==0&&key_sr2==1&&key_sr3==1)
{
uiKeyTimeCnt++; //去抖动延时
if(uiKeyTimeCnt>const_key_time)
{
uiKeyTimeCnt=0;
ucKeyLock=1; //自锁标志置位,以免一直触发,只有松开按键,此标志位才会被清零
ucKeySec=1; //触发1号键
}
}
else if(key_sr1==1&&key_sr2==0&&key_sr3==1)
{
uiKeyTimeCnt++; //去抖动延时
if(uiKeyTimeCnt>const_key_time)
{
uiKeyTimeCnt=0;
ucKeyLock=1; //自锁标志置位,以免一直触发,只有松开按键,此标志位才会被清零
ucKeySec=5; //触发5号键
}
}
else if(key_sr1==1&&key_sr2==1&&key_sr3==0)
{
uiKeyTimeCnt++; //去抖动延时
if(uiKeyTimeCnt>const_key_time)
{
uiKeyTimeCnt=0;
ucKeyLock=1; //自锁标志置位,以免一直触发,只有松开按键,此标志位才会被清零
ucKeySec=9; //触发9号键
}
}
}
break;
case 4: //按键扫描输出第二列低电平
key_dr1=1;
key_dr2=0;
key_dr3=1;
key_dr4=1;
uiKeyTimeCnt=0;
ucKeyStep++;
break;
case 5:
uiKeyTimeCnt++;
if(uiKeyTimeCnt>1)
{
uiKeyTimeCnt=0;
ucKeyStep++;
}
break;
case 6:
if(key_sr1==1&&key_sr2==1&&key_sr3==1)
{
ucKeyStep++;
ucKeyLock=0;
uiKeyTimeCnt=0;
}
else if(ucKeyLock==0)
{
if(key_sr1==0&&key_sr2==1&&key_sr3==1)
{
uiKeyTimeCnt++;
if(uiKeyTimeCnt>const_key_time)
{
uiKeyTimeCnt=0;
ucKeyLock=1;
ucKeySec=2;
}
}
else if(key_sr1==1&&key_sr2==0&&key_sr3==1)
{
uiKeyTimeCnt++;
if(uiKeyTimeCnt>const_key_time)
{
uiKeyTimeCnt=0;
ucKeyLock=1;
ucKeySec=6;
}
}
if(key_sr1==1&&key_sr2==1&&key_sr3==0)
{
uiKeyTimeCnt++;
if(uiKeyTimeCnt>const_key_time)
{
uiKeyTimeCnt=0;
ucKeyLock=1;
ucKeySec=10;
}
}
}
break;
case 7: //按键扫描输出第三列低电平
key_dr1=1;
key_dr2=1;
key_dr3=0;
key_dr4=1;
uiKeyTimeCnt=0;
ucKeyStep++;
break;
case 8:
uiKeyTimeCnt++;
if(uiKeyTimeCnt>1)
{
uiKeyTimeCnt=0;
ucKeyStep++;
}
break;
case 9:
if(key_sr1==1&&key_sr2==1&&key_sr3==1)
{
ucKeyStep++;
ucKeyLock=0;
uiKeyTimeCnt=0;
}
else if(ucKeyLock==0)
{
if(key_sr1==0&&key_sr2==1&&key_sr3==1)
{
uiKeyTimeCnt++;
if(uiKeyTimeCnt>const_key_time)
{
uiKeyTimeCnt=0;
ucKeyLock=1;
ucKeySec=3;
}
}
else if(key_sr1==1&&key_sr2==0&&key_sr3==1)
{
uiKeyTimeCnt++;
if(uiKeyTimeCnt>const_key_time)
{
uiKeyTimeCnt=0;
ucKeyLock=1;
ucKeySec=7;
}
}
else if(key_sr1==1&&key_sr2==1&&key_sr3==0)
{
uiKeyTimeCnt++;
if(uiKeyTimeCnt>const_key_time)
{
uiKeyTimeCnt=0;
ucKeyLock=1;
ucKeySec=11;
}
}
}
break;
case 10: //按键扫描输出第四列低电平
key_dr1=1;
key_dr2=1;
key_dr3=1;
key_dr4=0;
uiKeyTimeCnt=0;
ucKeyStep++;
break;
case 11:
uiKeyTimeCnt++;
if(uiKeyTimeCnt>1)
{
uiKeyTimeCnt=0;
ucKeyStep++;
}
break;
case 12:
if(key_sr1==1&&key_sr2==1&&key_sr3==1)
{
ucKeyStep=1; //如果没有按键按下,返回到第一步,重新开始扫描
ucKeyLock=0; //按键自锁标志清零
uiKeyTimeCnt=0;
}
else if(ucKeyLock==0)
{
if(key_sr1==0&&key_sr2==1&&key_sr3==1)
{
uiKeyTimeCnt++;
if(uiKeyTimeCnt>const_key_time)
{
uiKeyTimeCnt=0;
ucKeyLock=1;
ucKeySec=4;
}
}
else if(key_sr1==1&&key_sr2==0&&key_sr3==1)
{
uiKeyTimeCnt++;
if(uiKeyTimeCnt>const_key_time)
{
uiKeyTimeCnt=0;
ucKeyLock=1;
ucKeySec=8;
}
}
else if(key_sr1==1&&key_sr2==1&&key_sr3==0)
{
uiKeyTimeCnt++;
if(uiKeyTimeCnt>const_key_time)
{
uiKeyTimeCnt=0;
ucKeyLock=1;
ucKeySec=12;
}
}
}
break;
}
}
void key_service() //第三区,按键服务应用程序
{
switch(ucKeySec)
{
case 1:
uiVoiceCnt=const_voice_short;
ucKeySec=0;
break;
case 2:
uiVoiceCnt=const_voice_short;
ucKeySec=0;
break;
case 3:
uiVoiceCnt=const_voice_short;
ucKeySec=0;
break;
case 4:
uiVoiceCnt=const_voice_short;
ucKeySec=0;
break;
case 5:
uiVoiceCnt=const_voice_short;
ucKeySec=0;
break;
case 6:
uiVoiceCnt=const_voice_short;
ucKeySec=0;
break;
case 7:
uiVoiceCnt=const_voice_short;
ucKeySec=0;
break;
case 8:
uiVoiceCnt=const_voice_short;
ucKeySec=0;
break;
case 9:
uiVoiceCnt=const_voice_short;
ucKeySec=0;
break;
case 10:
uiVoiceCnt=const_voice_short;
ucKeySec=0;
break;
case 11:
uiVoiceCnt=const_voice_short;
ucKeySec=0;
break;
case 12:
uiVoiceCnt=const_voice_short;
ucKeySec=0;
break;
}
}
{
switch(ucKeySec)
{
case 1:
uiVoiceCnt=const_voice_short;
ucKeySec=0;
break;
case 2:
uiVoiceCnt=const_voice_short;
ucKeySec=0;
break;
case 3:
uiVoiceCnt=const_voice_short;
ucKeySec=0;
break;
case 4:
uiVoiceCnt=const_voice_short;
ucKeySec=0;
break;
case 5:
uiVoiceCnt=const_voice_short;
ucKeySec=0;
break;
case 6:
uiVoiceCnt=const_voice_short;
ucKeySec=0;
break;
case 7:
uiVoiceCnt=const_voice_short;
ucKeySec=0;
break;
case 8:
uiVoiceCnt=const_voice_short;
ucKeySec=0;
break;
case 9:
uiVoiceCnt=const_voice_short;
ucKeySec=0;
break;
case 10:
uiVoiceCnt=const_voice_short;
ucKeySec=0;
break;
case 11:
uiVoiceCnt=const_voice_short;
ucKeySec=0;
break;
case 12:
uiVoiceCnt=const_voice_short;
ucKeySec=0;
break;
}
}
void T0_time() interrupt 1
{
TF0=0;
TR0=0;
key_scan();
if(uiVoiceCnt!=0)
{
uiVoiceCnt--;
beep_dr=0;
}
else
{
;
beep_dr=1;
}
TH0=0xf8;
TL0=0x2f;
TR0=1;
}
{
TF0=0;
TR0=0;
key_scan();
if(uiVoiceCnt!=0)
{
uiVoiceCnt--;
beep_dr=0;
}
else
{
;
beep_dr=1;
}
TH0=0xf8;
TL0=0x2f;
TR0=1;
}
void delay_long(unsigned int uiDelayLong)
{
unsigned int i;
unsigned int j;
for(i=0;i<uiDelayLong;i++)
for(j=0;j<500;j++)
;
}
{
unsigned int i;
unsigned int j;
for(i=0;i<uiDelayLong;i++)
for(j=0;j<500;j++)
;
}
void initial_myself() //第一区,初始化单片机
{
beep_dr=1;
TMOD=0x01; //设定 定时器0 工作方式 1
TH0=0xf8; //重装初始值(65535-2000)=63535=0xf82f
TL0=0x2f;
}
{
beep_dr=1;
TMOD=0x01; //设定 定时器0 工作方式 1
TH0=0xf8; //重装初始值(65535-2000)=63535=0xf82f
TL0=0x2f;
}
void initial_peripheral() //第二区,初始化外围
{
EA=1;
ET0=1;
TR0=1;
}
{
EA=1;
ET0=1;
TR0=1;
}