程序思路来自于网络,感谢大佬的开源,点击我即可跳转原网页
定时器初始化函数:设置单片机的定时器工作模式,用来做按键扫描的延时,代替delay延时,释放单片机的资源,定时器设置为12分频用来兼容传统的8051单片机,方便程序移植,更改头文件即可直接运行。
/*定时器0初始化函数*/
void TimeStart() //定时器初始化
{
EA = 1; //打开总中断
ET0 = 1; //打开定时器0中断
TR0 = 1; //打开定时器0
TMOD = 0X01; //设置定时器0为工作模式1 16位定时器模式
TH0 = 0XED;
TL0 = 0XFF; //定时5毫秒
}
按键检测函数:通过定时器去扫描按键的状态,原理都在程序注释里面。
第一步:创建一个局部的静态变量,用来表示按键扫描到哪一个步骤了,变量的初始值为0x00。
第二步:判断按键1是否被按下,如果被按下,就把之前创建的静态变量改为0x01,等待下次计时到后执行消抖。
第三步:定时器定时10毫秒到后调用函数,再次判断按键是否被按下(第二次判断为按键消抖),一、如果按键确实被按下,就开始计数,然后把变量改为0x02,进行下一步判断按键是长按还是短按。二、否则就判断为已经抬起,变量改为0x00。
第三步:定时器定时10毫秒又到后再次调用函数,一、判断这时按键的状态是否为弹起,如果是那么就判断为短按,执行LED1的状态反转一次,将变量改为0x00。二、如果按键按下状态超过250毫秒,那么就执行LED3的状态反转一次,变量改为0x03。
第四步:定时器定时10毫秒又到后再次调用函数,判断按键是否已经松开,如果是,那么就将变量的状态改为0x00。
/*按键1 单击 长按 检测函数*/
void KEYS1() //按键1扫描函数
{
static uchar num = 0; //局部静态变量
switch(num)
{
case 0x00: if(KEY_S1 == 0) //判断按键1是否被按下
{
num = 0x01; //跳转到第二条语句 消抖
}
break; //跳出循环
case 0x01: if(KEY_S1 == 0) //再次判断按键是否被按下
{
key_time_s1 = 0; //开始计数
num = 0x02; //跳转到第三条语句 判断单击或者长按
}
else //否则判断为毛刺
{
num = 0x00; //跳转到第一条语句 等待下次触发
}
break; //跳出循环
case 0x02: if(KEY_S1 == 1) //判断是否松手
{
LED1 =~ LED1; //跳转到第一条语句,等待下次按键按下
num = 0x00; //跳转到第一条语句 判断为单击按键
}
else if(++key_time_s1 >= 50) //如果计时的时间超过250毫秒则判断为长按
{
LED3 =~ LED3; //执行LED3状态反转一次
num = 0x03; //跳转到第4条语句 松手检测
}
break; //跳出循环
case 0x03: if(KEY_S1 == 1) //如果按键松开
{
num = 0x00; //跳转到第一条语句 等待下次按键被按下
}
break; //跳出循环
default: break;
}
}
定时器0中断处理函数:
定义一个时间标志位来计算定时器的计时时间。
当定时器0进中断一次标志位就加1,表示计时了5毫秒,如果标志位加到2,就表示10毫秒计时时间到了,然后执行一次按键扫描函数。
/*定时器0中断处理函数*/
void Timer0()interrupt 1
{
static uchar i; //时间标志位 用来计算定时时间
TH0 = 0XED;
TL0 = 0XFF; //定时5毫秒时间到后重新给寄存器赋初始值
i++; //时间标志位加1 加1表示5毫秒1次 两次表示十毫秒到
if(i == 2) //判断10毫秒是否到了
{
i = 0; //10毫秒时间到,时间标志位清零
KEYS1(); //扫描按键1
// KEYS2(); //扫描按键2
}
}