2.8 STM32_按键扫描_安富莱

1、程序优点

扩展性非常强,功能比较齐全;
bsp_key按键驱动程序用于扫描独立按键,具有软件滤波机制,采用FIFO机制保存键值。可以检测如下事件:

按键按下。
按键弹起。
长按键。
长按时自动连发。

我们将按键驱动分为两个部分来介绍,一部分是FIFO的实现,一部分是按键检测的实现。
在这里插入图片描述
bsp_key.c 文件包含按键检测和按键FIFO的实现代码。

bsp.c 文件会调用bsp_InitKey()初始化函数。

bsp.c 文件会调用bsp_KeyScan按键扫描函数。

bsp_timer.c 中的Systick中断服务程序调用 bsp_RunPer10ms。

中断程序和主程序通过FIFO接口函数进行信息传递。

函数调用关系图
在这里插入图片描述
按键FIFO的原理

FIFO是First Input First Output的缩写,先入先出队列。我们这里以5个字节的FIFO空间进行说明。Write变量表示写位置,Read变量表示读位置。初始状态时,Read = Write = 0。
在这里插入图片描述
我们依次按下按键K1,K2,那么FIFO中的数据变为:
在这里插入图片描述
如果Write!= Read,则我们认为有新的按键事件。

我们通过函数bsp_GetKey读取一个按键值进行处理后,Read变量变为1。Write变量不变。
在这里插入图片描述
我们继续通过函数bsp_GetKey读取3个按键值进行处理后,Read变量变为4。此时Read = Write = 4。两个变量已经相等,表示已经没有新的按键事件需要处理。

有一点要特别的注意,如果FIFO空间写满了,Write会被重新赋值为0,也就是重新从第一个字节空间填数据进去,如果这个地址空间的数据还没有被及时读取出来,那么会被后来的数据覆盖掉,这点要引起大家的注意。我们的驱动程序开辟了10个字节的FIFO缓冲区,对于一般的应用足够了。

设计按键FIFO主要有三个方面的好处:

可靠地记录每一个按键事件,避免遗漏按键事件。特别是需要实现按键的按下、长按、自动连发、弹起等事件时。
读取按键的函数可以设计为非阻塞的,不需要等待按键抖动滤波处理完毕。
按键FIFO程序在嘀嗒定时器中定期的执行检测,不需要在主程序中一直做检测,这样可以有效地降低系统资源消耗。

详细参考:第19章 STM32H7的GPIO应用之按键FIFO

2、代码 bsp_key.c

/*
*********************************************************************************************************
*
*	模块名称 : 独立按键驱动模块
*	文件名称 : bsp_key.c
*	版    本 : V1.0
*	说    明 : 扫描独立按键,具有软件滤波机制,具有按键FIFO。可以检测如下事件:
*				(1) 按键按下
*				(2) 按键弹起
*				(3) 长按键
*				(4) 长按时自动连发
*
*	修改记录 :
*		版本号  日期        作者     说明
*		V1.0    2013-02-01 armfly  正式发布
*		V1.1    2013-06-29 armfly  增加1个读指针,用于bsp_Idle() 函数读取系统控制组合键(截屏)
*								   增加 K0 K2 组合键 和 K1 K3 组合键,用于系统控制
*		V1.2    2015-08-08 armfly  K1,K2,K3独立按键进行排他判断,修改  IsKeyDown1()等函数
*
*
*********************************************************************************************************
*/

#include "bsp_key.h"

/*
	正点原子STM32-V5 按键口线分配:
		K0 键      : PH3    (低电平表示按下)
		K1 键      : PH2    (低电平表示按下)
		K2 键      : PC13    (低电平表示按下)
		K3 键      : PA0    (--- 高电平表示按下)
*/


static KEY_T s_tBtn[KEY_COUNT];
static KEY_FIFO_T s_tKey;		/* 按键FIFO变量,结构体 */

static void bsp_InitKeyVar(void);
static void bsp_InitKeyHard(void);
static void bsp_DetectKey(uint8_t i);

/*
*********************************************************************************************************
*	函 数 名: IsKeyDownX
*	功能说明: 判断按键是否按下
*	形    参: 无
*	返 回 值: 返回值1 表示按下,0表示未按下
*********************************************************************************************************
*/

/* 为了区分2个事件: K0 K1 K2 K_UP单独按键;K1 K_UP组合,K0 K2组合*/
//K0
static uint8_t IsKeyDown1(void)
{
	if ( HAL_GPIO_ReadPin(KEY0_GPIO_Port,KEY0_Pin) == 0 && HAL_GPIO_ReadPin(KEY1_GPIO_Port,KEY1_Pin) != 0
		&& HAL_GPIO_ReadPin(KEY2_GPIO_Port,KEY2_Pin) != 0 && HAL_GPIO_ReadPin(KEY_UP_GPIO_Port,KEY_UP_Pin) == 0)
		return 1;
	else 
		return 0;
}
//K1
static uint8_t IsKeyDown2(void)
{
	if ( HAL_GPIO_ReadPin(KEY0_GPIO_Port,KEY0_Pin) != 0 && HAL_GPIO_ReadPin(KEY1_GPIO_Port,KEY1_Pin) == 0
		&& HAL_GPIO_ReadPin(KEY2_GPIO_Port,KEY2_Pin) != 0 && HAL_GPIO_ReadPin(KEY_UP_GPIO_Port,KEY_UP_Pin) == 0)
		return 1;
	else 
		return 0;
}
//K2
static uint8_t IsKeyDown3(void)
{
	if (HAL_GPIO_ReadPin(KEY0_GPIO_Port,KEY0_Pin) != 0  && HAL_GPIO_ReadPin(KEY1_GPIO_Port,KEY1_Pin) != 0
		&& HAL_GPIO_ReadPin(KEY2_GPIO_Port,KEY2_Pin) == 0 && HAL_GPIO_ReadPin(KEY_UP_GPIO_Port,KEY_UP_Pin) == 0)
		return 1;
	else 
		return 0;
}
//K3
static uint8_t IsKeyDown4(void)
{
	if (HAL_GPIO_ReadPin(KEY0_GPIO_Port,KEY0_Pin) != 0  && HAL_GPIO_ReadPin(KEY1_GPIO_Port,KEY1_Pin) != 0
		&& HAL_GPIO_ReadPin(KEY2_GPIO_Port,KEY2_Pin) != 0 && HAL_GPIO_ReadPin(KEY_UP_GPIO_Port,KEY_UP_Pin) != 0)
		return 1;
	else 
		return 0;
}

//K0 K2
static uint8_t IsKeyDown5(void)	/* K0 K2组合键 */
{
	if (HAL_GPIO_ReadPin(KEY0_GPIO_Port,KEY0_Pin) == 0  && HAL_GPIO_ReadPin(KEY1_GPIO_Port,KEY1_Pin) != 0
		&& HAL_GPIO_ReadPin(KEY2_GPIO_Port,KEY2_Pin) == 0 && HAL_GPIO_ReadPin(KEY_UP_GPIO_Port,KEY_UP_Pin) == 0)
		return 1;
	else 
		return 0;
}

//K1 K3
static uint8_t IsKeyDown6(void)	/* K1 K3组合键 */
{
	if ( HAL_GPIO_ReadPin(KEY0_GPIO_Port,KEY0_Pin) != 0  && HAL_GPIO_ReadPin(KEY1_GPIO_Port,KEY1_Pin) == 0
		&& HAL_GPIO_ReadPin(KEY2_GPIO_Port,KEY2_Pin) != 0  && HAL_GPIO_ReadPin(KEY_UP_GPIO_Port,KEY_UP_Pin) != 0)
		return 1;
	else 
		return 0;
}



/*
*********************************************************************************************************
*	函 数 名: bsp_InitKey
*	功能说明: 初始化按键. 该函数被 bsp_Init() 调用。
*	形    参:  无
*	返 回 值: 无
*********************************************************************************************************
*/
void bsp_InitKey(void)
{
	bsp_InitKeyVar();			/* 初始化按键变量 */
	bsp_InitKeyHard();		/* 初始化按键硬件 */
}

/*
*********************************************************************************************************
*	函 数 名: bsp_PutKey
*	功能说明: 将1个键值压入按键FIFO缓冲区。可用于模拟一个按键。
*	形    参:  _KeyCode : 按键代码
*	返 回 值: 无
*********************************************************************************************************
*/
void bsp_PutKey(uint8_t _KeyCode)
{
	s_tKey.Buf[s_tKey.Write] = _KeyCode;

	if (++s_tKey.Write  >= KEY_FIFO_SIZE)
	{
		s_tKey.Write = 0;
	}
}

/*
*********************************************************************************************************
*	函 数 名: bsp_GetKey
*	功能说明: 从按键FIFO缓冲区读取一个键值。
*	形    参:  无
*	返 回 值: 按键代码
*********************************************************************************************************
*/
uint8_t bsp_GetKey(void)
{
	uint8_t ret;

	if (s_tKey.Read == s_tKey.Write)
	{
		return KEY_NONE;
	}
	else
	{
		ret = s_tKey.Buf[s_tKey.Read];

		if (++s_tKey.Read >= KEY_FIFO_SIZE)
		{
			s_tKey.Read = 0;
		}
		return ret;
	}
}

/*
*********************************************************************************************************
*	函 数 名: bsp_GetKey2
*	功能说明: 从按键FIFO缓冲区读取一个键值。独立的读指针。
*	形    参:  无
*	返 回 值: 按键代码
*********************************************************************************************************
*/
uint8_t bsp_GetKey2(void)
{
	uint8_t ret;

	if (s_tKey.Read2 == s_tKey.Write)
	{
		return KEY_NONE;
	}
	else
	{
		ret = s_tKey.Buf[s_tKey.Read2];

		if (++s_tKey.Read2 >= KEY_FIFO_SIZE)
		{
			s_tKey.Read2 = 0;
		}
		return ret;
	}
}

/*
*********************************************************************************************************
*	函 数 名: bsp_GetKeyState
*	功能说明: 读取按键的状态
*	形    参:  _ucKeyID : 按键ID,从0开始
*	返 回 值: 1 表示按下, 0 表示未按下
*********************************************************************************************************
*/
uint8_t bsp_GetKeyState(KEY_ID_E _ucKeyID)
{
	return s_tBtn[_ucKeyID].State;
}

/*
*********************************************************************************************************
*	函 数 名: bsp_SetKeyParam
*	功能说明: 设置按键参数
*	形    参:_ucKeyID : 按键ID,从0开始
*			_LongTime : 长按事件时间
*			 _RepeatSpeed : 连发速度
*	返 回 值: 无
*********************************************************************************************************
*/
void bsp_SetKeyParam(uint8_t _ucKeyID, uint16_t _LongTime, uint8_t  _RepeatSpeed)
{
	s_tBtn[_ucKeyID].LongTime = _LongTime;			/* 长按时间 0 表示不检测长按键事件 */
	s_tBtn[_ucKeyID].RepeatSpeed = _RepeatSpeed;			/* 按键连发的速度,0表示不支持连发 */
	s_tBtn[_ucKeyID].RepeatCount = 0;						/* 连发计数器 */
}


/*
*********************************************************************************************************
*	函 数 名: bsp_ClearKey
*	功能说明: 清空按键FIFO缓冲区
*	形    参:无
*	返 回 值: 按键代码
*********************************************************************************************************
*/
void bsp_ClearKey(void)
{
	s_tKey.Read = s_tKey.Write;
}

/*
*********************************************************************************************************
*	函 数 名: bsp_InitKeyHard
*	功能说明: 配置按键对应的GPIO
*	形    参:  无
*	返 回 值: 无
*********************************************************************************************************
*/
static void bsp_InitKeyHard(void)
{
	;
}

/*
*********************************************************************************************************
*	函 数 名: bsp_InitKeyVar
*	功能说明: 初始化按键变量
*	形    参:  无
*	返 回 值: 无
*********************************************************************************************************
*/
static void bsp_InitKeyVar(void)
{
	uint8_t i;

	/* 对按键FIFO读写指针清零 */
	s_tKey.Read = 0;
	s_tKey.Write = 0;
	s_tKey.Read2 = 0;

	/* 给每个按键结构体成员变量赋一组缺省值 */
	for (i = 0; i < KEY_COUNT; i++)
	{
		s_tBtn[i].LongTime = KEY_LONG_TIME;			/* 长按时间 0 表示不检测长按键事件 */
		s_tBtn[i].Count = KEY_FILTER_TIME / 2;		/* 计数器设置为滤波时间的一半 */
		s_tBtn[i].State = 0;							/* 按键缺省状态,0为未按下 */
		//s_tBtn[i].KeyCodeDown = 3 * i + 1;				/* 按键按下的键值代码 */
		//s_tBtn[i].KeyCodeUp   = 3 * i + 2;				/* 按键弹起的键值代码 */
		//s_tBtn[i].KeyCodeLong = 3 * i + 3;				/* 按键被持续按下的键值代码 */
		s_tBtn[i].RepeatSpeed = 0;						/* 按键连发的速度,0表示不支持连发 */
		s_tBtn[i].RepeatCount = 0;						/* 连发计数器 */
	}

	/* 如果需要单独更改某个按键的参数,可以在此单独重新赋值 */
	/* 比如,我们希望按键1按下超过1秒后,自动重发相同键值 */
	s_tBtn[KID_JOY_OK].LongTime = 100;
	s_tBtn[KID_JOY_OK].RepeatSpeed = 5;	/* 每隔50ms自动发送键值 */

//	s_tBtn[KID_JOY_D].LongTime = 100;
//	s_tBtn[KID_JOY_D].RepeatSpeed = 5;	/* 每隔50ms自动发送键值 */

//	s_tBtn[KID_JOY_L].LongTime = 100;
//	s_tBtn[KID_JOY_L].RepeatSpeed = 5;	/* 每隔50ms自动发送键值 */

//	s_tBtn[KID_JOY_R].LongTime = 100;
//	s_tBtn[KID_JOY_R].RepeatSpeed = 5;	/* 每隔50ms自动发送键值 */

	/* 判断按键按下的函数 */
	s_tBtn[0].IsKeyDownFunc = IsKeyDown1;
	s_tBtn[1].IsKeyDownFunc = IsKeyDown2;
	s_tBtn[2].IsKeyDownFunc = IsKeyDown3;
	s_tBtn[3].IsKeyDownFunc = IsKeyDown4;


	/* 组合键 */
	s_tBtn[4].IsKeyDownFunc = IsKeyDown5;
	s_tBtn[5].IsKeyDownFunc = IsKeyDown6;
}

/*
*********************************************************************************************************
*	函 数 名: bsp_DetectKey
*	功能说明: 检测一个按键。非阻塞状态,必须被周期性的调用。
*	形    参:  按键结构变量指针
*	返 回 值: 无
*********************************************************************************************************
*/
static void bsp_DetectKey(uint8_t i)
{
	KEY_T *pBtn;

	/*
		如果没有初始化按键函数,则报错
		if (s_tBtn[i].IsKeyDownFunc == 0)
		{
			printf("Fault : DetectButton(), s_tBtn[i].IsKeyDownFunc undefine");
		}
	*/
/*按键按下*/
	pBtn = &s_tBtn[i];
	if (pBtn->IsKeyDownFunc()==1)
	{
		/*短按键,软件处理消抖*/
		if (pBtn->Count < KEY_FILTER_TIME)
		{
			pBtn->Count = KEY_FILTER_TIME;
		}
		else if(pBtn->Count < 2 * KEY_FILTER_TIME)
		{
			pBtn->Count++;
		}	
		else
		{
			if (pBtn->State == 0)
			{
				pBtn->State = 1;

				/* 发送按钮按下的消息 */
				bsp_PutKey((uint8_t)(3 * i + 1));
			}

			/*处理长按键*/
			if (pBtn->LongTime > 0)
			{
				if (pBtn->LongCount < pBtn->LongTime)
				{
					/* 发送按钮长按下的消息 */
					if (++pBtn->LongCount == pBtn->LongTime)
					{
						/* 键值放入按键FIFO */
						bsp_PutKey((uint8_t)(3 * i + 3));
					}
				}
				else
				{
					if (pBtn->RepeatSpeed > 0)
					{
						if (++pBtn->RepeatCount >= pBtn->RepeatSpeed)
						{
							pBtn->RepeatCount = 0;
							/* 长按键后,每隔pBtn->RepeatSpeed*10ms发送1个按键 */
							bsp_PutKey((uint8_t)(3 * i + 1));
						}
					}
				}
			}
		}
	}
	else
	{
		if(pBtn->Count > KEY_FILTER_TIME)
		{
			pBtn->Count = KEY_FILTER_TIME;
		}
		else if(pBtn->Count != 0)
		{
			pBtn->Count--;
		}
		else
		{
			if (pBtn->State == 1)
			{
				pBtn->State = 0;

				/* 松开按键KEY_FILTER_TIME后 发送按钮弹起的消息 */
				bsp_PutKey((uint8_t)(3 * i + 2));
			}
		}

		pBtn->LongCount = 0;
		pBtn->RepeatCount = 0;
	}
}

/*
*********************************************************************************************************
*	函 数 名: bsp_KeyScan
*	功能说明: 扫描所有按键。非阻塞,被systick中断周期性的调用
*	形    参:  无
*	返 回 值: 无
*********************************************************************************************************
*/
void bsp_KeyScan(void)
{
	uint8_t i;

	for (i = 0; i < KEY_COUNT; i++)
	{
		bsp_DetectKey(i);
	}
}

/***************************** 安富莱电子 www.armfly.com (END OF FILE) *********************************/

bsp_key.h

/*
*********************************************************************************************************
*
*	模块名称 : 按键驱动模块
*	文件名称 : bsp_key.h
*	版    本 : V1.0
*	说    明 : 头文件
*
*	Copyright (C), 2013-2014, 安富莱电子 www.armfly.com
*
*********************************************************************************************************
*/

#ifndef __BSP_KEY_H
#define __BSP_KEY_H
#include "stm32f4xx_hal.h"
#include "main.h"
#define KEY_COUNT    6	   					/* 按键个数, 4个独立建 + 3个组合键 */

/* 根据应用程序的功能重命名按键宏 */
#define KEY_DOWN_K0		KEY_0_DOWN
#define KEY_UP_K0		  KEY_0_UP
#define KEY_LONG_K0		KEY_0_LONG

#define KEY_DOWN_K1		KEY_1_DOWN
#define KEY_UP_K1			KEY_1_UP
#define KEY_LONG_K1		KEY_1_LONG

#define KEY_DOWN_K2		KEY_2_DOWN
#define KEY_UP_K2		  KEY_2_UP
#define KEY_LONG_K2		KEY_2_LONG

#define KEY_DOWN_K3		KEY_3_DOWN		/* 上 */
#define KEY_UP_K3			KEY_3_UP
#define KEY_LONG_K3		KEY_3_LONG


#define SYS_DOWN_K0K2	KEY_4_DOWN		/* K0 K2 组合键 */
#define SYS_UP_K0K2	  KEY_4_UP
#define SYS_LONG_K0K2	KEY_4_LONG

#define SYS_DOWN_K1K3	KEY_5_DOWN		/* K1 K3 组合键 */
#define SYS_UP_K1K3  	KEY_5_UP
#define SYS_LONG_K1K3	KEY_5_LONG

/* 按键ID, 主要用于bsp_KeyState()函数的入口参数 */
typedef enum
{
	KID_K0 = 0,
	KID_K1,
	KID_K2,
	KID_JOY_OK,
	KID_JOY_U,
	KID_JOY_D,
	KID_JOY_L,
	KID_JOY_R,
}KEY_ID_E;

/*
	按键滤波时间50ms, 单位10ms。
	只有连续检测到50ms状态不变才认为有效,包括弹起和按下两种事件
	即使按键电路不做硬件滤波,该滤波机制也可以保证可靠地检测到按键事件
*/
#define KEY_FILTER_TIME   5
#define KEY_LONG_TIME     100			/* 单位10ms, 持续1秒,认为长按事件 */

/*
	每个按键对应1个全局的结构体变量。
*/
typedef struct
{
	/* 下面是一个函数指针,指向判断按键手否按下的函数 */
	uint8_t (*IsKeyDownFunc)(void); /* 按键按下的判断函数,1表示按下 */

	uint8_t  Count;			/* 滤波器计数器 */
	uint16_t LongCount;		/* 长按计数器 */
	uint16_t LongTime;		/* 按键按下持续时间, 0表示不检测长按 */
	uint8_t  State;			/* 按键当前状态(按下还是弹起) */
	uint8_t  RepeatSpeed;	/* 连续按键周期 */
	uint8_t  RepeatCount;	/* 连续按键计数器 */
}KEY_T;

/*
	定义键值代码, 必须按如下次序定时每个键的按下、弹起和长按事件

	推荐使用enum, 不用#define,原因:
	(1) 便于新增键值,方便调整顺序,使代码看起来舒服点
	(2) 编译器可帮我们避免键值重复。
*/
typedef enum
{
	KEY_NONE = 0,			/* 0 表示按键事件 */

	KEY_0_DOWN,				/* 0键按下 */
	KEY_0_UP,				  /* 0键弹起 */
	KEY_0_LONG,				/* 0键长按 */
	
	KEY_1_DOWN,				/* 1键按下 */
	KEY_1_UP,				  /* 1键弹起 */
	KEY_1_LONG,				/* 1键长按 */

	KEY_2_DOWN,				/* 2键按下 */
	KEY_2_UP,				  /* 2键弹起 */
	KEY_2_LONG,				/* 2键长按 */

	KEY_3_DOWN,				/* 3键按下 */
	KEY_3_UP,				  /* 3键弹起 */
	KEY_3_LONG,				/* 3键长按 */


	/* 组合键 */
	KEY_4_DOWN,				/* 4键按下 */
	KEY_4_UP,				  /* 4键弹起 */
	KEY_4_LONG,				/* 4键长按 */

	KEY_5_DOWN,			/* 5键按下 */
	KEY_5_UP,				/* 5键弹起 */
	KEY_5_LONG,			/* 5键长按 */
}KEY_ENUM;

/* 按键FIFO用到变量 */
#define KEY_FIFO_SIZE	10

typedef struct
{
	uint8_t Buf[KEY_FIFO_SIZE];		/* 键值缓冲区 */
	uint8_t Read;					/* 缓冲区读指针1 */
	uint8_t Write;					/* 缓冲区写指针 */
	uint8_t Read2;					/* 缓冲区读指针2 */
}KEY_FIFO_T;

/* 供外部调用的函数声明 */
void bsp_InitKey(void);
void bsp_KeyScan(void);
void bsp_PutKey(uint8_t _KeyCode);
uint8_t bsp_GetKey(void);
uint8_t bsp_GetKey2(void);
void bsp_SetKeyParam(uint8_t _ucKeyID, uint16_t _LongTime, uint8_t  _RepeatSpeed);
void bsp_ClearKey(void);

#endif

/***************************** 安富莱电子 www.armfly.com (END OF FILE) *********************************/

扫描

void app_main (void const* arg) 
{
//	osStatus_t status;
		/* 创建任务 */
	AppTaskCreate();
			/* 创建任务通信机制 */
	AppObjCreate();
  while(1) {
		/* 按键扫描 */
		bsp_KeyScan();
		osDelay(10);
  }
}

void main_task (void * arg) 
{
	uint8_t ucKeyCode;
	 while(1)
	{
		ucKeyCode = bsp_GetKey(); 
		if (ucKeyCode != KEY_NONE)
		{
			switch (ucKeyCode)	
			{
				/* K1键按下,打印调试说明 */
				case KEY_DOWN_K0:
					printf("K1键按下\r\n");
					break;
				case KEY_UP_K0:
					printf("K1键松开\r\n");
					break;
				case KEY_LONG_K0:
					printf("K1键长按\r\n");
					break;
				
				case KEY_DOWN_K1:
					printf("K2键按下\r\n");
					break;
				case KEY_UP_K1:
					printf("K2键松开\r\n");
					break;
				case KEY_LONG_K1:
					printf("K2键长按\r\n");
					break;
				
				case KEY_DOWN_K2:
					printf("K3键按下\r\n");
					break;
				case KEY_UP_K2:
					printf("K3键松开\r\n");
					break;
				case KEY_LONG_K2:
					printf("K3键长按\r\n");
					break;
				
				case KEY_DOWN_K3:
					printf("K4键按下\r\n");
					break;
				case KEY_UP_K3:
					printf("K4键松开\r\n");
					break;
				case KEY_LONG_K3:
					printf("K4键长按\r\n");
					break;
				
				case SYS_DOWN_K0K2:
					printf("K0K2键按下\r\n");
					break;
				case SYS_UP_K0K2:
					printf("K0K2键松开\r\n");
					break;
				case SYS_LONG_K0K2:
					printf("K0K2键长按\r\n");
					break;
				
				case SYS_DOWN_K1K3:
					printf("K1K3键按下\r\n");
					break;
				case SYS_UP_K1K3:
					printf("K1K3键松开\r\n");
					break;
				case SYS_LONG_K1K3:
					printf("K1K3键长按\r\n");
					break;
				default:
					break;
			}	
		}
		
		osDelay(100);
		LED1_Toggle();
		osThreadYield();
	}
}

  • 7
    点赞
  • 37
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值