触摸屏校准分析
----------Vector(2013-05-14) 1.基础知识
我们传统的鼠标是一种相对定位系统,只和前一次鼠标的位置坐标有关。
而触摸屏则是一种绝对坐标系统,要选哪就直接
点哪,与相对定位系统有着本质的区别。
绝对坐标系统的特点是每一次定位坐标与上一次定位坐标没有关系,每次触摸的数据通过校准转为屏幕上的坐标,不管在什么情况下,触摸屏这套坐标在同一点的输出数据是稳定的。
不过由于技术原理的原因,并不能保证同一点触摸每一次采样数据相同,不能保证绝对坐标定位,点不准,这就是触摸屏最怕出现的问题:漂移。
对于性能质量好的触摸屏来说,漂移的情况出现并不是很严重。
所以很多应用触摸屏的系统启动后,进入应用程序前,先要执行校准程序。
通常应用程序中使用的LCD坐标是以像素为单位的。
比如说:左上角的坐标是一组非0的数值,比如(20,20),而右下角的坐标为(620,460)。
这些点的坐标都是以像素为单位的,而从触摸屏中读出的是点的物理坐标,其坐标轴的方向、XY值的比例因子、
偏移量、缩放因子都与LCD坐标不同,图是LCD坐标和触摸屏的物理坐标的比较。
(友善之臂mini2440开发板采用这种对应关系)
2.触摸屏校准原理
以上说了触摸屏需要校准的原因,问题出在,物理坐标和屏幕坐标并不匹配,不匹配有两个方面:第一,物理坐标的1个单位和屏幕坐标的1个单位并不相等,我们知道屏幕坐标1个单位一般是一个像素,而物理坐标的1个单位并不是1个像素.第二,假设我们把屏幕的左上角定义为(0,0),那么触摸屏的左上角的物理坐标并不是(0,0)(我们点击之后的物理采样数据)。
LCD 坐标和触摸屏坐标对应关系如下:
Vx = xFactor*Px + xOffset //Vx:LCD 像素坐标,Px: 触摸屏物理坐标
Vy = yFactor*Py + yOffset //同上
综上,校准有两个方面:第一,物理采样坐标与屏幕像素坐标的对应关系,也就是伸缩系数,
即单位物理采样数据代表几个单位屏幕像素数据,x坐标和y坐标各有一个伸缩系数,分别记作:xScale和yScale。
计算方法很简单,为了精确,可以采样屏幕上的四个点,让用户点击,比如(20,20),(20,200),(300, 200),(300,20),通过横着的线段除以物理采样的数据线段,得到了x的伸缩系数。
同理可以得到y的伸缩系数。
第二,物理坐标的相对于屏幕像素坐标的偏移,假如我们不计算偏移,只计算伸缩系数的话,假设用户在屏幕点(20,20)点击,我们经过转换物理采样数据,即乘上伸缩系数,发现,校准后的数据并不是(20,20)点,原因就是因为有偏移,原因是触摸屏的物理采样数据,在左上角并不是(0,0),而是某个正数对,采样到的数据不会是0的,这就是偏移产生的原因,所以,在计算过伸缩系数之后,比如点击屏幕(20,20),采样到的数据是(45,78),而第一步计算出的伸缩系数分别是0.78和0.67,那么物理坐标转换成屏幕坐标后是
(45*0.78,78*0.67),此时虽然我们得到了物理坐标对应的屏幕坐标,但是现在屏幕坐标和我们(20,20)所在的屏幕坐标并不在一个坐标系,即(0,0)点不同,所以我们要减去一个坐标系偏移,假设分别是xOffset和yOffset,那么两个坐标做差便得到了xOffset和yOffset。
根据上面的四个参数,我们来举个例子,假如屏幕坐标左上角为(0,0),当我们点击屏幕,此时我们从驱动那里得到物理x和y数据,分别乘上xScale和yScale 得到相对屏幕坐标,加上(平移)xOffset和yOffset,得到了当前的屏幕坐标。
3.示例代码:
int pointBas[4][2] = //预先在屏上绘制出的四个十字标记
{
20, 20, //A
20, 300, //B
219, 300,//C
219, 20, //D
};
int pointGet[4][2] =
{
40, 274,
40, 60,
191, 60,
191, 274, //实际点按触摸屏得到的数值
};
STATUS PenCalibratePoint(void)
{
float tmpBas = 0.0;
float tmpGet = 0.0;
//xScale
tmpBas = pointBas[3][0] - pointBas[0][0];
//printf("tmpBas:%f\n",tmpBas);
tmpGet = pointGet[3][0] - pointGet[0][0];
//printf("tmpGet:%f\n",tmpGet);
_gPenConfig.xFactor = tmpBas/tmpGet;
printf("xFactor:%f\n",_gPenConfig.xFactor);
//yScale
tmpBas = pointBas[1][1] - pointBas[0][1];
tmpGet = pointGet[1][1] - pointGet[0][1];
_gPenConfig.yFactor = tmpBas/tmpGet;
printf("yFactor:%f\n",_gPenConfig.yFactor);
//xOffset
tmpBas = pointBas[3][0]-pointGet[3][0]*_gPenConfig.xFactor;
_gPenConfig.xOffset = tmpBas;
printf("xOffset:%f\n",_gPenConfig.xOffset);
//yOffset
tmpBas = pointBas[3][1]-pointGet[3][1]*_gPenConfig.yFactor;
_gPenConfig.yOffset = tmpBas;
printf("yOffset:%f\n",_gPenConfig.yOffset);
return 0;
}
U16 PenMapX(U16 x)
{
float tmp;
tmp=x*_gPenConfig.xFactor+_gPenConfig.xOffset;
return (U16)tmp;
}
U16 PenMapY(U16 y)
{
float tmp;
tmp=y*_gPenConfig.yFactor+_gPenConfig.yOffset;
return (U16)tmp;
}。