STM32CubeMX(12) ——利用状态机实现按键的长短按和双击

利用状态机实现按键的长短按和双击


前言

状态机是一种根据当前状态来执行相应动作,根据输入去改变状态的方法,出处应该在数字电路中。
我们利用状态机的思想来实现按键的消抖和一些其他功能的实现

一、状态图

在这里插入图片描述
我们的按键实验,就是以此状态图为基础,然后做延申,实现长短按和双击。

二、Cubemax配置

1、IO口配置

这个配置很简单,看自己的板子上按键的IO口是哪个,我这里以KEY0做演示
在这里插入图片描述
配置PH3为输出IO,而且由电路图可知,应该设置为上拉。
在这里插入图片描述

2、定时器配置

我们需要配置一个10ms的定时器,以10ms去检测按键的状态
在这里插入图片描述
在这里插入图片描述

三、代码

1、编写有关按键的结构体和定义相关参数

#define IOSTATE HAL_GPIO_ReadPin(GPIOH, GPIO_PIN_3)			//读取PH3的IO信息

typedef struct
{
		uint8_t flag;				//双击标志
		uint8_t mode;				//按键模式,0为短按,1为长按,2为双击
		uint8_t press_state;		//表示按键按下时,IO口为高电平还是低电平
}Key;

2、结构体初始化


void Key_Init()
{
		key.mode = 2;
		key.press_state = 0;
		key.flag = 0;
		HAL_TIM_Base_Start_IT(&htim2);
}	

3、状态机编写

我这里用一个变量a去观察结果

//此函数在定时器中每10ms调用一次
void Key_Check()
{
		static uint8_t state = 0, key_time = 0, twice_time = 0;
	
		if(key.flag == 1)
		{
				twice_time++;
				if(twice_time == 100)			//双击的间隔时间
				{
						twice_time = 0;
						key.flag = 0;
				}
		}
		
		switch(state)
		{
			case 0:
				if(IOSTATE == key.press_state) state = 1;
				break;
			
			case 1:
				if(IOSTATE == key.press_state)
				{
						if(key.mode == 0)	a++;			//单击模式
						else if(key.mode == 2)				//双击模式
						{
								key.flag++;
								if(key.flag == 2)
								{
										a++;
										key.flag = 0;
										twice_time = 0;
								}
						}
						state = 2;
			
				}
				else state = 0;
				break;
				
			case 2:
				if(IOSTATE != key.press_state)
				{
						state = 0;
						key_time = 0;
				}
				else	if(key.mode == 1)									//长按模式
				{
						key_time++;	
						if(key_time == 50)									//长按时间
						{
								a++;
						}
				}
				break;
		}
}

4、10ms定时器中反复检测按键状态

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
		if(htim->Instance == htim2.Instance)
		{
					Key_Check();
		}
}

总结

状态机的思想,适用于状态多变的场所,不仅是按键中。
具体的参考代码在下面的gitee中自取:代码仓库

  • 3
    点赞
  • 66
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 12
    评论
在使用STM32CubeMX实现按键输入的单击、双击按功能时,需要先配置GPIO口为输入模式并使能中断。然后在中断服务函数中判断按键事件类型,根据不同的事件类型执行相应的操作。 下面是一个示例代码,实现了PA0口的单击、双击按事件: ``` #include "main.h" #define DEBOUNCE_TIME 20 // 消抖时间,单位ms #define LONG_PRESS_TIME 1000 // 按时间,单位ms GPIO_TypeDef* KEY_PORT = GPIOA; uint16_t KEY_PIN = GPIO_PIN_0; volatile uint32_t press_time = 0; // 按键按下时间 volatile uint32_t release_time = 0; // 按键释放时间 void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) { if (GPIO_Pin == KEY_PIN) { if (HAL_GPIO_ReadPin(KEY_PORT, KEY_PIN) == GPIO_PIN_RESET) { // 按键按下 press_time = HAL_GetTick(); } else { // 按键释放 release_time = HAL_GetTick(); uint32_t duration = release_time - press_time; if (duration < DEBOUNCE_TIME) { // 消抖处理 return; } if (duration < LONG_PRESS_TIME) { // 短按 // 执行单击或双击操作 // 双击的判断方法是在两次单击之间的时间小于一定值 } else { // 按 // 执行按操作 } } } } int main(void) { // 初始化代码省略 // ... // 配置PA0为输入模式 GPIO_InitTypeDef GPIO_InitStruct = {0}; GPIO_InitStruct.Pin = KEY_PIN; GPIO_InitStruct.Mode = GPIO_MODE_INPUT; GPIO_InitStruct.Pull = GPIO_PULLUP; HAL_GPIO_Init(KEY_PORT, &GPIO_InitStruct); // 使能PA0中断 HAL_NVIC_SetPriority(EXTI0_IRQn, 0, 0); HAL_NVIC_EnableIRQ(EXTI0_IRQn); while (1) { // 主循环代码省略 // ... } } void EXTI0_IRQHandler(void) { HAL_GPIO_EXTI_IRQHandler(KEY_PIN); } ``` 需要注意的是,在使用HAL库的情况下,需要在`stm32xx_it.c`文件中手动添加`EXTI0_IRQHandler`函数的实现

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

lzzzzzzm

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

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

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

打赏作者

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

抵扣说明:

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

余额充值