按键的实现方案挺多,本次先尝试一下按键扫描。
硬件上按键采用按下时对GND短接,故需要配置GPIO引脚为内置上拉电阻,以稳定空闲按键电平。硬件原理图如下:

软件的按键初始化与检测代码如下:
void bsp_gpio_init(void)
{
GPIO_Config_T gpioConfig;
gpioConfig.speed = GPIO_SPEED_2MHz;
gpioConfig.mode = GPIO_MODE_IN;
gpioConfig.pupd = GPIO_PUPD_PU;
gpioConfig.pin = GPIO_PIN_0;
GPIO_Config(GPIOA, &gpioConfig);
gpioConfig.pin = GPIO_PIN_1;
GPIO_Config(GPIOA, &gpioConfig);
}
static inline int keybutton_ispressd(key_id_t key_id)
{
int ret = 0;
switch (key_id)
{
case key_id_0:
{
ret = GPIO_ReadInputBit(GPIOA, GPIO_PIN_0);
break;
}
case key_id_1:
{
ret = GPIO_ReadInputBit(GPIOA, GPIO_PIN_1);
break;
}
}
if(ret == 0)
{
return (1);
}
else
{
return (0);
}
}由于采用轮询方式回读GPIO状态,所以,我们必须添加软件去抖的算法。我这里和其它实现方案一样,也是采用状态机实现方式。简单说,两次采样一致则认为状态稳定。我定义Key的状态如下:
typedef enum
{
kb_state_initial = 0,
kb_state_idle,
kb_state_down,
kb_state_down2,
kb_state_up,
kb_state_up2
} kb_state_t;按键的状态轮转图如下图所示:

本次代码还是蛮多的,于是先写了一段测试代码:
int main(void)
{
int ret = 0;
bsp_init();
SysTick_Config(SystemCoreClock / 1000);
while (1)
{
ret = keybutton_ispressd(key_id_0);
reg_zone[0] = ret;
ret = keybutton_ispressd(key_id_1);
reg_zone[1] = ret;
}
}当我按下按键时,可以看到reg_zone[0]=1。这也验证了我的GPIO输入引脚工作正常。
第一阶段已经验证完毕,我们赶紧实现状态机的代码。
void keybutton_init(void)
{
key_inst[0].id = key_id_0;
key_inst[0].event = kb_event_null;
key_inst[0].state = kb_state_idle;
key_inst[1].id = key_id_1;
key_inst[1].event = kb_event_null;
key_inst[1].state = kb_state_idle;
}
void keybutton_scan(key_class_t *kb)
{
int ret = 0;
switch (kb->state)
{
case kb_state_idle:
{
ret = keybutton_ispressd(kb->id);
if (ret != 0)
{
kb->state = kb_state_down;
}
break;
}
case kb_state_down:
{
ret = keybutton_ispressd(kb->id);
if (ret != 0)
{
kb->state = kb_state_down2;
}
else
{
kb->state = kb_state_idle;
}
break;
}
case kb_state_down2:
{
ret = keybutton_ispressd(kb->id);
if (ret == 0)
{
kb->state = kb_state_up;
}
break;
}
case kb_state_up:
{
ret = keybutton_ispressd(kb->id);
if (ret == 0)
{
kb->state = kb_state_up2;
}
else
{
kb->state = kb_state_down2;
}
break;
}
case kb_state_up2:
{
ret = keybutton_ispressd(kb->id);
if (ret == 0)
{
kb->event = kb_event_click;
kb->state = kb_state_idle;
}
else
{
kb->state = kb_state_up;
}
break;
}
}
}实现了一下,效果还是不错的。

我要赚赏金
