【ESP32-IDF笔记】06-触摸传感IO配置

配置环境

Visual Studio Code :版本1.98.2
ESP32:ESP32-S3
ESP-IDF:V5.4

概述

触摸传感器系统由保护覆盖层、触摸电极、绝缘基板和走线组成,保护覆盖层位于最上层,绝缘基板上设有电极及走线。触摸覆盖层将引起电容变化,根据电容变化,可以判断此次触摸是否为有效触摸行为。

触摸传感器可以以矩阵或滑条等方式组合使用,从而覆盖更大触感区域及更多触感点。触摸传感由软件或专用硬件计时器发起,由有限状态机 (FSM) 硬件控制。

ESP32-S3 提供了多达 14 个电容式传感 GPIO,能够探测由手指或其他物品直接接触或接近而产生的电容差异。

这种设计具有低噪声和高灵敏度的特点,可以用于支持使用相对较小的触摸板。设计中也可以使用触摸板阵列以探测更大区域或更多点。ESP32-S3 的触摸传感器同时还支持防水和数字滤波等功能来进一步提高传感器的性能。

功能介绍

下面将 API 分解成几个函数组进行介绍:

  • 初始化触摸传感器驱动程序
  • 配置触摸传感器 GPIO 管脚
  • 触摸状态测量
  • 调整测量参数(优化测量)
  • 滤波采样
  • 触摸监测方式
  • 设置中断信号监测触碰动作
  • 中断触发,唤醒睡眠模式

请前往 API 参考 章节,查看某一函数的具体描述。应用示例 章节则介绍了此 API 的具体实现。

初始化触摸传感器驱动程序

使用触摸传感器之前,需要先调用 touch_pad_init() 函数初始化触摸传感器驱动程序。此函数设置了 API 参考 项下的 Macros 中列出的几项 .._DEFAULT 驱动程序参数,同时删除之前设置过的触摸传感器信息(如有),并禁用中断。

如果不再需要该驱动程序,可以调用 touch_pad_deinit() 释放已初始化的驱动程序。

配置触摸传感器 GPIO 管脚

可调用 touch_pad_config() 使能某一 GPIO 的触感功能。ESP32 最多可支持 10 个电容式触摸传感器通道。

触摸传感器通道GPIO 管脚
T0GPIO4
T1GPIO0
T2GPIO2
T3MTDO
T4MTCK
T5MTDI
T6MTMS
T7GPIO27
T832K_XN
T932K_XP

使用 touch_pad_set_fsm_mode() 选择触摸传感器测量(由 FSM 操作)是由硬件定时器自动启动,还是由软件自动启动。如果选择软件模式,请使用 touch_pad_sw_start() 启动 FSM。

触摸状态测量

借助以下两个函数从传感器读取原始数据和滤波后的数据:

  • touch_pad_read_raw_data()
  • touch_pad_read_filtered()

这两个函数也可以用于检查触碰和释放触摸传感器时传感器读数变化范围,然后根据这些信息设定触摸传感器的触摸阈值。

备注

使用 touch_pad_read_filtered()之前,需要先调用 滤波采样 中特定的滤波器函数来初始化并配置该滤波器。

测量方式

请参考应用示例 peripherals/touch_sensor/touch_sensor_v1/touch_pad_read,查看如何使用读取触摸传感器数据。

测量方式

触摸传感器会统计固定时间内的充放电次数,其计数结果即为原始数据,可由 touch_pad_read_raw_data() 读出。上述固定时间可通过 touch_pad_set_measurement_clock_cycles() 设置。完成一次测量后,触摸传感器会在下次测量开始前保持睡眠状态。两次测量之前的间隔时间可由 touch_pad_set_measurement_interval() 进行设置。

备注

若设置的计数时间太短(即测量持续的时钟周期数太小),则可能导致结果不准确,但是过大的计数时间也会造成功耗上升。另外,若睡眠时间加测量时间的总时间过长,则会造成触摸传感器响应变慢。

优化测量

触摸传感器设有数个可配置参数,以适应触摸传感器设计特点。例如,如果需要感知较细微的电容变化,则可以缩小触摸传感器充放电的参考电压范围。使用 touch_pad_set_voltage() 函数,可以设置电压参考低值和参考高值。

优化测量除了可以识别细微的电容变化之外,还可以降低应用程序功耗,但可能会增加测量噪声干扰。如果得到的动态读数范围结果比较理想,则可以调用 touch_pad_set_measurement_clock_cycles() 函数来减少测量时间,从而进一步降低功耗。

可用的测量参数及相应的 ‘set’ 函数总结如下:

  • 触摸传感器充放电参数:

    • 电压门限:touch_pad_set_voltage()
    • 速率(斜率):touch_pad_set_cnt_mode()
  • 单次测量所用的时钟周期:touch_pad_set_measurement_clock_cycles()

电压门限(参考低值/参考高值)、速率(斜率)与测量时间的关系如下图所示:
在这里插入图片描述

上图中的 Output 代表触摸传感器读值,即一个测量周期内测得的脉冲计数值。

所有函数均成对出现,用于设定某一特定参数,并获取当前参数值。例如:touch_pad_set_voltage()touch_pad_get_voltage()

滤波采样

如果测量中存在噪声,可以使用提供的 API 函数对采样进行滤波。使用滤波器之前,请先调用 touch_pad_filter_start() 启动该滤波器。

滤波器类型为 IIR(无限脉冲响应滤波器),可以调用 touch_pad_set_filter_period() 配置此类滤波器的采样周期。

如需停止滤波器,请调用 touch_pad_filter_stop() 函数。如果不再使用该滤波器,请调用 touch_pad_filter_delete() 删除此滤波器。

触摸监测

触摸监测基于配置的阈值和 FSM 执行的原始测量,并由 ESP32 硬件实现。可以调用 touch_pad_get_status() 查看被触碰的触摸传感器,或调用 touch_pad_clear_status() 清除触摸状态信息。

也可以将硬件触摸监测连接至中断,详细介绍见下一章节。

如果测量中存在噪声,且电容变化幅度较小,硬件触摸监测结果可能就不太理想。如需解决这一问题,不建议使用硬件监测或中断信号,建议在自己的应用程序中进行采样滤波,并执行触摸监测。请参考 peripherals/touch_sensor/touch_sensor_v1/touch_pad_interrupt,查看以上两种触摸监测的实现方式。

中断触发

在对触摸监测启用中断之前,请先设置一个触摸监测阈值。然后使用 触摸状态测量 中所述的函数读取并显示触摸和释放触摸传感器时测得的结果。如果测量中存在噪声且相对电容变化较小,请使用滤波器。也可以根据应用程序和环境条件,测试温度和电源电压变化对测量值的影响。

确定监测阈值后就可以在初始化时调用 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() 清除触摸传感器状态信息。

备注

触摸监测中的中断信号基于原始/未经滤波的采样(对比设置的阈值),并在硬件中实现。启用软件滤波 API(请参考 滤波采样)并不会影响这一过程。

从睡眠模式唤醒

如果使用触摸传感器中断将芯片从睡眠模式唤醒,可以选择配置一些触摸传感器,例如 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 参考

头文件

  • components/driver/touch_sensor/esp32/include/driver/touch_sensor.h
  • components/driver/touch_sensor/include/driver/touch_sensor_common.h
#include "driver/touch_sensor.h"
#include "driver/touch_sensor_common.h"

CMakeLists.txt添加

REQUIRES driver

函数

初始化触控模块
esp_err_t touch_pad_init(void)

返回:* ESP_OK成功

  • ESP_ERR_NO_MEM 触摸板初始化错误
  • ESP_ERR_NOT_SUPPORTED触摸板正在为外部 XTAL 提供电流

注意

如果 default 参数与使用场景不匹配,可以在执行此函数后进行更改。

卸载触摸板驱动程序
esp_err_t touch_pad_deinit(void)

返回:

  • ESP_OK成功

  • ESP_FAIL 触摸板驱动程序未初始化

注意

调用该函数后,禁止调用其他触控函数。

初始化触摸板 GPIO
esp_err_t touch_pad_io_init(touch_pad_t touch_num)

参数:

  • touch_num – 触摸板索引

返回:

  • 成功ESP_OK

  • ESP_ERR_INVALID_ARG 如果参数错误

设置触摸传感器的高电压阈值
esp_err_t touch_pad_set_voltage(touch_high_volt_t refh, touch_low_volt_t refl, touch_volt_atten_t atten)

触摸传感器通过对通道进行充电和放电来测量通道电容值。所以高阈值应小于电源电压。

参数:

  • refh – DREFH 的值

  • refl – DREFL 的值

  • atten – DREFH 上的衰减

返回:

  • 成功ESP_OK

  • ESP_ERR_INVALID_ARG 如果参数错误

获取触摸传感器参考电压
esp_err_t touch_pad_get_voltage(touch_high_volt_t *refh, touch_low_volt_t *refl, touch_volt_atten_t *atten)

参数:

  • refh – 接受 DREFH 值的指针

  • refl – 接受 DREFL 值的指针

  • atten – 接受 DREFH 衰减的指针

返回:

  • 成功ESP_OK
设置每个焊盘的触摸传感器充放电速度

esp_err_t touch_pad_set_cnt_mode(touch_pad_t touch_num, touch_cnt_slope_t slope, touch_tie_opt_t opt)

如果斜率为 0,则计数器将始终为零。如果斜率为 1,则相应地充电和放电会很慢。如果斜率设置为 7(最大值),则充电和放电将很快。

参数:

  • touch_num – 触摸板索引

  • slope – 触摸板充放电速度

  • opt – 初始电压

返回:

  • 成功ESP_OK

  • ESP_ERR_INVALID_ARG 如果参数错误

注意:

充放电电流越高,触摸通道的抗扰度就越大,但会增加系统功耗。

获取每个焊盘的触摸传感器充电/放电速度

esp_err_t touch_pad_get_cnt_mode(touch_pad_t touch_num、 touch_cnt_slope_t *slope、 touch_tie_opt_t *opt)

参数:

  • touch_num – 触摸板索引

  • slope – 接受触摸板充电/放电斜率的指针

  • opt – 接受初始电压的指针

返回:

  • 成功ESP_OK

  • ESP_ERR_INVALID_ARG 如果参数错误

取消注册
esp_err_t touch_pad_isr_deregister(void (fn)(void)), void *arg)

取消注册以前使用 touch_pad_isr_handler_register 注册的处理程序。

参数:

  • fn – 要调用的处理程序函数(传递给 touch_pad_isr_handler_register)

  • arg – 处理程序的参数(传递给 touch_pad_isr_handler_register)

.h文件

touch.h

#ifndef __TOUCH_H
#define __TOUCH_H

#include "esp_err.h"



void touch_init(void);         //初始化
void touch_read_task(void );   //测试案例
#endif

.c文件

touch.c

#include "touch.h"
 #include <stdio.h>
 #include "freertos/FreeRTOS.h"
 #include "freertos/task.h"
 #include "freertos/queue.h"
 #include "esp_log.h"
 #include "driver/touch_pad.h"
 
//参考案例 peripherals/touch_sensor/touch_sensor_v2/touch_pad_interrupt

 static const char *TAG = "touch->";


  // 自定义添加需要配置的触摸IO
  #define TOUCH_BUTTON_NUM    2
  static const touch_pad_t button[TOUCH_BUTTON_NUM] = {
      TOUCH_PAD_NUM1,     // 
      TOUCH_PAD_NUM2,     // 
      // If this pad be touched, other pads no response.
  };
  /*
  * 触摸阈值。该阈值决定了触摸的灵敏度。
  * 此阈值是通过测试不同触摸通道读数的变化得出的。
  * 如果 (原始数据 - 基准值) > 基准值 * 阈值,则触摸板被激活。
  * 如果 (原始数据 - 基准值) < 基准值 * 阈值,则触摸板未被激活。
  */
  static const float button_threshold[TOUCH_BUTTON_NUM] = {
      0.2, // 20%.
      0.2, // 20%.
  };

  static QueueHandle_t que_touch = NULL;
  typedef struct touch_msg {
      touch_pad_intr_mask_t intr_mask;
      uint32_t pad_num;
      uint32_t pad_status;
      uint32_t pad_val;
  } touch_event_t;

 

 #define TOUCH_BUTTON_WATERPROOF_ENABLE 0       //防水功能
 #define TOUCH_BUTTON_DENOISE_ENABLE    1
 #define TOUCH_CHANGE_CONFIG            0       //是否更改默认配置


 
/*
    处理触摸板被触摸时触发的中断。
    识别被触摸的是哪个触摸板,并将其记录在表格中。
*/
 static void touchsensor_interrupt_cb(void *arg)
 {
     int task_awoken = pdFALSE;
     touch_event_t evt;
     evt.intr_mask = touch_pad_read_intr_status_mask();
     evt.pad_status = touch_pad_get_status();
     evt.pad_num = touch_pad_get_current_meas_channel();
     //ESP_LOGW(TAG, "interrupt cb");
    
     xQueueSendFromISR(que_touch, &evt, &task_awoken);
     if (task_awoken == pdTRUE) {
         portYIELD_FROM_ISR();
     }
 }
 /// @brief 设置中断阈值
 /// @param  
 static void touch_set_thresholds(void)
 {
     uint32_t touch_value;
     for (int i = 0; i < TOUCH_BUTTON_NUM; i++) {
         //读取基准值
         touch_pad_read_benchmark(button[i], &touch_value);
         //设置中断阈值
         touch_pad_set_thresh(button[i], touch_value * button_threshold[i]);
         ESP_LOGI(TAG, "touch pad [%d] base %"PRIu32", thresh %"PRIu32, \
                  button[i], touch_value, (uint32_t)(touch_value * button_threshold[i]));
     }
 }
 
 static void touch_set_filter_set(touch_filter_mode_t mode)
 {
     /* 滤波功能 */
     touch_filter_config_t filter_info = {
         .mode = mode,           // Test jitter and filter 1/4.
         .debounce_cnt = 1,      // 1 time count.
         .noise_thr = 0,         // 50%
         .jitter_step = 4,       // use for jitter mode.
         .smh_lvl = TOUCH_PAD_SMOOTH_IIR_2,
     };
     touch_pad_filter_set_config(&filter_info);
     touch_pad_filter_enable();
     ESP_LOGI(TAG, "touch pad filter init");
 }
 

 void touch_init(void)
 {
     if (que_touch == NULL) {
         que_touch = xQueueCreate(TOUCH_BUTTON_NUM, sizeof(touch_event_t));
     }
     // 初始化触模块外设,它将启动一个定时器来运行滤波器。
     ESP_LOGI(TAG, "Initializing touch pad");
     /* 初始化触模块 */
     touch_pad_init();
     for (int i = 0; i < TOUCH_BUTTON_NUM; i++) {
         touch_pad_config(button[i]);   //为每个触摸通道配置参数。
     }
 

     /* 触摸模块0的去噪设置。. */
     touch_pad_denoise_t denoise = {
         /* 要消除的位是根据噪声水平来确定的。 */
         .grade = TOUCH_PAD_DENOISE_BIT4,
         /* 通过调整参数,T0的读数应近似于被测通道的读数。 */
         .cap_level = TOUCH_PAD_DENOISE_CAP_L4,
     };
     touch_pad_denoise_set_config(&denoise);
     touch_pad_denoise_enable();
     ESP_LOGI(TAG, "Denoise function init");

     /* 滤波模设置 */
     touch_set_filter_set(TOUCH_PAD_FILTER_IIR_16);   //滤波模式为一阶无限冲激响应(IIR)滤波器。系数为16(典型值) 。  
     touch_pad_timeout_set(true, TOUCH_PAD_THRESHOLD_MAX);  //启用超时检查,并为所有触摸传感器通道测量设置超时阈值。
     /* 注册触摸中断中断服务程序(ISR),启用中断类型 . */
     touch_pad_isr_register(touchsensor_interrupt_cb, NULL, TOUCH_PAD_INTR_MASK_ALL);
     /* 如果你有其他触摸算法,你可以在生成 `TOUCH_PAD_INTR_MASK_SCAN_DONE` 中断后获取测量值。. */
     touch_pad_intr_enable(TOUCH_PAD_INTR_MASK_ACTIVE | TOUCH_PAD_INTR_MASK_INACTIVE | TOUCH_PAD_INTR_MASK_TIMEOUT);
 
     /* 启用触摸传感器时钟。工作模式为“定时器触发”。 */
     touch_pad_set_fsm_mode(TOUCH_FSM_MODE_TIMER);
     touch_pad_fsm_start();     //启动触摸传感器有限状态机
     /* 等待触摸传感器初始化完成 */
     vTaskDelay(50 / portTICK_PERIOD_MS);
     touch_set_thresholds();
 }
 //测试案例
 void touch_read_task(void )
 {
    touch_event_t evt = {0};
    int ret = xQueueReceive(que_touch, &evt, (TickType_t)0);    //
    if (ret != pdTRUE) {
        return;
    }
    if (evt.intr_mask & TOUCH_PAD_INTR_MASK_ACTIVE) {       //对其中一个已启用的通道生效。
        ESP_LOGI(TAG, "TouchSensor [%"PRIu32"] be activated, status mask 0x%"PRIu32"", evt.pad_num, evt.pad_status);
    }
    if (evt.intr_mask & TOUCH_PAD_INTR_MASK_INACTIVE) {     //对其中一个已启用的通道无效。
        ESP_LOGI(TAG, "TouchSensor [%"PRIu32"] be inactivated, status mask 0x%"PRIu32, evt.pad_num, evt.pad_status);
    }
    if (evt.intr_mask & TOUCH_PAD_INTR_MASK_SCAN_DONE) {    //对所有已启用的通道进行测量。
        ESP_LOGI(TAG, "The touch sensor group measurement is done [%"PRIu32"].", evt.pad_num);
    }
    if (evt.intr_mask & TOUCH_PAD_INTR_MASK_TIMEOUT) {      //其中一个已启用通道超时。
        /* 在这里添加你的异常处理。*/
        ESP_LOGI(TAG, "Touch sensor channel %"PRIu32" measure timeout. Skip this exception channel!!", evt.pad_num);
        touch_pad_timeout_resume(); // 指向下一个要测量的通道。
    }
     
 }
 

使用

  1. 在.c文件中添加需要使用的触摸IO
// 添加需要配置的触摸IO
  #define TOUCH_BUTTON_NUM    2  //个数
  static const touch_pad_t button[TOUCH_BUTTON_NUM] = {
      TOUCH_PAD_NUM1,     // 对应ESP32S3 -> GPIO1
      TOUCH_PAD_NUM2,     // 对应ESP32S3 -> GPIO2
      
  };
  1. 在.c文件中设置触摸阈值
static const float button_threshold[TOUCH_BUTTON_NUM] = {
      0.2, // 20%.
      0.2, // 20%.
  };
  1. 在app_main中进行初始化和调用
//....
#include "touch.h"
//....
void app_main(void)
{
	//....
	touch_init();
	while (1)
    {
        touch_read_task();        
        vTaskDelay(50/portTICK_PERIOD_MS);
    }
}

运行结果

用手触摸GPIO1然后离开时
在这里插入图片描述

用手触摸GPIO2 然后离开时
在这里插入图片描述
GPIO2短接3.3V时或者短接GND时
在这里插入图片描述

安卓期末大作业—Android图书管理应用源代码(高分项目),个人经导师指导并认可通过的高分设计项目,评审分98分,项目中的源码都是经过本地编译过可运行的,都经过严格调试,确保可以运行!主要针对计算机相关专业的正在做大作业、毕业设计的学生和需要项目实战练习的学习者,资源项目的难度比较适中,内容都是经过助教老师审定过的能够满足学习、使用需求,如果有需要的话可以放心下载使用。 安卓期末大作业—Android图书管理应用源代码(高分项目)安卓期末大作业—Android图书管理应用源代码(高分项目)安卓期末大作业—Android图书管理应用源代码(高分项目)安卓期末大作业—Android图书管理应用源代码(高分项目)安卓期末大作业—Android图书管理应用源代码(高分项目)安卓期末大作业—Android图书管理应用源代码(高分项目)安卓期末大作业—Android图书管理应用源代码(高分项目)安卓期末大作业—Android图书管理应用源代码(高分项目)安卓期末大作业—Android图书管理应用源代码(高分项目)安卓期末大作业—Android图书管理应用源代码(高分项目)安卓期末大作业—Android图书管理应用源代码(高分项目)安卓期末大作业—Android图书管理应用源代码(高分项目)安卓期末大作业—Android图书管理应用源代码(高分项目)安卓期末大作业—Android图书管理应用源代码(高分项目)安卓期末大作业—Android图书管理应用源代码(高分项目)安卓期末大作业—Android图书管理应用源代码(高分项目)安卓期末大作业—Android图书管理应用源代码(高分项目)安卓期末大作业—Android图书管理应用源代码(高分项目)安卓期末大作业—Android图书管理应用源代码(高分项目)安卓期末大作业—Android图书管理应用源代码(高分项目)安卓期末大作业—And
本文以电动汽车销售策略为研究对象,综合运用层次分析法、决策树、皮尔逊相关性分析、BP神经网络及粒子群优化等多种方法,深入探讨了影响目标客户购买电动汽车的因素及相应的销售策略。研究结果显示,客户对合资品牌电动汽车的满意度为78.0887,对自主品牌的满意度为77.7654,对新势力品牌的满意度为77.0078。此外,研究还发现电池性能、经济性、城市居住年限、居住区域、工作单位、职务、家庭年收入、个人年收入、家庭可支配收入、房贷占比、车贷占比等因素对电动汽车销量存在显著影响。通过BP神经网络对目标客户的购买意愿进行预测,其预测数据拟合程度超过80%,且与真实情况高度接近。基于研究结果,本文为销售部门提出了提高销量的建议,包括精准定位尚未购买电动汽车的目标客户群体,制定并实施更具针对性的销售策略,在服务难度提升不超过5%的前提下,选择实施最具可行性和针对性的销售方案。 在研究过程中,层次分析法被用于对目标客户购买电动汽车的影响因素进行系统分析与评价;决策树模型则用于对缺失数据进行预测填充,以确保数据的完整性和准确性;BP神经网络用于预测目标客户的购买意愿,并对其预测效果进行评估;粒子群优化算法对BP神经网络模型进行优化,有效提升了模型的稳定性和预测能力;皮尔逊相关性分析用于探究不同因素与购买意愿之间的相关性。通过这些方法的综合运用,本文不仅揭示了影响电动汽车销量的关键因素,还为销售策略的优化提供了科学依据。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

@Hwang

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值