目录

前言

一、电容按键原理

1.1、无手指触摸电容按键

1.2、有手指触摸电容按键

1.3、Vc 电压与充电时间关系

二、程序设计

2.1、设计思路

2.2、检测电容按键按下的具体过程

2.3、工程代码


前言

(参考《野火参考手册》)

通过输入捕获功能,来做一个电容触摸按键。用 TIM5 的通道 2(PA1)来做输入捕获,并实现一个简单的电容触摸按键,通过该按键控制 DS1 的亮灭。

电容按键不需要任何外部机械部件,使用方便,成本低,很容易制成与周围环境相密封的键盘, 以起到防潮防湿的作用。电容按键优势突出使得越来越多电子产品使用它代替传统的机械按键。

一、电容按键原理

电容器 (简称为电容) 就是可以容纳电荷的器件,两个金属块中间隔一层绝缘体就可以构成一个最简单的电容。有两个金属片,之间有一个绝缘介质,这样就构成了一个电容。这样一个电容在电路板上非常容易实现,一般设计四周的铜片与电路板地信号连通, 这样一种结构就是电容按键的模型。当电路板形状固定之后,该电容的容量也是相对稳定的。

电路板制作时都会在表面上覆盖一层绝缘层,用于防腐蚀和绝缘,所以实际电路板设计时情况 如图无手指触摸情况。电路板最上层是绝缘材料,下面一层是导电铜箔,我们根据电路走线情况 设计决定铜箔的形状,再下面一层一般是 FR-4 板材。金属感应片与地信号之间有绝缘材料隔着, 整个可以等效为一个电容 Cx。一般在设计时候,把金属感应片设计成方便手指触摸大小。

1.1、无手指触摸电容按键

在电路板未上电时,可以认为电容 是没有电荷的,在上电时,在电阻作用下,电容 就会有一个充电过程,直到电容充满,即 电压值为 3.3V,这个充电过程的时间长短受到电阻 R 阻值和电容容值的直接影响。但是在选择合适电阻 R 并焊接固定到电路板上后,这个充电 时间就基本上不会变了,因为此时电阻 R 已经是固定的,电容 在无外界明显干扰情况下基本上也是保持不变的。

1.2、有手指触摸电容按键

当我们用手指触摸时,金属感应片除了与地信号形成一个等效电容 外,还会与手指形成一个 等效电容。

此时整个电容按键可以容纳的电荷数量就比没有手指触摸时要多了,可以看成是 叠加的效果。在相同的电阻 R 情况下,因为电容容值增大了,导致需要更长的充电时间。也就是这个充电时间变长使得我们区分有无手指触摸,也就是电容按键是否被按下。

最主要的任务就是测量充电时间。充电过程可以看出是一个信号从低电平变成高电平的过 程,现在就是要求出这个变化过程的时间。我们可以利用定时器输入捕获功能计算充电时间,即 设置 TIMx_CH 为定时器输入捕获模式通道。这样先测量得到无触摸时的充电时间作为比较基准, 然后再定时循环测量充电时间与无触摸时的充电时间作比较,如果超过一定的阈值就认为是有手指触摸。

1.3、Vc 电压与充电时间关系

为测量充电时间,需要设置定时器输入捕获功能为上升沿触发,图中 VH 就是被触发上升沿的电压值,也是 STM32 认为是高电平的最低电压值,大约为 1.8V。

t1 和 t2 可以通过定时器捕获/比较寄存器获取得到。

在测量充电时间之前,要制作这个充电过程。在电路板上电时会有充电过程,现在要求在程序运行中循环检测按键,所以必须可以控制充电过程的生成。 可以控制 TIMx_CH 引脚作为普通的 GPIO 使用,使其输出一小段时间的低电平,为电容 Cx 放电,即 Vc 为 0V。当重新配置TIMx_CH 为输入捕获时电容 Cx 在电阻 R 的作用下就可以产生充电过程。

二、程序设计

2.1、设计思路

(1) 编写定时器输入捕获相关函数 (2) 测量电容按键空载的充电时间 T1 (3) 测量电容按键有手触摸的充电时间 T2 (4) 只需要比较 T2 与 T1 的时间即可检测出按键是否有手指触摸

2.2、检测电容按键按下的具体过程 

  1. TPAD引脚设置为推挽输出,输出0,实现电容放电到0。
  2. TPAD引脚设置为浮空输入(IO复位后的状态),电容开始充电。
  3. 同时开启TPAD引脚的输入捕获开始捕获。
  4. 等待充电完成(充电到底Vx,检测到上升沿)。
  5. 计算充电时间。

2.3、工程代码

tpad.c代码如下所示:

#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;TIM5_CH2_Cap_Init(TPAD_ARR_MAX_VAL,psc-1);//以1Mhz的频率计数 for(i=0;i<10;i++)//连续读取10次{                buf[i]=TPAD_Get_Val();delay_ms(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;}}}temp=0;for(i=2;i<8;i++)temp+=buf[i];//取中间的6个数据进行平均tpad_default_val=temp/6;printf("tpad_default_val:%d\r\n",tpad_default_val);  if(tpad_default_val>TPAD_ARR_MAX_VAL/2)return 1;//初始化遇到超过TPAD_ARR_MAX_VAL/2的数值,不正常!return 0;
}
//复位一次
void TPAD_Reset(void)
{GPIO_InitTypeDef  GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);     //使能PA端口时钟//设置GPIOA.1为推挽使出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);                         //PA.1输出0,放电delay_ms(5);TIM_SetCounter(TIM5,0);        //归0TIM_ClearITPendingBit(TIM5, TIM_IT_CC2|TIM_IT_Update); //清除中断标志//设置GPIOA.1为浮空输入GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;  //浮空输入GPIO_Init(GPIOA, &GPIO_InitStructure);}
//得到定时器捕获值
//如果超时,则直接返回定时器的计数值.
u16 TPAD_Get_Val(void)
{                  TPAD_Reset();while(TIM_GetFlagStatus(TIM5, TIM_IT_CC2) == RESET)//等待捕获上升沿{if(TIM_GetCounter(TIM5)>TPAD_ARR_MAX_VAL-500)return TIM_GetCounter(TIM5);//超时了,直接返回CNT的值};    return TIM_GetCapture2(TIM5);
}
//读取n次,取最大值
//n:连续获取的次数
//返回值:n次读数里面读到的最大读数值
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,可以开始检测;>0,还不能开始检测     u8 res=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))//大于tpad_default_val+TPAD_GATE_VAL,有效{                           if(keyen==0)res=1;      //keyen==0,有效 //printf("r:%d\r\n",rval);                                           keyen=3;                //至少要再过3次之后才能按键有效   } if(keyen)keyen--;                                                                            return res;
}
//定时器2通道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);   //使能TIM5时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);     //使能PA端口时钟//设置GPIOA.1为浮空输入GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;                //PA1 端口配置GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;   //速度50MHzGPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN_FLOATING;    //浮空输入GPIO_Init(GPIOA, &GPIO_InitStructure);    //设置为浮空输入//初始化TIM5  TIM_TimeBaseStructure.TIM_Period = arr; //设定计数器自动重装值   TIM_TimeBaseStructure.TIM_Prescaler =psc;     //预分频器     TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割:TDTS = Tck_timTIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式TIM_TimeBaseInit(TIM5, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位//初始化通道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);//初始化I5 IC2TIM_Cmd(TIM5,ENABLE );   //使能定时器5
}

tpad.h代码如下所示:

#ifndef __TPAD_H
#define __TPAD_H
#include "sys.h"      extern vu16 tpad_default_val;void TPAD_Reset(void);
u16  TPAD_Get_Val(void);
u16 TPAD_Get_MaxVal(u8 n);
u8   TPAD_Init(u8 psc);
u8   TPAD_Scan(u8 mode);
void TIM5_CH2_Cap_Init(u16 arr,u16 psc);
#endif

main.c代码如下所示:

#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);//设置NVIC中断分组2:2位抢占优先级,2位响应优先级uart_init(115200);  //串口初始化为115200LED_Init();               //LED端口初始化TPAD_Init(6);            //初始化触摸按键while(1){                                                   if(TPAD_Scan(0))   //成功捕获到了一次上升沿(此函数执行时间至少15ms){LED1=!LED1;       //LED1取反}t++;if(t==15)       {t=0;LED0=!LED0;     //LED0取反,提示程序正在运行}delay_ms(10);}}

学习记录:TIM—电容按键检测相关推荐

  1. python小括号报错_Python学习记录:括号配对检测问题

    Python学习记录:括号配对检测问题 一.问题描述 在练习Python程序题的时候,我遇到了括号配对检测问题. 问题描述:提示用户输入一行字符串,其中可能包括小括号 (),请检查小括号是否配对正确, ...

  2. STM32CubeMX学习笔记(24)——通用定时器接口使用(电容按键检测)

    一.电容按键简介 电容器(简称为电容)就是可以容纳电荷的器件,两个金属块中间隔一层绝缘体就可以构成一个最简单的电容.如图 32-1(俯视图),有两个金属片,之间有一个绝缘介质,这样就构成了一个电容.这 ...

  3. 【瑞萨RA_FSP】CTSU——电容按键检测

    文章目录 一.1. 电容按键介绍 二.电容按键原理 三.瑞萨QE在电容按键上面的运用 四.电容按键实验 1. 硬件设计 2. FSP配置 3.复制文件 4.主函数 一.1. 电容按键介绍 电容式感应触 ...

  4. STM32学习记录——触摸屏虚拟按键

    视频演示:(有点粗糙,很多没细节没去弄了) 电子锁触摸屏 直接使用正点原子实验26触摸屏实验进行添加: 这里借用了博客基于STM32的TFT触摸屏虚拟按键_鱼鱼不秃头的博客-CSDN博客_stm32触 ...

  5. STM32——GPIO输入——按键检测

    硬件介绍 当按键置空时,IO接地 按键按下之后,IO口接通3.3V高电压,电流比较大,为了避免损坏IO,这里需要加装一个限流电阻.可以看到IO口是默认低电平,按键按下后产生一个上升沿,和平常的电路设计 ...

  6. 【按键精灵学习记录】以DOTA2人机为例

    [按键精灵学习记录]以DOTA2人机为例 一.写在前面 二.准备工作 1.环境准备 2.需求分析 3.流程图 三.代码实现 1.命令分析 2.代码实现 状态判断 主循环 英雄选择 游戏中 3.实测 四 ...

  7. STN32单片机学习笔记(五)-按键检测

    写在前面:本系列内容均为自学笔记,参考资料为野火指南者开发板资料及芯片参考手册等,使用野火指南者开发板进行学习,该系列内容仅用于记录笔记,不做其他用途,笔记的内容可能会存在不准确或者错误等,如有大佬看 ...

  8. CVPR2019| 百度17篇CVPR论文学习记录(包含:无人驾驶、神经网络、GAN、无监督学习、目标检测)

    首先感谢现在网上资源丰富,能够获得很多人的总结,结合自身实际进行了学习记录. 并着重标注了其中关键核心 目录 1)Taking A Closer Look at Domain Shift: Categ ...

  9. 51单片机学习记录(五)矩阵按键

    文章目录 1.矩阵按键的控制原理 2.矩阵按键实现 1.行列式法实现矩阵按键 2.线翻转法实现矩阵按键 3.按键实战 1.矩阵按键的控制原理 独立按键与单片机连接时, 每一个按键都需要单片机的一个 I ...

最新文章

  1. 微信小程序showModel使用注意
  2. Java:全局变量(成员变量)与局部变量
  3. 华为机考HJ17坐标移动
  4. elasticSearch6源码分析(8)RepositoriesModule模块
  5. Scala 空返回值Unit
  6. 从体验出发构建以增长为目标的视频服务体系
  7. Anaconda 安装 Tensorflow 教程
  8. 汇编语言---函数调用栈
  9. excel向下自动填充单元格
  10. DocumentFormat.OpenXml
  11. 微信公众号跳转到关注页面
  12. 华为路由器DDNS设置and NAT内网映射 and SSH
  13. 计算机重启命令编码,电脑倒计时重启代码是什么
  14. 云开发魔都团长头像制作微信小程序源码/带流量主
  15. UT单元测试总结实践篇
  16. 王传福的梦想,不止7000亿
  17. 32.判断日期的合法性(对于8位数的判断)
  18. 如何在linux上开发安卓软件,使用Xamarin在Visual Studio中开发Android应用
  19. iTop 4412 移植linux-5.8.6
  20. 关于保留小数点后几位数字“

热门文章

  1. [TL-WR841N V5~V9] 如何当作无线交换机使用?
  2. LTspice软件电源设置
  3. matlab画三相电,如何手画三相电相(线)电压(流)波形图
  4. 论文快读:DETReg(CVPR2022)
  5. 通配符中一个星号两个星号和globstar的关系(by quqi99)
  6. 一、自然语言处理(新手上路)
  7. 如何绘制甘特图?这个软件来帮你
  8. Sqoop-1.4.7-部署与常见案例
  9. Numbers ZOJ - 3987[思维暴力]
  10. pandas使用dropna函数删除dataframe数据中指定数据列的内容为缺失值的数据行(使用subset参数指定数据列)