按键
按键组件实现了 GPIO 和 ADC 两种按键,并允许同时创建两种不同的按键。下图显示了两种按键的硬件设计:
![../_images/button_hardware.png](../_images/button_hardware.png)
GPIO 按键优点有:每一个按键占用独立的 IO,之间互不影响,稳定性高;缺点有:按键数量多时占用太多 IO 资源。
ADC 按键优点有:可多个按键共用一个 ADC 通道,占用 IO 资源少;缺点有:不能同时按下多按键,当按键因氧化等因素导致闭合电阻增大时,容易误触,稳定性不高。
备注
GPIO 按键需注意上下拉问题,组件内部会启用芯片内部的上下拉电阻,但是在仅支持输入的 IO 内部没有电阻, 需要外部连接。
ADC 按键需注意电压不能超过 ADC 量程。
按键事件
每个按键拥有下表的 8 个事件:
事件 |
触发条件 |
---|---|
BUTTON_PRESS_DOWN |
按下 |
BUTTON_PRESS_UP |
弹起 |
BUTTON_PRESS_REPEAT |
按下弹起次数 >= 2次 |
BUTTON_PRESS_REPEAT_DONE |
重复按下结束 |
BUTTON_SINGLE_CLICK |
按下弹起 1 次 |
BUTTON_DOUBLE_CLICK |
按下弹起 2 次 |
BUTTON_MULTIPLE_CLICK |
指定重复按下次数 N 次,达成时触发 |
BUTTON_LONG_PRESS_START |
按下时间达到阈值的瞬间 |
BUTTON_LONG_PRESS_HOLD |
长按期间一直触发 |
BUTTON_LONG_PRESS_UP |
长按弹起 |
BUTTON_PRESS_REPEAT_DONE |
多次按下弹起结束 |
BUTTON_PRESS_END |
表示 button 此次检测已结束 |
每个按键可以有 回调 和 轮询 两种使用方式:
回调:一个按键的每个事件都可以为其注册一个回调函数,产生事件时回调函数将会被调用。这种方式的效率和实时性高,不会丢失事件。
轮询:在程序中周期性调用
iot_button_get_event()
查询按键当前的事件。这种方式使用简单,适合任务简单的场合
当然你也可以将以上两种方式组合使用。
注意
回调函数中不能有 TaskDelay 等阻塞的操作
配置项
BUTTON_PERIOD_TIME_MS : 扫描周期
BUTTON_DEBOUNCE_TICKS : 消抖次数
BUTTON_SHORT_PRESS_TIME_MS : 连续短按有效时间
BUTTON_LONG_PRESS_TIME_MS : 长按有效时间
ADC_BUTTON_MAX_CHANNEL : ADC 按钮的最大通道数
ADC_BUTTON_MAX_BUTTON_PER_CHANNEL : ADC 一个通道最多的按钮数
ADC_BUTTON_SAMPLE_TIMES : 每次扫描的样本数
BUTTON_SERIAL_TIME_MS : 长按期间触发的 CALLBACK 间隔时间
BUTTON_LONG_PRESS_TOLERANCE_MS : 用于设置长按的容错时间。
应用示例
创建按键
// create gpio button
button_config_t gpio_btn_cfg = {
.type = BUTTON_TYPE_GPIO,
.long_press_time = CONFIG_BUTTON_LONG_PRESS_TIME_MS,
.short_press_time = CONFIG_BUTTON_SHORT_PRESS_TIME_MS,
.gpio_button_config = {
.gpio_num = 0,
.active_level = 0,
},
};
button_handle_t gpio_btn = iot_button_create(&gpio_btn_cfg);
if(NULL == gpio_btn) {
ESP_LOGE(TAG, "Button create failed");
}
// create adc button
button_config_t adc_btn_cfg = {
.type = BUTTON_TYPE_ADC,
.long_press_time = CONFIG_BUTTON_LONG_PRESS_TIME_MS,
.short_press_time = CONFIG_BUTTON_SHORT_PRESS_TIME_MS,
.adc_button_config = {
.adc_channel = 0,
.button_index = 0,
.min = 100,
.max = 400,
},
};
button_handle_t adc_btn = iot_button_create(&adc_btn_cfg);
if(NULL == adc_btn) {
ESP_LOGE(TAG, "Button create failed");
}
// create matrix keypad button
button_config_t matrix_button_cfg = {
.type = BUTTON_TYPE_MATRIX,
.long_press_time = CONFIG_BUTTON_LONG_PRESS_TIME_MS,
.short_press_time = CONFIG_BUTTON_SHORT_PRESS_TIME_MS,
.matrix_button_config = {
.row_gpio_num = 0,
.col_gpio_num = 1,
}
};
button_handle_t matrix_button = iot_button_create(&matrix_button_cfg);
if(NULL == matrix_button) {
ESP_LOGE(TAG, "Button create failed");
}
备注
当 IDF 版本大于等于 release/5.0 时, ADC 按钮使用的是 ADC1 ,当项目中还有其他地方使用到了 ADC1 时,请传入 adc_handle 和 adc_channel 来配置 ADC 按钮。
注册回调函数
Button 组件支持为多个事件注册回调函数,每个事件都可以注册一个回调函数,当事件发生时,回调函数将会被调用。
其中,
BUTTON_LONG_PRESS_START
和BUTTON_LONG_PRESS_UP
支持设置特殊的长按时间。BUTTON_MULTIPLE_CLICK
支持设置多次按下的次数。简单写法
static void button_single_click_cb(void *arg,void *usr_data) { ESP_LOGI(TAG, "BUTTON_SINGLE_CLICK"); } iot_button_register_cb(gpio_btn, BUTTON_SINGLE_CLICK, button_single_click_cb,NULL);
多个回调函数写法
static void button_long_press_1_cb(void *arg,void *usr_data) { ESP_LOGI(TAG, "BUTTON_LONG_PRESS_START_1"); } static void button_long_press_2_cb(void *arg,void *usr_data) { ESP_LOGI(TAG, "BUTTON_LONG_PRESS_START_2"); } button_event_config_t cfg = { .event = BUTTON_LONG_PRESS_START, .event_data.long_press.press_time = 2000, }; iot_button_register_event_cb(gpio_btn, cfg, BUTTON_LONG_PRESS_START, button_long_press_1_cb, NULL); cfg.event_data.long_press.press_time = 5000; iot_button_register_event_cb(gpio_btn, cfg, BUTTON_LONG_PRESS_START, button_long_press_2_cb, NULL);
查询按键事件
button_event_t event;
event = iot_button_get_event(button_handle);
动态修改按键默认值
iot_button_set_param(btn, BUTTON_LONG_PRESS_TIME_MS, 5000);
低功耗支持
在 light_sleep 模式下,esp_timer 定时器会定时触发,导致 cpu 整体功耗居高不下。为了解决这个问题,button 组件提供了低功耗模式。
所需配置:
打开 CONFIG_GPIO_BUTTON_SUPPORT_POWER_SAVE 选项, 会在组件中增加低功耗相关代码
确保创建的所有按键类型为 GPIO 按键, 并且都开启了 enable_power_save,如存在其他按键,会导致低功耗模式失效
备注
该功能只保证 Button 组件只在使用中才唤醒 CPU, 不保证 CPU 一定会进入低功耗模式
功耗对比:
未开启低功耗模式,按下一次按键
开启低功耗模式,按下一次按键
因为 GPIO 唤醒 CPU, 仅支持电平触发,所以当按键为工作电平时,CPU 会支持的被唤醒,取决于按下去的时长,因此在低功耗模式下,单次按下的平均电流高于未开启低功耗模式。但是在大的工作周期中,会比未开启低功耗模式更加省电。
未开启低功耗模式下,在 4s 内按下三次按键
低功耗模式下,在 4s 内按下三次按键
如图,低功耗模式下更加的省电。
button_config_t btn_cfg = {
.type = BUTTON_TYPE_GPIO,
.gpio_button_config = {
.gpio_num = button_num,
.active_level = BUTTON_ACTIVE_LEVEL,
.enable_power_save = true,
},
};
button_handle_t btn = iot_button_create(&btn_cfg);
什么时候进入 Light Sleep
使用 Auto Light Sleep: 会在 button 自动关闭 esp_timer 后进入 Light Sleep
用户控制 Light Sleep: 需要在
enter_power_save_cb
回调到来时进入 Light Sleep
void btn_enter_power_save(void *usr_data)
{
ESP_LOGI(TAG, "Can enter power save now");
}
button_power_save_config_t config = {
.enter_power_save_cb = btn_enter_power_save,
};
iot_button_register_power_save_cb(&config);
开启和关闭
组件支持在任意时刻开启和关闭。
// stop button
iot_button_stop();
// resume button
iot_button_resume();
API Reference
Header File
Functions
-
button_handle_t iot_button_create(const button_config_t *config)
Create a button.
- 参数
config – pointer of button configuration, must corresponding the button type
- 返回
A handle to the created button, or NULL in case of error.
-
esp_err_t iot_button_delete(button_handle_t btn_handle)
Delete a button.
- 参数
btn_handle – A button handle to delete
- 返回
ESP_OK Success
ESP_FAIL Failure
-
esp_err_t iot_button_register_cb(button_handle_t btn_handle, button_event_t event, button_cb_t cb, void *usr_data)
Register the button event callback function.
- 参数
btn_handle – A button handle to register
event – Button event
cb – Callback function.
usr_data – user data
- 返回
ESP_OK on success
ESP_ERR_INVALID_ARG Arguments is invalid.
ESP_ERR_INVALID_STATE The Callback is already registered. No free Space for another Callback.
ESP_ERR_NO_MEM No more memory allocation for the event
-
esp_err_t iot_button_register_event_cb(button_handle_t btn_handle, button_event_config_t event_cfg, button_cb_t cb, void *usr_data)
Register the button event callback function.
- 参数
btn_handle – A button handle to register
event_cfg – Button event configuration
cb – Callback function.
usr_data – user data
- 返回
ESP_OK on success
ESP_ERR_INVALID_ARG Arguments is invalid.
ESP_ERR_INVALID_STATE The Callback is already registered. No free Space for another Callback.
ESP_ERR_NO_MEM No more memory allocation for the event
-
esp_err_t iot_button_unregister_event(button_handle_t btn_handle, button_event_config_t event_cfg, button_cb_t cb)
Unregister the button event callback function. In case event_data is also passed it will unregister function for that particular event_data only.
- 参数
btn_handle – A button handle to unregister
event_cfg – Button event
cb – callback to unregister
- 返回
ESP_OK on success
ESP_ERR_INVALID_ARG Arguments is invalid.
ESP_ERR_INVALID_STATE The Callback was never registered with the event
-
esp_err_t iot_button_unregister_cb(button_handle_t btn_handle, button_event_t event)
Unregister all the callbacks associated with the event.
- 参数
btn_handle – A button handle to unregister
event – Button event
- 返回
ESP_OK on success
ESP_ERR_INVALID_ARG Arguments is invalid.
ESP_ERR_INVALID_STATE No callbacks registered for the event
-
size_t iot_button_count_cb(button_handle_t btn_handle)
counts total callbacks registered
- 参数
btn_handle – A button handle to the button
- 返回
0 if no callbacks registered, or 1 .. (BUTTON_EVENT_MAX-1) for the number of Registered Buttons.
ESP_ERR_INVALID_ARG if btn_handle is invalid
-
size_t iot_button_count_event(button_handle_t btn_handle, button_event_t event)
how many callbacks are registered for the event
- 参数
btn_handle – A button handle to the button
event – Button event
- 返回
0 if no callbacks registered, or 1 .. (BUTTON_EVENT_MAX-1) for the number of Registered Buttons.
ESP_ERR_INVALID_ARG if btn_handle is invalid
-
button_event_t iot_button_get_event(button_handle_t btn_handle)
Get button event.
- 参数
btn_handle – Button handle
- 返回
Current button event. See button_event_t
-
uint8_t iot_button_get_repeat(button_handle_t btn_handle)
Get button repeat times.
- 参数
btn_handle – Button handle
- 返回
button pressed times. For example, double-click return 2, triple-click return 3, etc.
-
uint16_t iot_button_get_ticks_time(button_handle_t btn_handle)
Get button ticks time.
- 参数
btn_handle – Button handle
- 返回
Actual time from press down to up (ms).
-
uint16_t iot_button_get_long_press_hold_cnt(button_handle_t btn_handle)
Get button long press hold count.
- 参数
btn_handle – Button handle
- 返回
Count of trigger cb(BUTTON_LONG_PRESS_HOLD)
-
esp_err_t iot_button_set_param(button_handle_t btn_handle, button_param_t param, void *value)
Dynamically change the parameters of the iot button.
- 参数
btn_handle – Button handle
param – Button parameter
value – new value
- 返回
ESP_OK on success
ESP_ERR_INVALID_ARG Arguments is invalid.
-
uint8_t iot_button_get_key_level(button_handle_t btn_handle)
Get button key level.
- 参数
btn_handle – Button handle
- 返回
1 if key is pressed
0 if key is released or invalid button handle
-
esp_err_t iot_button_resume(void)
resume button timer, if button timer is stopped. Make sure iot_button_create() is called before calling this API.
- 返回
ESP_OK on success
ESP_ERR_INVALID_STATE timer state is invalid.
-
esp_err_t iot_button_stop(void)
stop button timer, if button timer is running. Make sure iot_button_create() is called before calling this API.
- 返回
ESP_OK on success
ESP_ERR_INVALID_STATE timer state is invalid
Unions
-
union button_event_data_t
- #include <iot_button.h>
Button events data.
Public Members
-
struct button_event_data_t::long_press_t long_press
long press struct, for event BUTTON_LONG_PRESS_START and BUTTON_LONG_PRESS_UP
-
struct button_event_data_t::multiple_clicks_t multiple_clicks
multiple clicks struct, for event BUTTON_MULTIPLE_CLICK
-
struct button_event_data_t::long_press_t long_press
Structures
-
struct button_event_config_t
Button events configuration.
Public Members
-
button_event_t event
button event type
-
button_event_data_t event_data
event data corresponding to the event
-
button_event_t event
-
struct button_custom_config_t
custom button configuration
Public Members
-
uint8_t active_level
active level when press down
-
esp_err_t (*button_custom_init)(void *param)
user defined button init
-
uint8_t (*button_custom_get_key_value)(void *param)
user defined button get key value
-
esp_err_t (*button_custom_deinit)(void *param)
user defined button deinit
-
void *priv
private data used for custom button, MUST be allocated dynamically and will be auto freed in iot_button_delete
-
uint8_t active_level
-
struct button_config_t
Button configuration.
Public Members
-
button_type_t type
button type, The corresponding button configuration must be filled
-
uint16_t long_press_time
Trigger time(ms) for long press, if 0 default to BUTTON_LONG_PRESS_TIME_MS
-
uint16_t short_press_time
Trigger time(ms) for short press, if 0 default to BUTTON_SHORT_PRESS_TIME_MS
-
button_gpio_config_t gpio_button_config
gpio button configuration
-
button_matrix_config_t matrix_button_config
matrix key button configuration
-
button_custom_config_t custom_button_config
custom button configuration
-
union button_config_t::[anonymous] [anonymous]
button configuration
-
button_type_t type
Type Definitions
-
typedef void (*button_cb_t)(void *button_handle, void *usr_data)
-
typedef void *button_handle_t
Enumerations
-
enum button_event_t
Button events.
Values:
-
enumerator BUTTON_PRESS_DOWN
-
enumerator BUTTON_PRESS_UP
-
enumerator BUTTON_PRESS_REPEAT
-
enumerator BUTTON_PRESS_REPEAT_DONE
-
enumerator BUTTON_SINGLE_CLICK
-
enumerator BUTTON_DOUBLE_CLICK
-
enumerator BUTTON_MULTIPLE_CLICK
-
enumerator BUTTON_LONG_PRESS_START
-
enumerator BUTTON_LONG_PRESS_HOLD
-
enumerator BUTTON_LONG_PRESS_UP
-
enumerator BUTTON_PRESS_END
-
enumerator BUTTON_EVENT_MAX
-
enumerator BUTTON_NONE_PRESS
-
enumerator BUTTON_PRESS_DOWN