hal库 stm32 按键单击、双击、三击、四击以及长按的实现与使用

STM32按键中断处理与多击检测
这篇博客介绍了如何在STM32中使用CubeMX配置定时器和GPIO中断,实现按键的单击、双击、三击和长按功能。通过设置不同的时间间隔判断按键的点击次数,从而触发不同的操作。代码中定义了按键标志位和延时函数,以及针对不同点击次数的回调函数,提供了一个基础的按键处理框架。

对于cubemx的配置

打开一个定时器,打开对应的按键中断即可。

代码

KeyMode.h

#ifndef __KEY_MODE_H_
#define __KEY_MODE_H_

#include "stdint.h"

#define KeyTim 	 htim7
#define KeyMode  TIM7

#endif /*__KEY_MODE_H_*/

KeyMode.c

#include "tim.h"
#include "gpio.h"
#include "KeyMode.h"

/*handle end*/

/*Private variables start*/
//bit0~3是按键PA0 的标志位
//bit4~7是按键PC13的标志位
//第0 位是按键第一次按下的标志位
//第1 位是按键第二次按下的标志位
//第2 位是按键第二次按下的标志位
//第3 位是按键第二次按下的标志位

static uint8_t KeyMode_Flag=0;

/*Private variables end*/

void singleClick_Key1Fun(void);	//按键1单击处理函数
void singleClick_Key2Fun(void);	//按键2单击处理函数

void doubleClick_Key1Fun(void);	//按键1双击处理函数
void doubleClick_Key2Fun(void);	//按键2双击处理函数

void longTerm_Key1Fun(void);	//按键1长时间按下处理函数
void longTerm_Key2Fun(void); //按键2长时间按下处理函数


void yxy_delay_us(uint32_t us)
{
		SysTick->CTRL =0;	
		SysTick->LOAD =72*us-1;
		SysTick->VAL =0;	
		SysTick->CTRL =5;	
		while((SysTick->CTRL & 0x10000) == 0);
	SysTick->CTRL =0;	
}

void yxy_delay_ms(uint32_t ms)
{
	
	while(ms--)
	{
		SysTick->CTRL =0;	
		SysTick->LOAD =72000-1;
		SysTick->VAL =0;	
		SysTick->CTRL =5;	
		while((SysTick->CTRL & 0x10000) == 0);
		
	}
	SysTick->CTRL =0;	
}

/*单击*/
void singleClick_Key1Fun(void)
{
	
}

/*双击*/
void doubleClick_Key1Fun(void)
{
	
}

/*三击*/
void threeClick_Key1Fun(void)
{
	
}

/*四击*/
void fourClick_Key1Fun(void)
{
	
}

/*长按*/
void longTerm_Key1Fun(void)
{
	
}



/* 流程

按键先按下,在300ms内没有第二次按下就代表是单击,
一但在300ms以内按下第二次就代表是双击,
当按键一直未松手,超过1500ms时就是长按。

*/



void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
	printf("EX\r\n");
  if(GPIO_Pin == GPIO_PIN_0)  //PA0
  {		
		if((KeyMode_Flag&0x08) == 0x08)	//判断按键1在之前是否按下3次
		{			
			KeyMode_Flag |= 0x08;//代表第四次按下了
		}		
		
		if((KeyMode_Flag&0x02) == 0x02)	//判断按键1在之前是否按下2次
		{			
			KeyMode_Flag |= 0x04;//代表第三次按下了
		}
		
		if((KeyMode_Flag&0x01) == 0x01)	//判断按键1在之前是否按下
		{			
			KeyMode_Flag |= 0x02;//代表第二次按下了
		}
		
		KeyMode_Flag |= 0x01;	//按键1按下标志位置位
		
		// 计数器值清零,,从当前开始计数,也充当了短暂的按键消抖的作用
    __HAL_TIM_SET_COUNTER(&KeyTim, 0);   
  }
}

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)	//TIM7
{
	static uint8_t Key1_Cnt30 = 0;//判断单击还是双击的变量

	uint8_t long_termK1=0;	//判断长按的还是其他的变量
	
  if(htim->Instance == KeyMode)	//来只定时器6的溢出中断
	{		
		if((KeyMode_Flag&0x01) == 0x01)	//按键1按下计时
		{			
			while(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_SET)	//这里代表按键还未松开(对于野火来说按下时是高电平)
			{
				if(((KeyMode_Flag&0x02) == 0x02) || ((KeyMode_Flag&0x04) == 0x04) || ((KeyMode_Flag&0x08) == 0x08))//当确认是第二次以上按下的时候,直接跳出长时间按下处理函数
				{
					break;
				}
				
				yxy_delay_ms(10);//计时
								
				long_termK1++;
				if(long_termK1>=100) // 10ms*100 == 1000ms
				{
					long_termK1=0;
					KeyMode_Flag = 0;	//清空标志位
					longTerm_Key1Fun();//处理长时间按下的函数
					break;
				}
			}
			Key1_Cnt30++;
			
			
			if(Key1_Cnt30>=50 && (KeyMode_Flag&0x08) == 0x08)//四击
			{
				fourClick_Key1Fun();//四击处理函数
				Key1_Cnt30=0;
				KeyMode_Flag = 0;//清空标志位
			}
			
			if(Key1_Cnt30>=40 && (KeyMode_Flag&0x08) != 0x08)//三击
			{
				threeClick_Key1Fun();//三击处理函数
				Key1_Cnt30=0;
				KeyMode_Flag = 0;//清空标志位
			}
			
			if(Key1_Cnt30>=30 && (KeyMode_Flag&0x04) != 0x04)
			{
				if((KeyMode_Flag&0x02) == 0x02)//代表在一定的时间内,连续按下两次了,说明是双击
				{
					doubleClick_Key1Fun();//双击处理函数
				}
				else	//说明是单击
				{
					singleClick_Key1Fun();//单击处理函数
				}
				
				Key1_Cnt30=0;
				KeyMode_Flag = 0;//清空标志位
			}
		}
	}
}

使用

只要更改KeyMode.c的这些回调函数,里面的内容就可以实现功能

/*单击*/
void singleClick_Key1Fun(void)
{
	
}

/*双击*/
void doubleClick_Key1Fun(void)
{
	
}

/*三击*/
void threeClick_Key1Fun(void)
{
	
}

/*四击*/
void fourClick_Key1Fun(void)
{
	
}

/*长按*/
void longTerm_Key1Fun(void)
{
	
}

### HAL实现按键单击双击按检测功能STM32使用HAL实现按键单击双击功能,通常需要结合外部中断(EXTI)和定时器(Timer)。以下是具体的实现方法: #### 1. 硬件软件配置 首先,需要通过STM32CubeMX进行硬件配置: - 配置GPIO引脚为输入模式,并启用外部中断(EXTI)。 - 配置一个通用定时器用于延时检测,例如TIM2或TIM3。 - 在初始化代码中生成HAL的框架代码。 #### 2. 按键事件检测逻辑 按键单击双击按检测逻辑如下: - **单击**:按键按下后,在指定的时间内(如300ms)没有再次按下,则认为是单击[^2]。 - **双击**:按键按下后,在指定的时间内(如300ms)再次按下,则认为是双击[^2]。 - ****:在双击的基础上,再次按下按键并在指定时间内完成,则认为是。 - **按**:按键按下后,保持超过一定时间(如700ms),则认为是按[^2]。 #### 3. 实现步骤 以下是具体实现步骤的代码示例: ##### (1) 初始化全局变量 ```c volatile uint8_t keyPressCount = 0; // 记录按键次数 volatile uint8_t keyState = 0; // 当前按键状态 volatile uint8_t longPressFlag = 0; // 按标志 ``` ##### (2) EXTI中断回调函数 当按键触发外部中断时,调用以下回调函数: ```c void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) { if (GPIO_Pin == KEY_PIN) { // 检测是否为按键引脚 HAL_Delay(20); // 消抖处理 if (HAL_GPIO_ReadPin(KEY_GPIO_Port, KEY_PIN) == GPIO_PIN_RESET) { keyState = 1; // 标记按键有效 } } } ``` ##### (3) 定时器周期回调函数 在定时器的周期回调函数中,检测按键的状态并判断事件类型: ```c void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { if (htim->Instance == TIM2) { // 检查是否为定时器2 if (keyState == 1) { if (keyPressCount == 0) { keyPressCount++; // 第一次按下 HAL_TIM_Base_Start_IT(&htim2); // 启动定时器 } else if (keyPressCount == 1) { keyPressCount++; // 第二次按下 HAL_TIM_Base_Start_IT(&htim2); // 再次启动定时器 } else if (keyPressCount == 2) { keyPressCount++; // 第三次按下 HAL_TIM_Base_Stop_IT(&htim2); // 停止定时器 keyState = 0; // 清除状态 // 触发事件 } } else if (longPressFlag == 1) { // 触发按事件 longPressFlag = 0; } else if (keyPressCount == 1) { // 触发单击事件 keyPressCount = 0; } else if (keyPressCount == 2) { // 触发双击事件 keyPressCount = 0; } } } ``` ##### (4) 主循环检测 在主循环中持续检测按键状态: ```c while (1) { if (keyState == 1) { if (HAL_GPIO_ReadPin(KEY_GPIO_Port, KEY_PIN) == GPIO_PIN_SET) { // 按键松开,检查是否为按 if (HAL_GetTick() - lastPressTime > LONG_PRESS_TIME) { longPressFlag = 1; } } } HAL_Delay(10); // 循环延迟 } ``` #### 4. 参数定义 以下是一些关键参数的定义: ```c #define SHORT_PRESS_TIME 300 // 单击/双击检测时间(ms) #define LONG_PRESS_TIME 700 // 按检测时间(ms) ``` --- ###
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

嵌入一下?

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

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

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

打赏作者

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

抵扣说明:

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

余额充值