基于状态机思想的按键扫描程序支持单按,连续按,长按模式。

typedef enum {
	ButtonsStateUp           = 0,
	ButtonsStateDownJitter      ,
	ButtonsStateDown            ,
	ButtonsStateUpJitter
} EnumButtonsState;

typedef unsigned char uint8;
typedef unsigned long uint32;

#define BUTTONS_UP    0
#defien BUTTONS_DOWN  1

#define BUTTONS_EVENT_NONE           0x00
#define BUTTONS_EVENT_SINGLE_DOWN    0x01
#define BUTTONS_EVENT_SERIES_DOWN    0x02
#define BUTTONS_EVENT_CONTINUE_DOWN  0x03
#define BUTTONS_EVENT_UP             0x04

EnumButtonsState ButtonsState;

void ButtonsScanSM(uint8 *event_type)
{
	uint8 buttons_status;
	
	static uint32 time_point        = 0;
	static uint8  series_down_flg   = 0;
	
	buttons_status = GetButtonsStatus();
	
	switch(ButtonsState)
	{
		case ButtonsStateUp:
		{		
			if(GetSysTicks() - time_point > 1000u)
			{
				series_down_flg = 0;
			}
			
			if(buttons_status == BUTTONS_UP)
			{
				;
			}
			else
			{
				ButtonsState = ButtonsStateDownJitter;
				
好的,以下是一个使用状态机方式运行的,能够识别5个独立按键并且能够识别双按键同时按下、按、短按、按键双击、按键按的程序。这个程序使用了STM32G030为硬件平台,使用了HAL库进行编程。 ```c #include "stm32g0xx_hal.h" #include <stdbool.h> // 定义按键名称 #define KEY_UP 0x01 #define KEY_DOWN 0x02 #define KEY_LEFT 0x04 #define KEY_RIGHT 0x08 #define KEY_CENTER 0x10 // 定义按键状态 typedef enum { KEY_RELEASED = 0, // 按键释放状态 KEY_PRESSED = 1 // 按键按下状态 } KeyState; // 定义按键信息结构体 typedef struct { GPIO_TypeDef* port; // GPIO端口 uint16_t pin; // GPIO引脚 bool inverted; // 是否反相 KeyState state; // 按键状态 uint32_t time; // 按键按下的时间 uint8_t name; // 按键名称 } KeyInfo; // 初始化按键 void KeyInit(KeyInfo* key, GPIO_TypeDef* port, uint16_t pin, bool inverted, uint8_t name) { key->port = port; key->pin = pin; key->inverted = inverted; key->state = KEY_RELEASED; key->time = 0; key->name = name; GPIO_InitTypeDef GPIO_InitStruct = {0}; GPIO_InitStruct.Pin = pin; GPIO_InitStruct.Mode = GPIO_MODE_INPUT; GPIO_InitStruct.Pull = GPIO_NOPULL; HAL_GPIO_Init(port, &GPIO_InitStruct); } // 获取按键状态 KeyState GetKeyState(KeyInfo* key) { bool isPressed = HAL_GPIO_ReadPin(key->port, key->pin) ^ key->inverted; if (isPressed && (key->state == KEY_RELEASED)) { key->state = KEY_PRESSED; key->time = HAL_GetTick(); } else if (!isPressed && (key->state == KEY_PRESSED)) { key->state = KEY_RELEASED; } return key->state; } // 判断是否为按事件 bool IsLongPress(KeyInfo* key) { if (GetKeyState(key) == KEY_PRESSED) { uint32_t timeDiff = HAL_GetTick() - key->time; if (timeDiff >= 1000) { return true; } } return false; } // 判断是否为短按事件 bool IsShortPress(KeyInfo* key) { if (GetKeyState(key) == KEY_RELEASED) { uint32_t timeDiff = HAL_GetTick() - key->time; if (timeDiff < 1000) { return true; } } return false; } // 判断是否为双击事件 bool IsDoubleClick(KeyInfo* key) { if (GetKeyState(key) == KEY_RELEASED) { uint32_t timeDiff = HAL_GetTick() - key->time; if ((timeDiff > 100) && (timeDiff < 300)) { return true; } } return false; } // 判断是否为双键同时按下事件 bool IsKeyCombination(KeyInfo* key1, KeyInfo* key2) { if ((GetKeyState(key1) == KEY_PRESSED) && (GetKeyState(key2) == KEY_PRESSED)) { return true; } return false; } int main(void) { // 初始化GPIO HAL_Init(); __HAL_RCC_GPIOA_CLK_ENABLE(); __HAL_RCC_GPIOB_CLK_ENABLE(); // 初始化按键 KeyInfo key_up, key_down, key_left, key_right, key_center; KeyInit(&key_up, GPIOA, GPIO_PIN_0, false, KEY_UP); KeyInit(&key_down, GPIOA, GPIO_PIN_1, false, KEY_DOWN); KeyInit(&key_left, GPIOA, GPIO_PIN_2, false, KEY_LEFT); KeyInit(&key_right, GPIOA, GPIO_PIN_3, false, KEY_RIGHT); KeyInit(&key_center, GPIOB, GPIO_PIN_4, false, KEY_CENTER); // 进入状态机 KeyState state = KEY_RELEASED; uint8_t curKey = 0, prevKey = 0; uint32_t curTime = 0, prevTime = 0; while (1) { switch (state) { case KEY_RELEASED: if (IsKeyCombination(&key_up, &key_down)) { state = KEY_UP_DOWN; } else if (IsKeyCombination(&key_left, &key_right)) { state = KEY_LEFT_RIGHT; } else if (IsLongPress(&key_center)) { state = KEY_CENTER_LONG; } else if (IsShortPress(&key_center)) { state = KEY_CENTER_SHORT; } else if (IsDoubleClick(&key_center)) { state = KEY_CENTER_DOUBLE; } else if (GetKeyState(&key_up) == KEY_PRESSED) { state = KEY_UP; } else if (GetKeyState(&key_down) == KEY_PRESSED) { state = KEY_DOWN; } else if (GetKeyState(&key_left) == KEY_PRESSED) { state = KEY_LEFT; } else if (GetKeyState(&key_right) == KEY_PRESSED) { state = KEY_RIGHT; } break; case KEY_UP: curKey = KEY_UP; curTime = HAL_GetTick(); if (IsShortPress(&key_up)) { printf("Key Up Short Pressed\n"); state = KEY_RELEASED; } else if (IsLongPress(&key_up)) { printf("Key Up Long Pressed\n"); state = KEY_RELEASED; } else if (IsDoubleClick(&key_up)) { printf("Key Up Double Clicked\n"); state = KEY_RELEASED; } break; case KEY_DOWN: curKey = KEY_DOWN; curTime = HAL_GetTick(); if (IsShortPress(&key_down)) { printf("Key Down Short Pressed\n"); state = KEY_RELEASED; } else if (IsLongPress(&key_down)) { printf("Key Down Long Pressed\n"); state = KEY_RELEASED; } else if (IsDoubleClick(&key_down)) { printf("Key Down Double Clicked\n"); state = KEY_RELEASED; } break; case KEY_LEFT: curKey = KEY_LEFT; curTime = HAL_GetTick(); if (IsShortPress(&key_left)) { printf("Key Left Short Pressed\n"); state = KEY_RELEASED; } else if (IsLongPress(&key_left)) { printf("Key Left Long Pressed\n"); state = KEY_RELEASED; } else if (IsDoubleClick(&key_left)) { printf("Key Left Double Clicked\n"); state = KEY_RELEASED; } break; case KEY_RIGHT: curKey = KEY_RIGHT; curTime = HAL_GetTick(); if (IsShortPress(&key_right)) { printf("Key Right Short Pressed\n"); state = KEY_RELEASED; } else if (IsLongPress(&key_right)) { printf("Key Right Long Pressed\n"); state = KEY_RELEASED; } else if (IsDoubleClick(&key_right)) { printf("Key Right Double Clicked\n"); state = KEY_RELEASED; } break; case KEY_CENTER_SHORT: printf("Key Center Short Pressed\n"); state = KEY_RELEASED; break; case KEY_CENTER_LONG: printf("Key Center Long Pressed\n"); state = KEY_RELEASED; break; case KEY_CENTER_DOUBLE: printf("Key Center Double Clicked\n"); state = KEY_RELEASED; break; case KEY_UP_DOWN: printf("Key Up and Down Pressed\n"); state = KEY_RELEASED; break; case KEY_LEFT_RIGHT: printf("Key Left and Right Pressed\n"); state = KEY_RELEASED; break; } // 判断按键双击 if ((curKey != 0) && (curKey == prevKey)) { uint32_t timeDiff = curTime - prevTime; if ((timeDiff > 100) && (timeDiff < 300)) { printf("Key %d Double Clicked\n", curKey); curKey = 0; } } // 记录上一个按下的按键和时间 if (curKey != 0) { prevKey = curKey; prevTime = curTime; } } } ``` 在这个程序中,我们首先定义了按键名称以及按键状态枚举类型。然后我们定义了包含按键信息的结构体`KeyInfo`,包含GPIO端口、引脚、状态、按下时间以及按键名称等信息。接着我们定义了一些函数,包括初始化按键、获取按键状态、判断是否为按事件、短按事件、双击事件以及双键同时按下事件等。最后我们通过状态机的方式来处理按键事件,包括按键短按、按、双击事件以及双键同时按下事件等。同时我们还记录了上一个按下的按键以及时间,以便判断按键双击事件。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值