按键
按键组件实现了 GPIO 和 ADC 两种按键,并允许同时创建两种不同的按键。下图显示了两种按键的硬件设计:
 
- 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 : 每次 ADC 扫描的样本数 
- BUTTON_LONG_PRESS_HOLD_SERIAL_TIME_MS : 长按期间触发的 CALLBACK 间隔时间 
应用示例
创建按键
// create gpio button
const button_config_t btn_cfg = {0};
const button_gpio_config_t btn_gpio_cfg = {
    .gpio_num = 0,
    .active_level = 0,
};
button_handle_t gpio_btn = NULL;
esp_err_t ret = iot_button_new_gpio_device(&btn_cfg, &btn_gpio_cfg, &gpio_btn);
if(NULL == gpio_btn) {
    ESP_LOGE(TAG, "Button create failed");
}
// create adc button
const button_config_t btn_cfg = {0};
button_adc_config_t btn_adc_cfg = {
    .unit_id = ADC_UNIT_1,
    .adc_channel = 0,
    .button_index = 0,
    .min = 100,
    .max = 400,
};
button_handle_t adc_btn = NULL;
esp_err_t ret = iot_button_new_adc_device(&btn_cfg, &btn_adc_cfg, &adc_btn);
if(NULL == adc_btn) {
    ESP_LOGE(TAG, "Button create failed");
}
// create matrix keypad button
const button_config_t btn_cfg = {0};
const button_matrix_config_t matrix_cfg = {
    .row_gpios = (int32_t[]){4, 5, 6, 7},
    .col_gpios = (int32_t[]){3, 8, 16, 15},
    .row_gpio_num = 4,
    .col_gpio_num = 4,
};
button_handle_t matrix_button = NULL;
esp_err_t ret = iot_button_new_matrix_device(&btn_cfg, &matrix_cfg, btns, &matrix_button);
if(NULL == matrix_button) {
    ESP_LOGE(TAG, "Button create failed");
}
备注
当 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, NULL, 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_args_t args = { .long_press.press_time = 2000, }; iot_button_register_cb(gpio_btn, BUTTON_LONG_PRESS_START, &args, button_auto_check_cb_1, NULL); args.long_press.press_time = 5000; iot_button_register_cb(gpio_btn, BUTTON_LONG_PRESS_START, &args, 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 组件提供了低功耗模式。
所需配置:
- 确保创建的所有按键类型为 GPIO 按键, 并且都开启了 enable_power_save,如存在其他按键,会导致低功耗模式失效 
备注
该功能只保证 Button 组件只在使用中才唤醒 CPU, 不保证 CPU 一定会进入低功耗模式
功耗对比:
- 未开启低功耗模式,按下一次按键 
- 开启低功耗模式,按下一次按键 
因为 GPIO 唤醒 CPU, 仅支持电平触发,所以当按键为工作电平时,CPU 会支持的被唤醒,取决于按下去的时长,因此在低功耗模式下,单次按下的平均电流高于未开启低功耗模式。但是在大的工作周期中,会比未开启低功耗模式更加省电。
- 未开启低功耗模式下,在 4s 内按下三次按键 
- 低功耗模式下,在 4s 内按下三次按键 
如图,低功耗模式下更加的省电。
button_config_t btn_cfg = {0};
button_gpio_config_t gpio_cfg = {
    .gpio_num = button_num,
    .active_level = BUTTON_ACTIVE_LEVEL,
    .enable_power_save = true,
};
button_handle_t btn;
iot_button_new_gpio_device(&btn_cfg, &gpio_cfg, &btn);
什么时候进入 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);
开启 CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP 选项后,如何正常使用按键?
- 开启这个宏后,GPIO 模块会下电,如果需要使用按键功能,必须选用 RTC/LP GPIO,并将唤醒源修改为 EXT 1 
| GPIO 类型 | 是否开启 CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP | 唤醒源 | 
|---|---|---|
| 数字管脚 | N | GPIO 电平触发 | 
| 数字管脚 | Y | 无 | 
| RTC/LP 管脚 | N | GPIO 电平触发 / EXT 1 | 
| RTC/LP 管脚 | Y | EXT 1 | 
备注
ESP32-C5, ESP32-C6 的 LP GPIO 可以支持 GPIO 电平唤醒和 EXT 1 唤醒,同时也需要开启 gpio_hold_en
开启和关闭
组件支持在任意时刻开启和关闭。
// stop button
iot_button_stop();
// resume button
iot_button_resume();
API Reference
Header File
Functions
- 
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_event_args_t *event_args, button_cb_t cb, void *usr_data)
- Register the button event callback function. - 参数
- btn_handle – A button handle to register 
- event – Button event 
- event_args – Button event arguments 
- 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_cb(button_handle_t btn_handle, button_event_t event, button_event_args_t *event_args)
- Unregister all the callbacks associated with the event. - 参数
- btn_handle – A button handle to unregister 
- event – Button event 
- event_args – Used for unregistering a specific callback. 
 
- 返回
- 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_cb(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 
 
- 
const char *iot_button_get_event_str(button_event_t event)
- Get the string representation of a button event. - This function returns the corresponding string for a given button event. If the event value is outside the valid range, the function returns error string “event value is invalid”. - 参数
- event – [in] The button event to be converted to a string. 
- 返回
- Pointer to the event string if the event is valid. 
- ”invalid event” if the event value is invalid. 
 
 
- 
esp_err_t iot_button_print_event(button_handle_t btn_handle)
- Log the current button event as a string. - This function prints the string representation of the current event associated with the button. - 参数
- btn_handle – [in] Handle to the button object. 
- 返回
- ESP_OK: Successfully logged the event string. 
- ESP_FAIL: Invalid button handle. 
 
 
- 
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. 
 
- 
uint32_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 
 
 
- 
esp_err_t iot_button_register_power_save_cb(const button_power_save_config_t *config)
- Register a callback function for power saving. The config->enter_power_save_cb function will be called when all keys stop working. - 参数
- config – Button power save config 
- 返回
- ESP_OK on success 
- ESP_ERR_INVALID_STATE No button registered 
- ESP_ERR_INVALID_ARG Arguments is invalid 
- ESP_ERR_NO_MEM Not enough memory 
 
 
Unions
- 
union button_event_args_t
- #include <iot_button.h>Button events arg. Public Members - 
struct button_event_args_t::long_press_t long_press
- long press struct, for event BUTTON_LONG_PRESS_START and BUTTON_LONG_PRESS_UP 
 - 
struct button_event_args_t::multiple_clicks_t multiple_clicks
- multiple clicks struct, for event BUTTON_MULTIPLE_CLICK 
 
- 
struct button_event_args_t::long_press_t long_press
Structures
- 
struct button_power_save_config_t
- Structs to store power save callback info. - Public Members - 
button_power_save_cb_t enter_power_save_cb
- Callback function when entering power save mode 
 - 
void *usr_data
- User data for the callback 
 
- 
button_power_save_cb_t enter_power_save_cb
Type Definitions
- 
typedef void (*button_cb_t)(void *button_handle, void *usr_data)
- 
typedef void (*button_power_save_cb_t)(void *usr_data)
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



