这是一段独立按键的检测函数 ,仅供参考,错的地方多多包含
首先定义一下,按键的按下的时间和要检测的个数
#define PRESS_LONG_TIME 1000
#define PRESS_CHECK_TIME 70
#define KEY_BUFF_LEN 32
我这里定义了五个按键,根据上面可知最多可检测32位按键
#define KEY0 (!gpio_input_bit_get(GPIOB,GPIO_PIN_13))
#define KEY1 (!gpio_input_bit_get(GPIOB,GPIO_PIN_14))
#define KEY2 (!gpio_input_bit_get(GPIOB,GPIO_PIN_15))
#define KEY3 (!gpio_input_bit_get(GPIOC,GPIO_PIN_6))
#define KEY4 (!gpio_input_bit_get(GPIOC,GPIO_PIN_7))
使用个枚举定义一下按键的状态.typedef+enum,大家可以先了解一下通过使用 typedef,来定义一个新类型名称的用法,typedef可以声明新的类型名来代替已有的类型名,但却不能增加新的类型。我们可以将 enum
定义的枚举类型命名为KEY_STATUS_DEF ,以后就可以使用 Weekday
来声明变量,而不需要关注实际的枚举值。
typedef enum
{
KEY_UP, //按键抬起
KEY_DOWN, //按键按下
KEY_PRESS, //按键短按
KEY_PRESS_LONG, //按键长按
}KEY_STATUS_DEF;//新类型名称
typedef+struct,与上面枚举同理。嵌套了枚举的定义的新名称status。
typedef struct
{
uint64_t time;
KEY_STATUS_DEF status;
}Key_flag;//新的结构体
//按键状态
Key_flag key_flag[KEY_BUFF_LEN]={0};//将key_flag[KEY_BUFF_LEN]={0}替换掉Key_flag,里面包含着按键个数
//当前实时按键状态
uint32_t key_status =0;
然后铺垫完成,开始进入到最简单的gpio初始化,因为我用的是GD32l233系列的国产单片机,可能固件库会与stm32不同,大家用的时候注意一下。
void key_gpio_Init(void)
{
rcu_periph_clock_enable(RCU_GPIOC);
rcu_periph_clock_enable(RCU_GPIOB);
gpio_mode_set(GPIOC,GPIO_MODE_INPUT,GPIO_PUPD_PULLUP ,GPIO_PIN_6 | GPIO_PIN_7);
gpio_mode_set(GPIOB,GPIO_MODE_INPUT,GPIO_PUPD_PULLUP ,GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15);
}
在这里使用弱声明,可更好的调用函数 ,分别是抬起,按下,长按。
__WEAK void KeyUp(uint8_t index)
{
}
__WEAK void KeyPress(uint8_t index)
{
}
__WEAK void KeyLongPress(uint8_t index)
{
}
下面才是这段代码的重中之重,按键的检测,大家仔细理解
void Key_Check(uint16_t pointTime)
{
uint8_t i;
uint8_t status;
for(i=0;i<KEY_BUFF_LEN;i++)
{
status=(key_status >>i) & 0x01;
switch (key_flag[i].status)
{
case KEY_UP:
if(!status)
{
key_flag[i].time +=pointTime;
}
else
{
key_flag[i].time =0;
key_flag[i].status=KEY_DOWN;
}
break;
case KEY_DOWN:
if(!status)
{
key_flag[i].time =0;
key_flag[i].status =KEY_UP;
}
else
{
key_flag[i].time +=pointTime;
if(key_flag[i].time >=PRESS_CHECK_TIME)
{
key_flag[i].time=0;
key_flag[i].status =KEY_PRESS;
KeyPress(i);
}
}
break;
case KEY_PRESS:
if(!status)
{
key_flag[i].time =0;
key_flag[i].status =KEY_UP;
KeyUp(i);
}
else
{
key_flag[i].time += pointTime;
if(key_flag[i].time >= PRESS_LONG_TIME)
{
key_flag[i].time =0;
key_flag[i].status=KEY_PRESS_LONG;
KeyLongPress(i);
}
}
break;
case KEY_PRESS_LONG:
if(!status)
{
key_flag[i].time= 0;
key_flag[i].status =KEY_UP;
KeyUp(i);
}
else
{
key_flag[i].time +=pointTime;
}
break;
}
}
}
因为写法的顺序问题,再最后就是按键的初始化和线程的创建
void KeyThread (void *argument)
{
uint8_t q;
while(1)
{
osDelay(10);
key_status =KEY0 |(KEY1<<1)|(KEY2 <<2)|(KEY3 <<3)|(KEY4 <<4);
Key_Check(10);
osThreadYield();
}
}
int Init_KeyThread(void)
{
osThreadAttr_t th ={.stack_size =256};
osThreadId_t tidThread =osThreadNew(KeyThread,NULL,&th);
if(tidThread ==NULL)
{
return(-1);
}
return(0);
}
void Key_Init (void )
{
Key_gpio_Init();
Init_KeyThread();
}
可能这段代码对于大部分人来说没有什么难度,但是作为公司小白的我移植改造的第一个代码,可谓是困难重重,刚开始也有很多写法和函数上的不明白,好在有公司前辈的帮助和解惑,很感谢大佬们。
写这篇文章的意义是可以在自己复习的时候有个记录,也是可以让大家进行参考,为了写代码我也是每天逛各种资源网站,很理解书到用时方恨少的感觉。如果有什么不对的地方也很 感谢大家提出来。