在stm32工程中,长按和短按的代码书写, 调用的读取按键状态的底层函数。封装成的按键函数代码。下面是函数的头文件,和.c文件的代码。使用定时器来扫描按键。
-
#define KEY_ON 1
-
#define KEY_OFF 0
-
#define KEY_NULL 0
-
#define KEY_SHORT 1
-
#define KEY_LONG 10
-
#define SHORT_TIME 200
-
uint8_t Key_state(GPIO_TypeDef* GPIOx,uint16_t GPIO_Pin)
-
{
-
static
uint8_t key_value = KEY_NULL;
-
static
uint16_t longtime;
-
if( (longtime ==
0) && (key_value != KEY_NULL))
//当按键状态为长按或者短按时,而longtime 不为零,则按键状态清零
-
{
-
key_value = KEY_NULL;
-
}
-
if ( time ==
5 )
/* 5 * 1 ms = 5ms 定时时间到 */
-
{
-
time =
0;
-
if(
KEY_PRESS(GPIOx,GPIO_Pin))
//按键按下
-
{
-
longtime++;
-
}
-
else
//按键松开
-
{
-
if((longtime >=
3) && (longtime <= SHORT_TIME))
//短按
-
{
-
key_value = KEY_SHORT;
-
}
-
else
if( longtime > SHORT_TIME )
//长按
-
{
-
key_value = KEY_LONG;
-
}
-
else
//去抖动
-
{
-
key_value = KEY_NULL;
-
}
-
longtime =
0;
//清零
-
}
-
}
-
return key_value;
-
}
上面的代码,是按键松开才能判断按键的状态,是长按还是短按。在实际项目中我需要,按键按下一段时间后,判断为按键长按,不用松开,返回按键长按。参考网上的代码,使用状态机写了如下代码
-
#define KEY_PRESS(GPIOx,GPIO_Pin) GPIO_ReadInputDataBit(GPIOx,GPIO_Pin)
-
#define KEY_INPUT KEY_PRESS(GPIOx,GPIO_Pin) //读取按键状态
-
-
#define KEY_STATE_0 0 // 按键状态位
-
#define KEY_STATE_1 1
-
#define KEY_STATE_2 2
-
#define KEY_STATE_3 3
-
-
#define LONG_KEY_TIME 300 //长按的3秒时间
-
#define SINGLE_KEY_TIME 3 // 短按的消抖时间
-
-
#define N_KEY 0 // 无状态
-
#define S_KEY 1 // 单击
-
#define L_KEY 10 // 长按
函数的主体部分,代码中按下按键读取到高电平。
-
unsigned char key_driver(GPIO_TypeDef* GPIOx,uint16_t GPIO_Pin))
-
{
-
static
unsigned
char key_state =
0;
// 按键状态变量
-
static
unsigned
int key_time =
0;
// 按键计时变量
-
unsigned
char key_press, key_return;
-
-
key_return = N_KEY;
// 清除 返回按键值
-
-
key_press = KEY_INPUT;
// 读取当前键值
-
-
switch (key_state)
-
{
-
case KEY_STATE_0:
// 按键状态0:判断有无按键按下
-
if (key_press == KEY_ON)
// 有按键按下
-
{
-
key_time =
0;
// 清零时间间隔计数
-
key_state = KEY_STATE_1;
// 然后进入 按键状态1
-
}
-
break;
-
-
case KEY_STATE_1:
// 按键状态1:软件消抖(确定按键是否有效,而不是误触)。按键有效的定义:按键持续按下超过设定的消抖时间。
-
if (key_press == KEY_ON)
-
{
-
key_time++;
// 一次10ms
-
if(key_time>=SINGLE_KEY_TIME)
// 消抖时间为:SINGLE_KEY_TIME*10ms = 30ms;
-
{
-
key_state = KEY_STATE_2;
// 如果按键时间超过 消抖时间,即判定为按下的按键有效。按键有效包括两种:单击或者长按,进入 按键状态2, 继续判定到底是那种有效按键
-
}
-
}
-
else key_state = KEY_STATE_0;
// 如果按键时间没有超过,判定为误触,按键无效,返回 按键状态0,继续等待按键
-
break;
-
-
case KEY_STATE_2:
// 按键状态2:判定按键有效的种类:是单击,还是长按
-
if(key_press == KEY_OFF)
// 如果按键在 设定的长按时间 内释放,则判定为单击
-
{
-
key_return = S_KEY;
// 返回 有效按键值:单击
-
key_state = KEY_STATE_0;
// 返回 按键状态0,继续等待按键
-
}
-
else
-
{
-
key_time++;
-
-
if(key_time >= LONG_KEY_TIME)
// 如果按键时间超过 设定的长按时间(LONG_KEY_TIME*10ms=200*10ms=2000ms), 则判定为 长按
-
{
-
key_return = L_KEY;
// 返回 有效键值值:长按
-
key_state = KEY_STATE_3;
// 去状态3,等待按键释放
-
}
-
}
-
break;
-
-
case KEY_STATE_3:
// 等待按键释放
-
if (key_press == KEY_OFF)
-
{
-
key_state = KEY_STATE_0;
// 按键释放后,进入 按键状态0 ,进行下一次按键的判定
-
}
-
break;
-
-
default:
// 特殊情况:key_state是其他值得情况,清零key_state。这种情况一般出现在 没有初始化key_state,第一次执行这个函数的时候
-
key_state = KEY_STATE_0;
-
break;
-
}
-
-
return key_return;
// 返回 按键值
-
}
-
unsigned char key_handle(GPIO_TypeDef* GPIOx,uint16_t GPIO_Pin)
-
{
-
unsigned
char key_value;
-
if ( time >=
10 )
/* 10 * 1 ms = 10ms 定时器 */
-
{
-
time =
0;
-
key_value =
key_driver(GPIOx,GPIO_Pin);
-
}
-
return key_value;
-
}
time 这个变量,定义在了定时器文件中
在main.c中调用
-
int main(void)
-
{
-
int8_t key_value;
-
/* led 初始化*/
-
LED_GPIO_Config();
-
-
BASIC_TIM_Init();
-
-
Key_GPIO_Config();
-
-
while(
1)
-
{
-
-
// key_value = Key_state(KEY1_GPIO_PORT,KEY1_GPIO_PIN);
-
key_value =
key_handle(KEY1_GPIO_PORT,KEY1_GPIO_PIN);
-
-
if(key_value == KEY_SHORT)
-
{
-
-
LED1_TOGGLE;
-
}
-
else
if(key_value == KEY_LONG)
-
{
-
LED2_TOGGLE;
-
}
-
-
}
-
}
这样可以实现长按不松手,执行长按的代码。以后遇到好的思想会继续学习,总结下来。
代码风格不是特别好,很早之前写的了,放在这里了,仅供参考
链接 提取码:66zh
https://blog.csdn.net/xiaohu1996/article/details/103236089
这个是我写的按键二的博客,一些思想可以提供学习