按键函数

Pursue

上拉输入:

1
2
3
4
5
6
if (HAL_GPIO_ReadPin(KEY_GPIO_Port, KEY_Pin) == GPIO_PIN_SET) {  // 按下
OSTimeDly(20,OS_OPT_TIME_DLY,&err); // 去抖
if (HAL_GPIO_ReadPin(KEY_GPIO_Port, KEY_Pin) == GPIO_PIN_SET) {
/* 用户代码 */
}
}

长按短按:

1
2
3
4
5
6
7
8
9
10
11
12
if (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_12) == GPIO_PIN_RESET) {  // 按下
HAL_Delay(20); // 去抖
if (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_12) == GPIO_PIN_RESET) {
HAL_Delay(500); // 判断长按
if (HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_12) == GPIO_PIN_RESET) {
/* 长按 */
}
else {
/* 短按 */
}
}
}

key.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
#include "key.h"

#define KEY_NUM 3
#define LONG_PRESS_TIME 1000
#define DEBOUNCE_TIME 20

Key_t keys[KEY_NUM];

/**
* @brief 初始化按键接口参数
*/
void Key_Init(void)
{
keys[0].port = KEY_L_GPIO_Port;
keys[0].pin = KEY_L_Pin;
keys[0].active_level = 1;
keys[0].state = KEY_IDLE;
keys[0].last_level = 0;

keys[1].port = KEY_M_GPIO_Port;
keys[1].pin = KEY_M_Pin;
keys[1].active_level = 0;
keys[1].state = KEY_IDLE;
keys[1].last_level = 1;

keys[2].port = KEY_R_GPIO_Port;
keys[2].pin = KEY_R_Pin;
keys[2].active_level = 0;
keys[2].state = KEY_IDLE;
keys[2].last_level = 1;
}

/**
* @brief 按键扫描函数
* @retval result.key_id 按键id
* @retval result.event 事件类型
*/
KeyEvent_t Key_Scan(void)
{
KeyEvent_t result = {0, KEY_EVENT_NONE};

for(uint8_t i = 0; i < KEY_NUM; i++)
{
bool current_level;
if (HAL_GPIO_ReadPin(keys[i].port, keys[i].pin) == keys[i].active_level)
{
current_level = 1;
}
else current_level = 0;

switch (keys[i].state)
{
case KEY_IDLE:
if (current_level && !keys[i].last_level)
{
keys[i].state = KEY_PRESSED;
keys[i].timer = HAL_GetTick();
}
break;

case KEY_PRESSED:
if (current_level)
{
if (HAL_GetTick() - keys[i].timer >= DEBOUNCE_TIME)
{
keys[i].state = KEY_HOLD;
}
}
else keys[i].state = KEY_IDLE;
break;

case KEY_HOLD:
if (current_level)
{
if (HAL_GetTick() - keys[i].timer >= LONG_PRESS_TIME)
{
result.key_id = i;
result.event = KEY_EVENT_LONG;
keys[i].state = KEY_RELEASED;
keys[i].last_level = current_level;
return result; // 长按事件
}
}
else
{
if (HAL_GetTick() - keys[i].timer >= DEBOUNCE_TIME)
{
result.key_id = i;
result.event = KEY_EVENT_SHORT;
keys[i].state = KEY_IDLE;
keys[i].last_level = current_level;
return result; // 短按事件
}
else keys[i].state = KEY_RELEASED;
}
break;

case KEY_RELEASED:
if (!current_level && (HAL_GetTick() - keys[i].timer >= DEBOUNCE_TIME))
{
keys[i].state = KEY_IDLE;
}
break;


default:
break;
}
keys[i].last_level = current_level;
}
return result;
}

key.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#ifndef __KEY_H
#define __KEY_H

#include "main.h"

#include <stdbool.h>

// 按键状态枚举
typedef enum {
KEY_IDLE, // 空闲
KEY_PRESSED, // 按下(去抖中)
KEY_HOLD, // 持续按下
KEY_RELEASED // 释放(去抖中)
} KeyState;

// 按键事件枚举
typedef enum {
KEY_EVENT_NONE, // 无事件
KEY_EVENT_SHORT, // 短按
KEY_EVENT_LONG // 长按
} KeyEvent;

// 按键事件返回结构体
typedef struct {
uint8_t key_id; // 按键ID
KeyEvent event; // 事件类型
} KeyEvent_t;

// 按键结构体
typedef struct {
GPIO_TypeDef* port; // GPIO端口
uint16_t pin; // GPIO引脚
bool active_level; // 按下时的有效电平(true: 高电平, false: 低电平)
KeyState state; // 当前状态
uint32_t timer; // 计时器
bool last_level; // 上次电平
} Key_t;

void Key_Init(void);
KeyEvent_t Key_Scan(void);



#endif

评论
目录
按键函数