stm32 按键长按短按组合按键状态机,并注释代码
时间: 2023-07-13 08:09:45 浏览: 164
以下是一个基于状态机的STM32按键长按短按组合按键的示例代码:
```c
/* 定义按键状态机的不同状态 */
typedef enum {
KEY_IDLE = 0, // 按键空闲状态
KEY_SHORT, // 按键短按状态
KEY_LONG, // 按键长按状态
KEY_COMB // 按键组合按状态
} KeyState_t;
/* 定义按键结构体 */
typedef struct {
GPIO_TypeDef* port; // 按键所在的GPIO端口
uint16_t pin; // 按键所在的GPIO引脚
uint32_t shortPressMs; // 短按时间阈值(单位:毫秒)
uint32_t longPressMs; // 长按时间阈值(单位:毫秒)
uint32_t combPressMs; // 组合按时间阈值(单位:毫秒)
KeyState_t state; // 当前按键状态
uint32_t pressTimeMs; // 按键按下的时间点(单位:毫秒)
} Key_t;
/* 定义按键结构体数组 */
Key_t keys[] = {
{GPIOA, GPIO_PIN_0, 50, 1000, 5000, KEY_IDLE, 0},
{GPIOB, GPIO_PIN_12, 50, 1000, 5000, KEY_IDLE, 0},
{GPIOC, GPIO_PIN_1, 50, 1000, 5000, KEY_IDLE, 0},
// ... 其他按键
};
/* 定义按键扫描函数 */
void KeyScan(void) {
static uint32_t lastTick = 0;
uint32_t tick = HAL_GetTick();
if (tick - lastTick < 10) { // 每10毫秒扫描一次按键
return;
}
lastTick = tick;
for (int i = 0; i < sizeof(keys) / sizeof(keys[0]); i++) {
Key_t* key = &keys[i];
GPIO_PinState pinState = HAL_GPIO_ReadPin(key->port, key->pin);
switch (key->state) {
case KEY_IDLE:
if (pinState == GPIO_PIN_RESET) {
key->state = KEY_SHORT;
key->pressTimeMs = tick;
}
break;
case KEY_SHORT:
if (pinState == GPIO_PIN_SET) {
if (tick - key->pressTimeMs < key->shortPressMs) {
key->state = KEY_IDLE;
} else if (tick - key->pressTimeMs < key->longPressMs) {
key->state = KEY_SHORT;
} else if (tick - key->pressTimeMs < key->combPressMs) {
key->state = KEY_LONG;
} else {
key->state = KEY_COMB;
}
}
break;
case KEY_LONG:
case KEY_COMB:
if (pinState == GPIO_PIN_SET) {
key->state = KEY_IDLE;
}
break;
}
}
}
```
在上述代码中,首先定义了一个按键状态机的不同状态,然后定义了一个按键结构体,该结构体包含了按键所在的GPIO端口和引脚、短按时间阈值、长按时间阈值、组合按时间阈值、当前按键状态以及按键按下的时间点等信息。接着定义了一个按键结构体数组,其中包含了所有需要扫描的按键。
在按键扫描函数中,首先判断是否到达了扫描的时间间隔,如果没有则直接返回。然后依次扫描每个按键,根据当前按键状态和GPIO引脚的电平状态进行状态转移。具体来说,当按键处于空闲状态时,如果检测到GPIO引脚的电平为低电平,则将按键状态转移为短按状态,并记录按键按下的时间点;当按键处于短按状态时,如果检测到GPIO引脚的电平为高电平,则根据按键按下的时间点和短按时间阈值、长按时间阈值、组合按时间阈值进行状态转移;当按键处于长按状态或组合按状态时,如果检测到GPIO引脚的电平为高电平,则将按键状态转移为空闲状态。最后,按键扫描函数结束。
需要注意的是,上述代码中使用了HAL库中的函数进行GPIO操作和时间戳获取,需要根据实际情况进行修改。此外,还需要在主函数中周期性地调用按键扫描函数,例如使用定时器中断进行调用。
阅读全文