触摸传感器


文章目录

  • 触摸传感器
  • 1. 触摸传感器简介
  • 1.1 触摸传感器结构
  • 1.2 触摸传感器原理
  • 1.3 触摸传感器的灵敏度优化
  • 1.4 esp32检测过程
  • 2. 触摸传感器框图剖析
  • 2.1 触发源
  • 2.2 触摸传感器控制器
  • 2.3 触摸传感器执行器
  • 2.4 处理器
  • 3. 触摸传感器配置流程
  • 3.1 触摸传感器初始化
  • 3.2 配置触摸传感器参数
  • 3.2.1 配置触发模式
  • 3.2.2 设置充放电参数
  • 3.2.4 设置IIR滤波器
  • 3.2.5 载入配置
  • 3.3 配置相关的gpio
  • 3.4 配置触发阈值
  • 3.5 配置相关中断
  • 4. 触摸传感器实验
  • 4.1 脉冲读取实验
  • 4.1.1 实验目的
  • 4.1.2 软件设计
  • 4.2 基于轮询的触摸按键检测实验
  • 4.2.1 实验目的
  • 4.2.2 硬件设计
  • 4.2.3 软件设计
  • 4.2.3.1 定义相关的宏
  • 4.2.3.2 定义相关的数据结构体
  • 4.2.3.4 触摸传感器的使能函数
  • 4.2.3.3 触摸传感器的配置
  • 4.2.3.4 按键状态监测
  • 4.2.3.5 主函数
  • 4.2.4 完整代码
  • 4.2.4.1 bsp_touch.h
  • 4.2.4.2 bsp_touch.cpp
  • 4.2.4.4 main
  • 5.参考资料

1. 触摸传感器简介

  关于触摸传感器原理非常详细的介绍可以看官方的文章,“ESP32 触摸传感器应用方案简介”。这里做简要讲解。

1.1 触摸传感器结构

  我们先来看触摸传感器的结构[3]

esp32 触摸 中断 esp32触摸传感器_#include

  典型的触摸传感器结构包括: 保护层、触摸电极、绝缘基板、走线

  • 保护层:保护层位置处在触摸电极的上层,必须是绝缘的,起到保护电极的作用。但是保护层也会使得触摸灵敏度下降
  • 触摸电极:触摸电极与gnd形成电容,这个电容量用于指示电极有没有被触摸。
  • 绝缘基板:绝缘基板主要对触摸电极起支撑作用
  • 走线:走线会引入干扰和寄生电容,在pcb设计的时候,走线一定要尽可能的短。

1.2 触摸传感器原理

  我们知道一个显而易见的道理,就是在充电电流一定的情况下,给电容充电到相同电压,电容容量越大,充电时间越长。其实触摸传感器就是利用这个原理设计的。

  我们需要了解的是,构成触摸传感器电容量的要素有那些[3]

esp32 触摸 中断 esp32触摸传感器_#include_02

电容组成

说明

Cground

触摸电路参考地和大地之间的电容

Ccomponet

ESP32 内部寄生电容

Ctrace

走线与电路参考地之间的寄生电容

Celectrode

触摸电极与电路参考地之间的寄生电容

Ctouch

手指与触摸电极所形成的相对于大地的触摸电容

  这其中起到最主要作用的就是触摸电极和参考地之间的电容。当手指触摸到触摸电极的时候,手指与触摸电极之间也会形成电容,增大了触摸电极处的整体电容量。这样的话,对触摸电极进行充电的时候,充电时间就会变长。

esp32 触摸 中断 esp32触摸传感器_初始化_03

   图A是无手指触摸的充电特性曲线,图B是有手指触摸的充电特性曲线。利用这个充电时间的长短,我们就可以判断触摸电极有没有被触摸

1.3 触摸传感器的灵敏度优化

  同时,我们也注意到,影响触摸传感器灵敏度的决定性因素,其实就是触摸电容和寄生电容之间的相对大小。如果触摸电容相对较大,手指触摸以后,整体电容就有明显变化,充电时间也就有明显差异。

  因此,如果要提高触摸按键的灵敏度,我们应该减少寄生电容,并且尽量增加触摸电容。

电容类型

组成

电容优化方向

优化方法

寄生电容 Cp

Ctrace + Celectrode + Ccomponet

减少

减少走线长度,优化 PCB 布局

触摸电容

Ctouch

增加

覆盖层与电极紧密贴合,选用介电常数大的覆盖层,减少覆盖层厚度,增大触摸电极的面积

固定电容

Cground

-

-

1.4 esp32检测过程

   esp32的触摸传感器检测原理上,大致也是采取的上述原理。

esp32 触摸 中断 esp32触摸传感器_esp32 触摸 中断_04

  当检测开始的时候,触摸传感器的引脚会产生一段时间的三角波,对触摸电极进行不断的充放电,然后esp32会把这段三角波每一个变化周期记录为一个脉冲,最后统计这段时间内产生的脉冲数量。如果手触摸的电极,充电时间变长,脉冲数会减少。因此,设定一个阈值,如果测定的脉冲数量小于阈值,就可认为电极被触摸了。

2. 触摸传感器框图剖析

esp32 触摸 中断 esp32触摸传感器_嵌入式_05

  触摸传感器可以分为四个功能模块

  • (1):触发源
  • (2):触摸传感器控制器
  • (3):触摸传感器执行器
  • (4):处理器

2.1 触发源

  触摸传感器如果想要发出检测三角波,需要有一个触发源,告诉触摸传感器什么时候发出这个检测电波。

  触发源包括硬件触发和软件触发。可以通过touch_pad_set_fsm_mode() 进行设置

 硬件触发是指,启动一个定时器,每隔一段时间就自动发送一段检测电波。

 软件触发是指,默认情况下不发送检测电波,只有运行touch_pad_read_raw_data() 等需要获取脉冲数的相关函数的时候,才会发送检测电波进行触摸检测。

2.2 触摸传感器控制器

  触摸传感器控制器的主要功能是使能相应的触摸传感器,并且对产生的三角波特性进行配置。包括:

  • 使能相应的控制器及引脚
  • 设定每次发送检测电波的持续时间
  • 设定触摸传感器的触发阈值
  • 设定输出检测电波的电压范围
  • 与下游执行器发送指令与交互数据

2.3 触摸传感器执行器

  执行器主要完成的任务是,当接收到控制器传输来的检测电波发送命令的时候,按照控制器的设定,进行输出。同时,对输出的电平进行测量,记录产生的脉冲数量,然后把数据返回给控制器

2.4 处理器

  处理器主要是处理控制器产生的请求,包括

  • 脉冲计数达到阈值的时候产生的中断请求
  • 触摸传感器产生的cpu唤醒请求。

3. 触摸传感器配置流程

3.1 触摸传感器初始化

//初始化传感器驱动程序
	touch_pad_init();

3.2 配置触摸传感器参数

3.2.1 配置触发模式
//设置硬件触发
touch_pad_set_fsm_mode(TOUCH_FSM_MODE_TIMER);
3.2.2 设置充放电参数
//设置充电门限,必须设置
touch_pad_set_voltage();

//设置充电速率,非必须
 touch_pad_set_cnt_mode();
 
 //设置测量时间,非必须
 touch_pad_set_meas_time();
  • 充电门限

  用户可以设置触摸传感器内部电路充放电的电压门限、高电压衰减值(HATTEN)。门限的范围越小,脉冲计数值越大。但门限过小会导致读数的稳定性变差。选择合适的门限电压可以提高读数的稳定性。

  下图是示波器抓取某一触摸管脚上的充放电电压波形,不同的电压参数的对比。

电压参数为:refh = 2.4V, refl = 0.8V, atten = 0V。

esp32 触摸 中断 esp32触摸传感器_esp32 触摸 中断_06

电压参数为:refh = 2.4V, refl = 0.8V, atten = 0.5V。

esp32 触摸 中断 esp32触摸传感器_#include_07

   可以看到,高电压衰减使得能够达到的最大值减小了。

   不同电压值对稳定性和灵敏度有一定的影响,门限电压范围越大,系统抗干扰能力越强。电压值建议选择 (refh = 2.7V, refl = 0.5V, atten = 0V) 或者 (refh = 2.4V, refl = 0.8V, atten = 0V) 组合。
  如果高电压门限在供电电源允许范围内,衰减值应设置为 0V。

  • 测量时间

esp32 触摸 中断 esp32触摸传感器_#define_08

  • 充电速率

  充电速率是通过调节充电电流大小进行调整的。高的充放电电流会增加抗干扰能力,建议选择 TOUCH_PAD_SLOPE_7。

3.2.4 设置IIR滤波器
touch_pad_filter_start(10);

  ESP32 触摸传感器驱动包含无限脉冲响应滤波器(IIR)功能,用户可以使用此接口读取滤波之后的脉冲计数值。IIR 产生与 RC 滤波器相类似的阶跃响应。 IIR 滤波器能够衰减高频噪声成分,并忽略低频信号。下图是手指触摸响应的波形。

  用户可以通过 API 设置 IIR 滤波器的采样周期。周期越大读数稳定性越高,相应的也会产生延迟。建议滤波周期的范围 10 ms~25 ms。下图是采样周期设置成 10 ms 与 20 ms 的滤波效果和延迟的对比图。黄色是滤波之后的读数,红色是没有经过滤波的读数。

  • IIR 滤波周期:10 ms

esp32 触摸 中断 esp32触摸传感器_esp32 触摸 中断_09

  • IIR 滤波周期:20 ms

esp32 触摸 中断 esp32触摸传感器_嵌入式_10

   下面两个图分别是 10 ms 和 20 ms 滤波周期滤波效果的对比图,黄色是滤波之后的读数。

  • IIR 滤波周期:10 ms

esp32 触摸 中断 esp32触摸传感器_#include_11

  • IIR 滤波周期:20 ms

esp32 触摸 中断 esp32触摸传感器_#include_12

  值得说明的是,如果开启了滤波,数据的读取函数是

touch_pad_read_filtered(); //读取滤波后的数据
touch_pad_read_raw_data(); //读取原始的数据

  没开启滤波使用

touch_pad_read();
3.2.5 载入配置
touch_pad_config(channel, 0);

  如果这里第二个数字写的不是0,就是配置了触发阈值,如果不想在这里配置,可以写0,然后后面再进行配置

3.3 配置相关的gpio

  把gpio配置为输出模式

gpio_pad_select_gpio(gpio);
gpio_set_direction(gpio, GPIO_MODE_OUTPUT);

  需要注意的是,触摸传感器的通道与gpio是绑定的,必须对应使用。

触摸传感器通道

管脚

T0

GPIO4

T1

GPIO0

T2

GPIO2

T3

MTDO

T4

MTCK

T5

MTDI

T6

MTMS

T7

GPIO27

T8

32K_XN

T9

32K_XP

3.4 配置触发阈值

  触发阈值在后面设定的原因是,有时候,不同的产品设计出来以后,触发阈值可能与较大的差异,可以采用自适应的方法设定阈值。就是在启动后,读取没有触摸的脉冲数量,然后再取其2/3作为触发阈值

//读取初始化没有触摸时候的脉冲数
	uint16_t value;
	
	touch_pad_read_filtered(Touch_Channel, &value);
	

	//这个脉冲数的2/3作为阈值
	Threshold = value * 2 / 3;

  如果要使用中断的话,通过
touch_pad_set_thresh() 配置触发阈值

3.5 配置相关中断

  中断的配置方法就是

  • 配置中断阈值 touch_pad_config()或touch_pad_set_thresh()
  • 配置中断模式touch_pad_set_trigger_mode()
  • 写中断服务函数
  • 载入中断服务函数touch_pad_isr_register()
  • 使能中断 touch_pad_intr_enable()

  不过,触摸传感器的中断使用下来感觉不怎么好用。主要原因是,只要你的手在传感器上,就会不断的触发中断,不太好控制。就比如如果要用这个控制led的话,没有办法很好的控制led亮灭。

4. 触摸传感器实验

4.1 脉冲读取实验

4.1.1 实验目的

  读取触摸传感器的脉冲数。

4.1.2 软件设计

  这个实验中,不使用中断,因此也不需要配置触发阈值

#include "driver/gpio.h"
#include "driver/touch_pad.h"

uint16_t value;
void setup() {
	touch_pad_init(); //初始化传感器驱动程序
	touch_pad_set_voltage(TOUCH_HVOLT_2V7, TOUCH_LVOLT_0V5, TOUCH_HVOLT_ATTEN_0V); 
	
	touch_pad_set_fsm_mode(TOUCH_FSM_MODE_TIMER);//设置为硬件触发
	touch_pad_config(TOUCH_PAD_NUM0, 0); //不使用中断,因此也不需要设置阈值
	touch_pad_filter_start(10); //设置IIR滤波器
	uint16_t value;
	while (1)
	{
	
	
		
		touch_pad_read_raw_data(TOUCH_PAD_NUM0, &value);  //读取原始数据
		printf("raw data = %d\n", value);
		touch_pad_read_filtered(TOUCH_PAD_NUM0, &value); //读取滤波后的数据
		printf("IIR data = %d\n", value);
		vTaskDelay(10 / portTICK_PERIOD_MS);
		
		
	}
	
}


void loop() {
	


}

4.2 基于轮询的触摸按键检测实验

4.2.1 实验目的

  因为感觉触摸传感器的中断不是非常好用,所以这里实现了一个基于轮询的led开关控制的实验。

4.2.2 硬件设计

  使用esp32开发板上gpio2带的led进行实验。采用gpio4(touch0)进行触摸检测,并且把gpio4用杜邦线引出。

  主要现象就是,手触碰gpio4的时候,led亮灭状态会进行翻转。

4.2.3 软件设计
4.2.3.1 定义相关的宏
//定义触摸按键序号
#define Touch0  0
#define Touch1  1
#define Touch2  2
#define Touch3  3
#define Touch4  4
#define Touch5  5
#define Touch6  6
#define Touch7  7
#define Touch8  8
#define Touch9  9


//定义触摸按键的GPIO
#define T0 GPIO_NUM_4
#define T1 GPIO_NUM_1
#define T2 GPIO_NUM_2
#define T3 GPIO_NUM_15
#define T4 GPIO_NUM_13
#define T5 GPIO_NUM_12
#define T6 GPIO_NUM_14
#define T7 GPIO_NUM_27
#define T8 GPIO_NUM_33
#define T9 GPIO_NUM_32


//定义触摸按键的通道
#define Touch_Channel0  TOUCH_PAD_NUM0
#define Touch_Channel1  TOUCH_PAD_NUM1
#define Touch_Channel2  TOUCH_PAD_NUM2
#define Touch_Channel3  TOUCH_PAD_NUM3
#define Touch_Channel4  TOUCH_PAD_NUM4
#define Touch_Channel5  TOUCH_PAD_NUM5
#define Touch_Channel6  TOUCH_PAD_NUM6
#define Touch_Channel7  TOUCH_PAD_NUM7
#define Touch_Channel8  TOUCH_PAD_NUM8
#define Touch_Channel9  TOUCH_PAD_NUM9
4.2.3.2 定义相关的数据结构体
//定义相关的存储数据结构
gpio_num_t		Touch_Gpio[10] ={T0,T1,T2,T3,T4,T5,T6,T7,T8,T9}; //引脚
touch_pad_t		Touch_Channel[10] ={Touch_Channel0,Touch_Channel1,Touch_Channel2,Touch_Channel3,Touch_Channel4,Touch_Channel5,Touch_Channel6,Touch_Channel7,Touch_Channel8,Touch_Channel9}; //通道
uint16_t		Threshold[10] = { 0,0,0,0,0,0,0,0,0,0 }; //用来存储阈值
4.2.3.4 触摸传感器的使能函数
/**
*  @brief 开启触摸按键功能
**/
void touch_init()
{
	//初始化传感器驱动程序
	touch_pad_init();
}
4.2.3.3 触摸传感器的配置
/**
*  @brief 配置触摸按键通道,一共T0-T9 10个通道,这里只定义了T0和T7
*  @param[in] Touchx: Touch[0..9] 使用第几个触摸按键
**/
void touch_config(uint8_t Touchx)
{
	touch_mode_config(Touchx); //初始化触摸按键
	touch_gpio_config(Touchx); //初始化相关的gpio
	touch_thresh_config(Touchx); //初始化阈值

}

  相关函数

//设置触摸按键模式
static void touch_mode_config(uint8_t Touchx)
{
	

	//01 设置检测电压范围0-2.7V
	touch_pad_set_voltage(TOUCH_HVOLT_2V7, TOUCH_LVOLT_0V5, TOUCH_HVOLT_ATTEN_0V);

	//02 设置触发模式是硬件定时器触发
	touch_pad_set_fsm_mode(TOUCH_FSM_MODE_TIMER);

	//03 载入配置,设置阈值0就是不设置中断
	touch_pad_config(Touch_Channel[Touchx], 0);

	//04 开启滤波器,如果不开滤波器,读取脉冲数方法不一样
	touch_pad_filter_start(10); 

}

//设置触摸按键相关的gpio
static void touch_gpio_config(uint8_t Touchx)
{
	gpio_pad_select_gpio(Touch_Gpio[Touchx]);
	gpio_set_direction(Touch_Gpio[Touchx], GPIO_MODE_OUTPUT);
}

//设置触摸按键的检测阈值
//手摸按键周期会变长,脉冲数会减少
static void touch_thresh_config(uint8_t Touchx)
{
	//读取初始化没有触摸时候的脉冲数
	uint16_t value;
	
	touch_pad_read_filtered(Touch_Channel[Touchx], &value);
	

	//这个脉冲数的2/3作为阈值
	Threshold[Touchx] = value * 2 / 3;

	
}
4.2.3.4 按键状态监测
/**
*  @brief 检测触摸按键是否被按键
*  @param[in] Touchx: Touch[0..9] 使用第几个触摸按键
*  @retval true:按下  false:没有按下
**/
bool touch_state(uint8_t Touchx)
{
	//用轮询的方法进行检测
	uint16_t value;
	touch_pad_read_filtered(Touch_Channel[Touchx], &value);
	if (value < Threshold[Touchx])
	{
		vTaskDelay(2/ portTICK_PERIOD_MS);
		touch_pad_read_filtered(Touch_Channel[Touchx], &value);
		if (value < Threshold[Touchx])
		{
			while (value < Threshold[Touchx])
			{
				touch_pad_read_filtered(Touch_Channel[Touchx], &value);
			}

			return true;
		}
		
			
		
	}

	return false;
}
4.2.3.5 主函数
void setup() {

	//01 初始化led
	led_init(); 

	//02 初始化触摸按键
	touch_init();
	touch_config(Touch0);



	while (1)
	{
	
		if (touch_state(Touch0) == true)
		{
			led_toggle();
			
		}
	}
}
4.2.4 完整代码
4.2.4.1 bsp_touch.h
#ifndef _BSP_TOUCH_H_
#define _BSP_TOUCH_H_

#include <stdio.h>
#include "driver/gpio.h"
#include "driver/touch_pad.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"


//定义触摸按键序号
#define Touch0  0
#define Touch1  1
#define Touch2  2
#define Touch3  3
#define Touch4  4
#define Touch5  5
#define Touch6  6
#define Touch7  7
#define Touch8  8
#define Touch9  9


//定义触摸按键的GPIO
#define T0 GPIO_NUM_4
#define T1 GPIO_NUM_1
#define T2 GPIO_NUM_2
#define T3 GPIO_NUM_15
#define T4 GPIO_NUM_13
#define T5 GPIO_NUM_12
#define T6 GPIO_NUM_14
#define T7 GPIO_NUM_27
#define T8 GPIO_NUM_33
#define T9 GPIO_NUM_32


//定义触摸按键的通道
#define Touch_Channel0  TOUCH_PAD_NUM0
#define Touch_Channel1  TOUCH_PAD_NUM1
#define Touch_Channel2  TOUCH_PAD_NUM2
#define Touch_Channel3  TOUCH_PAD_NUM3
#define Touch_Channel4  TOUCH_PAD_NUM4
#define Touch_Channel5  TOUCH_PAD_NUM5
#define Touch_Channel6  TOUCH_PAD_NUM6
#define Touch_Channel7  TOUCH_PAD_NUM7
#define Touch_Channel8  TOUCH_PAD_NUM8
#define Touch_Channel9  TOUCH_PAD_NUM9



//函数声明
void touch_init(); //初始化触摸按键
void touch_config(uint8_t Touchx); //配置触摸按键
bool touch_state(uint8_t Touchx); //使用轮询的方法检测按键是否被按键
#endif
4.2.4.2 bsp_touch.cpp
#include "bsp_touch.h"




//定义相关的存储数据结构
gpio_num_t		Touch_Gpio[10] ={T0,T1,T2,T3,T4,T5,T6,T7,T8,T9}; //引脚
touch_pad_t		Touch_Channel[10] ={Touch_Channel0,Touch_Channel1,Touch_Channel2,Touch_Channel3,Touch_Channel4,Touch_Channel5,Touch_Channel6,Touch_Channel7,Touch_Channel8,Touch_Channel9}; //通道
uint16_t		Threshold[10] = { 0,0,0,0,0,0,0,0,0,0 }; //用来存储阈值


//设置触摸按键模式
static void touch_mode_config(uint8_t Touchx)
{
	

	//01 设置检测电压范围0-2.7V
	touch_pad_set_voltage(TOUCH_HVOLT_2V7, TOUCH_LVOLT_0V5, TOUCH_HVOLT_ATTEN_0V);

	//02 设置触发模式是硬件定时器触发
	touch_pad_set_fsm_mode(TOUCH_FSM_MODE_TIMER);

	//03 载入配置,设置阈值0就是不设置中断
	touch_pad_config(Touch_Channel[Touchx], 0);

	//04 开启滤波器,如果不开滤波器,读取脉冲数方法不一样
	touch_pad_filter_start(10); 

}

//设置触摸按键相关的gpio
static void touch_gpio_config(uint8_t Touchx)
{
	gpio_pad_select_gpio(Touch_Gpio[Touchx]);
	gpio_set_direction(Touch_Gpio[Touchx], GPIO_MODE_OUTPUT);
}

//设置触摸按键的检测阈值
//手摸按键周期会变长,脉冲数会减少
static void touch_thresh_config(uint8_t Touchx)
{
	//读取初始化没有触摸时候的脉冲数
	uint16_t value;
	
	touch_pad_read_filtered(Touch_Channel[Touchx], &value);
	

	//这个脉冲数的2/3作为阈值
	Threshold[Touchx] = value * 2 / 3;

	
}

/**
*  @brief 开启触摸按键功能
**/
void touch_init()
{
	//初始化传感器驱动程序
	touch_pad_init();
}


/**
*  @brief 配置触摸按键通道,一共T0-T9 10个通道,这里只定义了T0和T7
*  @param[in] Touchx: Touch[0..9] 使用第几个触摸按键
**/
void touch_config(uint8_t Touchx)
{
	touch_mode_config(Touchx); //初始化触摸按键
	touch_gpio_config(Touchx); //初始化相关的gpio
	touch_thresh_config(Touchx); //初始化阈值

}
/**
*  @brief 检测触摸按键是否被按键
*  @param[in] Touchx: Touch[0..9] 使用第几个触摸按键
*  @retval true:按下  false:没有按下
**/
bool touch_state(uint8_t Touchx)
{
	//用轮询的方法进行检测
	uint16_t value;
	touch_pad_read_filtered(Touch_Channel[Touchx], &value);
	if (value < Threshold[Touchx])
	{
		vTaskDelay(2/ portTICK_PERIOD_MS);
		touch_pad_read_filtered(Touch_Channel[Touchx], &value);
		if (value < Threshold[Touchx])
		{
			while (value < Threshold[Touchx])
			{
				touch_pad_read_filtered(Touch_Channel[Touchx], &value);
			}

			return true;
		}
		
			
		
	}

	return false;
}
4.2.4.4 main
#include "bsp_led.h"
#include "bsp_touch.h"

void setup() {

	//01 初始化led
	led_init(); 

	//02 初始化触摸按键
	touch_init();
	touch_config(Touch0);



	while (1)
	{
	
		if (touch_state(Touch0) == true)
		{
			led_toggle();
			
		}
	}
}

5.参考资料

  • [1] esp32 技术参考指南:29.2 电容式触摸传感器
  • [2] 触摸传感器
  • [3] ESP32 触摸传感器应用方案简介