思路:
问题:机械按键在按下的过程中会出现抖动的现象,导致导致单片机多判或者误判。
解决:方法一 延时 但会大量占用单片机资源。方法二 利用定时器代替延时,每经过一定的时间进入中断函数扫描按键状态减少单片机资源的占用。
静态局部变量使用static修饰符定义,即使在声明时未赋初值,编译器也会把它初始化为0。且静态局部变量存储于进程的全局数据区,即使函数返回,它的值也会保持不变。
按键单击
按键模块
#include <REGX52.H>
sbit k1=P3^1;
sbit k2=P3^0;
sbit k3=P3^2;
sbit k4=P3^3;
unsigned char temp;
unsigned char key()
{
unsigned char keynum=0;
if(k1==0) keynum=1;
if(k2==0) keynum=2;
if(k3==0) keynum=3;
if(k4==0) keynum=4;
return keynum;
}
/****
*@介绍 用于定时器扫描函数,达到要求置位相应的键码
*@参数 无
*@返回值 无
*/
void key_loop()
{
static unsigned char now,last;
last=now;
now=key();
if(last==1&&now==0)
{
temp=1;
}
if(last==2&&now==0)
{
temp=2;
}
if(last==3&&now==0)
{
temp=3;
}
if(last==4&&now==0)
{
temp=4;
}
}
/****
*@介绍 返回键码,并将键码置零
*@参数 无
*@返回值 key_temp
*/
unsigned char key_return()
{
static unsigned char key_temp;
key_temp=temp;
temp=0; //定义一个新变量,使键值置零,不会导致重复操作
return key_temp;
}
定时器T0模块
#include <REGX52.H>
void Timer0_Init()//定时器T0初始化
{
TMOD&=0XF0;
TMOD|=0X01;
TL0 = (65536-1000)%256; //设置定时初值 1ms
TH0 = (65536-1000)/256; //设置定时初值
TR0=1;
TF0=0;
EA=1;
ET0=1;
}
/*
void Timer0() interrupt 1
{
int count;
TL0 = (65536-1000)%256; //设置定时初值
TH0 = (65536-1000)/256; //设置定时初值
if(count++>20)//每20ms调用一次
{
key_loop();
count=0;
}
}
*/
主程序
unsigned char key_temp=0;
void main()
{
Timer0_Init();
while(1)
{
key_temp=key_return();
}
}
void Timer0() interrupt 1
{
int count;
TL0 = (65536-1000)%256; //设置定时初值
TH0 = (65536-1000)/256; //设置定时初值
if(count++>20)//每20ms调用一次
{
key_loop();
count=0;
}
}
按键单击和双击
按键模块
#include <REGX52.H>
sbit k1=P3^1;
sbit k2=P3^0;
sbit k3=P3^2;
sbit k4=P3^3;
unsigned char temp,count;
char key_flag;
unsigned char key()
{
unsigned char keynum=0;
if(k1==0) keynum=1;
if(k2==0) keynum=2;
if(k3==0) keynum=3;
if(k4==0) keynum=4;
return keynum;
}
/****
*@介绍 用于定时器扫描函数,达到要求置位相应的键码
*@参数 无
*@返回值 无
*/
void key_loop()
{
static unsigned char now,last;
last=now;
now=key();
if(last==1&&now==0)
{
key_flag++;//按键按下,标志位自加
}
if(last==2&&now==0)
{
temp=2;
}
if(last==3&&now==0)
{
temp=3;
}
if(last==4&&now==0)
{
temp=4;
}
//
if(count<=20&&key_flag==2)//当标志位为2且两次按键间隔少于400ms,表示为连击
{
count=0;
temp=10;
key_flag=0;
}
if(count>=20&&key_flag==1)//当标志位为1且两次按键间隔大于400ms,表示为单击
{
count=0;
temp=1;
key_flag=0;
}
}
/****
*@介绍 返回键码,并将键码置零
*@参数 无
*@返回值 key_temp
*/
unsigned char key_return()
{
static unsigned char key_temp;
key_temp=temp;
temp=0;
return key_temp;
}
主程序
#include <REGX52.H>
#include "NIXIE.H"
#include "key.H"
#include "TIMER0.H"
#include "DELAY.H"
char key_temp;//key_temp用于承接键值
extern unsigned char count;//为全局变量,当key_flag为1时开始计数,用于判断按键是否连击
extern char key_flag;//为全局变量,记录按键按下的次数
void main()
{
Timer0_Init();
while(1)
{
key_temp=key_return();
}
}
/****
*@介绍 定时器1,用于定时器扫描按键和单击双击的计时
*@参数
*@返回值
*/
void Timer0() interrupt 1
{
TL0 = (65536-20000)%256; //设置定时初值
TH0 = (65536-20000)/256; //设置定时初值
key_loop();
if(key_flag==1)
{
count++;
}
}
按键的单击和连击
按键模块
#include <REGX52.H>
sbit k1=P3^1;
sbit k2=P3^0;
sbit k3=P3^2;
sbit k4=P3^3;
unsigned char temp,count;
bit key_flag;
unsigned char key()
{
unsigned char keynum=0;
if(k1==0) {keynum=1;key_flag=1;}
if(k2==0) {keynum=2;key_flag=1;}
if(k3==0) keynum=3;
if(k4==0) keynum=4;
return keynum;
}
/****
*@介绍 用于定时器扫描函数,达到要求置位相应的键码
*@参数 无
*@返回值 无
*/
void key_loop()
{
static unsigned char now,last;
last=now;
now=key();
if(count>=50&&last==1)//计时1000ms
{
temp=10;
}
if(count>=50&&last==2)//计时1000ms
{
temp=20;
}
if(last==1&&now==0)
{
key_flag=0;
count=0;
temp=1;
}
if(last==2&&now==0)
{
key_flag=0;
count=0;
temp=2;
}
if(last==3&&now==0)
{
temp=3;
}
if(last==4&&now==0)
{
temp=4;
}
}
/****
*@介绍 返回键码,并将键码置零
*@参数 无
*@返回值 key_temp
*/
unsigned char key_return()
{
static unsigned char key_temp;
key_temp=temp;
temp=0;
return key_temp;
}
主程序
#include <REGX52.H>
#include "NIXIE.H"
#include "key.H"
#include "TIMER0.H"
#include "DELAY.H"
unsigned char key_temp,num;//key_temp承接键值
extern bit key_flag;//按键按下后置位为1,定时器开始计时
extern unsigned char count;//用于定时器的计数,当大于一定值时,判定为长按否则为短按
unsigned char count1;//用于定时,长按时使num按一定的时间间隔连续加减
void show()
{
display(7,num/100);
display(6,num/10%10);
display(5,num%10);
}
void main()
{
Timer0_Init();
while(1)
{
key_temp=key_return();
if(key_temp==1)
{
num++;
}
if(key_temp==10&&count1%20==0)
{
count1=0;
num++;
}
if(key_temp==2)
{
num--;
}
if(key_temp==20&&count1%20==0)
{
count1=0;
num--;
}
if(key_temp==3)
{
num=0;
}
show();
}
}
void Timer0() interrupt 1
{
TL0 = (65536-20000)%256; //设置定时初值
TH0 = (65536-20000)/256; //设置定时初值
key_loop();
if(key_flag==1)
{
count++;count1++;
}
}
纯粹学习笔记