四线电阻式触摸屏驱动的优化

     
触摸屏在电子产品中用得越来越多,其技术也在不断发展。目前常见的有电阻式、电容式、红外式和表面声波式等几大类,其中电阻式最为普遍。最近在WinCE下调试了一款四线电阻式的触摸屏驱动,利用检测触摸压力的方法实现了动态调整触摸屏的灵敏度。

本节的触摸屏驱动也是使用之前的输入子系统

     
一般的嵌入式处理器中会有几个通道的AD,通常有四个通道用于连接触摸屏的XP、XM、YP和YM。如果MCU
没有Touch Screen
Interface,可以选择如TSC2003一类的触摸屏控制器芯片。MCU可通过IIC总线与其通讯,以得到相应的触摸屏AD采样值。目前正在调试的TCC8900芯片内部集成了触摸屏控制器,原厂的BSP中也提供了相应的驱动,实际测试时发现,该驱动在4.3寸屏上工作得挺好,但在某些7寸屏上经常会出现跳笔,尤其是在开始按下和最后抬起时,跳笔非常严重。在快速手写时也有跳笔的情况,并且导致笔迹非常不圆滑。在触摸驱动中使用多次采样、去头掐尾求平均等简单滤波算法,问题仍然存在。经分析,问题的根源在于轻点触摸屏时采样值严重不准,所以即使采用滤波算法也无济于事了。解决问题要从根本出发,在上报数据时须严进宽出,压力较小的采样直接PASS,这样可以很好的去除一些抖动和跳笔。


     
参考TSC2003获取触摸压力的方法修改触摸驱动,单独获取XP、YP等值,通过计算得到按下触摸屏时的电阻值。该值与点击触摸屏的位置无关,只与点击触摸屏压力大小有关,压力越大,该值越小。在实际使用时规定一个参考值,当该值小于该参考值时才认为是可靠按下,将采样得到的坐标值上报,否则直接扔掉。由于触摸屏硬件的差别,不同触摸屏的灵敏度可能不一样,可以通过应用程序修改驱动中的参考值,从而实现动态调整触摸屏灵敏度。修改后实际测试发现,效果比原来要好一点。

 

      按下四线电阻式触摸屏,采样时的等效电路图如下所示。

 

威尼斯官方网站登录 1

1.先来回忆之前第12节分析的输入子系统

XPOS=V*R2/(R1+R2) (式1)

其中输入子系统层次如下图所示,

Z1POS=V*R2/(R3+Rt+R2) (式2)

 威尼斯官方网站登录 2

Z2POS=V*(Rt+R2)/(R3+Rt+R2) (式3)

其中事件处理层的函数都是通过input_register_handler()函数注册到input_handler_list链表中

由式2和3可得,Rt=(Z2/Z1-1)*R2 (式4)

搜索input_register_handler注册函数,就可以看到都是事件处理层里的函数:

由式1可得R2=XPOS*(R1+R2)/V,即R2=XPOS*(RXplate)/V (式5)

所以最终如下图所示:

将式5和式4可得,

 威尼斯官方网站登录 3

威尼斯官方网站登录 4

 

     
对于同一触摸屏来说,Rx-plate是固定的,因为使用的是12bit的AD,故除以4096。对于触摸屏压力检测来说,式6即能说明当前压力大小关系。

 

Ft=XPOS*Z2POS/Z1POS-XPOS (式6)

右边的驱动事件处理,内核是已经写好了的,所以我们的触摸屏只需要写具体的驱动设备,然后内核会与触摸屏驱动tsdev.c自动连接    

     
Ft的绝对值越小,说明按下越可靠,采样值有效。反之,可以认为是轻按,采样值无效。

2.本节需要用到的结构体成员如下:

struct input_dev {     
       void *private;
       const char *name;  //设备名字
       const char *phys;  //文件路径,比如 input/buttons
       const char *uniq;  
       struct input_id id;

       unsigned long evbit[NBITS(EV_MAX)];  //表示支持哪类事件,常用有以下几种事件(可以多选)
       //EV_SYN      同步事件,当使用input_event()函数后,就要使用这个上报个同步事件
       //EV_KEY       键盘事件
       //EV_REL       (relative)相对坐标事件,比如鼠标
       //EV_ABS       (absolute)绝对坐标事件,比如摇杆、触摸屏感应
       //EV_MSC      其他事件,功能
       //EV_LED       LED灯事件
       //EV_SND      (sound)声音事件
       //EV_REP       重复键盘按键事件
       //(内部会定义一个定时器,若有键盘按键事件一直按下/松开,就重复定时,时间一到就上报事件)  

       //EV_FF         受力事件
       //EV_PWR      电源事件
       //EV_FF_STATUS  受力状态事件

       unsigned long keybit[NBITS(KEY_MAX)];   //存放支持的键盘按键值
       //键盘变量定义在:include/linux/input.h, 比如: KEY_L(按键L)、BTN_TOUCH(触摸屏的按键)

       unsigned long relbit[NBITS(REL_MAX)];    //存放支持的相对坐标值
       unsigned long absbit[NBITS(ABS_MAX)];   //存放支持的绝对坐标值,存放下面4个absxxx[]
       unsigned long mscbit[NBITS(MSC_MAX)];   //存放支持的其它事件,也就是功能
       unsigned long ledbit[NBITS(LED_MAX)];    //存放支持的各种状态LED
       unsigned long sndbit[NBITS(SND_MAX)];    //存放支持的各种声音
       unsigned long ffbit[NBITS(FF_MAX)];       //存放支持的受力设备
       unsigned long swbit[NBITS(SW_MAX)];     //存放支持的开关功能
         ... ...


/*以下4个数组都会保存在上面成员absbit[]里,数组号为:ABS_xx ,位于include/linux/input.h */
/*比如数组0,标志就是ABS_X,以下4个的absXXX[0]就是表示绝对位移X方向的最大值、最小值... */
/*对于触摸屏常用的标志有:
ABS_X(X坐标方向), ABS_Y(Y坐标方向), ABS_PRESSURE(压力方向,比如绘图,越用力线就越粗)* / 
       int absmax[ABS_MAX + 1];      //绝对坐标的最大值
       int absmin[ABS_MAX + 1];      //绝对坐标的最小值
       int absfuzz[ABS_MAX + 1];     //绝对坐标的干扰值,默认为0,
       int absflat[ABS_MAX + 1];     //绝对坐标的平焊位置,默认为0
... ...

 

3.本节需要用到的函数:

struct input_dev *input_allocate_device(void);  //向内存中分配input_dev结构体

input_free_device(struct input_dev *dev);   //释放内存中的input_dev结构体

input_register_device(struct input_dev *dev);   //注册一个input_dev,若有对应的驱动事件,
则在/sys/class/input下创建这个类设备

input_unregister_device(struct input_dev *dev);   //卸载/sys/class/input目录下的
input_dev这个类设备


set_bit(nr,p);                  //设置某个结构体成员p里面的某位等于nr,支持这个功能
/* 比如:
set_bit(EV_KEY,buttons_dev->evbit);   //设置input_dev结构体buttons_dev->evbit支持EV_KEY
set_bit(KEY_S,buttons_dev->keybit);  //设置input_dev结构体buttons_dev->keybit支持按键”S”

*/

input_set_abs_params(struct input_dev *dev, int axis, int min, int max, int fuzz, int flat); 
//设置绝对位移的支持参数
//dev: 需要设置的input_dev结构体
//axis : 需要设置的数组号,常用的有: ABS_X(X坐标方向), ABS_Y(Y坐标方向), ABS_PRESSURE(压力方向)//min: axis方向的最小值, max:axis方向的最大值, fuzz: axis方向的干扰值, flat:axis方向的平焊位置


input_report_abs(struct input_dev *dev, unsigned int code, int value);   
//上报EV_ABS事件
//该函数实际就是调用的input_event(dev, EV_ABS, code, value);
//*dev :要上报哪个input_dev驱动设备的事件
// code: EV_ABS事件里支持的哪个方向,比如X坐标方向则填入: ABS_X
//value:对应的方向的值,比如X坐标126

input_report_key(struct input_dev *dev, unsigned int code, int value);  
//上报EV_KEY事件 

input_sync(struct input_dev *dev); //同步事件通知,通知系统有事件上报

struct  clk *clk_get(struct device *dev, const char *id);    
//获得*id模块的时钟,返回一个clk结构体
//*dev:填0即可,     *id:模块名字, 比如"adc","i2c"等,名字定义在clock.c中

clk_enable(struct clk *clk);   
//开启clk_get()到的模块时钟,就是使能CLKCON寄存器的某个模块的位

4.电阻式触摸屏介绍:

如下图所示,2440开发板使用的是4线触摸屏,该4线连接在2440的AIN4~AIN7引脚上,该引脚专门是用来接收模拟输入信号.

 威尼斯官方网站登录 5

引脚说明:

YM: (Y
Minus)触摸屏的Y坐标的负线,也可以用Y -表示

YP : (Y Power)触摸屏的Y坐标的正线,
也可以用Y+表示

XM: (Y Minus)触摸屏的Y坐标的负线,
也可以用X-表示

XP : (Y Power)触摸屏的Y坐标的正线,
也可以用X+表示

4.1
 4线触摸屏包含了两个阻性层,如下图所示:

 威尼斯官方网站登录 6

 

当没有触摸按下时,X层和Y层是分离的,此时就测不到电压

4.2 测X坐标方向时:

如下图,  把XP接3.3V , XM接0V,
YP和YM悬空,我们以按压X坐标的中间位置,
X层和Y层便闭合了,此时YP就会输出当前X坐标值的1.66V给CPU 

 威尼斯官方网站登录 7

4.3 测Y坐标方向时:

如下图, 把YP接3.3V , YM接0V,
XP和XM悬空,我们以按压X坐标的中间位置,
X层和Y层便闭合了,此时XP就会输出当前X坐标值的1.66V给CPU 

 威尼斯官方网站登录 8

 

5.接下来开始看2440手册

如下图,2440的ADC分辨率为10位(0~0X3FFF)

 威尼斯官方网站登录 9

如下图,若工作在普通ADC模式,则通过寄存器ADCCON->SEL_MUX来选择转换哪个引脚的模拟信号

当设置为ADC等待中断模式时,测到有屏幕笔尖触摸,就会产生INT_TC中断

其中ADC的工作频率最大为2.5MHZ,需要设置寄存器ADCCON->PRSCVL更改分频系数

 威尼斯官方网站登录 10

威尼斯官方网站登录 ,5.1
获取笔尖触摸按下/松开使用的是ADC等待中断模式:

当笔尖落下时触摸屏控制器产生中断(INT_TC)信号。需要设置寄存器ADCTSC=0xd3/0x1d3 

设置寄存器ADCTSC=0x0d3/0x1d3 (X 1101
0011)时(如下图):

威尼斯官方网站登录 11

开启 YM开关,使能XP上拉,
开启等待中断模式

当有笔尖按下时,X层和Y层闭合,然后会拉低XP和XM电平,输出低电平

设置为0x0d3是检测触摸低电平,
设置为0x1d3是检测触摸上拉电平

(PS:
 ADCDAT0的bit15位用来标志笔尖是按下还是松开)

 

5.2
获取XY坐标时使用的是自动 X/Y 方向转换模式

当ADC转换成功,  X 坐标值到 ADCDAT0 和 Y
坐标值到ADCDAT1 后,就会产生INT_ADC中断

自动获取XY坐标时(如下图):

威尼斯官方网站登录 12

设置寄存器ADCTSC=0X0C
(关闭XP上拉、启动自动XY方向转换)

设置寄存器ADCCON的位[0]=1(开启一次ADC转换,当ADC转换成功该位清0)

 

6.编写代码

步骤如下:

6.1
在init入口函数中:

1)分配一个input_dev结构体

2)设置input_dev的成员

  ->
2.1)设置input_dev->evbit支持按键事件,绝对位移事件

      (触摸屏:通过按键BTN_TOUCH获取按下/松开,通过绝对位移获取坐标)

  -> 2.2)设置input_dev->
keybit支持BTN_TOUCH触摸屏笔尖按下

  -> 2.3)设置input_dev-> absbit
支持ABS_X、ABS_Y、 ABS_PRESSURE

      
  input_set_abs_params(ts.dev, ABS_X, 0, 0x3FF, 0, 0);  

发表评论

电子邮件地址不会被公开。 必填项已用*标注

相关文章