电容触摸按键原理

前置技能

   
  输入按键-GPIO输入

  通用定时器原理
RC充放电电路原理

RC充放电电路

如图:
    电阻R和电容C串联
    当开关断开时,电阻R,电容0两端电压都是0,无电流
    当开关闭合时(瞬间),电阻R两端V1(上端)和0(下端)有电压差,产生电流
    此时电子通过电阻R积累在电容正极(上端),直到电容C电压为V1,充电完成
    此时R两端电压均为V1,无压差,不再有电流经过

电容C的电压从0-V1,充电过程中,有充电时间t和电容C的电压Vt之间的关系(右图)
看以看出随充电时间越来越长,充电的效率(斜率)越来越低

分析:
    当按键按下瞬间,电阻R两端电压V1和0,此时瞬间电流为I = V1 / R
    当电容C充电一段时间后,假设电容C此时的电压为Vc,那么此时电阻C两端的电压为V1和Vc,此时的瞬间电流为I = (V1-Vc) / R
    所以随着充电时间的增加,电容C的电压增加,电阻R两端压差减小,电流降低,电子积累速度减慢,充电效率降低

RC电路充放电公式

Vt = V0 + (V1 - V0) * [1 - exp(-t / RC)]

V0:电容的初始电压值
V1:电容最终可以冲/放到的电压值
Vt:电容t时刻的电压值

若电容C从0V开始充电,那么V0 = 0,则公式简化为:
Vt =V1 * [1 - exp(-t / RC)]

公式中V1, R均为常数,要达到相同的充电电压Vt,那么充电时间t和电容值C,成正比

RC电路电容与电阻关系

结论:
    同样条件下,电容C和充电时间t成正比
    达到相同的电压,电容越大,所需要的充电时间越长

R:外接电容充放电电阻
Cs:TPAD与PCB之间存在杂散电容
Cx:当手指按下时,手指和TPAD之间的电容

图A:
    手指未按下时的电路,TPAD与PCB之间存在电容Cs

图B:
    当手指按下时,手指与TPAD之间存在电容Cx,此时相当于Cs与Cx并联,电容总值=Cs+Cx

根据上边”RC充放电电路原理”可知:

当R一定时,达到相同的电压,电容越大,需要的充电时间越长
    所以,我们假设未触摸时充电时间为T1,触摸时充电时间为T2(T2 > T1)

检测电容触摸按键过程

1,电容放电到0
     TPAD引脚设置为推挽输出,放电
     放电到0V后,将计数器值设置为0,充电计时使用

2,电容充电
     TPAD引脚设置为浮空输入(IO复位后的状态)

3,充电完成(Vx)进入输入捕获
     TPAD引脚开启输入捕获
     因为放完电的时候C的电压为 0,所以设置上升沿捕获

4,是否按下-计算充电时间,对比是否按下
     当未按下时,记录充电完成的时间T1(计数器频路*数值)
     检测当次充电时间T2,与T1对比,如果超过预设时间T3,说明按键按下

电容触摸按键的硬件连接

电容触摸按键的硬件连接

PA1引脚说明:

PA1引脚说明

如图:
     电容触摸按键TPAD(黄色部分),TPAD引脚与PA1项链
     使用TIM5_CH2进行输入捕获

代码实现

tpad.h声明功能函数

#ifndef __TPAD_H
#define __TPAD_H
#include "sys.h"

// 未按下电容触摸按键时的充电时间
extern vu16 tpad_default_val;

// 复位TPAD:
// 设置推挽输出放电到0;再设置浮空输入充电,计数器CNT=0
void  TPAD_Reset(void);

// 获取一次捕获事件得到充电时间:
// 复位TPAD,等待捕获上升沿,得到计数器值,计算充电时间
u16   TPAD_Get_Val(void);

// n次调用TPAD_Get_Val取最大值
u16   TPAD_Get_MaxVal(u8 n);

// 初始化TPAD:
// 系统启动后初始化输入捕获,10次调用TPAD_Get_Val()
// 取中间n次平均值,作为未按下时的充电时间tpad_default_val
u8     TPAD_Init(u8 psc);

// 扫描TPAD:
// 调用TPAD_Get_MaxVal获取多次充电中最大充电时间
// 与tpad_default_val对比,若超过tpad_default_val+TPAD_GATE_VAL则为触摸
u8     TPAD_Scan(u8 mode);

// 输入捕获通道初始化
void  TIM5_CH2_Cap_Init(u16 arr,u16 psc);

#endif

tpad.c-tpad.h声明功能函数的实现

#include "tpad.h"
#include "delay.h"
#include "usart.h"

#define TPAD_ARR_MAX_VAL 0XFFFF    // ARR最大值
vu16 tpad_default_val=0;           // 没有按下是的充电时间

// 初始化触摸按键
// 获取空载时触摸按键取值
// 返回值: 0:初始化成功 1:初始化失败
u8 TPAD_Init(u8 psc)
{
    u16 buf[10];
    u16 temp;
    u8 j,i;

// 初始化定时器5通道2输入捕获
    TIM5_CH2_Cap_Init(TPAD_ARR_MAX_VAL, psc-1);//以1Mhz的频率计算

// 连续读取10次TPAD_Get_Val(),间隔10ms
    for(i=0;i<10;i++)
    {
        buf[i]=TPAD_Get_Val();// 10次定时器值装入数组
        delay_ms(10);
    }

// 将10次计数器值按升序排序
    for(i=0;i<9;i++)
    {
        for(j=i+1;j<10;j++)
        {
            if(buf[i]>buf[j])// 升序
            {
                temp=buf[i];
                buf[i]=buf[j];
                buf[j]=temp;
            }
        }
    }

// 取第2-8次充电时间取平均值,串口打印输出
    temp=0;
    for(i=2;i<8;i++)temp+=buf[i];
    tpad_default_val=temp/6;
    printf("tpad_default_val:%d\r\n",tpad_default_val);

//  初始化遇到超过TPAD_ARR_MAX_VAL/2的数值,不正常
    if(tpad_default_val>TPAD_ARR_MAX_VAL/2) return 1;

return 0;
}

// TPAD复位
void TPAD_Reset(void)
{
    GPIO_InitTypeDef  GPIO_InitStructure;
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); // 使能GPIOA时钟

// 设置PA1为推挽输出
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;             // PA1引脚
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;      // 推挽输出
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

GPIO_ResetBits(GPIOA, GPIO_Pin_1);                    // PA1输出0,放电

delay_ms(5);     //延迟5ms 等待放电结束,电容电压此时为0V

TIM_SetCounter(TIM5, 0);        //定时器5计数器设置为0
    TIM_ClearITPendingBit(TIM5, TIM_IT_CC2|TIM_IT_Update); //清除中断标志

//设置PA1为浮空输入-开始充电
    GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

}

// 获得定时器捕获值-上升沿捕获
u16 TPAD_Get_Val(void)
{
    // TPAD复位:PA1推挽输出放电到0,再设置PA1浮空输入充电,定时器=1,清除中断标志
    TPAD_Reset();

// 等待捕获上升沿
    while(TIM_GetFlagStatus(TIM5, TIM_IT_CC2) == RESET)
    {
        // 超时,返回CNT值
        if(TIM_GetCounter(TIM5)>TPAD_ARR_MAX_VAL-500)
            return TIM_GetCounter(TIM5);
    };

return TIM_GetCapture2(TIM5); // 返回通道2的捕获值
}

// 连续n次读取TPAD_Get_Val,返回最大值
u16 TPAD_Get_MaxVal(u8 n)
{
    u16 temp=0;    // 本次值
    u16 res=0;     // 最大值
    while(n--)
    {
        temp=TPAD_Get_Val();   // 获取一次充电计数
        if(temp>res)res=temp;  // 记录最大值
    };
    return res;
}

// 扫描触摸按键
// mode:0,不支持连续,1,支持联系
// 返回值:0,没有按下;1,有按下
#define TPAD_GATE_VAL 100    //门限值:大于tpad_default_val+TPAD_GATE_VAL视为按下
u8 TPAD_Scan(u8 mode)
{
    static u8 keyen=0;    // 是否可检测状态位 0:可以开始检验 1: 还不能检验
    u8 res=0;             // 返回是否按下 1:按下 0:未按下
    u8 sample=3;          // 默认采样3次
    u16 rval;             // 捕获到上升沿的最大值

// 如果支持连续触发
    if(mode)
    {
        sample=6;         // 连续触发时,采样为6此
        keyen=0;          //支持连续
    }

//取采样次数的最大值
    rval=TPAD_Get_MaxVal(sample);

//对比是否按下了
    if(rval>(tpad_default_val+TPAD_GATE_VAL))
    {
        if(keyen==0)res=1;      // keyen==0,有效,返回1
        //printf("r:%d\r\n",rval);
        keyen=3;                // 至少再扫描3次后按键才能生效
    }
    if(keyen)keyen--;

return res;
}

// 定时器5通道2输入捕获初始化
void TIM5_CH2_Cap_Init(u16 arr, u16 psc)
{
    GPIO_InitTypeDef  GPIO_InitStructure;
    TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
    TIM_ICInitTypeDef  TIM5_ICInitStructure;

RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5, ENABLE);    // 使能定时器5时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);   // 使能GPIOA时钟

// 初始化GPIOA-浮空输入
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;               // PA1
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;       // 50Mhz
    GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;     // 浮空输入
    GPIO_Init(GPIOA, &GPIO_InitStructure);

//定时器5初始化
    TIM_TimeBaseStructure.TIM_Period = arr;                 // 重装载值
    TIM_TimeBaseStructure.TIM_Prescaler =psc;               // 预分频器
    TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; // 设置时钟分割:TDTS = Tck_tim
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;// 向上计数
    TIM_TimeBaseInit(TIM5, &TIM_TimeBaseStructure);

//初始化通道2
    TIM5_ICInitStructure.TIM_Channel = TIM_Channel_2; // CC1S=01 设置IC2映射到TI5
    TIM5_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; // 上升沿捕获
    TIM5_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
    TIM5_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; // 配置输入分频-不分频
    TIM5_ICInitStructure.TIM_ICFilter = 0x03;// IC2F=0011 配置输入滤波器-8个定时器时钟周期滤波
    TIM_ICInit(TIM5, &TIM5_ICInitStructure);// 初始化定时器5 IC2

TIM_Cmd(TIM5, ENABLE ); // 使能定时器5
}

main.c 当捕获到电容触摸按键按下(捕获上升沿),LED1反转

#include "led.h"
#include "delay.h"
#include "key.h"
#include "sys.h"
#include "usart.h"
#include "tpad.h"

int main(void)
 {
    u8 t=0;                      // 计数器
    delay_init();                // 延时函数初始化
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);// 中断优先级分组配置
    uart_init(115200);           // 串口初始化 115200
    LED_Init();                  // LED初始化
    TPAD_Init(6);                // TPAD初始化

while(1)
    {
        if(TPAD_Scan(0))        // 捕获到上升沿(此函数执行至少15ms)
        {
            LED1=!LED1;          // LED1取反
        }

t++;
        if(t==15)
        {
            t=0;
            LED0=!LED0;          // LED0闪烁,标志程序正在运行
        }

delay_ms(10);            // 延时10ms
    }
 }

实验结果

LED0每间隔一段时间闪烁,标志程序正在运行中
当手指按下电容触摸按键时,LED1取反
---------------------
作者:BraveWangDev
来源:CSDN
原文:https://blog.csdn.net/ABAP_Brave/article/details/52937091
版权声明:本文为博主原创文章,转载请附上博文链接!

原文地址:https://www.cnblogs.com/wanghuaijun/p/9901593.html

时间: 2024-08-12 22:07:39

电容触摸按键原理的相关文章

电容退耦原理分享

本文转自:http://www.qiyeku.com/xinwen/106161.html 1.应用于电源电路,实现旁路.去藕.滤波和储能方面电容的作用,下面分类详述之: 1)滤波 滤波是电容的作用中很重要的一部分.几乎所有的电源电路中都会用到.从理论上(即假设 电容为纯电容)说,电容越大,阻抗越小,通过的频率也越高.但实际上超过1uF 的电容 大多为电解电容,有很大的电感成份,所以频率高后反而阻抗会增大.有时会看到有一个电 容量较大电解电容并联了一个小电容,这时大电容通低频,小电容通高频.电容

电容触摸按键走线原则

https://wenku.baidu.com/view/569fd3f10c22590102029dd7.html https://wenku.baidu.com/view/ff2739c489eb172ded63b714.html?sxts=1573437291276 原文地址:https://www.cnblogs.com/qinlongqiang/p/11834526.html

35-电容触摸按键实验

1.电容触摸按键原理 通过触摸这个logo来执行相应的命令. 通过I/O口的边沿触发来检测电容Cs在充电到达某个电压值时,所需要的时间,这通过输入捕获,这个时间记为t1:当按下触摸屏TPAD的时候,此时电容增大,那么充电的时间也会增加,通过记录此时到达相同电压值时的时间不同,来判断是否有按下,这时候的时间记为t2,t2肯定大于t1.也是通过输入捕获来判断他们的时间.别忘了充电后,要记得放电. 2.硬件连接 3.程序设计思路 程序思路 3.程序代码 main.c

去耦电容的选择

有许多同志在设计电路和制作PCB的过程中,对去耦电容的选择还是缺乏认识甚至是存在很大的盲目性.这里就涉及的问题谈谈一二. 利用去耦电容滤除电路板上电源的高频噪声是工程中常用的方法.好的高频去耦电容电路可去除高达1GHz的高频成分.设计印制电路板的时,每个集成电路的电源和地之间都要加一个去耦电容.通常,瓷介电容和多层瓷介电容的高频特性较好. 去耦电容一般作如下作用: 1).旁路掉器件的高频噪声(在电源和地之间为高频噪声提供低阻抗通路).一般而言,工作频率越高,电容值越大,则电容的阻抗越小. 2).

电源完整性设计

电源完整性 (1)为什么要重视电源噪声 芯片内部有成千上万个晶体管,这些晶体管组成内部的门电路.组合逻辑.寄存器.计数器.延迟线.状态机.以及其他逻辑功能.随着芯片的集成度越来越高,内部晶体管数量越来越大.芯片的外部引脚数量有限,为每一个晶体管提供单独的供电引脚是不现实的.芯片的外部电源引脚提供给内部晶体管一个公共的供电节点,因此内部晶体管状态的转换必然引起电源噪声在芯片内部的传递. 对内部各个晶体管的操作通常由内核时钟或片内外设时钟同步,但是由于内部延时的差别,各个晶体管的状态转换不可能是严格

BA-siemens-symaro传感器简介

1 传感器的原理 传感器.控制器.执行机构是构成控制系统 3 个要素,传感器的作 用一般用来测量工艺参数,提供给控制器或显示仪表,实现工艺过程的 监测或控制.传感器的类型是按测量参数不同分类的,主要分为温度.压力.液位.流量,在空调应用中湿度和空气质量也是一个重要的类 别,尤其是湿度.根据传感器的作用,传感器一般由 3 部分组成,即敏 感元件.转换电路和测量电路,其中敏感元件为传感器的最重要部分, 它不但决定传感器的测量性能. 1.1 温度传感器 温度传感 器的 敏感 元件 一般 采用 热电 阻

脉动的直流电

大小不断变化而方向不变的叫脉动直流电 直流电的波形应该是平直的,脉动直流的波形虽然只有正半周,但并不连续,这就是脉动直流 脉动直流电流是方向不变,但是电流的大小有周期性的变化.例如,正弦波的交流电经过全波整流后就变成了单向的脉动电流.因为它没有方向的变化,所以称为脉动直流电流. 整流出来的就是这种脉动直流.整流电路只是运用单向导电性把交流电变成了单向的脉动直流,要变成平滑的直流还要经过滤波电路. 电容也是可以对其有作用,详细见电容滤波原理

stm32学习基本知识点

1.AHB系统总线分为APB1(36MHz)和APB2(72MHz),其中2>1,意思是APB2接高速设备 2.Stm32f10x.h相当于reg52.h(里面有基本的位操作定义),另一个为stm32f10x_conf.h专门控制外围器件的配置,也就是开关头文件的作用 3. HSE Osc(High Speed External Oscillator)高速外部晶振,一般为8MHz,HSI RC(High Speed InternalRC)高速内部RC,8MHz 4. LSE Osc(Low Sp

DAC杂谈

DAC种类: 有权电阻网络DAC 输出电压变化范围为:0~-(2^n-1)/2^n*Vref 当位数很高时,每个电阻都有很高精度是十分困难的. 倒T型电阻网络DAC(比如AD7520 10bit 已停产 乘法) 输出电压变化范围为:0~-(2^n-1)/2^n*Vref 权电流型DAC 尽管倒T型电阻网络D/A转换器具有较高的转换速度,但由于电路中存在模拟开关电压降,当流过各支路的电流稍有变化时,就会产生转换误差.为进一步提高D/A转换器的精度,可采用权电流型D/A转换器. 权电容DAC 原理通