前言
这是做车窗自动升降模块时做的按键程序,感觉做的不错记录一下防止以后找不着了
代码实现
#include "key.h"
#define U1 P17
#define D1 P54
#define U2 P55
#define D2 P32
//#define KEY_QUANTITY 4 //按键数量
#define LONG_TIME 50 //长按时间50,时间乘以定时器时间
#define CLICK_TIME 10 //单击时间
#define POP_UP_TIME 50 //按键弹起时间
#define FILTEER_TIME 5 //滤波时间
#define LONG_PRESS 3 //长按
#define DBLCLICK 2 //双击
#define CLICK 1 //单击
static uchar Key_Num[KEY_QUANTITY] = {0}; //存放按键io的值
static uint KeyDown[KEY_QUANTITY] = {0}; //按键按下计数
static uchar KeyRelease[KEY_QUANTITY] = {0}; //按键释放计数
static uchar Key_Flag[KEY_QUANTITY] = {0}; //按键是否按下过计数
//uchar Key_Value[KEY_QUANTITY] = {0}; //存放按键键值,不记录按下时间用节省内存
uint Key_Value[KEY_QUANTITY] = {0}; //存放按键键值,记录按键按下时间用,
static void key() //获取io的值
{
int i = 0;
Key_Num[i++] = U1;
Key_Num[i++] = D1;
Key_Num[i++] = U2;
Key_Num[i++] = D2;
}
/*
按键键值:1:单击
2:双击
3:长按
键值单击和双击需要手动清零,长按松开自动置零
返回值:指向按键键值的指针,记录按下时间时由于是int数组,使用时需要强转一下uint *key=(uint*)Key_Read()
*/
uchar *Key_Read(void)
{
int i = 0;
key(); //获取io的值
for (i = 0; i < KEY_QUANTITY; i++)
{
if (Key_Num[i] == 0)
{
KeyDown[i]++; //按下计数自加
if (KeyRelease[i] == 0)
KeyRelease[i] = 1; //没有被按下过设置为1
if (KeyDown[i] > LONG_TIME)
/*按下时间超过LONG_TIME认为是长按,定时器时间,不会记录按下时间*/
//Key_Value[i] = LONG_PRESS;
/*记录长按时间,Key_Value*定时器时间=按下时间,最大值65535,溢出最小值3,没溢出最小值LONG_TIME*/
Key_Value[i] = KeyDown[i]>LONG_PRESS?KeyDown[i]:LONG_PRESS;
else if (KeyDown[i] > CLICK_TIME && KeyRelease[i] > CLICK_TIME)
Key_Flag[i] = 1; //按下计数超过设定,同时松开时间也超过设定认为是双击
}
else if (KeyRelease[i]) //松开时间计数
{
if (Key_Value[i] >= 3 || KeyDown[i] < FILTEER_TIME)
{ //长按松开或按下时间太短清零计数
KeyRelease[i] = 0; //??????????
KeyDown[i] = 0;
Key_Value[i] = 0;
continue; //退出不执行下面的if
}
if (KeyRelease[i]++ > POP_UP_TIME) //按键松开时间计数超过设定值
{
KeyRelease[i] = 0; //??????????
KeyDown[i] = 0;
if (Key_Flag[i]) //按键被按下过2次
{
Key_Value[i] = DBLCLICK; //设定为双击
Key_Flag[i] = 0;
}
else
Key_Value[i] = CLICK; //否则单击
}
}
}
return Key_Value;
}
按键的扫描是由定时器完成的
void tm1_isr() interrupt 3
{
time_flag=1;//通知外面按键扫描完成
Key_Read();
}
代码更改移植
- 代码非常简介(至少是我认为的)就不到80行,其中一半还是定义,代码需要改的地方只有3个
- 按键端口的定义:
#define D2 P32
,增加或者减少都可以 - 按键数量的定义:
#define KEY_QUANTITY 4 //按键数量
,改成实际的按键数量 - 更改函数实现:
key()
,只需要复制前面一句更改"="后面的值就可以前面不用改
- 按键端口的定义:
- 稍微高级一点的功能更改:长按记录按下时间(代码就是),可以改成不记录时间的节省内存
1.更改数组声明
//uchar Key_Value[KEY_QUANTITY] = {0}; //存放按键键值,不记录按下时间用节省内存
uint Key_Value[KEY_QUANTITY] = {0}; //存放按键键值,记录按键按下时间用,
- 更改函数实现
/*按下时间超过LONG_TIME认为是长按,定时器时间,不会记录按下时间*/
//Key_Value[i] = LONG_PRESS;
/*记录长按时间,Key_Value*定时器时间=按下时间,最大值65535,溢出最小值3,没溢出最小值LONG_TIME*/
Key_Value[i] = KeyDown[i]>LONG_PRESS?KeyDown[i]:LONG_PRESS;
- 这一堆东西可以尝试改改找到合适的手感,我的定时器10ms中断
#define LONG_TIME 50 //长按时间50,时间乘以定时器时间
#define CLICK_TIME 10 //单击时间
#define POP_UP_TIME 50 //按键弹起时间
#define FILTEER_TIME 5 //滤波时间
- 移植到其他单片机
只需要更改引脚定义和key()函数即可