写程序:
第一步:
一.
1.在A点显示"+" (fb_disp_cross(int x,int y ))
2.客户点击"+"
3.记录触摸屏坐标 (ts_read_raw)
二.在B、C、D、E上循环操作:显示、点击、读取
第二步:
根据这些数据确定公式(ts_calibrate)
第三步:
以后得到TS触点,可转换出LCD坐标(ts_read)
画十字架
代码存放在LCD内的geometry.c
画出十字架:
void fb_disp_cross(int x, int y,unsigned int color) //十字架代码
{
draw_line( x-10, y, x+10, y, color);
draw_line( x, y-10, x, y+10, color);
}
编辑touchscreen.c
//+ 坐标的x值(屏幕)
static int g_ts_x;
//+ 坐标的Y值(屏幕)
static int g_ts_y;
/表示数据并未有效
//设置成volatile类型,有两个地方会用到一个是中断report_ts_xy
//另一个是程序ts_read_raw,我们一定确保这个值是从内存中读取出来
//让双方得到真实的值
static volatile char g_ts_data_valid = 0;
void Isr_Adc(void)//ADC中断
{
int x = ADCDAT0;
int y = ADCDAT1;
if (!(x & (1<<15))) /* 如果仍然按下才打印 */ &and(都1才1)
{
x &= 0x3ff;
y &= 0x3ff;
//我们现在不能打印
//printf("x = %08d, y = %08d\n\r", x, y);
//实现report_ts_xy函数来打印
report_ts_xy(x, y);
/* 启动定时器以再次读取数据 */
ts_timer_enable();
}
else
{
ts_timer_disable();
enter_wait_pen_down_mode();
}
enter_wait_pen_up_mode();
}
//report_ts_xy函数的实现
void report_ts_xy(int x, int y)
{
//printf("x = %08d, y = %08d\n\r", x, y);
//一开始标记位=0表示没有数据
if (g_ts_data_valid == 0)
{
g_ts_x = x;
g_ts_y = y;
g_ts_data_valid = 1;
}
}
//读到原始数据
void ts_read_raw(int *px, int *py)
{
//当按下触摸屏时会产生ADC中断
while (g_ts_data_valid == 0);
*px = g_ts_x;
*py = g_ts_y;
//读完数据清零
g_ts_data_valid = 0;
}
回顾: 一开始标记位valid为0,表明没有数据这时候读ts_read_raw会在while (g_ts_data_valid == 0);卡死。当你按下触摸屏的时候,最终会产生ADC中断得到数据后report_ts_xy。在这里他发现这个标记位是0,那我就可以把数据保存在这里,然后设计这个标记位是1。ts_read_raw就可以从死循环里跳出来得到新数据。
校准函数
下面我们实现ts_calibrate校准函数,在tslib.c文件中 (根据这些数据确定公式(ts_calibrate))
//设置斜率为全局变量
static double g_kx;
static double g_ky;
static int g_ts_xc, g_ts_yc;
static int g_lcd_xc, g_lcd_yc;
//加一个调换的全局变量
static int g_ts_xy_swap = 0;
/*
----------------------------
| |
| +(A) (B)+ |
| |
| |
| |
| +(E) |
| |
| |
| |
| +(D) (C)+ |
| |
----------------------------
*/
把ABCDE这5个点都实现
void ts_calibrate(void)
{
unsigned int fb_base;
int xres, yres, bpp;
//定义ABCDE触摸屏坐标
int a_ts_x, a_ts_y;
int b_ts_x, b_ts_y;
int c_ts_x, c_ts_y;
int d_ts_x, d_ts_y;
int e_ts_x, e_ts_y;
/* X轴方向 */
int ts_s1, ts_s2;
int lcd_s;
/* Y轴方向 */
int ts_d1, ts_d2;
int lcd_d;
//通过调用framebuffer.c里面的函数,来获取LCD坐标
/* 获得LCD的参数: fb_base, xres, yres, bpp */
get_lcd_params(&fb_base, &xres, &yres, &bpp);
/* 对于ABCDE, 循环: 显示"+"、点击、读ts原始值 */
//A坐标,X分辨率50, Y分辨率50
/* A(50, 50) */
get_calibrate_point_data(50, 50, &a_ts_x, &a_ts_y);
//B坐标,X分辨率-50
/* B(xres-50, 50) */
get_calibrate_point_data(xres-50, 50, &b_ts_x, &b_ts_y);
//C坐标,X分辨率-50,Y分辨率-50
/* C(xres-50, yres-50) */
get_calibrate_point_data(xres-50, yres-50, &c_ts_x, &c_ts_y);
//D坐标,X分辨率位置50,Y分辨率-50
/* D(50, yres-50) */
get_calibrate_point_data(50, yres-50, &d_ts_x, &d_ts_y);
//E坐标,X分辨率除2,Y分辨率除2
/* E(xres/2, yres/2) */
get_calibrate_point_data(xres/2, yres/2, &e_ts_x, &e_ts_y);
//读取XY坐标值后确定XY是否反转
/* 确定触摸屏数据XY是否反转 */
g_ts_xy_swap = is_ts_xy_swap(a_ts_x, a_ts_y, b_ts_x, b_ts_y);
//如果反转,对调所有点的XY坐标
if (g_ts_xy_swap)
{
/* 对调所有点的XY坐标 */
swap_xy(&a_ts_x, &a_ts_y);
swap_xy(&b_ts_x, &b_ts_y);
swap_xy(&c_ts_x, &c_ts_y);
swap_xy(&d_ts_x, &d_ts_y);
swap_xy(&e_ts_x, &e_ts_y);
}
/* 确定公式的参数并保存 */
//Ts_S1值=B点ts和A点tsX轴方向的距离
ts_s1 = b_ts_x - a_ts_x;
//Ts_S2值
ts_s2 = c_ts_x - d_ts_x;
//lcd_s值
lcd_s = xres-50 - 50;
//ts_d1值
ts_d1 = d_ts_y - a_ts_y;
//ts_d2值
ts_d2 = c_ts_y - b_ts_y;
//lcd_d值
lcd_d = yres-50-50;
//X轴的斜率
g_kx = ((double)(2*lcd_s)) / (ts_s1 + ts_s2);
//Y轴的斜率
g_ky = ((double)(2*lcd_d)) / (ts_d1 + ts_d2);
//中心点E点的坐标
g_ts_xc = e_ts_x;
g_ts_yc = e_ts_y;
g_lcd_xc = xres/2;
g_lcd_yc = yres/2;
}
我们需要把 + 在LCD上显示出来并且读出数据
void get_calibrate_point_data(int lcd_x, int lcd_y, int *px, int *py)
{
fb_disp_cross(lcd_x, lcd_y, 0xffffff);
/* 等待点击 */
ts_read_raw(px, py);
}
//比如我们之前发现上报的X轴Y轴值反了
//比如正常情况下从A点移动到B点是x值变化比较大y值不变,但是目前的情况是y值变化比较大,x值不变
//我分根据这个特性分辨
int is_ts_xy_swap(int a_ts_x, int a_ts_y, int b_ts_x, int b_ts_y)
{
int dx = b_ts_x - a_ts_x;
int dy = b_ts_y - a_ts_y;
//减出来的值有可能是负数,我们需要取绝对值
if (dx < 0)
dx = 0 - dx;
if (dy < 0)
dy = 0 - dy;
if(dx > dy)
return 0; /* xy没有反转 */
else
return 1; /* xy反了 */
}
//如果是反的我们需要调换回来,我们需要确定XY是否反转
//我们写出一个对调函数
void swap_xy(int *px, int *py)
{
int tmp = *px;
*px = *py;
*py = tmp;
}
/*
* 读TS原始数据, 转换为LCD坐标
*/
void ts_read(int *lcd_x, int *lcd_y)
{
int ts_x, ts_y;
ts_read_raw(&ts_x, ts_y);
if (g_ts_xy_swap)
{
swap_xy(&ts_x, &ts_y);
}
/* 使用公式计算 */
//斜率 * (触摸屏坐标 - 中心点除,触摸屏坐标) + 中心点LCD坐标
*lcd_x = g_kx * (ts_x - g_ts_xc) + g_lcd_xc;
*lcd_y = g_ky * (ts_y - g_ts_yc) + g_lcd_yc;
}
接下来我们画线, 我们在framebuffer.c中把清屏函数单独实现
void clear_screen(unsigned int color)
{
int x, y;
unsigned char *p0;
unsigned short *p;
unsigned int *p2;
/* 往framebuffer中写数据 */
if (bpp == 8)
{
/* bpp: palette[color] */
p0 = (unsigned char *)fb_base;
for (x = 0; x < xres; x++)
for (y = 0; y < yres; y++)
*p0++ = color;
}
else if (bpp == 16)
{
/* 让LCD输出整屏的红色 */
/* 565: 0xf700 */
p = (unsigned short *)fb_base;
for (x = 0; x < xres; x++)
for (y = 0; y < yres; y++)
*p++ = convert32bppto16bpp(color);
}
else if (bpp == 32)
{
p2 = (unsigned int *)fb_base;
for (x = 0; x < xres; x++)
for (y = 0; y < yres; y++)
*p2++ = color;
}
}
先显示一个一个点,让后显示开始校准提示, 校准完提示 ok draw
打开我们的 touchscreen_test.c文件
void touchscreen_test(void)
{
unsigned int fb_base;
int xres, yres, bpp;
int x, y;
/* 获得LCD的参数: fb_base, xres, yres, bpp */
get_lcd_params(&fb_base, &xres, &yres, &bpp);
touchscreen_init();
/* 清屏 */
clear_screen(0);
//我们在70像素的地方显示文字,背景白色显示文字
/* 显示文字提示较准 */
fb_print_string(70, 70, "Touc cross to calibrate touchscreen", 0xffffff);
ts_calibrate();
/* 显示文字提示绘画 */
fb_print_string(70, yres - 70, "OK! To draw!", 0xffffff);
while (1)
{
ts_read(&x, &y);
//我们先打印值
printf(" x = %d, y = %d\n\r", x, y);
//描绿色的线
fb_put_pixel(x, y, 0xff00);
}
}