在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(void)
{
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;
}
在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;
}
}
}
这样可以实现长按不松手,执行长按的代码。以后遇到好的思想会继续学习,总结下来。
上一篇:STM32的按键部分
下一篇:关于STM32按键妙用详解
推荐阅读最新更新时间:2024-03-16 16:26
设计资源 培训 开发板 精华推荐
- 了解是德科技校准服务及5G 精彩专题,下载技术文章送好礼!
- 【EEWORLD第三十七届】2012年04月社区明星人物揭晓!
- Littelfuse|一个芯片实现过压、过流、短路和浪涌保护
- 【专题】TI MSP430FR59xx——将低功耗设计进行到底!
- 购买TI store MSP432P401R LaunchPad 晒单就送礼!
- 邀你参加:EEWORLD&ST 智能产品线下研讨会(12月6日-深圳)
- 直播主题: 助力“双碳”目标 — ADI 智能工厂方案
- Microchip有奖直播:如何充分利用零漂移运算放大器
- ADI有奖下载活动之10 无线通信测试解决方案
- 是德科技有奖直播:示波器在通用电子测量中的应用和技巧