mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
481 lines
18 KiB
ReStructuredText
481 lines
18 KiB
ReStructuredText
触摸元件
|
||
=============
|
||
|
||
:link_to_translation:`en:[English]`
|
||
|
||
概述
|
||
--------
|
||
|
||
触摸元件库是基于触摸传感器驱动设计的高度抽象的元件库,该库提供了统一且友好的软件接口,可以快速构建电容式触摸传感器的应用。有关触摸传感器驱动 API 的更多信息,请参阅 :doc:`../peripherals/touch_pad`。
|
||
|
||
架构
|
||
^^^^^^^^^^^^
|
||
|
||
触摸元件库通过触摸传感器驱动程序配置触摸传感器外设。使用时,部分必要的硬件参数需要传递给函数 :cpp:func:`touch_element_install`,但只有在调用 :cpp:func:`touch_element_start` 函数后,才会自动配置这些参数。这些参数配置会对实时系统产生很大的影响,因此步骤顺序很重要,必须在调用启动函数之后进行配置,确保系统正常运行。
|
||
|
||
上述参数包括触摸通道阈值、防水屏蔽传感器驱动级别等。触摸元件库会设置触摸传感器中断和 esp_timer 例程,并在触摸传感器中断服务例程中获取触摸传感器的硬件信息(通道状态、通道编号)。当特定通道事件发生时,硬件信息将传递给 esp_timer 回调例程,esp_timer 回调例程将触摸传感器通道信息分配给触摸元件(例如按键、滑条等)。随后,触摸元件库运行特定算法,更新触摸元件状态或计算其位置,并将结果分派给相应的处理程序。
|
||
|
||
因此,在使用触摸元件库时,你无需关注触摸传感器外设的工作细节,该库会处理大部分硬件信息,并将更有意义的信息传递给事件处理程序。
|
||
|
||
下图展示了触摸元件库的工作流程。
|
||
|
||
.. figure:: /../_static/touch_element/te_architecture.svg
|
||
:scale: 100 %
|
||
:align: center
|
||
|
||
触摸元件库架构
|
||
|
||
|
||
下表展示了 {IDF_TARGET_NAME} 中与触摸元件库有关的功能。
|
||
|
||
.. list-table::
|
||
:header-rows: 1
|
||
:widths: 70 30
|
||
:align: center
|
||
|
||
* - 功能
|
||
- ESP32S2
|
||
* - 防水
|
||
- ✔
|
||
* - 按键
|
||
- ✔
|
||
* - 触摸滑条
|
||
- ✔
|
||
* - 矩阵按键
|
||
- ✔
|
||
|
||
|
||
外设
|
||
^^^^^^^^^^
|
||
|
||
{IDF_TARGET_NAME} 集成了一个触摸传感器外设,具有多个物理通道。
|
||
|
||
.. only:: esp32s2 or esp32s3
|
||
|
||
- 14 个物理电容触摸通道
|
||
- 定时器或软件 FSM 触发模式
|
||
- 高达 5 种中断(高阈值和低阈值中断、测量单通道完成和测量所有通道完成中断、测量超时中断)
|
||
- 睡眠模式唤醒源
|
||
- 硬件内置降噪
|
||
- 硬件滤波器
|
||
- 硬件防水传感器
|
||
- 硬件近场感应传感器
|
||
|
||
这些通道的具体位置如下:
|
||
|
||
.. list-table::
|
||
:header-rows: 1
|
||
:widths: 50 50
|
||
:align: center
|
||
|
||
* - 通道
|
||
- {IDF_TARGET_NAME}
|
||
* - **通道 0**
|
||
- **GPIO 0(保留)**
|
||
* - **通道 1**
|
||
- **GPIO 1**
|
||
* - **通道 2**
|
||
- **GPIO 2**
|
||
* - **通道 3**
|
||
- **GPIO 3**
|
||
* - **通道 4**
|
||
- **GPIO 4**
|
||
* - **通道 5**
|
||
- **GPIO 5**
|
||
* - **通道 6**
|
||
- **GPIO 6**
|
||
* - **通道 7**
|
||
- **GPIO 7**
|
||
* - **通道 8**
|
||
- **GPIO 8**
|
||
* - **通道 9**
|
||
- **GPIO 9**
|
||
* - **通道 10**
|
||
- **GPIO 10**
|
||
* - **通道 11**
|
||
- **GPIO 11**
|
||
* - **通道 12**
|
||
- **GPIO 12**
|
||
* - **通道 13**
|
||
- **GPIO 13**
|
||
* - **通道 14**
|
||
- **GPIO 14**
|
||
|
||
|
||
.. only:: esp32
|
||
|
||
- 10 个物理电容触摸通道
|
||
- 定时器或软件 FSM 触发模式
|
||
- 2 种中断(超过阈值和低于阈值中断)
|
||
- 睡眠模式唤醒源
|
||
|
||
这些通道的具体位置如下:
|
||
|
||
.. list-table::
|
||
:header-rows: 1
|
||
:widths: 50 50
|
||
:align: center
|
||
|
||
* - 通道
|
||
- {IDF_TARGET_NAME}
|
||
* - **通道 0**
|
||
- **GPIO 0(有效)**
|
||
* - **通道 1**
|
||
- **GPIO 1**
|
||
* - **通道 2**
|
||
- **GPIO 2**
|
||
* - **通道 3**
|
||
- **GPIO 3**
|
||
* - **通道 4**
|
||
- **GPIO 4**
|
||
* - **通道 5**
|
||
- **GPIO 5**
|
||
* - **通道 6**
|
||
- **GPIO 6**
|
||
* - **通道 7**
|
||
- **GPIO 7**
|
||
* - **通道 8**
|
||
- **GPIO 8**
|
||
* - **通道 9**
|
||
- **GPIO 9**
|
||
|
||
|
||
术语
|
||
-----------
|
||
|
||
触摸元件库的有关术语如下:
|
||
|
||
.. list-table::
|
||
:header-rows: 1
|
||
:widths: 50 50
|
||
:align: center
|
||
|
||
* - 术语
|
||
- 定义
|
||
* - **触摸传感器 (touch sensor)**
|
||
- 芯片内部的触摸传感器外设
|
||
* - **触摸通道 (touch channel)**
|
||
- 触摸传感器外设内的触摸通道
|
||
* - **触摸焊盘 (touch pad)**
|
||
- 外部物理触摸焊盘,通常位于 PCB 内部
|
||
* - **降噪通道 (de-noise channel)**
|
||
- 内部降噪通道,始终为通道 0 且已预留
|
||
* - **屏蔽传感器 (shield sensor)**
|
||
- 防水传感器之一,用于小面积的水滴检测,并补偿水滴对读数的影响
|
||
* - **防护传感器 (guard sensor)**
|
||
- 防水传感器之一,用于大面积的涉水检测,并临时禁用触摸传感器
|
||
* - **屏蔽通道 (shield channel)**
|
||
- 防水屏蔽传感器连接的通道,始终为通道 14
|
||
* - **防护通道 (guard channel)**
|
||
- 防水防护传感器连接的通道
|
||
* - **屏蔽焊盘 (shield pad)**
|
||
- 外部物理屏蔽焊盘,通常是网格状,与防水传感器相连
|
||
* - **防护焊盘 (guard pad)**
|
||
- 外部物理防护焊盘,通常是环状,与防护传感器相连
|
||
|
||
.. figure:: /../_static/touch_element/te_component.svg
|
||
:scale: 100 %
|
||
:align: center
|
||
|
||
触摸传感器应用程序系统组件
|
||
|
||
|
||
触摸传感器信号
|
||
^^^^^^^^^^^^^^^^^^^
|
||
|
||
触摸传感器可提供以下信号:
|
||
|
||
- 原始信号:从触摸传感器获取、未经滤波的信号。
|
||
- 平滑信号:原始信号通过内部硬件滤波器滤波后的信号。
|
||
- 基准信号:经过滤波的信号,已过滤极低频噪声。
|
||
|
||
以上信号均可通过触摸传感器驱动程序 API 获取。
|
||
|
||
.. figure:: /../_static/touch_element/te_signal.png
|
||
:scale: 40 %
|
||
:align: center
|
||
|
||
触摸传感器信号
|
||
|
||
|
||
触摸传感器信号阈值
|
||
^^^^^^^^^^^^^^^^^^^^^^
|
||
|
||
触摸传感器阈值支持重新配置,可用于确定触摸传感器状态。当平滑信号和基准信号间的差值大于阈值,即 ``(平滑信号 - 基准信号)> 信号阈值`` 时,触摸通道状态改变,并触发触摸中断。
|
||
|
||
.. figure:: /../_static/touch_element/te_threshold.svg
|
||
:scale: 40 %
|
||
:align: center
|
||
|
||
触摸传感器信号阈值
|
||
|
||
|
||
灵敏度
|
||
^^^^^^^^^^^^^^^^
|
||
|
||
触摸传感器的一个重要性能参数,该值越大,表明触摸传感器越灵敏。可以通过以下公式计算:
|
||
|
||
.. math::
|
||
|
||
Sensitivity = \frac{Signal_{press} - Signal_{release}}{Signal_{release}} = \frac{Signal_{delta}}{Signal_{benchmark}}
|
||
|
||
|
||
防水性能
|
||
^^^^^^^^^^^^^^^^^^
|
||
|
||
防水性能是触摸传感器的硬件功能,包括防护传感器和屏蔽传感器(始终连接到通道 14),可以抵御一定程度的水滴影响,并检测水流。
|
||
|
||
|
||
触摸按键
|
||
^^^^^^^^^^^^^^^^^^
|
||
|
||
触摸按键占用触摸传感器的一个通道,外观如下图所示:
|
||
|
||
|
||
.. figure:: /../_static/touch_element/te_button.svg
|
||
:scale: 100 %
|
||
:align: center
|
||
|
||
触摸按键
|
||
|
||
|
||
触摸滑条
|
||
^^^^^^^^^^^^^^^^^^
|
||
|
||
触摸滑条占用触摸传感器的多个通道(至少三个),占用的通道越多,滑条的采样分辨率和准确度越高。触摸滑条外观如下图所示:
|
||
|
||
.. figure:: /../_static/touch_element/te_slider.svg
|
||
:scale: 100 %
|
||
:align: center
|
||
|
||
触摸滑条
|
||
|
||
|
||
触摸矩阵
|
||
^^^^^^^^^^^^^^^^^^
|
||
|
||
触摸矩阵按键占用触摸传感器的多个通道(至少 2 + 2 = 4 个通道),它支持通过较少通道获取更多按键。{IDF_TARGET_NAME} 最多支持 49 个按键。触摸矩阵按键外观如下图所示:
|
||
|
||
.. figure:: /../_static/touch_element/te_matrix.svg
|
||
:scale: 100 %
|
||
:align: center
|
||
|
||
触摸矩阵
|
||
|
||
|
||
使用触摸元件库
|
||
--------------
|
||
|
||
使用触摸元件库时,请遵循以下初始化流程:
|
||
|
||
1. 调用 :cpp:func:`touch_element_install`,初始化触摸元件库。
|
||
2. 调用 :cpp:func:`touch_xxxx_install`,初始化触摸元件(按键、滑条等)。
|
||
3. 调用 :cpp:func:`touch_xxxx_create`,创建新元件实例。
|
||
4. 调用 :cpp:func:`touch_xxxx_subscribe_event`,订阅事件通知。
|
||
5. 调用 :cpp:func:`touch_xxxx_set_dispatch_method`,选择事件通知的传递方式。
|
||
6. 选择使用回调函数传递事件通知时,调用 :cpp:func:`touch_xxxx_set_callback`,设置事件处理函数。
|
||
7. 调用 :cpp:func:`touch_element_start`,启用触摸元件库。
|
||
8. 选择使用回调函数传递事件通知时,若事件发生,驱动核心会调用回调函数,你无需做任何处理;选择使用事件任务传递事件通知时,你需要创建一个事件任务,并调用 :cpp:func:`touch_element_message_receive`,循环获取信息。
|
||
9. (可选)如果要暂停触摸元件的实时系统,或因某种原因无法获取触摸元件信息,应调用 :cpp:func:`touch_element_stop`,暂停触摸元件系统,然后再次调用 :cpp:func:`touch_element_start` 恢复系统。
|
||
|
||
上述流程代码如下所示:
|
||
|
||
.. code-block:: c
|
||
|
||
static touch_xxx_handle_t element_handle; //声明一个触摸元件句柄
|
||
|
||
//定义订阅的事件处理函数
|
||
void event_handler(touch_xxx_handle_t out_handle, touch_xxx_message_t out_message, void *arg)
|
||
{
|
||
//事件处理逻辑
|
||
}
|
||
|
||
void app_main()
|
||
{
|
||
//使用默认初始化器配置触摸元件库
|
||
touch_elem_global_config_t global_config = TOUCH_ELEM_GLOBAL_DEFAULT_CONFIG();
|
||
touch_element_install(&global_config);
|
||
|
||
//使用默认初始化器配置触摸元件
|
||
touch_xxx_global_config_t elem_global_config = TOUCH_XXXX_GLOBAL_DEFAULT_CONFIG();
|
||
touch_xxx_install(&elem_global_config);
|
||
|
||
//创建新的实例
|
||
touch_xxx_config_t element_config = {
|
||
...
|
||
...
|
||
};
|
||
touch_xxx_create(&element_config, &element_handle);
|
||
|
||
//通过事件掩码订阅特定事件
|
||
touch_xxx_subscribe_event(element_handle, TOUCH_ELEM_EVENT_ON_PRESS | TOUCH_ELEM_EVENT_ON_RELEASE, NULL);
|
||
|
||
//选择使用回调函数传递事件通知
|
||
touch_xxx_set_dispatch_method(element_handle, TOUCH_ELEM_DISP_CALLBACK);
|
||
|
||
//注册回调函数
|
||
touch_xxx_set_callback(element_handle, event_handler);
|
||
|
||
//启用触摸元件库处理
|
||
touch_element_start();
|
||
}
|
||
|
||
|
||
初始化
|
||
^^^^^^^^^^^^^^
|
||
|
||
1. 要初始化触摸元件库,请调用 :cpp:func:`touch_element_install` 函数,并传递一个 :cpp:type:`touch_elem_global_config_t` 类型的实例作为参数,以配置触摸传感器外设和触摸元件库。默认初始化器位于 :cpp:func:`TOUCH_ELEM_GLOBAL_DEFAULT_CONFIG` 中,此默认配置适用于多数常见应用场景。建议在充分了解触摸传感器外设前,不要更改默认配置,以免影响系统。
|
||
|
||
2. 要初始化特定的触摸元件,需要调用其构造函数 :cpp:func:`touch_xxxx_install`。在调用此构造函数前,所有触摸元件都不会工作,以节省内存。因此,若要设置所需元件,需要为每个要使用的触摸元件分别调用构造函数。
|
||
|
||
|
||
启动触摸元件实例
|
||
^^^^^^^^^^^^^^^^
|
||
|
||
1. 要创建新的触摸元件实例,请调用 :cpp:func:`touch_xxxx_create`,选择一个通道,并将其 `灵敏度`_ 传递给新的元件实例。
|
||
|
||
2. 要订阅事件通知,请调用 :cpp:func:`touch_xxxx_subscribe_event`。触摸元件库提供了多个事件,事件掩码存放在 :idf_file:`components/touch_element/include/touch_element/touch_element.h` 中。通过使用这些事件掩码,可以订阅单个特定事件,或将单个事件组合在一起,订阅多个事件。
|
||
|
||
3. 要配置传递事件通知的方式,请调用 :cpp:func:`touch_xxxx_subscribe_event`。触摸元件库提供了两种方式: :cpp:enumerator:`TOUCH_ELEM_DISP_EVENT` 和 :cpp:enumerator:`TOUCH_ELEM_DISP_CALLBACK`,支持以不同方式获取并处理触摸元件信息。
|
||
|
||
事件处理
|
||
^^^^^^^^^^^^^^^^^
|
||
|
||
如果配置的是 :cpp:enumerator:`TOUCH_ELEM_DISP_EVENT`,需要启用一个事件处理任务获取触摸元件信息。调用 :cpp:func:`touch_element_message_receive` 可以获取所有元件的原始信息,随后通过调用相应的信息解码器 :cpp:func:`touch_xxxx_get_message`,提取特定类型元件的信息,获取有关触摸操作的详细数据。如果配置的是 :cpp:enumerator:`TOUCH_ELEM_DISP_CALLBACK`,在触摸元件开始工作之前,需要调用 :cpp:func:`touch_xxxx_set_callback`,传递一个事件处理函数,有关触摸操作的详细数据都会传递到该事件处理函数。
|
||
|
||
.. warning::
|
||
|
||
由于事件处理函数在元件库的核心运行,即在 esp-timer 回调中运行,请避免执行可能导致阻塞或延迟的操作,如调用 :cpp:func:`vTaskDelay`。
|
||
|
||
|
||
事件处理过程代码如下所示:
|
||
|
||
.. code-block:: c
|
||
|
||
/* ---------------------------------------------- TOUCH_ELEM_DISP_EVENT ----------------------------------------------- */
|
||
void element_handler_task(void *arg)
|
||
{
|
||
touch_elem_message_t element_message;
|
||
while(1) {
|
||
if (touch_element_message_receive(&element_message, Timeout) == ESP_OK) {
|
||
const touch_xxxx_message_t *extracted_message = touch_xxxx_get_message(&element_message); //信息解码
|
||
... //事件处理逻辑
|
||
}
|
||
}
|
||
}
|
||
void app_main()
|
||
{
|
||
...
|
||
|
||
touch_xxxx_set_dispatch_method(element_handle, TOUCH_ELEM_DISP_EVENT); //设置以 TOUCH_ELEM_DISP_EVENT 传递事件通知
|
||
xTaskCreate(&element_handler_task, "element_handler_task", 2048, NULL, 5, NULL); //创建一个事件处理任务
|
||
|
||
...
|
||
}
|
||
/* -------------------------------------------------------------------------------------------------------------- */
|
||
|
||
...
|
||
/* ---------------------------------------------- TOUCH_ELEM_DISP_CALLBACK ----------------------------------------------- */
|
||
void element_handler(touch_xxxx_handle_t out_handle, touch_xxxx_message_t out_message, void *arg)
|
||
{
|
||
//事件处理逻辑
|
||
}
|
||
|
||
void app_main()
|
||
{
|
||
...
|
||
|
||
touch_xxxx_set_dispatch_method(element_handle, TOUCH_ELEM_DISP_CALLBACK); //设置以 ``TOUCH_ELEM_DISP_CALLBACK`` 传递事件通知
|
||
touch_xxxx_set_callback(element_handle, element_handler); //注册事件处理函数
|
||
|
||
...
|
||
}
|
||
/* -------------------------------------------------------------------------------------------------------------- */
|
||
|
||
|
||
使用防水功能
|
||
^^^^^^^^^^^^^^^^
|
||
|
||
1. 一旦初始化触摸元件的防水功能,防水屏蔽传感器会始终处于开启状态。防水屏蔽传感器为可选项,如果不需要,可以通过配置结构体,将 ``TOUCH_WATERPROOF_GUARD_NOUSE`` 传递给 :cpp:func:`touch_element_waterproof_install`。
|
||
|
||
2. 要关联触摸元件与防护传感器,请调用 :cpp:func:`touch_element_waterproof_add`,将触摸元件句柄添加到触摸元件防水功能的掩码列表中。触摸元件与防护传感器关联后,水流触发防护传感器时会关闭触摸元件,为其提供保护。
|
||
|
||
查看使用触摸元件防水功能的示例代码,请前往 ESP-IDF 示例的 :example:`peripherals/touch_sensor/touch_element/touch_element_waterproof` 目录。
|
||
|
||
配置防水功能的代码如下所示:
|
||
|
||
.. code-block:: c
|
||
|
||
void app_main()
|
||
{
|
||
...
|
||
|
||
touch_xxxx_install(); //初始化实例(按键、滑条等)
|
||
touch_xxxx_create(&element_handle); //创建新的触摸元件
|
||
|
||
...
|
||
|
||
touch_element_waterproof_install(); //初始化触摸元件防水功能
|
||
touch_element_waterproof_add(element_handle); //关联触摸元件与防护传感器
|
||
|
||
...
|
||
}
|
||
|
||
从 Light/Deep-sleep 模式唤醒
|
||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||
|
||
仅触摸按键可配置为唤醒源。
|
||
|
||
使用触摸传感器,可以唤醒从 Light-sleep 或 Deep-sleep 模式中唤醒芯片。在 Light-sleep 模式下,任何已安装的触摸按键都可以唤醒芯片。但在 Deep-sleep 模式下,只有睡眠按键可以唤醒芯片,触摸传感器还会立即进行校准。如果手指没有及时离开,可能导致校准参考值出错。尽管在手指离开后,校准参考值会自行恢复,不会影响驱动逻辑,但如果你不想在从 Deep-sleep 模式唤醒时看到错误的校准参考值,可以调用 :cpp:func:`touch_element_sleep_enable_wakeup_calibration`,禁用唤醒校准功能。
|
||
|
||
查看使用触摸元件唤醒芯片的示例代码,请前往 ESP-IDF 示例的 :example:`system/light_sleep` 目录。
|
||
|
||
.. code-block:: c
|
||
|
||
void app_main()
|
||
{
|
||
...
|
||
touch_element_install();
|
||
touch_button_install(); //初始化触摸按键
|
||
touch_button_create(&element_handle); //创建新的触摸元件
|
||
|
||
...
|
||
|
||
// ESP_ERROR_CHECK(touch_element_enable_light_sleep(&sleep_config));
|
||
ESP_ERROR_CHECK(touch_element_enable_deep_sleep(button_handle[0], &sleep_config));
|
||
// ESP_ERROR_CHECK(touch_element_sleep_enable_wakeup_calibration(button_handle[0], false)); //(可选)禁用唤醒校准,防止基准值更新为错误值
|
||
|
||
touch_element_start();
|
||
|
||
...
|
||
}
|
||
|
||
应用示例
|
||
-------------------
|
||
|
||
查看使用触摸元件库的示例代码,请前往 ESP-IDF 示例的 :example:`peripherals/touch_sensor/touch_element` 目录。
|
||
|
||
|
||
API 参考 - 触摸元件核心
|
||
----------------------------------
|
||
|
||
.. include-build-file:: inc/touch_element.inc
|
||
|
||
|
||
API 参考 - 触摸按键
|
||
----------------------------------
|
||
|
||
.. include-build-file:: inc/touch_button.inc
|
||
|
||
|
||
API 参考 - 触摸滑条
|
||
----------------------------------
|
||
|
||
.. include-build-file:: inc/touch_slider.inc
|
||
|
||
|
||
API 参考 - 触摸矩阵
|
||
----------------------------------
|
||
|
||
.. include-build-file:: inc/touch_matrix.inc
|