cubemx配置
- 打开串口
- 配置按键的 gpio口为 up input 模式
- 配置时钟树
代码
yxy_open_key.c
#include "yxy_open_key.h"
#include "stdlib.h"
#include "string.h"
#include "yxy_debug.h"
uint16_t keyNum = 0;
struct Key_Link * p_kl = NULL;
__weak void key_click(uint16_t key_id)
{
USER_PASS;
}
#if KEY_SUPPORT >= 2
__weak void key_double(uint16_t key_id)
{
USER_PASS;
}
#endif
#if KEY_SUPPORT >= 3
__weak void key_third(uint16_t key_id)
{
USER_PASS;
}
#endif
#if KEY_SUPPORT >= 4
__weak void key_fourth(uint16_t key_id)
{
USER_PASS;
}
#endif
__weak void key_long(uint16_t key_id)
{
USER_PASS;
}
static uint16_t Radical_2(uint16_t x);
static uint16_t Radical_2(uint16_t x)
{
uint16_t y = 0;
while(x)
{
x >>= 1;
y++;
}
y--;
return y;
}
HAL_StatusTypeDef openKey_init(void)
{
p_kl = (struct Key_Link *)malloc(sizeof(struct Key_Link));
if(p_kl == NULL)
{
yxy_DEBUG("open key initialization failed... \r\n");
return HAL_ERROR;
}
p_kl->p_kN = NULL;
strcpy((char *)p_kl->kC.keyName, "keyLinkHand");
p_kl->kC.keyID = 0xffff;
p_kl->kC.keyDownCnt = 0;
p_kl->kC.keyUpCnt = 0;
p_kl->kC.keyManyCliCnt = 0;
p_kl->kC.kDownLockState = KEY_NULL;
keyNum = 0;
yxy_DEBUG("open key initialization success !\r\n");
return HAL_OK;
}
HAL_StatusTypeDef key_add(User_Key * userKey, uint8_t * keyName, GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin)
{
struct Key_Link * p_keyLinkNode = p_kl;
uint8_t GPIOxName = (uint8_t)((((uint32_t)GPIOx - (uint32_t)GPIOA) / 0x00000400UL) + 'A');
uint16_t PinName = Radical_2(GPIO_Pin);
if(IS_GPIO_ALL_INSTANCE(GPIOx) != 1)
{
yxy_DEBUG("key add GPIOx error... \r\n");
return HAL_ERROR;
}
if((IS_GPIO_PIN(GPIO_Pin) != 1) && (GPIO_Pin != GPIO_PIN_All))
{
yxy_DEBUG("key add GPIO_Pin error... \r\n");
return HAL_ERROR;
}
while(p_keyLinkNode->p_kN != NULL)
{
p_keyLinkNode = p_keyLinkNode->p_kN;
}
p_keyLinkNode->p_kN = (struct Key_Link *)malloc(sizeof(struct Key_Link));
p_keyLinkNode = p_keyLinkNode->p_kN;
if(p_keyLinkNode == NULL)
{
yxy_DEBUG("key add failed... \r\n");
return HAL_ERROR;
}
p_keyLinkNode->p_kN = NULL;
strcpy((char *)p_keyLinkNode->kC.keyName, (const char *)keyName);
p_keyLinkNode->kC.keyID = keyNum;
keyNum++;
p_keyLinkNode->kC.GPIOx = GPIOx;
p_keyLinkNode->kC.GPIO_Pin = GPIO_Pin;
p_keyLinkNode->kC.keyDownCnt = 0;
p_keyLinkNode->kC.keyUpCnt = 0;
p_keyLinkNode->kC.keyManyCliCnt = 0;
p_keyLinkNode->kC.kDownLockState = KEY_NULL;
userKey->GPIOx = GPIOx;
userKey->GPIO_Pin = GPIO_Pin;
userKey->keyID = p_keyLinkNode->kC.keyID;
userKey->portname = GPIOxName;
userKey->pinName = PinName;
yxy_DEBUG("New key :\r\n name : \"%s\" \r\n", p_keyLinkNode->kC.keyName);
yxy_DEBUG(" port : GPIO%c\r\n", GPIOxName);
yxy_DEBUG(" Pin : PIN_%d\r\n", PinName);
yxy_DEBUG("\r\n");
return HAL_OK;
}
HAL_StatusTypeDef key_clear(User_Key * userKey)
{
struct Key_Link * p_keyLinkNode = p_kl;
struct Key_Link * p_keyNode_temp = NULL;
if(IS_GPIO_ALL_INSTANCE(userKey->GPIOx) != 1)
{
yxy_DEBUG("key clear GPIOx error... \r\n");
return HAL_ERROR;
}
if(IS_GPIO_PIN(userKey->GPIO_Pin) != 1)
{
yxy_DEBUG("key clear GPIO_Pin error... \r\n");
return HAL_ERROR;
}
while(p_keyLinkNode->p_kN != NULL)
{
if((p_keyLinkNode->p_kN->kC.GPIOx == userKey->GPIOx) && (p_keyLinkNode->p_kN->kC.GPIO_Pin == userKey->GPIO_Pin))
{
p_keyNode_temp = p_keyLinkNode->p_kN;
p_keyLinkNode->p_kN = p_keyNode_temp->p_kN;
free(p_keyNode_temp);
p_keyNode_temp = NULL;
userKey->GPIOx = NULL;
userKey->GPIO_Pin = 0;
userKey->keyID = 0xff;
yxy_DEBUG("key clear ok!\r\n");
return HAL_OK;
}
p_keyLinkNode = p_keyLinkNode->p_kN;
}
return HAL_ERROR;
}
void key_scan(void)
{
struct Key_Link * p_keyLinkNode = p_kl->p_kN;
while(p_keyLinkNode != NULL)
{
if((p_keyLinkNode->kC.GPIOx->IDR & p_keyLinkNode->kC.GPIO_Pin) == (uint32_t)GPIO_PIN_RESET)
{
p_keyLinkNode->kC.keyUpCnt = 0;
p_keyLinkNode->kC.keyDownCnt++;
switch(p_keyLinkNode->kC.kDownLockState)
{
case KEY_NULL:
{
if(p_keyLinkNode->kC.keyDownCnt >= KEY_Jitters_Elimination)
{
p_keyLinkNode->kC.keyDownCnt = 0;
p_keyLinkNode->kC.keyManyCliCnt = 0;
p_keyLinkNode->kC.kDownLockState = KEY_CLICK;
}
}
break;
case KEY_CLICK:
{
if((p_keyLinkNode->kC.keyDownCnt >= KEY_Jitters_Elimination) && (p_keyLinkNode->kC.keyManyCliCnt == 1))
{
p_keyLinkNode->kC.keyDownCnt = 0;
p_keyLinkNode->kC.keyManyCliCnt = 0;
#if KEY_SUPPORT >= 2
p_keyLinkNode->kC.kDownLockState = KEY_DOUBLE;
#else
p_keyLinkNode->kC.kDownLockState = KEY_NULL;
key_click(p_keyLinkNode->kC.keyID);
#endif
}
if((p_keyLinkNode->kC.keyDownCnt >= TIME_BASE_SLOT * 4) && (p_keyLinkNode->kC.keyManyCliCnt < 1))
{
p_keyLinkNode->kC.keyDownCnt = 0;
p_keyLinkNode->kC.kDownLockState = KEY_NULL;
key_long(p_keyLinkNode->kC.keyID);
while((p_keyLinkNode->kC.GPIOx->IDR & p_keyLinkNode->kC.GPIO_Pin) == (uint32_t)GPIO_PIN_RESET);
}
}
break;
#if KEY_SUPPORT >= 2
case KEY_DOUBLE:
{
if((p_keyLinkNode->kC.keyDownCnt >= KEY_Jitters_Elimination) && (p_keyLinkNode->kC.keyManyCliCnt == 2))
{
p_keyLinkNode->kC.keyDownCnt = 0;
p_keyLinkNode->kC.keyManyCliCnt = 0;
#if KEY_SUPPORT >= 3
p_keyLinkNode->kC.kDownLockState = KEY_THIRD;
#else
p_keyLinkNode->kC.kDownLockState = KEY_NULL;
key_double(p_keyLinkNode->kC.keyID);
#endif
}
}
break;
#endif
#if KEY_SUPPORT >= 3
case KEY_THIRD:
{
if((p_keyLinkNode->kC.keyDownCnt >= KEY_Jitters_Elimination) && (p_keyLinkNode->kC.keyManyCliCnt == 3))
{
p_keyLinkNode->kC.keyDownCnt = 0;
p_keyLinkNode->kC.keyManyCliCnt = 0;
#if KEY_SUPPORT >= 4
p_keyLinkNode->kC.kDownLockState = KEY_FOURTH;
#else
p_keyLinkNode->kC.kDownLockState = KEY_NULL;
key_third(p_keyLinkNode->kC.keyID);
#endif
}
}
break;
#endif
#if KEY_SUPPORT >= 4
case KEY_FOURTH:
{
}
break;
#endif
default:
break;
}
}
else
{
if(p_keyLinkNode->kC.kDownLockState != NULL)
{
p_keyLinkNode->kC.keyDownCnt = 0;
p_keyLinkNode->kC.keyUpCnt++;
switch(p_keyLinkNode->kC.kDownLockState)
{
case KEY_CLICK:
{
p_keyLinkNode->kC.keyManyCliCnt = 1;
}
break;
#if KEY_SUPPORT >= 2
case KEY_DOUBLE:
{
p_keyLinkNode->kC.keyManyCliCnt = 2;
}
break;
#endif
#if KEY_SUPPORT >= 3
case KEY_THIRD:
{
p_keyLinkNode->kC.keyManyCliCnt = 3;
}
break;
#endif
#if KEY_SUPPORT >= 4
case KEY_FOURTH:
{
p_keyLinkNode->kC.keyManyCliCnt = 4;
}
break;
#endif
default:
break;
}
if(p_keyLinkNode->kC.keyUpCnt >= TIME_BASE_SLOT)
{
p_keyLinkNode->kC.keyUpCnt = 0;
p_keyLinkNode->kC.keyManyCliCnt = 0;
switch(p_keyLinkNode->kC.kDownLockState)
{
case KEY_CLICK:
key_click(p_keyLinkNode->kC.keyID);
break;
#if KEY_SUPPORT >= 2
case KEY_DOUBLE:
key_double(p_keyLinkNode->kC.keyID);
break;
#endif
#if KEY_SUPPORT >= 3
case KEY_THIRD:
key_third(p_keyLinkNode->kC.keyID);
break;
#endif
#if KEY_SUPPORT >= 4
case KEY_FOURTH:
key_fourth(p_keyLinkNode->kC.keyID);
break;
#endif
default:
break;
}
p_keyLinkNode->kC.kDownLockState = KEY_NULL;
}
}
}
p_keyLinkNode = p_keyLinkNode->p_kN;
}
}
uint16_t get_key_Num(void)
{
return keyNum;
}
HAL_StatusTypeDef get_key_Name(User_Key * userKey, uint8_t * nameReadBuff)
{
struct Key_Link * p_keyLinkNode = p_kl->p_kN;
while(p_keyLinkNode != NULL)
{
if((p_keyLinkNode->kC.GPIOx == userKey->GPIOx) && (p_keyLinkNode->kC.GPIO_Pin == userKey->GPIO_Pin))
{
strcpy((char *)nameReadBuff, (const char *)p_keyLinkNode->kC.keyName);
return HAL_OK;
}
p_keyLinkNode = p_keyLinkNode->p_kN;
}
return HAL_ERROR;
}
yxy_open_key.h
#ifndef __KEY_H_
#define __KEY_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "gpio.h"
#ifdef YXY
#warning "这个警告要害死强迫症!"
#endif
#define KEY_SUPPORT 4
#define KEY_MAX_NUM 10
#define KEY_NUME_LEN_MAX 20
#define KEY_Jitters_Elimination 20
#define TIME_BASE_SLOT 100
typedef enum
{
KEY_NULL = 0 ,
KEY_CLICK = 1 ,
#if KEY_SUPPORT >= 2
KEY_DOUBLE = 2 ,
#endif
#if KEY_SUPPORT >= 3
KEY_THIRD = 3 ,
#endif
#if KEY_SUPPORT >= 4
KEY_FOURTH = 4 ,
#endif
KEY_MAX_VAL = 0xffff,
KEY_LONG_PRESS = KEY_MAX_VAL-1,
KEY_LAST_NULL_VAL = 0xffff
}KEY_STATE;
typedef struct
{
uint8_t keyName[KEY_NUME_LEN_MAX];
uint16_t keyID;
GPIO_TypeDef *GPIOx;
uint16_t GPIO_Pin;
uint16_t keyDownCnt;
uint16_t keyUpCnt;
uint16_t keyManyCliCnt;
KEY_STATE kDownLockState;
}key_Class;
struct Key_Link
{
key_Class kC;
struct Key_Link * p_kN;
};
typedef struct
{
uint16_t keyID;
GPIO_TypeDef *GPIOx;
uint16_t GPIO_Pin;
uint8_t portname;
uint16_t pinName;
}User_Key;
HAL_StatusTypeDef openKey_init(void);
HAL_StatusTypeDef key_add(User_Key * userKey, uint8_t * keyName, GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin);
HAL_StatusTypeDef key_clear(User_Key * userKey);
void key_scan(void);
uint16_t get_key_Num(void);
HAL_StatusTypeDef get_key_Name(User_Key * userKey, uint8_t * nameReadBuff);
void key_click(uint16_t key_id);
#if KEY_SUPPORT >= 2
void key_double(uint16_t key_id);
#endif
#if KEY_SUPPORT >= 3
void key_third(uint16_t key_id);
#endif
#if KEY_SUPPORT >= 4
void key_fourth(uint16_t key_id);
#endif
void key_long(uint16_t key_id);
#ifdef __cplusplus
}
#endif
#endif
使用
初次使用
在 yxy_open_key.h 中更改对应的宏配置
KEY_SUPPORT
- 按键多击支持(默认支持单击和长按)
- >=2 则可支持2击
- >=3 则可支持2、3击
- >=4 则可支持2、3、4击
KEY_MAX_NUM
KEY_NUME_LEN_MAX
KEY_Jitters_Elimination
TIME_BASE_SLOT
- 时间段落的长度,用于判断按键的不同击打模式的时间基准,单位ms。
main.c
main函数外需要添加的部分
头文件
#include "O_redirect.h"
#include "yxy_debug.h"
#include "yxy_open_key.h"
需要定义的全局变量
User_Key key0;
重写按键回调函数
void key_click(uint16_t key_id)
{
if(key_id == key0.keyID)
{
U_Printf("key0 click\r\n");
}
}
void key_double(uint16_t key_id)
{
if(key_id == key0.keyID)
{
U_Printf("key0 double\r\n");
}
}
void key_third(uint16_t key_id)
{
if(key_id == key0.keyID)
{
U_Printf("key0 third\r\n");
}
}
void key_fourth(uint16_t key_id)
{
if(key_id == key0.keyID)
{
U_Printf("key0 fourth\r\n");
}
}
void key_long(uint16_t key_id)
{
if(key_id == key0.keyID)
{
U_Printf("key0 long\r\n");
}
}
main函数非循环部分
openKey_init();
key_add(&Key0, (uint8_t *)"first key", KEY0_GPIO_Port, KEY0_Pin);
while循环中
key_scan();
HAL_Delay(1);
完整代码
开源按键完整工程代码点这里
|