STM32按键状态机的实现

本文详细介绍了按键状态机的设计与实现,包括按键状态机的作用、实现方法及核心函数。状态机能够识别按键的按下、松开,判断长按和短按,并记录按键次数。通过定时器或查询方式检测按键,更新按键结构体信息,从而执行相应功能。
摘要由CSDN通过智能技术生成

目录

一、按键状态机的作用

二、按键状态机的实现

1、按键状态机的宏定义

2、按键状态机的枚举与相关结构体

3、按键状态机的函数实现


一、按键状态机的作用

一般的按键状态机一般都具有以下功能:

  • 能够判断哪个按键按下
  • 能够判断按键是长按或者短按
  • 能够记录对应按键按下对应的次数

实现思想:

  • 首先,通过定时器或者查询方式等周期性查询按键状态机的状态
  • 接着在按键状态机中,需要获取得到对应按下的按键,然后通过对按键的前后状态进行对比,如果没有改变,则增加按键时间。如果按键松开,则对按键结构体进行修改,将对应信息赋值给按键结构体。

使用方法:

  • 通过不断检测按键状态机,当按键状态机改变后。通过对按键结构体的检索,可以得知按下按键的按键编号、按键时间长短、按键按下次数。
  • 然后执行对应按键的功能

二、按键状态机的实现

1、按键状态机的宏定义

/* 按键key的编号 */
#define KEY_DEFAULT_NUM					0x00
#define KEY_0_NUM						0x01
#define KEY_1_NUM						0x02
#define KEY_2_NUM						0x04
#define KEY_UP_NUM						0x08
#define KEY_ALL_NUM						0xFF

/* 按键时长状态定义 */
#define KEY_PRESS_SHORT				10U

2、按键状态机的枚举与相关结构体

/* 按键状态对比 */
typedef enum
{
	No_Change = 0,
	Pressed_State,
	Release_State,

}exKeyCompareStateEnum;

/* 按键按下时间长短 */
typedef enum
{
	Key_State_Default = 0,
	Key_State_Short,
	Key_State_Long,

}exKeyStateEnum;

/* 按键结构体 */
typedef struct
{
	uint8_t ucKeyNum;	/* 按键编号 */
	uint8_t ucKeyState;	/* 按键时长状态 */
	uint8_t ucKeyCount; /* 按键次数 */

}exKeyTypeDef;

3、按键状态机的函数实现

/**
 * 按键状态机
 * @para 	ucKeyNum: 需要检测的按键编号
 * @retval	0: 状态未改变 	1: 状态改变
 */
uint8_t ucKeyMachine(uint8_t ucKeyNum)
{
	static uint8_t ucNewKeyNum = 0, ucOldKeyNum = 0;
	static uint8_t ucKeyPressedTime = 0;
	static uint8_t ucEndFlag = 0;
	uint8_t ucKeyState = No_Change;

	/* 对应按键编号的按键状态 */
	ucNewKeyNum = ucKeyScan(ucKeyNum);

	/* 新按键状态 判断与处理 */
	ucKeyState = ucKeyStateCompare(ucNewKeyNum, ucOldKeyNum);
	switch(ucKeyState)
	{
	case No_Change: 	ucKeyPressedTime++;  break;								/* 按键状态改变,则增加按键时间 */
	case Pressed_State: ucOldKeyNum = ucNewKeyNum; ucKeyPressedTime = 0; break;	/* 按键按下,则更改按键缓存,并且将按键时间置0 */
	case Release_State: ucEndFlag = 1; break;									/* 按键松开,则进入按键结束 */
	}

	/* 按键结束 */
	if(ucEndFlag == 1)
	{
		/* 更新按键次数 */
		if(ex_KeyHandle.ucKeyNum == ucOldKeyNum)
			ex_KeyHandle.ucKeyCount++;
		else
		{
			ex_KeyHandle.ucKeyNum = ucOldKeyNum;
			ex_KeyHandle.ucKeyCount = 0;
		}

		/* 更新按键状态时长 */
		if(ucKeyPressedTime >= KEY_PRESS_SHORT)
			ex_KeyHandle.ucKeyState = Key_State_Long;
		else
			ex_KeyHandle.ucKeyState = Key_State_Short;

		/* 参数初始化 */
		ucEndFlag = 0;
		ucOldKeyNum = 0;
		ucKeyPressedTime = 0;

		return 1;
	}

	return 0;
}


/**
 * 按键扫描
 * @para 	ucKeyNum: 按键编号
 * @retval 	ucPressedKeyNum: 返回对应按下按键的编号, 未按下则返回 0
 */
uint8_t ucKeyScan(uint8_t ucKeyNum)
{
	uint8_t ucPressedKeyNum = 0;

	if(ucKeyNum & KEY_0_NUM)
	{
		if(HAL_GPIO_ReadPin(KEY_PORT, KEY_0_PIN) == GPIO_PIN_RESET)
			ucPressedKeyNum |= KEY_0_NUM;
	}

	if(ucKeyNum & KEY_1_NUM)
	{
		if(HAL_GPIO_ReadPin(KEY_PORT, KEY_1_PIN) == GPIO_PIN_RESET)
			ucPressedKeyNum |= KEY_1_NUM;
	}

	if(ucKeyNum & KEY_2_NUM)
	{
		if(HAL_GPIO_ReadPin(KEY_PORT, KEY_2_PIN) == GPIO_PIN_RESET)
			ucPressedKeyNum |= KEY_2_NUM;
	}

	if(ucKeyNum & KEY_UP_NUM)
	{
		if(HAL_GPIO_ReadPin(KEY_UP_PORT, KEY_UP_PIN) == GPIO_PIN_SET)
			ucPressedKeyNum |= KEY_UP_NUM;
	}

	return ucPressedKeyNum;
}


/**
 * 按键状态前后对比函数
 * @para 	ucNewKeyNum: 新键值状态
 * @para 	ucOldKeyNum: 旧键值状态
 * @retval 	返回对应键值改变的状态
 */
uint8_t ucKeyStateCompare(uint8_t ucNewKeyNum, uint8_t ucOldKeyNum)
{
	if(ucNewKeyNum == ucOldKeyNum)
		return No_Change;
	else if((ucNewKeyNum & ucOldKeyNum) == ucOldKeyNum)
		return Pressed_State;
	else
		return Release_State;
}

 

下面是一个简单的示例代码,用于实现 STM32按键有限状态机程序: ```c #include "stm32f4xx.h" #define KEY_DELAY 100000 typedef enum { KEY_STATE_IDLE = 0, KEY_STATE_PRESS, KEY_STATE_RELEASE, KEY_STATE_LONG_PRESS, KEY_STATE_NUM } key_state_t; typedef struct { GPIO_TypeDef* port; uint16_t pin; key_state_t state; uint32_t delay; } key_t; key_t keys[] = { {GPIOA, GPIO_Pin_0, KEY_STATE_IDLE, 0}, {GPIOA, GPIO_Pin_1, KEY_STATE_IDLE, 0}, {GPIOA, GPIO_Pin_2, KEY_STATE_IDLE, 0}, {GPIOA, GPIO_Pin_3, KEY_STATE_IDLE, 0} }; void init_key_gpio(void) { RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3; GPIO_Init(GPIOA, &GPIO_InitStructure); } void update_key_state(key_t* key) { GPIO_TypeDef* port = key->port; uint16_t pin = key->pin; GPIO_PinState state = GPIO_ReadInputDataBit(port, pin); switch (key->state) { case KEY_STATE_IDLE: if (state == GPIO_PIN_RESET) { key->state = KEY_STATE_PRESS; key->delay = 0; } break; case KEY_STATE_PRESS: if (state == GPIO_PIN_SET) { key->state = KEY_STATE_RELEASE; key->delay = 0; } else { key->delay++; if (key->delay > KEY_DELAY) { key->state = KEY_STATE_LONG_PRESS; } } break; case KEY_STATE_RELEASE: if (state == GPIO_PIN_RESET) { key->state = KEY_STATE_PRESS; key->delay = 0; } else { key->delay++; if (key->delay > KEY_DELAY) { key->state = KEY_STATE_IDLE; } } break; case KEY_STATE_LONG_PRESS: if (state == GPIO_PIN_SET) { key->state = KEY_STATE_RELEASE; key->delay = 0; } break; default: break; } } int main(void) { init_key_gpio(); while (1) { for (int i = 0; i < sizeof(keys)/sizeof(key_t); i++) { update_key_state(&keys[i]); switch (keys[i].state) { case KEY_STATE_PRESS: // do something when the key is pressed break; case KEY_STATE_LONG_PRESS: // do something when the key is pressed for a long time break; default: break; } } } } ``` 在这个示例代码中,我们定义了一个 `key_t` 结构体,用于存储每个按键的状态和相关信息。在 `init_key_gpio` 函数中,我们初始化了按键对应的 GPIO 引脚,并将其配置为上拉输入模式。在 `update_key_state` 函数中,我们根据按键当前的状态和输入状态,更新按键的状态。在 `main` 函数中,我们不断地遍历按键数组,调用 `update_key_state` 函数来更新按键状态。根据按键的状态,我们执行相应的操作,例如触发一个事件或者修改某个变量的值。 需要注意的是,在实际使用中,我们还需要根据具体的硬件和应用需求,对代码进行一定的修改和优化。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不吃鱼的猫丿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值