一种单片机按键检测方式
这个是目前自己在使用的按键功能模块,该功能使用定时器定时检测按键状态,避免了使用延时函数方式时会导致的程序卡顿问题。
- 具有基础的按键检测功能
- 具有检测按键持续按下和持续松开功能
- 支持组合键功能
程序内会使用的功能部分
- 记录按键状态
- 按键持续时间
- 持续时间的复位
//.h文件
#ifndef __KEY_SCANF_H__
#define __KEY_SCANF_H__
#include "STC.h" //单片机头文件
#ifndef uchar
#define uchar unsigned char
#endif
#ifndef uint
#define uint unsigned int
#endif
#ifndef ulong
#define ulong unsigned long
#endif
extern uint keep_key1;
extern uint keep_key2;
extern uint keep_key3;
extern uint keep_key4;
//定义操作名,方便调用
#define K1_PRESS ( old_key1 && !now_key1) //利用当前按键状态和上一个按键状态来判断按键操作
#define K1_LEASE (!old_key1 && now_key1)
#define K1_KEEP_PRESS (!now_key1 && keep_key1>10) //当按键持续存在一段时间时认定为持续
#define K1_KEEP_LEASE ( now_key1 && keep_key1>10)
#define K1_HAVE_PRESS (!now_KEY1)
#define K1_HAVE_LEASE ( now_KEY1)
#define K2_PRESS ( old_key2 && !now_key2)
#define K2_LEASE (!old_key2 && now_key2)
#define K2_KEEP_PRESS (!now_key2 && keep_key2>10)
#define K2_KEEP_LEASE ( now_key2 && keep_key2>10)
#define K2_HAVE_PRESS (!now_KEY2)
#define K2_HAVE_LEASE ( now_KEY2)
#define K3_PRESS ( old_key3 && !now_key3)
#define K3_LEASE (!old_key3 && now_key3)
#define K3_KEEP_PRESS (!now_key3 && keep_key3>10)
#define K3_KEEP_LEASE ( now_key3 && keep_key3>10)
#define K3_HAVE_PRESS (!now_KEY3)
#define K3_HAVE_LEASE ( now_KEY3)
#define K4_PRESS ( old_key4 && !now_key4)
#define K4_LEASE (!old_key4 && now_key4)
#define K4_KEEP_PRESS (!now_key4 && keep_key4>10)
#define K4_KEEP_LEASE ( now_key4 && keep_key4>10)
#define K4_HAVE_PRESS (!now_KEY4)
#define K4_HAVE_LEASE ( now_KEY4)
//定义按键io口
sbit K1 = P1^0
sbit K2 = P1^1
sbit K3 = P1^2
sbit K4 = P1^3
#endif
//.c
#include "key_scanf.h"
//记录按键状态
uchar now_key1,old_key1;
uchar now_key2,old_key2;
uchar now_key3,old_key3;
uchar now_key4,old_key4;
//状态保持时间
uint keep_key1;
uint keep_key2;
uint keep_key3;
uint keep_key4;
void read_key(){
//读取按键状态
old_key1=now_key1;now_key1=K1;
old_key2=now_key2;now_key2=K2;
old_key3=now_key3;now_key3=K3;
old_key4=now_key4;now_key4=K4;
//按键状态改变时,保持时间复位
if(IN1_PRESS || IN1_LEASE)keep_key1=0;
if(IN2_PRESS || IN2_LEASE)keep_key2=0;
if(IN3_PRESS || IN3_LEASE)keep_key3=0;
if(IN4_PRESS || IN4_LEASE)keep_key4=0;
//记录保持时间
if(keep_key1<65535)keep_key1++;
if(keep_key2<65535)keep_key2++;
if(keep_key3<65535)keep_key3++;
if(keep_key4<65535)keep_key4++;
}
void TIM_ISR(void) interrupt 1
{
read_key();
}
- 读取字符型按键
在逻辑上是一样的,所以这里只用一个按键来展示原理
//.h文件
#define K1_CHAR 0x01 //假设是0x01
#define K1_PRESS (old_key1!=K1_CHAR && now_key1==K1_CHAR)
#define K1_LEASE (old_key1==K1_CHAR && now_key1!=K1_CHAR)
#define K1_KEEP_PRESS (now_key1==K1_CHAR && keep_key1>10)
#define K1_KEEP_LEASE (now_key1!=K1_CHAR && keep_key1>10)
#define K1_HAVE_PRESS (now_key1==K1_CHAR)
#define K1_HAVE_LEASE (now_key1!=K1_CHAR)
extern uint keep_key1;
//.c文件
uchar now_key1,old_key1;
uint keep_key1;
void read_key(){
old_key1=now_key1;now_key1=read_char();
if(IN1_PRESS || IN1_LEASE)keep_key1=0;
if(keep_key1<65535)keep_key1++;
}
void TIM_ISR(void) interrupt 1
{
read_key();
}
- 调用示例
#include "STC.h"
#include "key_scanf.h"
sbit LED1 = P2^0;
#define ON 0
#define OFF 1
void main(){
TIM_INIT();//定时器初始化,固定时间刷新按键状态
while(1){
//基础功能
if(IN1_PRESS)LED1=!LED1; //按键按下
if(IN1_LEASE)LED1=!LED1; //按键松开
if(IN1_KEEP_PRESS)LED1=ON;else LED1=OFF;
if(IN1_KEEP_LEASE)LED1=OFF;else LED1=ON;
//长按一定的时间
//判断的数值大小视功能调用时间而定,可以判断一个时间范围允许误差
if(IN1_HAVE_PRESS && keep_key1==100){LED1=!LED1;}
//组合键
/*这个目前实现起来就有点蛋疼了*/
//按键1和按键2同时按下改变led的状态
if(IN1_HAVE_PRESS && IN2_HAVE_PRESS && (IN1_PRESS || IN2_PRESS))LED1=!LED1;
/*3个*/
if(IN1_HAVE_PRESS && IN2_HAVE_PRESS && IN3_KEEP_PRESS && (IN1_PRESS || IN2_PRESS || IN3_PRESS))LED1=!LED1;
//先按下按键1再按下按键2(这个仅支持两个有序按下)
if(IN1_HAVE_PRESS && !IN1_PRESS/*不包括同时按下*/ && IN2_PRESS)LED1=!LED1;
}
}
叮 +1
#define KEEPLEASE 0
#define PRESS 1
#define LEASE 2
#define KEEPPRESS 3
sbit K1=P0^0;
sbit K2=P0^1;
sbit K3=P0^2;
uchar KEY[3];
void KeyScan(){
KEY[0]=KEY[0]<<1|K1;
KEY[1]=KEY[1]<<1|K2;
KEY[2]=KEY[2]<<1|K3;
}
uchar ReadKey(uchar Key){
return KEY[key-1];
}