STM32 -- 实现按键的长按与短按检测(其他单片机可移植)

这篇具有很好参考价值的文章主要介绍了STM32 -- 实现按键的长按与短按检测(其他单片机可移植)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目录

资源获取

一 前言

二 思路

 三 实现代码

1.主要代码

四 完整代码

Key.h

Key.c

该改进版本(1ms太繁琐了,我改成了25ms检测一次) 

 1.定时器部分

2.按键检测部分

 五、参考


资源获取

欢迎关注微信公众号--星之援工作室 发送关键字(长短按检测)

stm32按键长按短按,学习心得,单片机,嵌入式硬件,stm32,c语言

一 前言

今天在逛博客的时候,偶然看到了一篇关于按键检测的文章,兴趣使然自己尝试了一番,写了一些代码去验证自己的思路,通过验证完美实现了长按和短按检测,后续有时间的我也会更新一下连按检测等

二 思路

首先说一下我使用的思路,第一就是使用我们的单片机的定时器去做一个轮询判断,首先建立一个1ms反转一次的定时器,定时器的选择根据自己手上有的单片机去配置一下就行,我用到是STM32F103C8T6,这款芯片有三个通用定时器,我选择的是使用TIM4去进行一个按键的检测,定时器以每1ms检测一次按键事件的方式,判断是否按下或长按按键,连续按下定时器会进行一个计数,检测一直按下就将计时器每轮询一次就加一,从而计算出按键按下的时间


 三 实现代码

1.主要代码

注意:⚠️我在后面没有放Time定时器的配置函数,但是我之前发过配置文件,大家可以直接使用

文章连接 :STM32学习记录 -- 通用定时器的配置(TIM2-TIM5)

需要注意,如果有同学使用STM32F103C8T6配置,需要屏蔽TIM5,因为STM32F103C8T6没有TIM5噢

这段主要检测按键的哪一个被按下了

/*********************************************************************************
 * @Function	:  按键处理函数
 * @Input		:  Gmode:0,不支持连续按;1,支持连续按;
 * @Output		:  None
 * @Return		:  0,没有任何按键按下
 *							 1,KEY1按下
 *						   2,KEY2按下
 *							 3,KEY3按下
 * @Others		:  注意此函数有响应优先级,KEY0>KEY1>KEY2>KEY3!!
 * @Date			:  2022-07-23
 **********************************************************************************/
u8 KEY_Scan(u8 mode)
{
	static u8 key_up = 1; // 按键按松开标志
	if (mode)
		key_up = 1; // 支持连按
	if (key_up && (KEY1 == KEY_ON || KEY2 == KEY_ON || KEY3 == KEY_ON || KEY4 == KEY_ON))
	{
		key_up = 0;
		if (KEY1 == KEY_ON)
			return KEY1_PRES;
		else if (KEY2 == KEY_ON)
			return KEY2_PRES;
		else if (KEY3 == KEY_ON)
			return KEY3_PRES;
		else if (KEY4 == KEY_ON)
			return KEY4_PRES;
	}
	else if (KEY1 == KEY_OFF && KEY2 == KEY_OFF && KEY3 == KEY_OFF && KEY4 == KEY_OFF)
		key_up = 1;
	return 0; // 无按键按下
}

这段代码主要是放在定时器里面做一个轮询判断,其中key_old,主要是保存上一次按下的按键值,方便我们进行判断,这里面的time_4 就是我们的计时器,我们通过判断time_4的值做一个长按和短按的检测,Key_Scan_Time是我自己定义的一个短按时长限制,我设置的是30

// 检测按键是否按下
static u16 time_4
static U8 key_old = 0;
u8 Check_Key_ON_OFF()
{
	u8 key;
	key = KEY_Scan(1);
	// 与上一次的键值比较 如果不相等,表明有键值的变化,开始计时
	if (key != 0 && time_4 == 0)
	{
		key_old = key;
		time_4 = 1;
	}
	if (key != 0 && time_4 >= 1 && time_4 <= 100) // 100ms
	{
		time_4++; // 时间记录器
	}
	if (key == 0 && time_4 > 0 && time_4 < Key_Scan_Time) // 短按
	{
		switch (key_old)
		{
		case KEY1_PRES:
			printf("Key1_Short\n");
			break;
		case KEY2_PRES:
			printf("Key2_Short\n");
			break;
		case KEY3_PRES:
			break;
		case KEY4_PRES:
			break;
		default:
			break;
		}
		time_4 = 0;
	}
	else if (key == 0 && time_4 >= Key_Scan_Time) // 长按
	{
		switch (key_old)
		{
		case KEY1_PRES:
			printf("Key1_Long\n");
			break;
		case KEY2_PRES:
			printf("Key2_Long\n");
			break;
		case KEY3_PRES:
			break;
		case KEY4_PRES:
			break;
		default:
			break;
		}
		time_4 = 0;
	}

	return 1;
}

最后我只需要在定时器中断中放入 Check_Key_ON_OFF()函数,即可实现功能

/*********************************************************************************
 * @Function	:  TIMER4定时器中断服务
 * @Input		:  None
 * @Output		:	 None
 * @Return		:  None
 * @Others		:	 None
 * @Date			:  2022-08-30
 **********************************************************************************/
#if GENERAL_TIM4
void TIM4_IRQHandler(void) // TIM4中断
{
	if (TIM_GetITStatus(TIM4, TIM_IT_Update) != RESET) // 检查TIM3更新中断发生与否
	{
		Check_Key_ON_OFF();
	
		TIM_ClearITPendingBit(TIM4, TIM_IT_Update); // 清除TIMx更新中断标志
	}
}
#endif

四 完整代码

Key.h

#ifndef __KEY_H
#define __KEY_H

#include "stm32f10x.h"

//  引脚定义
#define KEY1_GPIO_CLK RCC_APB2Periph_GPIOA
#define KEY1_GPIO_PORT GPIOA
#define KEY1_GPIO_PIN GPIO_Pin_0

#define KEY2_GPIO_CLK RCC_APB2Periph_GPIOC
#define KEY2_GPIO_PORT GPIOC
#define KEY2_GPIO_PIN GPIO_Pin_13

#define KEY3_GPIO_CLK RCC_APB2Periph_GPIOB
#define KEY3_GPIO_PORT GPIOB
#define KEY3_GPIO_PIN GPIO_Pin_14

#define KEY4_GPIO_CLK RCC_APB2Periph_GPIOB
#define KEY4_GPIO_PORT GPIOB
#define KEY4_GPIO_PIN GPIO_Pin_15

#define KEY1 GPIO_ReadInputDataBit(KEY1_GPIO_PORT, KEY1_GPIO_PIN) // 读取按键0
#define KEY2 GPIO_ReadInputDataBit(KEY2_GPIO_PORT, KEY2_GPIO_PIN) // 读取按键1
#define KEY3 GPIO_ReadInputDataBit(KEY3_GPIO_PORT, KEY3_GPIO_PIN) // 读取按键2
#define KEY4 GPIO_ReadInputDataBit(KEY4_GPIO_PORT, KEY4_GPIO_PIN) // 读取按键2

#define KEY1_PRES 1      // KEY1按下
#define KEY2_PRES 2      // KEY2按下
#define KEY3_PRES 3      // KEY3按下
#define KEY4_PRES 4      // KEY3按下
#define Key_Scan_Time 30 // 短按时长时间判断

/** 按键按下标置宏
 *  按键按下为高电平,设置 KEY_ON=1, KEY_OFF=0
 *  若按键按下为低电平,把宏设置成KEY_ON=0 ,KEY_OFF=1 即可
 */
#define KEY_ON 1
#define KEY_OFF 0
/*********************************************************************************
 * @Function	:  初始化控制LED的IO
 * @Input		:  None
 * @Output		:  None
 * @Return		:  None
 * @Others		:  None
 * @Date			:  2022-07-23
 **********************************************************************************/
void Key_GPIO_Config(void);
/*********************************************************************************
 * @Function	:  检测是否有按键按下
 * @Input		:  GPIOx:x 可以是 A,B,C,D或者 E
 *						:  GPIO_Pin:待读取的端口位
 * @Output		:  None
 * @Return		:  KEY_OFF(没按下按键)、KEY_ON(按下按键)
 * @Others		:  None
 * @Date			:  2022-07-23
 **********************************************************************************/
uint8_t Key_Scan(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin);
/*********************************************************************************
 * @Function	:  按键处理函数
 * @Input		:  Gmode:0,不支持连续按;1,支持连续按;
 * @Output		:  None
 * @Return		:  0,没有任何按键按下
 *							 1,KEY1按下
 *						   2,KEY2按下
 *							 3,KEY3按下
 * @Others		:  注意此函数有响应优先级,KEY0>KEY1>KEY2>KEY3!!
 * @Date			:  2022-07-23
 **********************************************************************************/
u8 KEY_Scan(u8 mode);
/*********************************************************************************
 * @Function	:  STM32程序软件复位
 * @Input		:  None
 *						:  None
 * @Output		:  None
 * @Return		:  None
 * @Others		:  None
 * @Date			:  2022-08-23
 **********************************************************************************/
void Sys_Restart(void);
#endif /* __KEY_H */

Key.c

#include "key.h"
#include "delay.h"
// 协议文件
/*********************************************************************************
 * @Function	:  初始化控制LED的IO
 * @Input		:  None
 * @Output		:  None
 * @Return		:  None
 * @Others		:  None
 * @Date			:  2022-07-23
 **********************************************************************************/
void Key_GPIO_Config(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;

	/*开启按键端口的时钟*/
	RCC_APB2PeriphClockCmd(KEY1_GPIO_CLK | KEY2_GPIO_CLK | KEY3_GPIO_CLK, ENABLE);

	// 选择按键的引脚
	GPIO_InitStructure.GPIO_Pin = KEY1_GPIO_PIN;
	// 设置按键的引脚为浮空输入
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;
	// 使用结构体初始化按键
	GPIO_Init(KEY1_GPIO_PORT, &GPIO_InitStructure);

	// 选择按键的引脚
	GPIO_InitStructure.GPIO_Pin = KEY2_GPIO_PIN;
	// 设置按键的引脚为浮空输入
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;
	// 使用结构体初始化按键
	GPIO_Init(KEY2_GPIO_PORT, &GPIO_InitStructure);

	// 选择按键的引脚
	GPIO_InitStructure.GPIO_Pin = KEY3_GPIO_PIN;
	// 设置按键的引脚为浮空输入
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;
	// 使用结构体初始化按键
	GPIO_Init(KEY3_GPIO_PORT, &GPIO_InitStructure);

	// 选择按键的引脚
	GPIO_InitStructure.GPIO_Pin = KEY4_GPIO_PIN;
	// 设置按键的引脚为浮空输入
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;
	// 使用结构体初始化按键
	GPIO_Init(KEY4_GPIO_PORT, &GPIO_InitStructure);

	GPIO_ResetBits(KEY1_GPIO_PORT, KEY1_GPIO_PIN);
	GPIO_ResetBits(KEY2_GPIO_PORT, KEY2_GPIO_PIN);
	GPIO_ResetBits(KEY3_GPIO_PORT, KEY3_GPIO_PIN);
	GPIO_ResetBits(KEY4_GPIO_PORT, KEY4_GPIO_PIN);
}
/*********************************************************************************
 * @Function	:  检测是否有按键按下
 * @Input		:  GPIOx:x 可以是 A,B,C,D或者 E
 *						:  GPIO_Pin:待读取的端口位
 * @Output		:  None
 * @Return		:  KEY_OFF(没按下按键)、KEY_ON(按下按键)
 * @Others		:  None
 * @Date			:  2022-07-23
 **********************************************************************************/
u8 Key_Scan(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin)
{
	/*检测是否有按键按下 */
	if (GPIO_ReadInputDataBit(GPIOx, GPIO_Pin) == KEY_ON)
	{
		/*等待按键释放 */
		while (GPIO_ReadInputDataBit(GPIOx, GPIO_Pin) == KEY_ON)
			;
		return KEY_ON;
	}
	else
		return KEY_OFF;
}
/*********************************************************************************
 * @Function	:  按键处理函数
 * @Input		:  Gmode:0,不支持连续按;1,支持连续按;
 * @Output		:  None
 * @Return		:  0,没有任何按键按下
 *							 1,KEY1按下
 *						   2,KEY2按下
 *							 3,KEY3按下
 * @Others		:  注意此函数有响应优先级,KEY0>KEY1>KEY2>KEY3!!
 * @Date			:  2022-07-23
 **********************************************************************************/
u8 KEY_Scan(u8 mode)
{
	static u8 key_up = 1; // 按键按松开标志
	if (mode)
		key_up = 1; // 支持连按
	if (key_up && (KEY1 == KEY_ON || KEY2 == KEY_ON || KEY3 == KEY_ON || KEY4 == KEY_ON))
	{
		delay_ms(10); // 去抖动
		key_up = 0;
		if (KEY1 == KEY_ON)
			return KEY1_PRES;
		else if (KEY2 == KEY_ON)
			return KEY2_PRES;
		else if (KEY3 == KEY_ON)
			return KEY3_PRES;
		else if (KEY4 == KEY_ON)
			return KEY4_PRES;
	}
	else if (KEY1 == KEY_OFF && KEY2 == KEY_OFF && KEY3 == KEY_OFF && KEY4 == KEY_OFF)
		key_up = 1;
	return 0; // 无按键按下
}

/*********************************************************************************
 * @Function	:  STM32程序软件复位
 * @Input		:  None
 *						:  None
 * @Output		:  None
 * @Return		:  None
 * @Others		:  None
 * @Date			:  2022-08-23
 **********************************************************************************/
void Sys_Restart(void)
{
	__set_FAULTMASK(1);
	NVIC_SystemReset();
}
// 检测按键是否按下
static u16 time_4
static u8 key_old = 0;
u8 Check_Key_ON_OFF()
{
	u8 key;
	key = KEY_Scan(1);
	// 与上一次的键值比较 如果不相等,表明有键值的变化,开始计时
	if (key != 0 && time_4 == 0)
	{
		key_old = key;
		time_4 = 1;
	}
	if (key != 0 && time_4 >= 1 && time_4 <= 100) // 100ms
	{
		time_4++; // 时间记录器
	}
	if (key == 0 && time_4 > 0 && time_4 < Key_Scan_Time) // 短按
	{
		switch (key_old)
		{
		case KEY1_PRES:
			printf("Key1_Short\n");
			break;
		case KEY2_PRES:
			printf("Key2_Short\n");
			break;
		case KEY3_PRES:
			break;
		case KEY4_PRES:
			break;
		default:
			break;
		}
		time_4 = 0;
	}
	else if (key == 0 && time_4 >= Key_Scan_Time) // 长按
	{
		switch (key_old)
		{
		case KEY1_PRES:
			printf("Key1_Long\n");
			break;
		case KEY2_PRES:
			printf("Key2_Long\n");
			break;
		case KEY3_PRES:
			break;
		case KEY4_PRES:
			break;
		default:
			break;
		}
		time_4 = 0;
	}

	return 1;
}
/*********************************************END OF FILE**********************/

串口效果如下

stm32按键长按短按,学习心得,单片机,嵌入式硬件,stm32,c语言

该改进版本(1ms太繁琐了,我改成了25ms检测一次) 

主要代码如下

 1.定时器部分

#if GENERAL_TIM4
void TIM4_IRQHandler(void) // TIM4中断
{
	if (TIM_GetITStatus(TIM4, TIM_IT_Update) != RESET) // 检查TIM3更新中断发生与否
	{
		time_4++;
		if (time_4 % 25 == 0)
		{
			Check_Key_ON_OFF();
			time_4 = 0;
		}

		TIM_ClearITPendingBit(TIM4, TIM_IT_Update); // 清除TIMx更新中断标志
	}
}
#endif

2.按键检测部分

Key_Scan_Time 检测次数我设置的为 10

// 检测按键是否按下
static U8 num_on = 0;
static U8 key_old = 0;
int Check_Key_ON_OFF()
{
	U8 key;
	key = KEY_Scan(1);
	// 与上一次的键值比较 如果不相等,表明有键值的变化,开始计时
	if (key != 0 && num_on == 0)
	{
		key_old = key;
		num_on = 1;
	}
	if (key != 0 && num_on >= 1 && num_on <= Key_Scan_Time) // 25*10ms
	{
		num_on++; // 时间记录器
	}
	if (key == 0 && num_on > 0 && num_on < Key_Scan_Time) // 短按
	{
		switch (key_old)
		{
		case KEY1_PRES:
			printf("Key1_Short\n");
			break;
		case KEY2_PRES:
			printf("Key2_Short\n");
			break;
		case KEY3_PRES:
			break;
		case KEY4_PRES:
			break;
		default:
			break;
		}
		num_on = 0;
	}
	else if (key == 0 && num_on >= Key_Scan_Time) // 长按
	{
		switch (key_old)
		{
		case KEY1_PRES:
			printf("Key1_Long\n");
			break;
		case KEY2_PRES:
			printf("Key2_Long\n");
			break;
		case KEY3_PRES:
			break;
		case KEY4_PRES:
			break;
		default:
			break;
		}
		num_on = 0;
	}

	return 1;
}

 五、参考

【stm32单片机基础】按键状态机实现长按和短按https://blog.csdn.net/qq_34142812/article/details/119721386?ops_request_misc=&request_id=&biz_id=102&utm_term=%E5%AE%9E%E7%8E%B0%E9%95%BF%E7%9F%AD%E6%8C%89&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~sobaiduweb~default-5-119721386.nonecase&spm=1018.2226.3001.4450


完整代码请关注卫星公众号进行获取和咨询文章来源地址https://www.toymoban.com/news/detail-523047.html


到了这里,关于STM32 -- 实现按键的长按与短按检测(其他单片机可移植)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • STM32独立按键实现单击双击长按功能

    目录 前言 一、按键功能定义 二、使用步骤 1.按键初始化 2.按键扫描函数(重点) 总结 在使用STM32或其他单片机开发项目时,经常需要用到独立按键进行控制。 通常一个独立按键需要使用一个IO口,如果项目需要按键实现多个功能,往往需要使用到多个按键,需要使用到多个

    2023年04月17日
    浏览(51)
  • STM32系列——用最简单的方法学会按键长按

    目录 前言 1. 按键长按原理 2. Cubmx配置 3. keil5编写代码 本教程基于stm32f103c8t6最小系统板,hal库开发。 操作简单,讲解直接清楚,旨在让大家少走弯路。 (1)要用1个定时器,设置好定时器周期并打开定时器中断。 (2)每隔一段时间进入定时器中断回调函数判断按键是否按下

    2024年02月15日
    浏览(37)
  • STM32独立按键扫描,支持同时按下、长按、快速键值

    有个项目在实际应用中,采用8个独立按键,每个按键都赋予不同功能,实际使用过程中很多时候都是需要比较特殊的按键操作,例如:长按10s按键、长按5s按键,或者长按需要有快速按键值的反馈,这个情况就类似,我们需要快速增加一个设定值时,按住加号+按键不松手,这

    2024年02月12日
    浏览(37)
  • 初学者思路-实现独立按键检测(以STM32为例)

            本文以初学者角度切入,详细剖析按键检测原理,实现按键短按、短按抬起、首次长按、持续长按次数、长按抬起功能; 目录 前言 波形图分析 抖动原因 为什么要消抖 如何消抖 原理图分析 程序设计思路 代码实践 按键配置 按键检测 实验结果 留下反思         如

    2024年01月16日
    浏览(57)
  • 短按开机/长按关机的电路和代码实现思路

    在我们实际的项目中,我们做的设备或者自己的DIY一个东西的时候,经常要实现的一个功能是:通过一个按键实现短按开机,长按关机。下面我就给大家简单介绍一下其中一种的实现方法,包含电路和代码的实现 首先是电路图: 先给大家介绍一下上面几个网络标号的意义:

    2024年02月12日
    浏览(90)
  • 正点原子STM32F103精英版+HAL库实现4×4矩阵按键检测

    首先声明,本人小白一枚,所做的工作都是借鉴网上的大佬+自己摸索,但是都是亲测实际有效的。 因为所需要的功能开发板自带按键不够用,所以购买了4×4矩阵按键,当时购买的时候以为一个按键对应一个IO口,后来发现不是这样的,会浪费太多的IO口,4×4矩阵键盘用8个

    2024年02月06日
    浏览(59)
  • rpc项目中的长连接与短连接的思考

    对于rpc项目,在接受大佬指导的时候曾问过对于长连接和短连接是处理处理的,在面试的时候也被问起 socket 是长连接还是短连接,发现自己没有好好思考过这个问题,因此好好总结一下。 前置知识点:rpc基础,tcp基础 类似于http的长连接和短连接的概念,rpc项目中的短连接

    2024年02月08日
    浏览(43)
  • 单个按钮实现长按开关机,短按可以当普通按钮控制单片机

    在看郭天祥老师的课程时学到的电路,之后发现这种控制原理很流行。 核心思路有两个: 1、用两个二极管隔离开q1和io_check,两端都可以响应按钮的状态,从而实现按钮复用。 2、用d2和q2,实现了与的功能,两者任意一个对地短路都可以保持mcu供电。 使用步骤: 1、长按sw

    2024年01月18日
    浏览(38)
  • STM32-按键检测

    做按键检测时,GPIO为输入操作 读取IO口输入电平调用的 库函数 为: uint8_t GPIO_ReadInputDataBit (GPIO_TypeDef* GPIOx,uint16_t GPIO_Pin); 读取IO口输入电平操作的 寄存器 为: GPIOx_IDR :端口输入寄存器 使用位带操作读取IO口输入电平: PEin(4) -读取GPIOE.4口电平 PEin(n) -读取 GPIOE.n口电平 按键输入

    2024年02月06日
    浏览(54)
  • STM32速成笔记—按键检测

    🎀 文章作者:二土电子 🌸 关注文末公众号获取其他资料和工程文件! 🐸 期待大家一起学习交流! 按键检测原理比较简单,按键按下和不按下,其连接引脚的电平是不一样的,按键检测正是通过检测按键引脚的电平变化来实现的。比如按键未按下时引脚电平为高电平,按

    2024年02月08日
    浏览(51)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包