
单片机模拟电容触摸按键.doc
5页单片机模拟电容触摸按键这里我们使用的是检测电容充放电时间的方法来判断是否有触摸,图中 R 是外接的电容充电电阻,Cs 是没有触摸按下时 TPAD 与 PCB 之间的杂散电容而 Cx 则是有手指按下的时候,手指与 TPAD 之间形成的电容图中的开关是电容放电开关(由实际使用时,由 STM32 的 IO 代替) 先用开关将 Cs(或 Cs+Cx)上的电放尽,然后断开开关,让 R 给 Cs(或 Cs+Cx)充电,当没有手指触摸的时候,Cs 的充电曲线如图中的 A 曲线而当有手指触摸的时候,手指和 TPAD 之间引入了新的电容 Cx,此时Cs+Cx 的充电曲线如图中的 B 曲线从上图可以看出,A、B 两种情况下,Vc 达到 Vth 的时间分别为 Tcs 和Tcs+Tcx其中,除了 Cs 和 Cx 我们需要计算,其他都是已知的,根据电容充放电公式:Vc=V0*(1-e^(-t/RC))其中 Vc 为电容电压,V0 为充电电压,R 为充电电阻, C 为电容容值,e 为自然底数,t 为充电时间根据这个公式,我们就可以计算出 Cs 和 Cx。
利用这个公式,我们还可以把战舰开发板作为一个简单的电容计,直接可以测电容容量了,有兴趣的朋友可以捣鼓下在本章中,其实我们只要能够区分 Tcs 和 Tcs+Tcx,就已经可以实现触摸检测了,当充电时间在 Tcs 附近,就可以认为没有触摸,而当充电时间大于 Tcs+Tx 时,就认为有触摸按下(Tx 为检测阀值) 本章,我们使用 PA1(TIM5_CH2)来检测 TPAD 是否有触摸,在每次检测之前,我们先配置 PA1 为推挽输出,将电容 Cs(或 Cs+Cx)放电,然后配置 PA1 为浮空输入,利用外部上拉电阻给电容 Cs(Cs+Cx)充电,同时开启TIM5_CH2 的输入捕获,检测上升沿,当检测到上升沿的时候,就认为电容充电完成了,完成一次捕获检测在 MCU 每次复位重启的时候,我们执行一次捕获检测(可以认为没触摸) ,记录此时的值,记为 tpad_default_val,作为判断的依据在后续的捕获检测,我们就通过与 tpad_default_val 的对比,来判断是不是有触摸发生关于输入捕获的配置,在上一章我们已经有详细介绍了,这里我们就不再介绍至此,电容触摸按键的原理介绍完毕2 硬件设计本实验用到的硬件资源有:1) 指示灯 DS0 和 DS12) 定时器 TIM53) 触摸按键 TPAD前面两个之前均有介绍,我们需要通过 TIM5_CH2(PA1)采集 TPAD 的信号,所以本实验需要用跳线帽短接多功能端口(P14)的 TPAD 和 ADC,以实现 TPAD 连接到 PA1。
如图 16.2.1 所示:3 软件设计软件设计我们在之前的工程上面增加,首先在 HARDWARE 文件夹下新建 TPAD 的文件夹然后打开 USER 文件夹下的工程,新建一个 tpad.c 的文件和 tpad.h 的头文件,保存在 TAPD 文件夹下,并将 TPAD 文件夹加入头文件包含路径我们在 tpad.c 里输入如下代码:#define TPAD_ARR_MAX_VAL 0XFFFF //最大的 ARR 值 vu16 tpad_default_val=0;//空载的时候 (没有手按下),计数器需要的时间//初始化触摸按键//获得空载的时候触摸按键的取值.//systick:系统时钟频率图 1、电容触摸按键原理图 2 TPAD 与 STM32 连接原理图//返回值:0,初始化成功;1,初始化失败u8 TPAD_Init(u8 systick){u16 buf[10];u16 temp;u8 j,i;TIM5_CH2_Cap_Init(TPAD_ARR_MAX_VAL,systick-1);//以 1Mhz 的频率计数for(i=0;ibuf[j])//升序排列{temp=buf;buf=buf[j];buf[j]=temp;}}}temp=0;for(i=2;iTPAD_ARR_MAX_VAL/2)return 1;//初始化遇到超过 TPAD_ARR_MAX_VAL/2 的数值,不正常!return 0; }//复位一次//释放电容电量,并清除定时器的计数值void TPAD_Reset(void){ GPIOA->CRL&=0XFFFFFF0F; //PA1 输入GPIOA->CRL|=0X00000030; //复用功能输出 GPIOA->ODR&=~(1SR=0; //清除标记TIM5->CNT=0; //归零 GPIOA->CRL&=0XFFFFFF0F; //PA1 输入GPIOA->CRL|=0X00000040; //复用功能输出 }//得到定时器捕获值//如果超时,则直接返回定时器的计数值.//返回值:捕获值/计数值(超时的情况下返回)u16 TPAD_Get_Val(void){ TPAD_Reset();while((TIM5->SR&0X04)==0)//等待捕获上升沿{if(TIM5->CNT>TPAD_ARR_MAX_VAL-500)return TIM5->CNT;//超时了,直接返回 CNT 的值}; return TIM5->CCR2; } //读取 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 80 //触摸的门限值,也就是必须大于 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,有效{ rval=TPAD_Get_MaxVal(sample); if((keyen==0)&&(rval>(tpad_default_val+TPAD_GATE_VAL)))//大于 tpad_default_val+TPAD_GATE_VAL,有效{res=1;} //printf("r:%d\r\n",rval); keyen=5; //至少要再过 5 次之后才能按键有效 }else if(keyen>2)keyen=2; //如果检测到按键松开,则直接将次数将为 2,以提高响应速度if(keyen)keyen--; return res;}//定时器 2 通道 2 输入捕获配置//arr:自动重装值//psc:时钟预分频数void TIM5_CH2_Cap_Init(u16 arr,u16 psc){//此部分需手动修改 IO 口设置RCC->APB1ENR|=1APB2ENR|=1CRL&=0XFFFFFF0F; //PA1 输入GPIOA->CRL|=0X00000040; //浮空输入 TIM5->ARR=arr; //设定计数器自动重装值//刚好 1ms TIM5->PSC=psc; //预分频器,1M 的计数频率TIM5->CCMR1|=1CCMR1|=3CCMR1|=0CCER|=0CCER|=1CR1|=0x01; //使能定时器 5}此部分代码包含 6 个函数,我们将介绍其中 4 个比较重要的函数:TIM5_CH2_Cap_Init、TPAD_Get_Val、TPAD_Init和 TPAD_Scan。
首先介绍 TIM5_CH2_Cap_Init 函数,该函数和上一章的输入捕获函数基本一样,不同的是,这里我们设置的是 CH2通道,并开启了输入滤波器通过该函数的设置,我们将可以捕获 PA1 上的上升沿我们再来看看 TPAD_Get_Val 函数,该函数用于得到定时器的一次捕获值该函数先调用 TPAD_Reset,将电容放电,同时设置 TIM5_CNT 寄存器为 0,然后死循环等待发生上升沿捕获(或计数溢出) ,将捕获到的值(或溢出值)作为返回值返回接着我们介绍 TPAD_Init 函数,该函数用于初始化输入捕获,并获取默认的 TPAD 值该函数有一个参数,用来传递系统时钟,其实是为了配置 TIM5_CH2_Cap_Init 为 1us 计数周期在该函数中连续 10 次读取 TPAD 值,将这些值升序排列后取中间 6 个值再做平均(这样做的目的是尽量减少误差) ,并赋值给 tpad_default_val,用于后续触摸判断的标准最后,我们来看看 TPAD_Scan 函数,该函数用于扫描 TPAD 是否有触摸,该函数的参数 mode,用于设置是否支持连续触发返回值如果是 0,说明没有触摸,如果是 1,则说明有触摸。
该函数同样包含了一个静态变量,用于检测控制,类似第八章的 KEY_Scan 函数所以该函数同样是不可重入的在函数中,我们通过连续读取 3 次(不支持连续按的时候)TPAD 的值,取这他们的最大值,和 tpad_default_val+TPAD_GATE_VAL 比较,如果大于则说明有触摸,如果小于,则说明无触摸其中 tpad_default_val 是我们在调用 TPAD_Init 函数的时候得到的值,而TPAD_GATE_VAL 则是我们设定的一个门限值(这个大家可以通过实验数据得出,根据实际情况选择适合的值就好了) ,这里我们设置为 80该函数,我们还做了一些其他的条件限制,让触摸按键有更好的效果,这个就请大家看代码自行参悟了我们将 tpad.c 文件保存,然后加入到 HARDWARE 组下接下来,在 tpad.h 文件里,我们输入如下代码:#ifndef __TPAD_H#define __TPAD_H#include "。












