在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
这个是我写的按键二的博客,一些思想可以提供学习