当前位置: 首页>編程日記>正文

笔记14:STM32F4之电容触摸按键

笔记14:STM32F4之电容触摸按键

一. 电容触摸按键原理
1.电路原理介绍
在这里插入图片描述

上图是基于整点原子STM32F4的原理图,其中蓝色TPAD部分就是我们电容触摸按键位置,红色的TPAD是悬空的,需要我们将其与其他引脚相连接起来。在开发板上,我们需要用跳线帽将STM ADC与TAPD连接起来,这样TAPD引脚就可以与PA5连接起来了。(也可以用其他引脚)
由于要用到捕获,因为我们需要在数据手册上查看PA5可以对应哪一个定时器通道。
在这里插入图片描述
由上图我们选择定时器2通道1。
在这里插入图片描述
上图是按键按下前后对比图。R:外接电容充放电电阻。
按键按下之前,电路之中只连接了一个电容Cs(TPAD和PCB间的杂散电容),按键按下之后,与Cs并联了一个Cx(手指按下时,手指和TPAD之间的电容),电路总电容变大。其中开关部分是电容放电开关,由STM32 IO口代替。也就是对应着第一张图片的红色TAPD脚。
根据电路知识可知,电容上的充放电公式为:
Vt = V0+(V1-V0)* [1-e(-t/RC)]
V0 为电容上的初始电压值;
V1 为电容最终可充到或放到的电压值;
Vt 为t时刻电容上的电压值。
RC为充电时间常数,是电容的端电压达到最大值的0.63倍时所需要的时间,通常认为时间达到5倍的充电时间常数后就认为充满了。时间常数越大,电容充放电就越慢(大电容和小电容相比肯定是大电容充电慢;大电阻和小电阻相比,大电阻起始电流较小,因此大电阻充电时间慢)。根据这个原理我便可涉及触摸按键的使用原理了。
2. 具体原理介绍
由以上分析我们得知,在电阻相同的条件下,电容越大,充电到某一电压值的时间越长,因此我们记录触摸按键没有触摸时电容的充电时间T1,之后的检测以这个时间做标准,按下TPAD,电容变大,所以充电时间为T2。我们可以通过检测充放电时间,来判断是否按下。如果T2-T1大于某个值,就可以判断有按键按下。
3. 检测电容触摸按键的过程
①. TPAD引脚设置为推挽输出,输出0,实现电容放电到0。(相当于将红色TPAD接地)
②. TPAD引脚设置为浮空输入(IO复位后的状态),电容开始充电。(相当于将红色TAPD断开)
③. 同时开启TPAD引脚的输入捕获开始捕获。
④. 等待充电完成(充电到底Vx,检测到上升沿)。
⑤. 计算充电时间。
二. 程序设计
1.具体程序及详细说明

头文件"tpad.h"里面就是对tapd.c里面的函数内容进行申明,具体内容如下:

#ifndef __TPAD_H
#define __TPAD_H
#include "sys.h"							   	    
void TPAD_Reset(void);
u16 TPAD_Get_Val(void);
u16 TPAD_Get_MaxVal(u8 n);
u8 TPAD_Init(u32 psc);		//初始化触摸按键,记录没有按下的电容充电时间,初始化成功返回0,未成功返回1;
u8 TPAD_Scan(u8 mode);
void TIM2_CH1_Cap_Init(u32 arr,u16 psc);#endif

宏定义及头文件部分:对于代码vu16类型说明:
typedef __IO uint16_t vu16; 这是本身在stm2f4xx.h头文件里面定义了的。

#include "tpad.h"
#include "delay.h"		    
#include "usart.h"
#define TPAD_ARR_MAX_VAL  0XFFFFFFFF	//最大的ARR值(TIM2是32位定时器),防止捕获的时候CCRX>ARR	  
vu16 tpad_default_val=0;				//空载的时候(没有手按下),计数器需要的时间
#define TPAD_GATE_VAL 100							//触摸的门限值,也就是必须tpad_default_val+TPAD_GATE_VAL,才认为是有效触摸

捕获相关程序-----TIM2_CH1_Cap_Init(),当电容开始充电并且达到能够捕获上升沿的电压时,就会捕获到一个上升沿。

void TIM2_CH1_Cap_Init(u32 arr,u16 psc)		//定时器 2 通道 1 输入捕获配置
{GPIO_InitTypeDef GPIO_InitStruct;TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;TIM_ICInitTypeDef TIM_ICInitStruct;RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);			//TIM2时钟使能RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);		//GPIOA时钟使能GPIO_InitStruct.GPIO_Pin=GPIO_Pin_5;						//GPIOA5GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF;						//复用功能GPIO_InitStruct.GPIO_Speed=GPIO_Speed_100MHz;GPIO_InitStruct.GPIO_OType=GPIO_OType_PP;					//推挽复用输出GPIO_InitStruct.GPIO_PuPd=GPIO_PuPd_NOPULL;					//不带上下拉GPIO_Init(GPIOA,&GPIO_InitStruct);							//初始化PA5GPIO_PinAFConfig(GPIOA,GPIO_PinSource5,GPIO_AF_TIM2);		//将GPIO5复用映射到TIM2TIM_TimeBaseInitStruct.TIM_Prescaler=psc;					//TIM2分频系数TIM_TimeBaseInitStruct.TIM_CounterMode=TIM_CounterMode_Up;	//TIM2向上计数模式TIM_TimeBaseInitStruct.TIM_Period=arr;						//重载值TIM_TimeBaseInitStruct.	TIM_ClockDivision=TIM_CKD_DIV1;TIM_TimeBaseInit(TIM2,&TIM_TimeBaseInitStruct);				//初始化定时器2TIM_ICInitStruct.TIM_Channel=TIM_Channel_1;					//TIM2的通道1TIM_ICInitStruct.TIM_ICPolarity=TIM_ICPolarity_Rising;		//上升沿捕获TIM_ICInitStruct.TIM_ICSelection=TIM_ICSelection_DirectTI;	//IC1映射到TI1上TIM_ICInitStruct.TIM_ICPrescaler=TIM_ICPSC_DIV1;					//不分频TIM_ICInitStruct.TIM_ICFilter=0000; 								//不滤波TIM_ICInit(TIM2,&TIM_ICInitStruct);							//初始化TIM2捕获通道1TIM_Cmd(TIM2,ENABLE);
}

TAPD_Reset(),主要作用就是让电容放电

void TPAD_Reset(void)		//复位一次,并让电容放电,清零定时计数器
{GPIO_InitTypeDef GPIO_InitStruct;GPIO_InitStruct.GPIO_Pin=GPIO_Pin_5;				//PA5GPIO_InitStruct.GPIO_Mode=GPIO_Mode_OUT;			//普通输出模式GPIO_InitStruct.GPIO_Speed=GPIO_Speed_100MHz;		//速度100MHZGPIO_InitStruct.GPIO_OType=GPIO_OType_PP;			//推挽输出GPIO_InitStruct.GPIO_PuPd=GPIO_PuPd_DOWN;			//下拉GPIO_Init(GPIOA,&GPIO_InitStruct);      			//初始化GPIOAGPIO_ResetBits(GPIOA,GPIO_Pin_5);					//PA5输出0,电容放电delay_ms(5);										//等待放电结束TIM_SetCounter(TIM2,0);								//TIM2计数器清0GPIO_InitStruct.GPIO_Pin=GPIO_Pin_5;				//PA5GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF;				//复用功能GPIO_InitStruct.GPIO_Speed=GPIO_Speed_100MHz;		//速度100MHZGPIO_InitStruct.GPIO_OType=GPIO_OType_PP;			//推挽复用输出GPIO_InitStruct.GPIO_PuPd=GPIO_PuPd_NOPULL;			//既不上拉也不下拉GPIO_Init(GPIOA,&GPIO_InitStruct);					//初始化GPIOA}

TPAD_Get_Val,这个函数作用是获取到达上升沿时的计数器里面的计数值,为计算电容充电时间提供数据。

u16 TPAD_Get_Val(void)			//得到定时器的捕获值
{TPAD_Reset();while(TIM_GetFlagStatus(TIM2, TIM_IT_CC1) == RESET)//等到电容充电到一个值后产生上升沿捕获{if(TIM_GetCounter(TIM2)>TPAD_ARR_MAX_VAL-500)		//超过正常按下时间,直接返回定时器计数值return TIM_GetCounter(TIM2);}return TIM_GetCapture1(TIM2);		//返回定时器捕获值}

TAPD_Get_MaxVal,这个函数的作用是为了后面判断按键触摸时触摸是否有效,取最大值判断更精确。

u16 TPAD_Get_MaxVal(u8 n)//n为读取的次数
{u16 temp=0,res=0;while(n--){temp=TPAD_Get_Val();if(temp>res)res=temp;}return res;
}				

TAPD_InIT()

u8 TPAD_Init(u32 psc)		//初始化触摸按键,记录没有按下的电容充电时间,初始化成功返回0,未成功返回1
{u16 ChargingTimeData[10],temp;u8 i,j;TIM2_CH1_Cap_Init(TPAD_ARR_MAX_VAL,psc-1);for(i=0;i<10;i++)		//读取10次值{ChargingTimeData[i]=TPAD_Get_Val();delay_ms(10);}for(i=0;i<9;i++)			//数组升序排列{for(j=0;j<10;j++){	if(ChargingTimeData[i]>ChargingTimeData[j])temp=ChargingTimeData[i];ChargingTimeData[i]=ChargingTimeData[j];ChargingTimeData[j]=temp;}}temp=0;for(i=2;i<8;i++)		//取中间6个数据做平均值temp+=ChargingTimeData[i];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;
}

触摸按键扫描部分

u8 TPAD_Scan(u8 mode) //mode=1支持一直按下,mode=0,不支持一直按下//返回值为1有按下,返回值为0没有按下
{static u8 keyen=0; //0,可以开始检测;>0,还不能开始检测u8 res=0,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)&&rval<(10*tpad_default_val))	//大于 tpad_default_val+TPAD_GATE_VAL,且小于 10 倍 tpad_default_val,则有效{if((keyen==0)&&(rval>(tpad_default_val+TPAD_GATE_VAL)))				//大于 tpad_default_val+TPAD_GATE_VAL,有效res=1;keyen=3; //至少要再过 3 次之后才能按键有效}if(keyen)keyen--;return res;}

整体思路:
在这里插入图片描述
流程图:

在这里插入图片描述


https://www.fengoutiyan.com/post/15312.html

相关文章:

  • 探灵笔记按什么键说话
  • 探灵笔记打开黑屏怎么办
  • 探灵笔记鼠标和按键对不上
  • 笔记被上面一排按键快捷键怎样关闭
  • 按键消抖电容大小
  • RC电容触摸感应按键
  • 电容式触摸按键原理
  • 电容触摸ic
  • 鏡像模式如何設置在哪,圖片鏡像操作
  • 什么軟件可以把圖片鏡像翻轉,C#圖片處理 解決左右鏡像相反(旋轉圖片)
  • 手機照片鏡像翻轉,C#圖像鏡像
  • 視頻鏡像翻轉軟件,python圖片鏡像翻轉_python中鏡像實現方法
  • 什么軟件可以把圖片鏡像翻轉,利用PS實現圖片的鏡像處理
  • 照片鏡像翻轉app,java實現圖片鏡像翻轉
  • 什么軟件可以把圖片鏡像翻轉,python圖片鏡像翻轉_python圖像處理之鏡像實現方法
  • matlab下載,matlab如何鏡像處理圖片,matlab實現圖像鏡像
  • 圖片鏡像翻轉,MATLAB:鏡像圖片
  • 鏡像翻轉圖片的軟件,圖像處理:實現圖片鏡像(基于python)
  • canvas可畫,JavaScript - canvas - 鏡像圖片
  • 圖片鏡像翻轉,UGUI優化:使用鏡像圖片
  • Codeforces,CodeForces 1253C
  • MySQL下載安裝,Mysql ERROR: 1253 解決方法
  • 勝利大逃亡英雄逃亡方案,HDU - 1253 勝利大逃亡 BFS
  • 大一c語言期末考試試題及答案匯總,電大計算機C語言1253,1253《C語言程序設計》電大期末精彩試題及其問題詳解
  • lu求解線性方程組,P1253 [yLOI2018] 扶蘇的問題 (線段樹)
  • c語言程序設計基礎題庫,1253號C語言程序設計試題,2016年1月試卷號1253C語言程序設計A.pdf
  • 信奧賽一本通官網,【信奧賽一本通】1253:抓住那頭牛(詳細代碼)
  • c語言程序設計1253,1253c語言程序設計a(2010年1月)
  • 勝利大逃亡英雄逃亡方案,BFS——1253 勝利大逃亡
  • 直流電壓測量模塊,IM1253B交直流電能計量模塊(艾銳達光電)
  • c語言程序設計第三版課后答案,【渝粵題庫】國家開放大學2021春1253C語言程序設計答案
  • 18轉換為二進制,1253. 將數字轉換為16進制
  • light-emitting diode,LightOJ-1253 Misere Nim
  • masterroyale魔改版,1253 Dungeon Master
  • codeformer官網中文版,codeforces.1253 B
  • c語言程序設計考研真題及答案,2020C語言程序設計1253,1253計算機科學與技術專業C語言程序設計A科目2020年09月國家開 放大學(中央廣播電視大學)
  • c語言程序設計基礎題庫,1253本科2016c語言程序設計試題,1253電大《C語言程序設計A》試題和答案200901
  • 肇事逃逸車輛無法聯系到車主怎么辦,1253尋找肇事司機