前段时间看了百为的tslib的一个例子,成功应用与 ucgui 上。
校正过程:
static BOOL perform_calibration(CALIBRATION_t *cal)
{
int j;
float n, x, y, x2, y2, xy, z, zx, zy;
float det, a, b, c, e, f, i;
float scaling = 65536.0;
// Get sums for matrix
n = x = y = x2 = y2 = xy = 0;
for (j = 0; j < 5; j++)
{
n += 1.0;
x += (float)cal->x[j];
y += (float)cal->y[j];
x2 += (float)(cal->x[j] * cal->x[j]);
y2 += (float)(cal->y[j] * cal->y[j]);
xy += (float)(cal->x[j] * cal->y[j]);
}
// Get determinant of matrix -- check if determinant is too small
det = n * (x2 * y2 - xy * xy) + x * (xy * y - x * y2) + y * (x * xy - y * x2);
if (det < 0.1 && det > -0.1)
{
return (FALSE);
}
// Get elements of inverse matrix
a = (x2 * y2 - xy * xy) / det;
b = (xy * y - x * y2) / det;
c = (x * xy - y * x2) / det;
e = (n * y2 - y * y) / det;
f = (x * y - n * xy) / det;
i = (n * x2 - x * x) / det;
// Get sums for x calibration
z = zx = zy = 0;
for (j = 0; j < 5; j++)
{
z += (float)cal->xfb[j];
zx += (float)(cal->xfb[j] * cal->x[j]);
zy += (float)(cal->xfb[j] * cal->y[j]);
}
// Now multiply out to get the calibration for framebuffer x coord
cal->a[0] = (int)((a * z + b * zx + c * zy) * (scaling));
cal->a[1] = (int)((b * z + e * zx + f * zy) * (scaling));
cal->a[2] = (int)((c * z + f * zx + i * zy) * (scaling));
// Get sums for y calibration
z = zx = zy = 0;
for (j = 0; j < 5; j++)
{
z += (float)cal->yfb[j];
zx += (float)(cal->yfb[j] * cal->x[j]);
zy += (float)(cal->yfb[j] * cal->y[j]);
}
// Now multiply out to get the calibration for framebuffer y coord
cal->a[3] = (int)((a * z + b * zx + c * zy) * (scaling));
cal->a[4] = (int)((b * z + e * zx + f * zy) * (scaling));
cal->a[5] = (int)((c * z + f * zx + i * zy) * (scaling));
// If we got here, we're OK, so assign scaling to a[6] and return
cal->a[6] = (int)scaling;
return (TRUE);
}
/*
功能:读取触摸屏读坐标,该坐标未做转换,不能直接使用
返回:0=无效坐标
1=有效坐标
说明:本函数连续采样2次,2次采样结果+-5范围内才算有效
*/
static BOOL TOUCH_MeasureXY(int *x, int *y)
{
int x1, y1;
int x2, y2;
int i;
x1 = TOUCH_X_MeasureX();
y1 = TOUCH_X_MeasureY();
for (i = 0; i < 1000; i++);
x2 = TOUCH_X_MeasureX();
y2 = TOUCH_X_MeasureY();
if (ABS(x1 - x2) < 50 && ABS(y1 - y2) < 50)
{
*x = (x1 + x2) / 2;
*y = (y1 + y2) / 2;
return TRUE;
}
else
{
return FALSE;
}
}
static BOOL check_touch_pressed(int xPhys,
int yPhys)
{
if ((xPhys < MIN_AD_X) ||
(xPhys > MAX_AD_X) ||
(yPhys < MIN_AD_Y) ||
(yPhys > MAX_AD_Y))
{
return (FALSE);
}
return (TRUE);
}
static void get_sample(CALIBRATION_t *cal,
int index,
int x,
int y,
BOOL isRight)
{
int xPhys, yPhys;
GUI_SetColor(GUI_WHITE);
GUI_FillCircle(x, y, 10);
GUI_SetColor(GUI_RED);
GUI_FillCircle(x, y, 5);
GUI_SetColor(GUI_WHITE);
if (isRight)
GUI_DispStringAt(MSG_PRESS_HERE, x - 80, y - 8);
else
GUI_DispStringAt(MSG_PRESS_HERE, x + 20, y - 8);
// Wait touch to release
while (1)
{
if (TOUCH_MeasureXY(&xPhys, &yPhys))
{
if (!check_touch_pressed(xPhys, yPhys))
break;
}
OSTimeDlyHMSM(0, 0, 0, 100);
}
// Wait touch pressed
while(1)
{
if (TOUCH_MeasureXY(&xPhys, &yPhys))
{
if (check_touch_pressed(xPhys, yPhys))
{
if (TOUCH_MeasureXY(&cal->x[index], &cal->y[index]))
break;
}
}
OSTimeDlyHMSM(0, 0, 0, 100);
};
/* Tell user to release */
GUI_Clear();
if (isRight)
GUI_DispStringAt(MSG_COMPLETE, x - 80, y - 8);
else
GUI_DispStringAt(MSG_COMPLETE, x + 20, y - 8);
cal->xfb[index] = x;
cal->yfb[index] = y;
}
/*********************************************************************
*
* _ExecCalibration
*
**********************************************************************
*/
BOOL ExecCalibration(CALIBRATION_t *cal)
{
BOOL result;
GUI_RECT rect;
int xPhys;
int yPhys;
/* _Calibrate upper left */
GUI_SetBkColor(GUI_RED);
GUI_Clear();
GUI_SetFont(&GUI_FontHZ_SimSun_16);
// Top Left
get_sample(cal, 0, 50, 50, FALSE);
// Top Right
get_sample(cal, 1, LCD_XSIZE - 50, 50, TRUE);
// Bottom Right
get_sample(cal, 2, LCD_XSIZE - 50, LCD_YSIZE - 50, TRUE);
// Bottom Left
get_sample(cal, 3, 50, LCD_YSIZE - 50, FALSE);
// Center
get_sample(cal, 4, LCD_XSIZE / 2, LCD_YSIZE / 2, FALSE);
rect.x0 = 0;
rect.x1 = LCD_XSIZE;
rect.y0 = 50;
rect.y1 = rect.y0 + 20;
GUI_Clear();
result = perform_calibration(cal);
if (result)
GUI_DispStringInRect(MSG_CALIBRATION_SUCCESSFUL,
&rect, GUI_TA_CENTER | GUI_TA_VCENTER);
else
GUI_DispStringInRect(MSG_CALIBRATION_SUCCESSFUL,
&rect, GUI_TA_CENTER | GUI_TA_VCENTER);
rect.y0 = 80;
rect.y1 = rect.y0 + 20;
GUI_DispNextLine();
GUI_DispStringInRect(MSG_PRESS_TOUCH_TO_CONTINUE,
&rect, GUI_TA_CENTER | GUI_TA_VCENTER);
OSTimeDlyHMSM(0, 0, 0, 200);
// Wait the touch to continue
while (1)
{
if (TOUCH_MeasureXY(&xPhys, &yPhys))
{
if (check_touch_pressed(xPhys, yPhys))
break;
}
OSTimeDlyHMSM(0, 0, 0, 10);
}
return (result);
}
复制代码
因为ucgui 内部使用的是简单的两点校正法,所以我们自己定义 GUI_TOUCH_Exec() 函数。
/*********************************************************************
*
* _StoreUnstable
*/
static void _StoreUnstable(int x, int y)
{
static int _xLast = -1;
static int _yLast = -1;
int xOut, yOut;
if ((x != -1) &&
(y != -1) &&
(_xLast != -1) &&
(_yLast != -1))
{
xOut = _xLast;
yOut = _yLast;
}
else
{
xOut = -1;
yOut = -1;
}
_xLast = x;
_yLast = y;
GUI_TOUCH_StoreUnstable(xOut, yOut);
}
/*********************************************************************
*
* My_GUI_TOUCH_Exec
*/
void My_GUI_TOUCH_Exec()
{
int xPhys, yPhys;
int x, y;
if (TOUCH_MeasureXY(&xPhys, &yPhys))
{
/* Convert values into logical values */
x = (int)((mCurrentSettings.cal.a[0] + mCurrentSettings.cal.a[1] * xPhys +
mCurrentSettings.cal.a[2] * yPhys) / mCurrentSettings.cal.a[6]);
y = (int)((mCurrentSettings.cal.a[3] + mCurrentSettings.cal.a[4] * xPhys +
mCurrentSettings.cal.a[5] * yPhys) / mCurrentSettings.cal.a[6]);
if ((x < 0) || (x > LCD_XSIZE) || (y < 0) || (y > LCD_YSIZE))
{
_StoreUnstable(-1, -1);
}
else
{
_StoreUnstable(x, y);
}
}
}
复制代码
替换掉原来的 GUI_TOUCH_Exec 变成 My_GUI_TOUCH_Exec 即可。
转载
|