32单片机按键扫描实现长短按功能详解

key.c

/**
 ****************************************************************************************************
 * @file           key.c
 * @author         Kyro Qu
 * @brief          按键驱动代码
 * 实验平台:       STM32G431RB开发板
 ****************************************************************************************************
 */

#include "key.h"
#include "lcd.h"
#include "stdio.h"


typedef struct
{
	GPIO_TypeDef *Key_Port;
	uint16_t Key_Pin;

}Key_GPIO_t;

static Key_GPIO_t g_KeyList[] =
{
	{ KEY_B1_GPIO_Port, KEY_B1_Pin },
	{ KEY_B2_GPIO_Port, KEY_B2_Pin },
	{ KEY_B3_GPIO_Port, KEY_B3_Pin },
	{ KEY_B4_GPIO_Port, KEY_B4_Pin }
    /* add other KEY, ... */
};

#define KEY_NUM_MAX  (sizeof(g_KeyList)/sizeof(g_KeyList[0]))


typedef enum
{
	KEY_RELEASE =0,		 /* 释放松开 */
	KEY_CONFIRM,		 /* 消抖确认 */
	KEY_SHORT_PRESS,	 /* 短按 */
	KEY_LONG_PRESS,		 /* 长按 */

}KEY_STATE;


#define CONFIRM_TIME  10		     /* 消抖时间 ms */
#define LONG_PRESS_TIME  2000		 /* 长按时间窗 ms */


typedef struct
{
	KEY_STATE keyState;			 /* 按键状态 */
	uint32_t  prvTime;			 /* 按键时间 */	

}Key_Info_t;

static Key_Info_t g_Key_Info[KEY_NUM_MAX];


/**
 * @brief       扫描单个按键不同状态函数
 * @param       按键端口号
 * @retval      键值
 */
static uint8_t keyScan(uint8_t keyIndex)
{
	uint8_t keyPress;

	keyPress=HAL_GPIO_ReadPin(g_KeyList[keyIndex].Key_Port,g_KeyList[keyIndex].Key_Pin);

	#if !ElECTRIC_LEVEL
	keyPress=!keyPress;
	#endif

	switch (g_Key_Info[keyIndex].keyState)								    /* 按键状态机 */
	{ 
		case KEY_RELEASE :
				if(keyPress )							            	  /* 如果按下 */													
				{
					g_Key_Info[keyIndex].keyState = KEY_CONFIRM;
					g_Key_Info[keyIndex].prvTime = HAL_GetTick();			/* 获取按下起始时间 */ 
				}
				break;
		case KEY_CONFIRM :
				if(keyPress )
				{
					if(HAL_GetTick()-g_Key_Info[keyIndex].prvTime>CONFIRM_TIME )
					{
						g_Key_Info[keyIndex].keyState = KEY_SHORT_PRESS;
					}
				}
				else
				{
					g_Key_Info[keyIndex].keyState = KEY_RELEASE;
				}
				break;
		case KEY_SHORT_PRESS :
				if(keyPress )
				{
					if(HAL_GetTick()-g_Key_Info[keyIndex].prvTime>LONG_PRESS_TIME )
					{
						g_Key_Info[keyIndex].keyState = KEY_LONG_PRESS;
					}
				}
				else										            	/* 如果松开 */ 
				{
					g_Key_Info[keyIndex].keyState = KEY_RELEASE;
					return (keyIndex+0x01);							/* 返回短按对应码值  0x01 0x02 0x03 .....    */				
				}
				break;
		case KEY_LONG_PRESS :
				if(!keyPress )										    	/* 如果松开 */ 
				{
					g_Key_Info[keyIndex].keyState = KEY_RELEASE;
					return (keyIndex+0x81);							        /* 返回短按对应码值  0x81 0x82 0x83 .....    */				
				} 
				break;
		default:
					g_Key_Info[keyIndex].keyState = KEY_RELEASE;
	}
		return 0;							
}


/**
 * @brief        扫描单个按键 按键的码值
 * @param        无
 * @retval       键值
 */
uint8_t GetKeyVal(void)
{
	uint8_t  res = 0; 

	for(uint8_t i=0;i<KEY_NUM_MAX;i++)
	{
		res = keyScan(i);					    /* 临时保存键值 */

		if(res!= 0)							/* 返回键值不为0,则跳出 */
		{
			break;
		}
	}
    return res;  /* 返回键值 */
}



/**
 * @brief        按键处理函数
 * @param        无
 * @retval       无
 */

void KeyHandler(void)
{
	uint8_t KEY_STATE;

	KEY_STATE=GetKeyVal();
	switch(KEY_STATE)
	{
		case B1_SHORT_PRESS:
					break;
		case B1_LONG_PRESS:

					break;
		case B2_SHORT_PRESS:

					break;
		case B2_LONG_PRESS:

					break;
		case B3_SHORT_PRESS:

					break;
		case B3_LONG_PRESS:

					break;
		case B4_SHORT_PRESS:
	
					break;
		case B4_LONG_PRESS:
	
					break;
	}
}







key.h

/**
 ****************************************************************************************************
 * @file           key.h
 * @author         Kyro Qu
 * @brief          按键驱动代码
 * 实验平台:       STM32G431RB开发板
 ****************************************************************************************************
 */

#ifndef __KEY_H
#define __KEY_H

#include "main.h"

//按键另一端口的电平  1为高电平   0为低电平
#define   ElECTRIC_LEVEL   0

/* 键值 */
#define B1_SHORT_PRESS 0x01
#define B1_LONG_PRESS  0x81

#define B2_SHORT_PRESS 0x02
#define B2_LONG_PRESS  0x82

#define B3_SHORT_PRESS 0x03
#define B3_LONG_PRESS  0x83

#define B4_SHORT_PRESS 0x04
#define B4_LONG_PRESS  0x84


uint8_t keyScan(uint8_t mode);/* 按键扫描函数 */
uint8_t GetKeyVal(void);
void KeyHandler(void);


#endif











物联沃分享整理
物联沃-IOTWORD物联网 » 32单片机按键扫描实现长短按功能详解

发表评论