按键判断单击、双击、长按【STM32】

本次实验使用的是蓝桥杯嵌入式大赛的指定开发板,STM32G431R8T6。

下面为CubeMX和代码部分

CubeMX配置

将按键引脚设置为双边沿中断触发模式,并设置上拉电阻。

定时器本次选择TIM3,选择内部时钟源,设置PSC为80-1,COUNTER Period为1000-1,实现1ms定时(频率为80MHz)

并打开定时器中断。

Key.c

#include "key.h"

/* 3个按键的结构体定义 */
key_data keys[3]={0};

/* 按键中断回调函数 */
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
	if(GPIO_Pin == KEY1_Pin)		//此时按键1被按下
	{
		static unsigned int old_time = 0;
		unsigned int new_time = HAL_GetTick();
		/* 消抖 */	
		if(new_time - old_time < DEBOUNCE)
			return ;
		old_time = new_time;
		/* 按键被按下 */
		if(HAL_GPIO_ReadPin(KEY1_GPIO_Port, KEY1_Pin) == GPIO_PIN_RESET)
		{
			if(keys[0].key_state == FREE)		/* 如果现在按键未被按下 */
			{
				keys[0].key_state = PRESSED;		/* 现在已经第一次按下,等待松手 */
				keys[0].waitetime = new_time;	/* 保存当前情况的时间节点 */
			}
			else if(keys[0].key_state == WAIT_DOUBLE){					/* 按键现在状态处于等待第二次按下时候 */
				keys[0].key_result = TWICE;		/* 按键第二次按下,按键最终状态为双击 */
				keys[0].key_state = FREE;
			}
		}
		else{			/* 按键因上升沿产生的中断,按键松开 */
			if(keys[0].key_state == PRESSED)
			{
				keys[0].key_state = WAIT_DOUBLE;		/* 将当前状态值设置为等待第二次按下 */
				keys[0].waitetime = new_time;
			}
		}
	}
	else if(GPIO_Pin == KEY2_Pin)		//此时按键2被按下
	{
	
	}
	else if(GPIO_Pin == KEY3_Pin)		//此时按键3被按下
	{
	
	}
}

/* 按键状态判断函数,每1ms调用一次 */
void key_process(void)
{
	unsigned char i;
	unsigned int time;
	time = HAL_GetTick();
	for(i=0 ; i<3 ; i++)
	{
		switch(keys[i].key_state){
			case PRESSED:			/* 当按键当前处于按下的时候进行对应操作 */
				if(time - keys[i].waitetime > LONGWAITETIME)			/* 当按键保持按下状态1s时 */
				{
					keys[i].key_result = LONG;							/* 按键最终的结果为长按 */
					keys[i].key_state = FREE;
				}
				break;
			case WAIT_DOUBLE:	/* 当按键处于等待第二次按下的时候进行操作 */
				if(time - keys[i].waitetime > DOUBLEWAITETIME)
				{
					keys[i].key_result = ONCE;							/* 按键最终的结果为单击 */
					keys[i].key_state = FREE;
				}
				break;
			default:
				break;
		}		
	}
}

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
	if(htim->Instance == TIM3)
	{
		key_process();		/* 每1ms进入一次 */
	}
}

key.h

#ifndef __KEY_H_
#define __KEY_H_

#include "main.h"

#define DEBOUNCE 20
#define LONGWAITETIME 1000
#define DOUBLEWAITETIME 400

/* 按键最后的状态:未按下,单击,双击,空闲 */
typedef enum{
	IDLE = 0,
	ONCE,
	TWICE,
	LONG
}keyresult_t;

/* 当前按键的三个状态,未被按下,按下,等待第二次按下 */
typedef enum{
	FREE = 0,
	PRESSED,
	WAIT_DOUBLE
}keystate_t;

/* 按键的信息:按键最后的结果,按键当前的值,等待时间存储 */
typedef struct{
	keyresult_t key_result;
	keystate_t key_state;
	unsigned int waitetime;	/* 用于判断长按的时间,和第二次按下的间隔 */
}key_data;

extern key_data keys[3];

/* 函数声明 */
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin);
void key_process(void);
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim);

#endif

main函数验证

while (1)
  {
		switch(keys[0].key_result){
			case IDLE:
				LCD_DisplayStringLine(Line1, (unsigned char *)" KEY1 IDLE  ");
				break;
			case ONCE:
				LCD_DisplayStringLine(Line1, (unsigned char *)" KEY1 ONCE  ");
				break;
			case TWICE:
				LCD_DisplayStringLine(Line1, (unsigned char *)" KEY1 TWIC  ");
				break;
			case LONG:
				LCD_DisplayStringLine(Line1, (unsigned char *)" KEY1 LONG  ");
				break;
		}
    /* USER CODE END WHILE */  

    /* USER CODE BEGIN 3 */
  }

主要在main中还需要打开定时器的中断模式,

/*使能定时器1中断*/
HAL_TIM_Base_Start_IT(&htim2);

演示视频

【B站链接——备战2025蓝桥杯——嵌入式】

如果您觉得这篇文章不错,且手里较为宽裕,可以支持一下博主,一分也是缘分😊
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇