基于嵌入式Linux和MiniGUI的通用触摸屏校准程序
本文介绍的正是笔者在制作实际的嵌入式Linux数控机床人机接口过程中,提出的一套基于嵌入式Linux和MiniGUI的通用触摸屏校准程序设计方案。
笔者基于的ARM9内核,使用,640×480的触摸屏,嵌入式Linux内核
2.4.20和MiniGUI1.3.0,Lite版本,设计了一套简单可行的方案,可以方便地实现触摸屏的校准。在开始校正触摸屏的坐标前,首先要修改
MiniGUI.cfg文件使其适应触摸屏驱动,该文件一般保存在开发板的/usr/local目录下。所做修改如表所示。
另外,在开发板的/dev/的目录下建立连接ln-s /dev/touchscreen/Oraw ts 。
配置文件修改的主要目的是把IAL(Input Abstract Layer,输入抽象层)改为SMDK2410,输入设备改为/dev/ts,鼠标类型IMPS2取消掉,使其适应触摸屏驱动。
通常应用程序中使用的LCD坐标是以像素为单位的。比如说:左上角的坐标是一组非0的数值,比如(20,20),而右下角的坐标为(620,
460)。这些点的坐标都是以像素为单位的,而从触摸屏中读出的是点的物理坐标,其坐标轴的方向、XY值的比例因子、偏移量、缩放因子都与LCD坐标不
同,所以,可以在IAL的某个函数(比如wait_event函数)中把物理坐标首先转换为像素坐标,然后再赋给POS结构,达到坐标转换的目的。图是
LCD坐标和触摸屏的物理坐标的比较。
在IAL的某个函数(比如wait_event函数)中加入调试信息,开发板上运行Calibrate程序,那么触摸屏上任何一点的坐标就可以在主
机监视屏上回显出来。于是,就采集到了4个角的物理坐标,假设是屏,640X480分辨率,则它们的像素坐标分别是(20,20)、(20,460)、
(620,460)和(620,20)。这样,使用待定系数法就可以算出坐标系之间的平移关系。比如:
Vx = xFactor*Px + xOffset
Vy = yFactor*Py + yOffset
在笔者使用的开发板上,系数xFactor、yFactor、xOffset、yOffset的值分别为0.211、-16.27、-19/116、625.23。那么,在IAL的特定函数中就可以按照这个变换关系把物理坐标转换为像素坐标赋给POS结构了。
因此,应用程序中首先弹出一个有若干点的界面,然后让用户去点,参照了Qt-embedded的对标程序,一般采用了触摸屏四个角的四个点。根据像素坐标和物理坐标计算参数,并保存到一个文件中。那么以后只要这个文件的内容有效则不必再经历屏幕校准的过程。
另外需要提醒的是,还要参照一下触摸屏驱动的读方法,确定从触摸屏读出的数据的组织格式。比如笔者使用的的驱动的读方法就是返回8个字节表示一点的坐标,所以在IAL的特定函数中首先要拼接才能得到点的物理坐标。
通过直接给屏幕划两个短线交叉的方法来实现。下面的代码表示,在(20,20)点画一个十字光标。
DrawLine (15, 20, 26, 20, 0xf800);
DrawLine (20, 15, 20, 26, 0xf800);
do {
// Calibrate Point 1 (20,20)
DrawLine (15, 20, 26, 20, 0xf800);
DrawLine (20, 15, 20, 26, 0xf800);
do
GetTouchvalue (tfd, &point[0].x, &point[0].y);
while (!(point[0].x > X1_SCOPE_MIN && point0].x <
X1_SCOPE_MAX && point[0].y > Y1_SCOPE_MIN &&
point[0].y
...
//上面是第一个定位点处理的方法,因为有四个点,其他的也和此一样。只不过定位点和判断范围不同罢了。
} while(CheckCalibratePont());
typedef struct
{
}PEN_CONFIG, *P_PEN_CONFIG;
在程序中通过计算获得此结构体,这些数据是非常重要的,它提供给IAL使用。以下是保存这个结构体的部分源码:
rt.left=(point[0].x + point[1].x)/2;
rt.top=(point[0].y + point[3].y)/2;
rt.right=(point[2].x + point[3].x)/2;
rt.bottom=(point[2].y + point[1].y)/2;
st.top=20;
st.left=20;
st.right=620;
st.bottom=460;
_PenCalibratePoint(&st,&rt);
// Open the file for writing config file
wfd = open("/var/pencfg", O_WRONLY);
if (wfd < 0) {
printf("Error: cannot open pencfg file./n");
exit(1);}
printf("The pencfg file was opened successfully./n");
if(write(wfd, &_gPenConfig, sizeof(_gPenConfig)) == sizeof(_gPenConfig)){
printf("Write Victor /n");}
close(wfd);
void GetTouchValue(int fp, int *x, int *y)
{ ts_event_t ts;
while (1) {
if(read(fp, &ts, sizeof(ts_event_t)) == sizeof(ts_event_t)){
if (ts.pressure == 0 ) break;
*x = ts.x;
*y = ABSY-ts.y;
}
}
printf (" x= %d, y= %d /n", *x, *y);//在屏幕上输出触摸屏坐标
printf ("_gPenConfig.xFactor = %x _gPenConfig.yFactor = %x /n",_gPenConfig.xFactor, _gPenConfig.yFactor);
printf ("_gPenConfig.xOffset = %x _gPenConfig.yOffset = %x /n",_gPenConfig.xOffset, _gPenConfig.yOffset);
printf ("_gPenConfig.scale = %x/n",_gPenConfig.scale);
其原理很简单,上面的程序已经把PEN_CONFIG保存到/var/pencfg文件中,只需在IAL中写上打开该文件的代码,并且从中读取数据就可以了,其源码如下,在Init2410Input函数中。
int rcfg;
rcfg = open ("/var/pencfg", O_RDONLY);
if (rcfg < 0) {
printf ("Open < /var/pencfg> File Error/n");
}
if(read(rcfg, &_gPenConfig, sizeof(_gPenConfig)) == sizeof(_gPenConfig)){
printf("Read Victor /n");
}
close(rcfg);
#define X1_SCOPE_MIN 45 //MIN和MAX的差值就是校准的精度
#define X1_SCOPE_MAX 75
#define X2_SCOPE_MIN 45
#define X2_SCOPE_MAX 75
#define X3_SCOPE_MIN 940
#define X3_SCOPE_MAX 970
启动应用程序前先运行“触摸屏校准程序”,再运行MiniGUI程序。这样使得运行应用程序前,IAL可以预先提取到“触摸屏校准程序”中的数据。