STM32独立按键扫描,支持同时按下、长按、快速键值

这篇具有很好参考价值的文章主要介绍了STM32独立按键扫描,支持同时按下、长按、快速键值。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

背景

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

原理图设计

如下图所示,采用STM32F103C8T6,进行按键设计,这里使用按键较多

KEY_TimeSet            ---->              时间设定功能,单击进去时间设定

KEY_Program/Back  ---->              返回按键,菜单选择

KEY_ON/OFF           ---->               启动按键

KEY_Temp+             ---->               设定温度增加按键,支持快速按键功能

KEY_Temp-              ---->               设定温度减少按键,支持快速按键功能

KEY_Threshold+     ---->                参数调整按键,支持快速按键功能

KEY_Threshold-      ---->               参数调整按键,支持快速按键功能

KEY_AutoTuning     ---->               单击功能

stm32长按,嵌入式系统,stm32,按键,长按,同时按下,快速键值

stm32长按,嵌入式系统,stm32,按键,长按,同时按下,快速键值

软件设计 

软件采用stm32cubemx,如下图所示,时钟选用外部时钟倍频到72Mhz

stm32长按,嵌入式系统,stm32,按键,长按,同时按下,快速键值

 对应原理图STM32对应管脚应配置为输入模式

这里就不再贴图了,比较简单,配置对应IO输入模式即可。

这里使用FREERTOS功能,可以通过如下配置,添加自己的任务或者信号量,队列等。

使用FREERTOS的目的,是将按键扫描的结果的有效值,放进队列中,供对应的按键处理任务进行使用。

stm32长按,嵌入式系统,stm32,按键,长按,同时按下,快速键值

配置按键扫描定时器,20ms扫描一次按键

stm32长按,嵌入式系统,stm32,按键,长按,同时按下,快速键值

实际代码如下

按键扫描中断函数,进行按键扫描,并将有效键值放入到队列


void TIM2_IRQHandler(void)  
{  
	uint8_t key;
	uint16_t msg;
	portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;

    TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
	
	//按键扫描函数
	//printf("RK\r\n");//test tim2 20ms 中断
	key = ReadKey();
	if(key != NO_KEY)
	{		
		msg = MSG_KEY_DOWN | key;
		xQueueSendFromISR( segscanQueue, &msg, &xHigherPriorityTaskWoken );
	}
	portEND_SWITCHING_ISR( xHigherPriorityTaskWoken );

}

读取按键流程如下



/******************************************************************************
* 函数名称: KeyPro()
* 功能描述: 按键扫描
* 输入参数: 
* 输出参数: 
* 返 回 值: 无
* 其它说明: 
* 修改日期      版本号      修改人     修改内容
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
* 2013/02/22    V1.0.0.0       
******************************************************************************/
static unsigned char ReadKey(void)
{
	static unsigned char KeyState = 0, KeyOldValue = NO_KEY;
	static unsigned char KeyOldReturn = 0, KeyTimeCnt = 0;
	static unsigned int no_key_times = 0;
	unsigned char KeyReturn = NO_KEY, KeyCurValue = NO_KEY;
	KeyCurValue = (KEY8_VAL << 7) | (KEY7_VAL << 6) | (KEY6_VAL << 5) | (KEY5_VAL << 4) | (KEY4_VAL << 3) | (KEY3_VAL << 2) | (KEY2_VAL<<1) | KEY1_VAL; //读取6个按键值

	switch(KeyState)
	{
		case 0:
		{
            if(NO_KEY != KeyCurValue)        //检测到有键按下
            {
               KeyOldValue =  KeyCurValue;   //保存键值
               KeyState++;                   //转到消抖确认状态 
               KeyTimeCnt = 0;
			   no_key_times = 0;
            }
			else
			{
				no_key_times++;
				if(no_key_times >= 500)//500*20ms=10s
				{
					no_key_times = 0;
					KeyReturn = NO_KEY_10S_DOWN;
					KeyOldReturn = NO_KEY;
				}
			}
			break;
		}
        case 1:
		{
            if(KeyCurValue == KeyOldValue)   //和上次按键相同确认有键按下
            {
                /*switch(KeyCurValue)          //键盘编码 返回编码值
                {
					case SET_KEY_DOWN:
						KeyReturn = SET_KEY_DOWN;
					break;
					case UP_KEY_DOWN:
						KeyReturn = UP_KEY_DOWN;
					break;
					case DOWN_KEY_DOWN:
						KeyReturn = DOWN_KEY_DOWN;
					break;
					case ENTER_KEY_DOWN:
						KeyReturn = ENTER_KEY_DOWN;
					break;
					case ONOFF_KEY_DOWN:
						KeyReturn = ONOFF_KEY_DOWN;
					break;
					default:
						KeyReturn = NO_KEY;
					break;
                }*/
				KeyState++;                  //转入等待按键释放状态
				
				if(KeyCurValue == KEY7_DOWN)
				{
					KeyState = 4;//单独对时间按键进行处理
				}
				else
				{
					KeyReturn = KeyCurValue;
					KeyOldReturn = KeyReturn;
					//这里针对按键做优化处理,长按加速、和检测长按释放
					if(KeyOldReturn == KEY1_DOWN || KeyOldReturn == KEY2_DOWN)//增加快速按键值
					{
						KeyState++;	
					}
				}
            }
            else
                KeyState--;                  //两次键值不同 返回等待按键状态
            KeyTimeCnt = 0;
            KeyOldValue = KeyCurValue; 
			break;
		}
        case 2:  
		{
            if(NO_KEY == KeyCurValue)           // 按键已经释放
            {
                KeyState = 0;
                KeyOldReturn = NO_KEY; 				
            }
            else
            {

            }
			break;
		}
        case 3:
		{
            if(NO_KEY == KeyCurValue)           // 按键已经释放
            {
                KeyState = 0;
                KeyOldReturn = NO_KEY; 
            }
            else
            {
                KeyTimeCnt++;
                if(KeyTimeCnt >= 10)      
                {
                    KeyReturn = KeyOldReturn;  //增加快速键值
                    KeyTimeCnt = 0; 
                }
            }
			break;
		}
		//增加时间按键的长按、短按检测
		case 4:  
		{
			if(NO_KEY == KeyCurValue)           // 按键已经释放
			{
					KeyReturn = KEY7_DOWN;
					KeyOldReturn = KeyReturn;	
					KeyState = 0;				
			}
			else
			{
					KeyTimeCnt++;
					if(KeyTimeCnt >= 100)      
					{
							KeyReturn = KEY7_DOWN_LONG;  //检测到长按
							KeyOldReturn = KeyReturn;
						  KeyTimeCnt = 0; 
							KeyState = 5;
					}
			}
			break;
		}
		case 5:  
		{
			if(NO_KEY == KeyCurValue)           // 按键已经释放
			{
					KeyState = 0;
					KeyOldReturn = NO_KEY;	
			}
			else
			{

			}
			break;
		}
		default:
		{
			KeyState = 0;
			break;
		}
    }
    return KeyReturn;
}

按键的定义如下

这里根据原理,将按键信息写入到代码中,每次定时器中断到来都对如下管脚进行扫描,用来获取新的按键消息。

//-----------按键配置 配置-------------------------------------------------------------------

#define KEY1_VAL   			            PAin(8)//KEY_Temp+
#define KEY2_VAL  			            PBin(3)//KEY_Temp-
#define KEY3_VAL  			            PBin(15)//KEY_Threshold+
#define KEY4_VAL    			          PAin(15)//KEY_Threshold-
#define KEY5_VAL  			            PBin(14)//KEY_AutoTuning
#define KEY6_VAL   			            PAin(12)//KEY_TimeSet
#define KEY7_VAL   			            PBin(1)//
#define KEY8_VAL   			            PBin(0)


#define KEY1_DOWN                  0xFE
#define KEY1_DOWN_LONG             (KEY1_DOWN | KEY_DOWN_LONG)

#define KEY2_DOWN                  0xFD
#define KEY2_DOWN_LONG             (KEY2_DOWN | KEY_DOWN_LONG)

#define KEY3_DOWN                  0xFB
#define KEY3_DOWN_LONG             (KEY3_DOWN | KEY_DOWN_LONG)

#define KEY4_DOWN                  0xF7
#define KEY4_DOWN_LONG             (KEY4_DOWN | KEY_DOWN_LONG)

#define KEY5_DOWN                  0xEF
#define KEY5_DOWN_LONG             (KEY5_DOWN | KEY_DOWN_LONG)

#define KEY6_DOWN                  0xDF
#define KEY6_DOWN_LONG             (KEY6_DOWN | KEY_DOWN_LONG)

#define KEY7_DOWN                  0xBF
#define KEY7_DOWN_LONG             0x61

#define KEY8_DOWN                  0x7F
#define KEY8_DOWN_LONG             (KEY8_DOWN | KEY_DOWN_LONG)

#define KEY_1_4_DOWN               0xF6

#define NO_KEY_10S_DOWN            0x60
#define NO_KEY                     0XFF    

对按键消息的处理

如下代码所示,在任务中如果需要按键响应,就直接获取按键消息,如果拿到想要的按键消息,则进行按键动作处理。如下代码中如果监测到1、4按键同时按下,则进行恢复出厂设置的动作处理。文章来源地址https://www.toymoban.com/news/detail-531896.html

		if( xQueueReceive( pq, &Msg, 1000 ) == pdPASS )
		{
			if(MSG_KEY_DOWN == (MSG_NAME(Msg)))
			{
					key = MSG_DATA(Msg);
					if(key == KEY8_DOWN)//Esc
					{
						menu1();						
					}
					else if(key == KEY_1_4_DOWN)//回复出厂设置按键,移位按键和加按键同时按下
					{
						    //清屏
						Dispay_Clear();
						factorySetting();
					}
			}
		}

到了这里,关于STM32独立按键扫描,支持同时按下、长按、快速键值的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

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

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

相关文章

  • 独立按键检测短按、长按,松手后响应操作

    有项目使用独立按键检测,短按、长按。根据使用效果,发现松手后,也就是按键弹起后响应操作比较好操作。 记得之前,博主写过一篇关于按键的检测的文章,但是过于复杂了。可能很难懂,这里就简单一点,只处理一个按键。并且这个按键,只检测短按、长按两种状态。

    2024年02月08日
    浏览(15)
  • STM32 多路ADC同时扫描采样

    在项目实际应用中,刚好有需求需要使用多路ADC同时采样,这里就选择STM32 ADC多路ADC同时采样,这里简单说明下配置过程,以及使用步骤 如下图所示,使用四路ADC输入 ADC_Voltage - 电压信号的采样,外部输入信号,交流电的输入信号,正选信号 ADC_Current - 电流电流的采样,外部

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

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

    2024年01月16日
    浏览(31)
  • 学习笔记|ADC反推电源电压|扫描按键(长按循环触发)|课设级实战练习|STC32G单片机视频开发教程(冲哥)|第十八集:ADC实战

    19.5.4 利用ADC第15通道(内部1.19V参考信号源)测量外部电压或电池电压 注意:这里的1.19V不是ADC 的基准电压ADC-Vref+,而是ADC15通道的固定输入信号源,1.19V STC32G系列ADC的第15通道用于测量内部参考信号源,由于内部参考信号源很稳定,约为1.19V,且不会随芯片的工作电压的改变而变化

    2024年02月07日
    浏览(13)
  • 【按键扫描】独立按键与矩阵按键

    我们通常提到按键,一般是指按键开关,也称为轻触开关。轻触开关是最常用的几种电子元器件之一,被各种电子产品广泛使用。 轻触开关与普通开关类似,但又略有不同。普通开关有闭合与断开两种状态,切换后状态会锁定,直到下次操作前不改变;而轻触开关内部有弹簧

    2024年02月04日
    浏览(10)
  • 定时器搭配GPIO做定时扫描按键 -- STM32

    在STM32F103系列的单片机应用中,定时器(TIM)和通用输入/输出(GPIO)是常用的模块之一。这两个模块结合起来,可以实现非常多的实际应用,其中,定时器可以用来实现定时扫描按键,而GPIO可以用来控制LED等设备。 本文将介绍,在STM32F103系列的单片机中如何通过定时器和

    2024年02月07日
    浏览(15)
  • STM32F103C8T6 按键扫描输入

    第一章 STM32F103C8T6 点亮LED灯 系列文章目录 前言 一、原理  1.按键类型  2.按键消抖 3.IO口输入配置 1)模拟输出 2)浮空输入模式 3)下拉输入模式(PULL DOWN) 4)上拉输入模式(PULL UP) 二、代码部分 main.c key.c key.h 总结         上一章我们成功入门了STM32F103C8T6,今天我们来

    2023年04月23日
    浏览(24)
  • 单片机独立按键扫描程序

    为了方便,写一些方便的程序片段以便以后使用 首先是定时器扫描按键给两个例子: 一: 二:

    2024年02月16日
    浏览(16)
  • stm32矩阵按键状态机(可快速移植)

    首先声明,所写内容是协会成员集体成果。其中过程艰难坎坷,寻找过大量资料,失败过无数次,最终成功运行。其中仍有不足,欢迎大佬批评指正! 目录 一、扫描按键思路 二、状态机思路 三、代码部分 四、小结   1.原理图  2.使用引脚的选择 IO口的选择很重要, 一定要

    2024年02月11日
    浏览(10)
  • 51单片机——秒表(定时器扫描独立按键和数码管)

            这次实验主要是用定时器来定时扫描独立按键和数码管,代替两个模块函数中的延时函数。用定时器定时扫描的好处就是,主函数中的延时并不会影响按键的检测和数码管的扫描,只会影响响应速度。因为定时器是溢出就会执行中断程序,是定时的扫描。 改进的

    2024年02月10日
    浏览(18)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包