Single-chip key scanning realizes short press_long press_repeat_key combination function detailed explanation

In the single-chip microcomputer project, the key operation is usually an indispensable function of the product and the user interaction, and the keys have short press, long press, repeat, and combination keys. This article introduces a method of key scanning, which can realize short press, Long press and repeat are the functions of the combination key.

Short press : Press the button and release it immediately, as shown in Figure 1. If the time tl is less than the maximum allowable time t_max, it is considered as a short press and
long press : Press the button for 3 seconds and then release it, as shown in Figure 2. The pressing time tl is greater than the time t_lmax
Repeat : that is, keep pressing the button and repeat the button, as shown in Figure 3, when the pressing time reaches t_rep, a button is generated, and when the time r1 is reached, a button is generated again to repeat.
We can determine whether it is a short press or a long press by calculating the length of time pressed, and when the key is released, the corresponding key value is generated.
Insert picture description here
Scanning operation flowchart
Insert picture description here

head File

#ifndef __KEY_H
#define	__KEY_H

#include "stm8l15x.h"
#include "stm8l15x_gpio.h"
#include "stm8l15x_exti.h"

/*--------按键标记 ------*/
#define KEY_NO	0x00	//无按键
#define KEY_S1	0x01	//按键1
#define KEY_S2	0x02	//按键2
#define KEY_S3	0x04
#define KEY_S4	0x08
#define KEY_REP_FLAG	0x40	//重复按下
#define KEY_LONG_FLAG	0x80	//长按3秒标记

//键值
typedef enum _key{
    
    
	KEY_OFF				= KEY_NO,	//没有任何键按下
	KEY_RIGHT			= KEY_S2,  //向右键
	KEY_DN				= KEY_S3,	//向下键
	KEY_UP				= KEY_S1,	//向上键
	KEY_LEFT			= KEY_S4,  //向左键
	KEY_L_UP			=(KEY_LONG_FLAG|KEY_UP), //左键+上键
	KEY_L_DN			=(KEY_LONG_FLAG|KEY_DN),
	KEY_L_RIGHT			=(KEY_LONG_FLAG|KEY_RIGHT),
	KEY_L_LEFT			=(KEY_LONG_FLAG|KEY_LEFT),
	KEY_R_UP			=(KEY_REP_FLAG|KEY_UP),
	KEY_R_DN			=(KEY_REP_FLAG|KEY_DN),
	KEY_R_RIGHT			=(KEY_REP_FLAG|KEY_RIGHT),
	KEY_R_LEFT			=(KEY_REP_FLAG|KEY_LEFT),
	KEY_L_UP_DN			=(KEY_LONG_FLAG|KEY_UP|KEY_DN), //+ - 长按
	KEY_L_LEFT_RIGHT	=(KEY_LONG_FLAG|KEY_RIGHT|KEY_LEFT), //OK ESC 长按
	KEY_L_LEFT_DN		=(KEY_LONG_FLAG|KEY_DN|KEY_LEFT), //DN ESC 长按
}KeyValue_ENUM;

/*----------按键计时-----------*/
#define KEY_DOWN_CNT	50  //按下时长
#define KEY_SPEED		40	//重复按下重载时间
#define KEY_REP_3S		2	//重复速度

//*-----------IO-----------*/
#define KEY1_PORT	GPIOA
#define KEY1_PIN	GPIO_Pin_2

#define KEY2_PORT	GPIOA
#define KEY2_PIN	GPIO_Pin_3

#define KEY3_PORT	GPIOC
#define KEY3_PIN	GPIO_Pin_0

#define KEY4_PORT	GPIOC
#define KEY4_PIN	GPIO_Pin_1

/*-----------读取按键-----------*/
#define Key1_ReadSta()		((BitStatus)(KEY1_PORT->IDR&KEY1_PIN))
#define Key2_ReadSta()		((BitStatus)(KEY2_PORT->IDR&KEY2_PIN))
#define Key3_ReadSta()		((BitStatus)(KEY3_PORT->IDR&KEY3_PIN))
#define Key4_ReadSta()		((BitStatus)(KEY4_PORT->IDR&KEY4_PIN))

/*--------函数-------*/
void KEY_Init(void);
KeyValue_ENUM KeyScan(void);

#endif /* __KEY_H */

Code

/************************************************************
Copyright (C), 2013-2020
@FileName: KEY.C
@Author  : 糊读虫 QQ:570525287
@Version : 2.0
@Date    : 2019-8-12
@Description: 按键扫描
@Function List:
@History    : 
<author> <time> <version > <desc>

***********************************************************/
#include "key.h"

//IO初始化
void KEY_Init(void)
{
    
    
	GPIO_Init(KEY1_PORT,KEY1_PIN,GPIO_Mode_In_PU_No_IT); //上拉无中断
	GPIO_Init(KEY2_PORT,KEY2_PIN,GPIO_Mode_In_PU_No_IT); //上拉无中断
	GPIO_Init(KEY3_PORT,KEY3_PIN,GPIO_Mode_In_PU_No_IT); //上拉无中断
	GPIO_Init(KEY4_PORT,KEY4_PIN,GPIO_Mode_In_PU_No_IT); //上拉无中断
}

//按键扫描
KeyValue_ENUM KeyScan(void)
{
    
    
	uint8_t io_value;
	static uint8_t key_Press;  // 这个是要返回的键值
	static uint8_t key_Old = 0x00;
	static uint8_t DownCnt = 0; //按下计数
	static struct _sta{
    
    
		uint8_t up:		1;  //弹起
		uint8_t dn:		1;	//按下
		uint8_t rep:	1;
	}Status;  //按键状态标记
	uint8_t ret;  
	
	io_value = 0x00;
	ret = KEY_OFF;

	//获取当前按下的按键
	if (!Key1_ReadSta())io_value |= KEY_S1;
	if (!Key2_ReadSta())io_value |= KEY_S2;
	if (!Key3_ReadSta())io_value |= KEY_S3;
	if (!Key4_ReadSta())io_value |= KEY_S4;

	if (io_value) //如果按键被按下
	{
    
    
		if (key_Old == io_value) //判断与上次扫描到的是否为同一个按键
		{
    
    
			DownCnt++; //计数

			if(DownCnt < KEY_DOWN_CNT)//当前计数小于长按的时间
			{
    
    
				if (Status.rep == 0) // 不是重复
				{
    
    
					Status.dn = 1;
					key_Press = io_value; //记下按键
				}				
			}

			if (DownCnt >= KEY_DOWN_CNT) //当前计数大于长按的时间
			{
    
    
				Status.rep = 1;  //标记重复

				if(CntLongPress++ == KEY_REP_3S)//按下超过3秒
				{
    
    
					ret = io_value | KEY_LONG_FLAG; //加长按标记
				}
				else
				{
    
    
					ret = io_value | KEY_REP_FLAG; //重复
				}
				
				DownCnt = KEY_SPEED;	//重复起始值				
			}
		}
		key_Old = io_value;	 //记录键值
	}
	else  //按键松开
	{
    
    
		if (Status.dn && !Status.rep) //返回松开前的键值
		{
    
    
			ret = key_Press;
		}

		//清除标记
		Status.dn = 0;
		Status.rep = 0;
		DownCnt = 0;
		key_Old = KEY_NO;
	}

	return (KeyValue_ENUM)ret;  //返回键值
}
//--------------END OF FILE---------------

Scan every 20ms in the main function

#include "key.h"

void main()
{
    
    
	//....
	KEY_Init();
	while(1)
	{
    
    
		if(delay_20ms == 1)
		{
    
    
			KeyValue_ENUM key;
			delay_20ms = 0;
			key = KeyScan();
			
			switch(key)
			{
    
    
			case KEY_RIGHT:
				//处理按键
				break;
			case KEY_UP:
				//处理按键
				break;
			//.....
			}	
		}
	}
}

Guess you like

Origin blog.csdn.net/Lennon8_8/article/details/104848734