文章内容来自百问网
目录
1. 电阻屏和电容屏
1.1 电阻屏原理
电阻屏就是基于欧姆定律制作的,它有上下两层薄膜,这两层薄膜就是两个 电阻,如下图所示:
平时上下两层薄膜无触触,当点击触摸屏时,上下两层薄膜接触:这时就可 以测量触点电压。过程如下:
测量X坐标:
在xp、xm两端施加3.3V电压,yp和ym不施加电压(yp就相当于探针), 测量yp电压值。该电压值就跟X坐标成正比关系,假设:X = 3.3*Vyp/Xmax
测量Y坐标:
在yp、ym两端施加3.3V电压,xp和xm不施加电压(xp就相当于探针), 测量xp电压值。该电压值就跟Y坐标成正比关系,假设:Y = 3.3*Vxp/Ymax
在实际使用时,电阻屏的 Xmax、Ymax 无从得知,所以使用之前要先较准: 依次点击触摸屏的四个角和中心点,推算出X、Y坐标的公式:X = func(Vyp) Y = func(Vxp)
1.2 电阻屏数据
Linux 驱动程序中,会上报触点的X、Y数据,注意:这不是LCD的坐标值, 需要APP再次处理才能转换为LCD坐标值。
对应的input_event结构体中,“type、code、value”如下:
1.3 电容屏原理
电容屏中有一个控制芯片,它会周期性产生驱动信号,接收电极接收到信号, 并可测量电荷大小。当电容屏被按下时,相当于引入了新的电容,从而影响了接 收电极接收到的电荷大小。主控芯片根据电荷大小即可计算出触点位置。
我们只需要编写程序,通过I2C读取芯片寄存器即可得到这些数据。
1.4 电容屏数据
触摸屏能分辨是哪一个触点,上报数据时会先上报触点ID,再上报它的数据。
2. tslib
2.1 简介
tslib 是一个触摸屏的开源库,可以使用它来访问触摸屏设备,可以给输入设备添加各种“filter”(过滤器,就是各种处理),地址是: tslib。
编译tslib 后,可以得到libts 库,还可以得到各种工具:较准工具、测试工具。
核心在于“plugins”目录里的“插件”,或称为“module”。这个目录下的每个文件都是一个module,每个module都提供2个函数:read、read_mt,前者用于读取单点触摸屏的数据,后者用于读取多点触摸屏的数据。
分析tslib的框架:
调用ts_open后,可以打开某个设备节点,构造出一个tsdev结构体。然后调用ts_config读取配置文件的处理,假设/etc/ts.conf内容如下:
module_raw input
module pthres pmin=1
module dejitter delta=100
module linear
每行表示一个“module”或“moduel_raw”。
对于所有的“module”,都会插入tsdev.list链表头,也就是tsdev.list 执行配置文件中最后一个“module”,配置文件中第一个“module”位于链表的尾部。
对于所有的“module_raw”,都会插入tsdev.list_raw链表头,一般只有 一个“module_raw”
因为是递归调用,所有最先使用input模块读取设备节点得到原始数据,再依次经过pthres模块、dejitter模块、linear模块处理后,才返回最终数据。
2.2 相关库函数
2.2.1 打开触摸屏设备
-
struct tsdev *ts_open(const char *dev_name, int nonblock);
-
const char *dev_name:指定了触摸屏的设备节点
-
int nonblock:以什么方式打开设备节点 阻塞0或非阻塞1
-
返回值:成功返回struct tsdev *指针指向触摸屏设备句柄,失败返回NULL
-
-
struct tsdev *ts_setup(const char *dev_name, int nonblock);
-
const char *dev_name:指定了触摸屏的设备节点,其意义与ts_open相同,但该值可以填NULL,当dev_name设置为NULL时,ts_setup() 函数内部会读取 TSLIB_TSDEVICE 环境变量,获取该环境变量的内容以得知触摸屏的设备节点
-
int nonblock:以什么方式打开设备节点 阻塞0或非阻塞1
-
返回值:成功返回struct tsdev *指针指向触摸屏设备句柄,失败返回NULL
-
2.2.2 关闭触摸屏设备
-
int ts_config(struct tsdev *ts);
-
struct tsdev *ts:指向触摸屏句柄
-
返回值:成功返回0,失败返回-1
-
2.2.3 读取触摸屏数据
2.2.3.1 单点触摸
-
int ts_read(struct tsdev *ts, struct ts_sample *samp, int nr);
-
struct tsdev *ts:指向触摸屏句柄
-
struct ts_sample *samp:struct ts_sample * 类型的指针,指向一个 struct ts_sample 对象, struct ts_sample 数据结构描述了触摸点的信息
-
int nr:对一个触摸点的采样数,设置为1
-
返回值:成功返回 0 ,失败返回 -1
-
/* 结构体参数的解释 */ struct ts_sample { int x; //X 坐标 int y; //Y 坐标 unsigned int pressure; //按压力大小 struct timeval tv; //时间 };
-
2.2.3.2 多点触摸
-
int ts_read_mt(struct tsdev *ts, struct ts_sample_mt **samp, int max_slots, int nr);
-
struct tsdev *ts:指向触摸屏句柄
-
struct ts_sample_mt **samp:二重指针,多点触摸应用程序,每一个触摸点的信息使用 struct ts_sample_mt 数据结构来描述;一个触摸点的数据使用一个 struct ts_sample_mt 对象来装载,将它们组织成一个 struct ts_sample_mt 数组,调用 ts_read_mt() 时,将数组地址赋值给 samp 参数。
-
int max_slots:触摸屏支持的最大触摸点数
-
int nr:对一个触摸点的采样数,设置为1
-
返回值:成功返回 0 ,失败返回 -1
-
/* 结构体参数的解释 */ struct ts_sample_mt { /* ABS_MT_* event codes. linux/include/uapi/linux/input-event-codes.h * has the definitions. */ int x; //X 坐标 int y; //Y 坐标 unsigned int pressure; //按压力大小 int slot; //触摸点 slot int tracking_id; //ID int tool_type; int tool_x; int tool_y; unsigned int touch_major; unsigned int width_major; unsigned int touch_minor; unsigned int width_minor; int orientation; int distance; int blob_id; struct timeval tv; //时间 /* BTN_TOUCH state */ short pen_down; //BTN_TOUCH 的状态 /* valid is set != 0 if this sample * contains new data; see below for the * bits that get set. * valid is set to 0 otherwise */ short valid; //此次样本是否有效标志 触摸点数据是否发生更新 };
-
2.3 示例代码
// 实现一个程序,不断打印2个触点的距离。
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <getopt.h>
#include <linux/input.h>
#include <sys/ioctl.h>
#include <tslib.h>
int distance(struct ts_sample_mt *point1, struct ts_sample_mt *point2)
{
int x = point1->x - point2->x;
int y = point1->y - point2->y;
return x*x + y*y;
}
int main(int argc, char **argv)
{
struct tsdev *ts;
int i;
int ret;
struct ts_sample_mt **samp_mt;
struct ts_sample_mt **pre_samp_mt;
int max_slots;
int point_pressed[20];
struct input_absinfo slot;
int touch_cnt = 0;
ts = ts_setup(NULL, 0);
if (!ts)
{
printf("ts_setup err\n");
return -1;
}
if (ioctl(ts_fd(ts), EVIOCGABS(ABS_MT_SLOT), &slot) < 0) {
perror("ioctl EVIOGABS");
ts_close(ts);
return errno;
}
max_slots = slot.maximum + 1 - slot.minimum;
samp_mt = malloc(sizeof(struct ts_sample_mt *));
if (!samp_mt) {
ts_close(ts);
return -ENOMEM;
}
samp_mt[0] = calloc(max_slots, sizeof(struct ts_sample_mt));
if (!samp_mt[0]) {
free(samp_mt);
ts_close(ts);
return -ENOMEM;
}
pre_samp_mt = malloc(sizeof(struct ts_sample_mt *));
if (!pre_samp_mt) {
ts_close(ts);
return -ENOMEM;
}
pre_samp_mt[0] = calloc(max_slots, sizeof(struct ts_sample_mt));
if (!pre_samp_mt[0]) {
free(pre_samp_mt);
ts_close(ts);
return -ENOMEM;
}
for ( i = 0; i < max_slots; i++)
pre_samp_mt[0][i].valid = 0;
while (1)
{
ret = ts_read_mt(ts, samp_mt, max_slots, 1);
if (ret < 0) {
printf("ts_read_mt err\n");
ts_close(ts);
return -1;
}
for (i = 0; i < max_slots; i++)
{
if (samp_mt[0][i].valid)
{
memcpy(&pre_samp_mt[0][i], &samp_mt[0][i], sizeof(struct ts_sample_mt));
}
}
touch_cnt = 0;
for (i = 0; i < max_slots; i++)
{
if (pre_samp_mt[0][i].valid && pre_samp_mt[0][i].tracking_id != -1)
point_pressed[touch_cnt++] = i;
}
if (touch_cnt == 2)
{
printf("distance: %08d\n", distance(&pre_samp_mt[0][point_pressed[0]], &pre_samp_mt[0][point_pressed[1]]));
}
}
return 0;
}