使用硬件触摸感应接口之前,我们先看看软件通过GPIO实现触摸的方法:
如上图,GPIO接个上接电阻(可用内部的或外部的),PCB上画个触摸盘即可。触摸盘等效于一个对地的电容,手指也等效于一个对地的电容,手指按上时相当于2电容并联,不按时只有一个电容。程序先向IO口写0对电容放电,之后变为输入检测该IO口电平,卡拉电阻对电容充电,当充到阀值(一般为0.7VDD)时程序读到IO口状态为1。
从上图可以看出手指按上时电容变大,充电时间变长(图中的t2),不按时的时间短(图中的t1),程序根据此时间的长短判断是否有键按下。
上述方法有2点局限:
1、因元器件参数的离散性及环境因素多变,该方式有时会出现判断错误的情况。2009年笔者在大中电器买的格兰仕电磁炉在农村的一个房子里曾按键不灵,很可能就是用这种方式实现的触摸按键。
2、因是查询方式,程序必须不断查询触摸情况,不能进入低功耗模式。
为方便使用,kinetis内置触摸感应接口TSI,可以在主振荡器停振的时候继续工作。其框图如下:
因是硬件的TSI,对电容的充放电是由电流源来完成的,充放电是三角波而不是RC充放电式的指数波。如下图:
TSI有2路上述振荡器,一路是基于内部电容的(下图蓝线),其周期固定;一路是基于外部触摸盘电容的(下图黑线),其周期随是否有手指触摸变化。系统就是根据固定个数黑线周期有多少个蓝线周期的计数来识别触摸情况的。
下面看下几个寄存器:
TSIx_GENCS-通用控制和状态寄存器,各位含义如下:
TSIx_SCANC-扫描控制寄存器,各位含义如下:
TSIx_PEN-引脚使能寄存器,第19~16位选择低功耗模式下扫描的引脚,第15~0位控制相应通道的使能。
TSIx_WUCNTR-唤醒通道计数寄存器。
TSIx_CNTRn-通道n计数寄存器,高16位是通道n计数值,低16位是通道n-1计数值,n=1,3,5……15。
TSIx_THRESHOLD-通道n 阈值寄存器,高16位是高阀值,低16位是低阀值。当扫描得到的相应通道的计数值>高阀值或<低阀值时,就是超出范围,如果使能了超出范围中断,将产生TSI中断。(悲剧的是V2版的参考手册取消了STATUS寄存器,进中断后没有相应的标识位来判断是哪个脚产生的)
下面例程是用TSI0_CH0和TSI0_CH13做触摸按键,在扫描完成中断服务程序中读相应的计数寄存器,来判断哪个键被按下。下面是完整代码:
/*
* main implementation: use this 'C' sample to create your own application
*
*/
#include <stdio.h>
#include "derivative.h" /* include peripheral declarations */
void InitTSI()
{
SIM_SCGC5 |= SIM_SCGC5_PORTB_MASK | SIM_SCGC5_PORTC_MASK;//打开PORTB、C时钟
PORTB_PCR0 = 0;//PTB0用作TSI
PORTC_PCR0 = 0;//PTC0用作TSI
SIM_SCGC5 |= (SIM_SCGC5_TSI_MASK);//打开TSI模块时钟
//设定TSI的工作参数,使能TSI中断,软件触发扫描
TSI0_GENCS |= ((TSI_GENCS_NSCN(10)) //对每个TSI电极扫描次数的设定,此处设为10次
|(TSI_GENCS_PS(3))) //对扫描频率的预分频设定,此处设为2^3
|(TSI_GENCS_TSIIE_MASK) //使能TSI中断
|(TSI_GENCS_ESOR_MASK)//扫描结束中断
|uq(TSI_GENCS_STM_MASK);
TSI0_SCANC |= ((TSI_SCANC_EXTCHRG(3)) //外部振荡器充电电流选择设定,此处设为4uA
|(TSI_SCANC_REFCHRG(31)) //参考时钟充电电路选择设定,此处设为32uA
|(TSI_SCANC_DELVOL(7)) //增量电压选择设定,此处设为600mV
|(TSI_SCANC_SMOD(0)) //设定扫描模数,此处设定为连续扫描
|(TSI_SCANC_AMPSC(0))); //激活模式预分频,此处设定值为1,即不分频
//引脚功能使能
TSI0_PEN |= (1<<13) | (1<<0);//通道0和13使能
//TSI功能使能
TSI0_GENCS |= (TSI_GENCS_TSIEN_MASK);
NVICISER2 |= 1<<19;//使能NVIC的TSI对应中断
nt main(void)
{
int counter = 0;
InitTSI();
printf("Hello (Kinetis) World in 'C' from MK60DX256Z derivative! \n\r");
for(;;) {
counter++;
}
return 0;
}
void TSI_ISR()
{
unsigned int key1,key2;
//TSI0_GENCS |= TSI_GENCS_OUTRGF_MASK;//清超出范围中断标识位
TSI0_GENCS |= TSI_GENCS_EOSF_MASK;//清扫描完成中断标识位
key1 = TSI0_CNTR1&0xFFFF;
key2 = TSI0_CNTR13>>16;
}
运行上面程序,无按键按下时,key1和key2在4000左右,如下图:
某个key按下时,其值在8000多,如下图:
我们选4000~8000之间的某值(如6000)作为阀值,认为大于阀值时有键按下。