010 _触摸屏编程_校准与画线编程

525 阅读2分钟

写程序:

第一步:

一.

1.在A点显示"+" (fb_disp_cross(int x,int y ))

2.客户点击"+"

3.记录触摸屏坐标 (ts_read_raw)

二.在B、C、D、E上循环操作:显示、点击、读取

第二步:

根据这些数据确定公式(ts_calibrate)

第三步:

以后得到TS触点,可转换出LCD坐标(ts_read)

画十字架

QQ图片20210512205904.png

代码存放在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(都11)
    {
        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)+  |
|                          |
----------------------------

*/ABCDE5个点都实现

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);
    }
}