(软件02)单片机按键处理,区分短按与长按

本文目录

  •     本篇前言
  •     代码思路
  •     实操练习

本篇前言

        今天接着上篇与大家继续分享软件方面关于按键事件的处理,上篇软件01篇已提到整个软件框架时基的处理,其中提到了关于按键的处理,这篇将具体地介绍按键处理的思路与实例。

        话不多说,加个封面图直接开始。

代码思路

        按键扫描函数思路:

        1.判断GPIO按键按下。

        2.记录按下时间,判断按下时间是否满足按键消抖时间(短按时间)。

        3.满足短按时间后,标记按键按下标志位。

        4.随着按下时长是否满足长按时间,并且按键是首次使用(防止一直进行这长按操作)。

        5.判断按键是否释放,释放后,根据按下标记与按键是否为首次使用标记,是否执行短按操作,接着,重置按下时间、按下标记、按键使用标记。

实操练习

        设计三个按键各自按下的短按(50ms),长按(3s)的处理。

        单片机硬件平台不要求,可移植到任何平台。

        按键扫描函数zj_app_key_scan.c

#define FALSE        0
#define TRUE         1

#define BSP_KEY_1_GPIO_PIN      	    GPIO_PIN_3
#define BSP_KEY_1_GPIO_PORT     	    GPIOB
#define BSP_KEY_1_GET 			    !GPIO_ReadInputDataBit(BSP_KEY_1_GPIO_PORT,BSP_KEY_1_GPIO_PIN)

#define BSP_KEY_2_GPIO_PIN      	    GPIO_PIN_4
#define BSP_KEY_2_GPIO_PORT     	    GPIOB
#define BSP_KEY_2_GET 			    !GPIO_ReadInputDataBit(BSP_KEY_2_GPIO_PORT,BSP_KEY_2_GPIO_PIN)

#define BSP_KEY_3_GPIO_PIN      	    GPIO_PIN_5
#define BSP_KEY_3_GPIO_PORT     	    GPIOB
#define BSP_KEY_3_GET 			    !GPIO_ReadInputDataBit(BSP_KEY_3_GPIO_PORT,BSP_KEY_3_GPIO_PIN)

#define KEY_1_LONG_CHECK_MS      3000
#define KEY_1_SHORT_CHECK_MS     50

#define KEY_2_LONG_CHECK_MS      3000
#define KEY_2_SHORT_CHECK_MS     50

#define KEY_3_LONG_CHECK_MS      3000
#define KEY_3_SHORT_CHECK_MS     50

uint16_t eKey_1_press_time 	    = 0;
uint8_t eKey_1_press_flag 		= 0;
uint8_t eKey_1_used_flag 		= 0;

uint16_t eKey_2_press_time 	    = 0;
uint8_t eKey_2_press_flag 		= 0;
uint8_t eKey_2_used_flag 		= 0;

uint16_t eKey_3_press_time 	    = 0;
uint8_t eKey_3_press_flag 		= 0;
uint8_t eKey_3_used_flag 		= 0;



static void zj_app_key_1_short(void)
{
  //这里写1号按键的短按处理
}

static void zj_app_key_1_long(void)
{
  //这里写1号按键的长按处理
}



static void zj_app_key_2_short(void)
{
  //这里写2号按键的短按处理
}

static void zj_app_key_2_long(void)
{
  //这里写2号按键的长按处理
}



static void zj_app_key_3_short(void)
{
  //这里写3号按键的短按处理
}

static void zj_app_key_3_long(void)
{
  //这里写3号按键的长按处理
}


static void zj_app_key_1_10ms_scan(void)
{	
	if(BSP_KEY_1_GET)
	{
		eKey_1_press_time++;
		if(eKey_1_press_time * 10 >= KEY_1_SHORT_CHECK_MS)  //防抖50ms
			eKey_1_press_flag 	= TRUE; //标记有按下
	}
	else
	{
		//松手处理
		if(eKey_1_press_flag && eKey_1_used_flag == FALSE) //不足长按时间3S
			zj_app_key_1_short(); //短按处理
		//恢复按键
		eKey_1_press_time 		= 0;
		eKey_1_press_flag 		= FALSE;
		eKey_1_used_flag 		= FALSE;
	}
	
	if(eKey_1_press_time * 10 >= KEY_1_LONG_CHECK_MS  && eKey_1_used_flag == FALSE)//满足长按时间3S,只有效一次长按
	{
		zj_app_key_1_long();//长按处理
		eKey_1_used_flag 		= TRUE;
	}
}


static void zj_app_key_2_10ms_scan(void)
{	
	if(BSP_KEY_2_GET)
	{
		eKey_2_press_time++;
		if(eKey_2_press_time * 10 >= KEY_2_SHORT_CHECK_MS)  //防抖50ms
			eKey_2_press_flag 	= TRUE; //标记有按下
	}
	else
	{
		//松手处理
		if(eKey_2_press_flag && eKey_2_used_flag == FALSE) //不足长按时间3S
			zj_app_key_2_short(); //短按处理
		//恢复按键
		eKey_2_press_time 		= 0;
		eKey_2_press_flag 		= FALSE;
		eKey_2_used_flag 		= FALSE;
	}
	
	if(eKey_2_press_time * 10 >= KEY_2_LONG_CHECK_MS  && eKey_2_used_flag == FALSE)//满足长按时间3S,只有效一次长按
	{
		zj_app_key_2_long();//长按处理
		eKey_2_used_flag 		= TRUE;
	}
}


static void zj_app_key_3_10ms_scan(void)
{	
	if(BSP_KEY_3_GET)
	{
		eKey_3_press_time++;
		if(eKey_3_press_time * 10 >= KEY_3_SHORT_CHECK_MS)  //防抖50ms
			eKey_3_press_flag 	= TRUE;	//标记有按下
	}
	else
	{
		//松手处理
		if(eKey_3_press_flag && eKey_3_used_flag == FALSE) //不足长按时间3S
			zj_app_key_3_short(); //短按处理
		//恢复按键
		eKey_3_press_time 		= 0;
		eKey_3_press_flag 		= FALSE;
		eKey_3_used_flag 		= FALSE;
	}
	
	if(eKey_3_press_time * 10 >= KEY_3_LONG_CHECK_MS  && eKey_3_used_flag == FALSE)//满足长按时间3S,只有效一次长按
	{
		zj_app_key_3_long();//长按处理
		eKey_3_used_flag 		= TRUE;
	}
}


void zj_app_key_scan_10ms_process(void)
{
	zj_app_key_1_10ms_scan();
	zj_app_key_2_10ms_scan();
	zj_app_key_3_10ms_scan();
}

        代码的移植只需要注意各个单片机的IO初始化,按键判断高低电平以及对应的库函数即可,将zj_app_key_scan_10ms_process(void)声明后放在10ms时基处理调用即可,按键的具体操作在各自的短按处理函数、长按处理函数设计即可。

小弟感谢大家的关注!

      (利他之心,原创分享)

  • 28
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 7
    评论
### 回答1: 在STM32单片机中,通过状态机实现按键按与短按是一种常见的做法。状态机是一种计算机程序设计思想,它根据输入和内部状态的变化来确定输出行为。 在按键按与短按的实现中,我们需要考虑按键的两种不同状态:按下和弹起。具体实现步骤如下: 1. 定义按键状态 首先需要定义按键的状态变量,可以用枚举类型或宏定义,例如: typedef enum{ KEY_IDLE, KEY_SHORT_PRESS, KEY_LONG_PRESS }KEY_STATE; 2. 初始化按键状态 在初始化时,将按键状态初始化为KEY_IDLE,表示按键处于空闲状态,即未被按下或弹起。 3. 检测按键状态 在每次中断中检测按键状态,如果按键被按下,则将状态变量设置为KEY_SHORT_PRESS,如果按键一直被按下,则将状态变量设置为KEY_LONG_PRESS。当按键被弹起时,将状态变量重新设置为KEY_IDLE。 4. 处理按键事件 根据按键状态变量的不同值来执行相应的操作。例如,当按键状态变量为KEY_SHORT_PRESS时,执行短按操作;当按键状态变量为KEY_LONG_PRESS时,执行按操作。 通过这种方法,我们可以实现按键按与短按的功能。需要注意的是,由于按键抖动等原因,需要对按键输入信号进行去抖处理。这里可以利用定时器来实现按键去抖。同时,还需要设置适当的按时间阈值,来确定按的时间范围。 ### 回答2: STM32单片机是一种广泛应用于电子工程的微控制器。其中实现按键功能主要是通过状态机实现按和短按的功能。 所谓状态机,就是将状态进行分类,并以此为基础对I/O接口进行判断和控制。实现按键的状态机,需要通过以下三个基本状态:Idle(空闲)、Press(按下)和Release(抬起)。 当用户按下按键时,状态转变为Press,此时需要启动一定的计时器来计算按键的持续时间,如果按键持续时间小于一定的时间阈值,就可以判断这个按键短按;反之,如果按键持续时间于一定的时间阈值,就可以判断这个按键按。 为了实现按键的状态转换,还需要一些状态标志来协助实现,比如:按键是否按下标志,按键按下后计数器,按键短按的时间阈值,按键按的时间阈值等。 举个例子,如果我们要实现实现PB8引脚的按键状态机的按键功能,可以采取下面的步骤: 定义状态变量state、按键按下计数器count、按键按下标志flag、按键短按时间阈值shortTime、按键按时间阈值longTime。 初始化所有状态变量,使其达到初始状态。 在主循环中监测按键是否被按下,并更新状态变量。 若按键被按下,将flag设为true,计数器count清零,并进入Press状态。 若按键抬起,将flag设为false,计算按键按下持续时间,根据时间阈值,判断是按还是短按,并根据不同结果,实现不同的响应。 以上仅仅是一个简化的按键状态机的实现过程。实际进行状态机编程需要充分考虑各种情况的差异,以避免状态机失控的情况发生,同时对状态机的各种标志进行准确的复位。 ### 回答3: stm32单片机按键状态机实现按与短按 在实际开发中,我们经常需要对按键进行扫描,并根据按键的不同状态进行相应的处理。一种常用的做法就是使用按键状态机。通过按键状态机,我们可以简单明了地实现按键短按按功能。 按键状态机的实现步骤如下: 1. 定义按键状态枚举类型 在程序中定义按键状态的枚举类型,包括三种状态:按下、释放、按。 2. 定义按键状态结构体 在程序中定义按键状态结构体,包括按键状态、按键计时器和按计时器等。 3. 编写按键状态机函数 按键状态机函数主要包括按键扫描和按键状态判断两个部分。按键扫描是以一定的时间间隔去扫描按键状态,根据当前按键状态和保存的按键状态来判断按键处于短按按还是释放状态。 4. 调用按键状态机函数 将按键状态机函数放在主循环中调用,即可完成按键状态的检测和处理。 下面是一份简单的示例代码: //按键状态枚举类型 typedef enum { KEY_STATE_UP = 0, KEY_STATE_DOWN, KEY_STATE_LONG }key_state_e; //按键状态结构体 typedef struct { key_state_e state; //按键状态 uint8_t timer_cnt; //按键计时器 uint8_t long_timer_cnt; //按计时器 uint8_t scan_interval; //按键扫描间隔 }key_status_t; //按键状态机函数 void key_state_machine(void) { static key_status_t key_status = {KEY_STATE_UP, 0, 0, 5}; uint8_t key_value = 0; //按键扫描 if(key_status.timer_cnt >= key_status.scan_interval) { key_value = get_key_value(); switch(key_status.state) { case KEY_STATE_UP: if(key_value == 0) //按键按下 { key_status.state = KEY_STATE_DOWN; key_status.timer_cnt = 0; } break; case KEY_STATE_DOWN: if(key_value == 0) //按计时 { key_status.timer_cnt = 0; key_status.long_timer_cnt ++; if(key_status.long_timer_cnt >= 200) //按200ms { key_status.long_timer_cnt = 200; key_status.state = KEY_STATE_LONG; //按状态 key_long_click_callback(); //按回调函数 } } else //短按处理 { key_status.timer_cnt = 0; key_status.long_timer_cnt = 0; key_status.state = KEY_STATE_UP; //回到按键状态 key_short_click_callback(); //短按回调函数 } break; case KEY_STATE_LONG: if(key_value != 0) //回到按键状态 { key_status.timer_cnt = 0; key_status.long_timer_cnt = 0; key_status.state = KEY_STATE_UP; } break; default: break; } key_status.timer_cnt = 0; //清零计时器 } else { key_status.timer_cnt ++; //计时器加一 } } //主函数 int main(void) { //初始化系统和按键 system_init(); key_init(); while(1) { //按键状态机处理 key_state_machine(); } } 在实际开发中,我们可以根据需要对上述代码进行修改和优化,以满足不同的应用场景。
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

BEXZJ

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

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

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

打赏作者

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

抵扣说明:

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

余额充值