资讯详情

ESP32学习笔记(16)——Touch Sensor(触摸按键)接口使用

一、简介

电容式触摸感应技术已经广泛应用于家用电器、消费电子等领域,以此发展的触摸按键产品与传统按键相比按键有下面的优点:

  • 无机械装置,不得磨损老化,使用寿命长。
  • 表面无缝隙,无水分和杂质渗透。
  • 减少元件的使用,BOM 成本降低。
  • 工业设计成本降低,面板不需要开孔。
  • 产品外观美观,设计灵活。

通过测量面板(传感器)及其环境之间的电容变化,检测触摸界面附近是否有触摸事件。

以下是由触摸传感器系统组成的典型示意图。

  • 保护覆盖层是指触摸面板。触摸面板必须是隔离触摸电极和外部环境的绝缘材料。但是,保护覆盖层会降低触摸的灵敏度,需要根据应用场景选择合适的厚度和材料。

  • 触摸电极是触摸传感器的重要组成部分。手指与触摸电极形成平行板电容器,改变触摸通道的电容。触摸电极必须是导电材料。风格多变,如 PCB 铜箔、金属板、触摸弹簧等。

  • 非导电材料支撑触摸电极。

  • 连接触摸电极和芯片,包括 PCB 布线和连接器。布线是引入干扰和寄生电容器的主要部件,布线布局需要仔细分配。

ESP-IDF 触摸感应器编程指南

1.1 FSM 描述

用户可以实时读取每个触摸传感器通道的脉冲计值(OUT),根据脉冲计值(OUT)判断是否有手值触摸。这种轮循方式占用较大 CPU 资源。ESP32 它还支持配置硬件寄存器来检测手指触摸动作,并定期检测硬件脉冲计的值。如果超过设定的阈值,则可能会触发通知应用层的触摸传感器通道。

内部硬件逻辑包括有限状态机 (Finite-State Machine, FSM)。FSM 检测触摸传感器内部结构描述的序列。该软件可以由专用寄存器操作 FSM。 FSM 如下图所示。

二、IO功能表

ESP32 提供了多达 10 支持电容式触摸传感器 IO,它可以检测触摸传感器上手指接触或接近引起的电容变化。芯片内的电容检测电路具有噪音低、灵敏度高的特点,支持用户使用较小的触摸垫来实现触摸检测功能。用户还可以使用触摸板阵列来检测更大的区域或更多的测试点。下表列出 ESP32 中 10 具有触摸传感功能的个人 IO。

TOUCH_PAD_NUM0 = 0, /*!< Touch pad channel 0 is GPIO4(ESP32) */ TOUCH_PAD_NUM1,     /*!< Touch pad channel 1 is GPIO0(ESP32) / GPIO1(ESP32-S2) */ TOUCH_PAD_NUM2,     /*!< Touch pad channel 2 is GPIO2(ESP32) / GPIO2(ESP32-S2) */ TOUCH_PAD_NUM3,     /*!< Touch pad channel 3 is GPIO15(ESP32) / GPIO3(ESP32-S2) */ TOUCH_PAD_NUM4,     /*!< Touch pad channel 4 is GPIO13(ESP32) / GPIO4(ESP32-S2) */ TOUCH_PAD_NUM5,     /*!< Touch pad channel 5 is GPIO12(ESP32) / GPIO5(ESP32-S2) */ TOUCH_PAD_NUM6,     /*!< Touch pad channel 6 is GPIO14(ESP32) / GPIO6(ESP32-S2) */ TOUCH_PAD_NUM7,     /*!< Touch pad channel 7 is GPIO27(ESP32) / GPIO7(ESP32-S2) */ TOUCH_PAD_NUM8,     /*!< Touch pad channel 8 is GPIO33(ESP32) / GPIO8(ESP32-S2) */ TOUCH_PAD_NUM9,     /*!< Touch pad channel 9 is GPIO32(ESP32) / GPIO9(ESP32-S2) */ 

三、功能概述

3.1 触摸板驱动程序的初始化

在使用触摸板之前,您需要初始化触摸板驱动程序touch_pad_init()。此函数设置“ API参考”中“宏”.._DEFAULT以下几个驱动程序参数。它还删除了之前接触过的打击垫的信息(如果有的话),并禁止中断。

如果不再需要驱动程序,请通过调用程序初始化touch_pad_deinit()

3.2 触摸板GPIO引脚的配置

使用可以是特定的GPIO启用触摸传感器功能touch_pad_config()

使用该功能touch_pad_set_fsm_mode()是否应通过硬件计时器或软件自动启动触摸板进行测量FSM操作)。如果选择软件模式,请使用touch_pad_sw_start()来启动FSM。

3.3 触摸状态测量

从传感器中轻松读取原始或过滤后的测量值:

  • touch_pad_read_raw_data()
  • touch_pad_read_filtered()

它们也可以用来评估特定的触摸板设计,例如通过检查触摸或释放触摸板时传感器读数的范围。然后使用此信息来建立触摸阈值。

3.4 调整测量参数

触摸传感器具有几个可配置的参数,以匹配特定触摸板设计的特征。例如,为了感测较小的容量变化,可以缩小触摸板被充电/放电的参考电压范围。高和低参考电压是使用功能设置的touch_pad_set_voltage()

除了识别较小的容量变化外,积极的副作用是降低低功耗应用程序的功耗。可能的负面影响是测量噪声的增加。如果读数的动态范围仍然令人满意,则可以通过减少测量时间来进一步降低功耗touch_pad_set_meas_time()

下表总结了可用的测量参数和相应的设置功能:

  • 触摸板充放电参数:

    • 电压范围 touch_pad_set_voltage()
    • 速度(坡度): touch_pad_set_cnt_mode()
  • 测量时间: touch_pad_set_meas_time()

电压范围(高/低参考电压)、速度(斜率)与测量时间的关系下图所示。

3.5 过滤测量

如果测量结果比较嘈杂,则可以使用提供的API函数对其进行过滤。在使用过滤器之前,请调用进行启动touch_pad_filter_start()

滤波器类型为IIR(无限脉冲响应),它具有可配置的周期,可以使用函数设置touch_pad_set_filter_period()

您可以使用停止过滤器touch_pad_filter_stop()。如果不再需要,可以通过调用删除过滤器touch_pad_filter_delete()

3.6 触摸侦测

ESP32的硬件基于用户配置的阈值和FSM执行的原始测量来实现触摸检测。使用功能touch_pad_get_status()检查已触摸了哪些打击垫并touch_pad_clear_status()清除了触摸状态信息。

如果测量结果嘈杂且容量变化很小,则硬件触摸检测可能不可靠。要解决此问题,请在您自己的应用程序中执行测量过滤并执行触摸检测,而不是使用硬件检测/提供的中断。有关这两种触摸检测方法的示例实现,请参阅外围设备/ touch_pad_interrupt。

3.7 触摸触发的中断

在启用触摸检测中断之前,应建立触摸检测阈值。触摸和释放打击垫时,请使用“触摸状态测量”中描述的功能来读取和显示传感器测量值。如果测量结果嘈杂且相对容量变化较小,请应用过滤器。根据您的应用和环境条件,测试温度和电源电压变化对测量值的影响。

建立检测阈值后,可以在初始化期间使用touch_pad_config()或在运行时使用设置检测阈值touch_pad_set_thresh()

在下一步中,配置如何触发中断。可以在阈值以下或阈值之上触发这些阈值,该阈值是通过功能设置的touch_pad_set_trigger_mode()

最后,使用以下功能配置和管理中断调用:

  • touch_pad_isr_register() / touch_pad_isr_deregister()
  • touch_pad_intr_enable() / touch_pad_intr_disable()

当中断可操作时,您可以通过调用touch_pad_get_status()并从中清除中断的状态来获取信息touch_pad_clear_status()

3.8 从睡眠模式唤醒

如果使用触摸板中断将芯片从睡眠模式唤醒,则可以选择应触摸的某些配置的触摸板(SET1或SET1和SET2),以触发中断并引起随后的唤醒。为此,请使用功能touch_pad_set_trigger_source()

可以通过以下方式为每个“ SET”管理焊盘所需位模式的配置:

  • touch_pad_set_group_mask() / touch_pad_get_group_mask()
  • touch_pad_clear_group_mask()

四、API说明

以下 Touch Sensor 接口位于

4.1 touch_pad_init

4.2 touch_pad_set_voltage

4.3 touch_pad_config

4.4 touch_pad_filter_start

4.5 touch_pad_read_raw_data

4.6 touch_pad_read_filtered

4.7 touch_pad_set_fsm_mode

4.8 touch_pad_set_thresh

4.9 touch_pad_isr_register

4.10 touch_pad_get_status

4.11 touch_pad_clear_status

4.12 touch_pad_intr_enable

五、触摸按键中断

根据 中的例程修改

#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "esp_log.h"

#include "driver/touch_pad.h"
#include "soc/rtc_periph.h"
#include "soc/sens_periph.h"

static const char *TAG = "Touch pad";

#define TOUCH_THRESH_NO_USE (0)
#define TOUCH_THRESH_PERCENT (80)
#define TOUCHPAD_FILTER_TOUCH_PERIOD (10)

static bool s_pad_activated[TOUCH_PAD_MAX];
static uint32_t s_pad_init_val[TOUCH_PAD_MAX];

/* Read values sensed at all available touch pads. Use 2 / 3 of read value as the threshold to trigger interrupt when the pad is touched. Note: this routine demonstrates a simple way to configure activation threshold for the touch pads. Do not touch any pads when this routine is running (on application start). */
static void tp_example_set_thresholds(void)
{ 
        
    uint16_t touch_value;
    for (int i = 0; i < TOUCH_PAD_MAX; i++) { 
        
        //read filtered value
        touch_pad_read_filtered(i, &touch_value);
        s_pad_init_val[i] = touch_value;
        ESP_LOGI(TAG, "test init: touch pad [%d] val is %d", i, touch_value);
        //set interrupt threshold.
        ESP_ERROR_CHECK(touch_pad_set_thresh(i, touch_value * 2 / 3));

    }
}

// 检测触摸中断任务
static void tp_example_read_task(void *pvParameter)
{ 
        
    static int show_message;

    while (1) 
    { 
        
        //interrupt mode, enable touch interrupt
        touch_pad_intr_enable();
        for (int i = 0; i < TOUCH_PAD_MAX; i++) { 
        
            if (s_pad_activated[i] == true) { 
        
                ESP_LOGI(TAG, "T%d activated!", i);
                // Wait a while for the pad being released
                vTaskDelay(200 / portTICK_PERIOD_MS);
                // Clear information on pad activation
                s_pad_activated[i] = false;
                // Reset the counter triggering a message
                // that application is running
                show_message = 1;
            }
        }

        vTaskDelay(10 / portTICK_PERIOD_MS);

        // If no pad is touched, every couple of seconds, show a message
        // that application is running
        if (show_message++ % 500 == 0) { 
        
            ESP_LOGI(TAG, "Waiting for any pad being touched...");
        }
    }
}

// 触摸中断处理函数。触摸过的端口保存在s_pad_activated数组中
static void tp_example_rtc_intr(void *arg)
{ 
        
    uint32_t pad_intr = touch_pad_get_status();
    //clear interrupt
    touch_pad_clear_status();
    for (int i = 0; i < TOUCH_PAD_MAX; i++) { 
        
        if ((pad_intr >> i) & 0x01) { 
        
            s_pad_activated[i] = true;
        }
    }
}

/* * Before reading touch pad, we need to initialize the RTC IO. */
static void tp_example_touch_pad_init(void)
{ 
        
    for (int i = 0; i < TOUCH_PAD_MAX; i++) { 
        
        //init RTC IO and mode for touch pad.
        touch_pad_config(i, TOUCH_THRESH_NO_USE);
    }
}

void app_main(void)
{ 
        
    // Initialize touch pad peripheral, it will start a timer to run a filter
    ESP_LOGI(TAG, "Initializing touch pad");
    touch_pad_init();
    // 如果使用中断触发模式,应将触摸传感器FSM模式设置为“ TOUCH_FSM_MODE_TIMER”
    touch_pad_set_fsm_mode(TOUCH_FSM_MODE_TIMER);
    // 设定充放电参考电压:高参考电压,低参考电压,高参考电压衰减
    // the high reference valtage will be 2.7V - 1V = 1.7V, The low reference voltage will be 0.5V.
    touch_pad_set_voltage(TOUCH_HVOLT_2V7, TOUCH_LVOLT_0V5, TOUCH_HVOLT_ATTEN_1V);
    // 配置触摸端口
    tp_example_touch_pad_init();
    // 初始化并启动软件滤波器
    touch_pad_filter_start(TOUCHPAD_FILTER_TOUCH_PERIOD);
    // 设定中断限值,此时不要触摸,2/3的读取值做为限值
    tp_example_set_thresholds();
    // 注册触摸中断ISR
    touch_pad_isr_register(tp_example_rtc_intr, NULL);
    // 开启一个任务处理电容触摸
    xTaskCreate(&tp_example_read_task, "touch_pad_read_task", 2048, NULL, 5, NULL);
}

查看打印:

六、轮询检测按键

根据 中的例程修改

#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "esp_log.h"

#include "driver/touch_pad.h"
#include "soc/rtc_periph.h"
#include "soc/sens_periph.h"

static const char *TAG = "Touch pad";

#define TOUCH_THRESH_NO_USE (0)
#define TOUCH_THRESH_PERCENT (80)
#define TOUCHPAD_FILTER_TOUCH_PERIOD (10)

static bool s_pad_activated[TOUCH_PAD_MAX];
static uint32_t s_pad_init_val[TOUCH_PAD_MAX];

/* Read values sensed at all available touch pads. Use 2 / 3 of read value as the threshold to trigger interrupt when the pad is touched. Note: this routine demonstrates a simple way to configure activation threshold for the touch pads. Do not touch any pads when this routine is running (on application start). */
static void tp_example_set_thresholds(void)
{ 
        
    uint16_t touch_value;
    for (int i = 0; i < TOUCH_PAD_MAX; i++) { 
        
        //read filtered value
        touch_pad_read_filtered(i, &touch_value);
        s_pad_init_val[i] = touch_value;
        ESP_LOGI(TAG, "test init: touch pad [%d] val is %d", i, touch_value);
    }
}

/* Check if any of touch pads has been activated by reading a table updated by rtc_intr() If so, then print it out on a serial monitor. Clear related entry in the table afterwards In interrupt mode, the table is updated in touch ISR. In filter mode, we will compare the current filtered value with the initial one. If the current filtered value is less than 80% of the initial value, we can regard it as a 'touched' event. When calling touch_pad_init, a timer will be started to run the filter. This mode is designed for the situation that the pad is covered by a 2-or-3-mm-thick medium, usually glass or plastic. The difference caused by a 'touch' action could be very small, but we can still use filter mode to detect a 'touch' event. */
static void tp_example_read_task(void *pvParameter)
{ 
        
    static int show_message;

    while (1) { 
        
        for (int i = 0; i < TOUCH_PAD_MAX; i++) { 
        
            uint16_t value = 0;
            touch_pad_read_filtered(i, &value);
            if (value < s_pad_init_val[i] * TOUCH_THRESH_PERCENT / 100) { 
        
                ESP_LOGI(TAG, "T%d activated!", i);
                ESP_LOGI(TAG, "value: %d; init val: %d", value, s_pad_init_val[i]);
                vTaskDelay(200 / portTICK_PERIOD_MS);
                // Reset the counter to stop changing mode.
                show_message = 1;
            }
        }

        vTaskDelay(10 / portTICK_PERIOD_MS);

        // If no pad is touched, every couple of seconds, show a message
        // that application is running
        if (show_message++ % 500 == 0) { 
        
            ESP_LOGI(TAG, "Waiting for any pad being touched...");
        }
    }
}

/* * Before reading touch pad, we need to initialize the RTC IO. */
static void tp_example_touch_pad_init(void)
{ 
        
    for (int i = 0; i < TOUCH_PAD_MAX; i++) { 
        
        //init RTC IO and mode for touch pad.
        touch_pad_config(i, TOUCH_THRESH_NO_USE);
    }
}

void app_main(void)
{ 
        
    // Initialize touch pad peripheral, it will start a timer to run a filter
    ESP_LOGI(TAG, "Initializing touch pad");
    touch_pad_init();
    // 设定充放电参考电压:高参考电压,低参考电压,高参考电压衰减
    // the high reference valtage will be 2.7V - 1V = 1.7V, The low reference voltage will be 0.5V.
    touch_pad_set_voltage(TOUCH_HVOLT_2V7, TOUCH_LVOLT_0V5, TOUCH_HVOLT_ATTEN_1V);
    // 配置触摸端口
    tp_example_touch_pad_init();
    // 初始化并启动软件滤波器
    touch_pad_filter_start(TOUCHPAD_FILTER_TOUCH_PERIOD);
    // 设定阈值
    tp_example_set_thresholds();
    // 开启一个任务处理电容触摸
    xTaskCreate(&tp_example_read_task, "touch_pad_read_task", 2048, NULL, 5, NULL);
}

查看打印:


• 由 Leung 写于 2021 年 5 月 12 日

• 参考:ESP32 开发笔记(三)源码示例 6_TouchPad_Interrupt 电容触摸中断实现触摸按钮     ESP32 触摸传感器应用方案简介

标签: 电容屏可以用导电的金属触摸吗

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台