zoukankan      html  css  js  c++  java
  • s3c2440裸机-电阻触摸屏编程(6.触摸屏校准实现-五点校准法)

    前面我们讲过触摸屏触摸屏校准原理就是让lcd能够与触摸屏坐标对应起来。

    一、五点法校准实现

    一、我们取A,B,C,D,E这五个点,那么这个时候我们需要把该5个点的触摸屏和LCD的坐标对应起来,这就是校准的过程。

     

    ①在LCD显示屏上A点显示一个“十字”形状

    ②用户在触摸屏上点击对应A点的“十字”形状

    ③记录触摸屏的数据坐标

    同理在B,C, D, E点循环该①②③过程,就能得到这五点触摸屏坐标。

    二 、然后根据这5个触摸屏坐标数据确定公式。

    三 、以后得到TS触点坐标,即可校准出期待的TS坐标。

    下面开始函数实现:

    在LCD上显示"十字"形状,定义为函数fb_disp_cross()

    记录触摸屏坐标,定义函数为ts_read_raw()

    根据这触摸屏坐标数据确定公式,定义函数为ts_calibrate()

    以后得到TS触点坐标,即可校准出期待的TS坐标,定位函数为ts_read()

    1.画线画圆函数实现

    前面的五、LCD上实现画点、线、圆实现了画点函数fb_put_pixel。基于画点函数即可画出线段以及各种图案。

     //-------------画圆函数。参数:圆心,半径,颜色----------        
     //            画1/8圆 然后其他7/8对称画  
     //                  ---------------->X  
     //                  |(0,0)   0  
     //                  |           7         1        
     //                  |          6           2  
     //                  |           5         3        
     //           (Y)V                  4  
     //  
     //          L = x^2 + y^2 - r^2  
     void draw_circle(int x, int y, int r, int color)  
     {        
         int a, b, num;  
         a = 0;  
         b = r;  
         while(22 * b * b >= r * r)                  // 1/8圆即可  
         {        
             fb_put_pixel(x + a, y - b,color); // 0~1  
             fb_put_pixel(x - a, y - b,color); // 0~7  
             fb_put_pixel(x - a, y + b,color); // 4~5  
             fb_put_pixel(x + a, y + b,color); // 4~3  
       
         fb_put_pixel(x + b, y + a,color); // 2~3  
         fb_put_pixel(x + b, y - a,color); // 2~1  
         fb_put_pixel(x - b, y - a,color); // 6~7  
         fb_put_pixel(x - b, y + a,color); // 6~5  
           
         a++;  
         num = (a * a + b * b) - r*r;  
         if(num > 0)  
         {        
             b--;  
             a--;  
         }        
         }        
     }        
       
     //-----------画线。参数:起始坐标,终点坐标,颜色--------        
     void draw_line(int x1,int y1,int x2,int y2,int color)        
     {        
         int dx,dy,e;  
         dx=x2-x1;         
         dy=y2-y1;        
         if(dx>=0)        
         {        
             if(dy >= 0) // dy>=0  
             {        
                 if(dx>=dy) // 1/8 octant  
                 {        
                     e=dy-dx/2;  
                     while(x1<=x2)        
                     {        
                         fb_put_pixel(x1,y1,color);  
                         if(e>0){y1+=1;e-=dx;}           
                         x1+=1;  
                         e+=dy;  
                     }        
                 }        
                 else                 // 2/8 octant        
                 {        
                     e=dx-dy/2;  
                     while(y1<=y2)        
                     {        
                         fb_put_pixel(x1,y1,color);  
                         if(e>0){x1+=1;e-=dy;}           
                         y1+=1;  
                         e+=dx;  
                     }        
                 }        
             }        
             else                        // dy<0  
             {        
                 dy=-dy;   // dy=abs(dy)  
                 if(dx>=dy) // 8/8 octant  
                 {        
                     e=dy-dx/2;  
                     while(x1<=x2)        
                     {        
                         fb_put_pixel(x1,y1,color);  
                         if(e>0){y1-=1;e-=dx;}           
                         x1+=1;  
                         e+=dy;  
                     }        
                 }        
                 else                 // 7/8 octant        
                 {        
                     e=dx-dy/2;  
                     while(y1>=y2)        
                     {        
                         fb_put_pixel(x1,y1,color);  
                         if(e>0){x1+=1;e-=dy;}           
                         y1-=1;  
                         e+=dx;  
                     }        
                 }        
             }           
         }        
         else //dx<0  
         {        
             dx=-dx;         //dx=abs(dx)  
             if(dy >= 0) // dy>=0  
             {        
                 if(dx>=dy) // 4/8 octant  
                 {        
                     e=dy-dx/2;  
                     while(x1>=x2)        
                     {        
                         fb_put_pixel(x1,y1,color);  
                         if(e>0){y1+=1;e-=dx;}           
                         x1-=1;  
                         e+=dy;  
                     }        
                 }        
                 else                 // 3/8 octant        
                 {        
                     e=dx-dy/2;  
                     while(y1<=y2)        
                     {        
                         fb_put_pixel(x1,y1,color);  
                         if(e>0){x1-=1;e-=dy;}           
                         y1+=1;  
                         e+=dx;  
                     }        
                 }        
             }        
             else                        // dy<0  
             {        
                 dy=-dy;   // dy=abs(dy)  
                 if(dx>=dy) // 5/8 octant  
                 {        
                     e=dy-dx/2;  
                     while(x1>=x2)        
                     {        
                         fb_put_pixel(x1,y1,color);  
                         if(e>0){y1-=1;e-=dx;}           
                         x1-=1;  
                         e+=dy;  
                     }        
                 }        
                 else                 // 6/8 octant        
                 {        
                     e=dx-dy/2;  
                     while(y1>=y2)        
                     {        
                         fb_put_pixel(x1,y1,color);  
                         if(e>0){x1-=1;e-=dy;}           
                         y1-=1;  
                         e+=dx;  
                     }        
                 }        
             }           
         }        
     }        
    View Code

    2.画一个十字架

    要画一个十字架,只需要用画两条短线段即可。

     

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

    3.记录触摸点原始坐标

    以前4.1获取触摸屏坐标)记录触摸屏坐标是在Isr_Adc中实现的,只是把转换结束后的坐标打印了出来,那现在我们把它先记录下来。

    static int g_ts_x;
    static int g_ts_y;
    static volatile  int g_ts_data_valid = 0;
    void report_ts_xy(int x, int y)
    {
        //printf("x = %08d, y = %08d
    
    ", x, y);
    
        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)
    {
        while (g_ts_data_valid == 0);
        *px = g_ts_x;
        *py = g_ts_y;
        g_ts_data_valid = 0;
    }
    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); }

    这里 ts_read_raw是阻塞式的读取数据,当一开始没有按下触摸屏,那么不会产生adc interrupt,那么ts_read_raw会被阻塞住。只有当用户按下后,才会立马返回坐标数据。

    这里对g_ts_data_validvolatile来修饰就是不让编译器优化,表示要让这个变量读取时一定是从内存里面读到的,对这个变量写入时,一定会把它写到内存中去。

    4.校准公式ts_calibrate()

    先获取lcd参数

    再显示5个校准点,且获取5个点的ts实际坐标

    确定校准公式

        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;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反了 */
        }
        void swap_xy(int *px, int *py)
        {
            int tmp = *px;
            *px = *py;
            *py = tmp;
        }
    /*
    ----------------------------
    |                          |
    |  +(A)              (B)+  |
    |                          |
    |                          |
    |                          |
    |            +(E)          |
    |                          |
    |                          |
    |                          |
    |  +(D)              (C)+  |
    |                          |
    ----------------------------
    */
    void ts_calibrate(void)
    {
        unsigned int fb_base;
        int xres, yres, bpp;
    
        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;
    
        /* 获得LCD的参数: fb_base, xres, yres, bpp */
        get_lcd_params(&fb_base, &xres, &yres, &bpp);
    
        /* 对于ABCDE, 循环: 显示"+"、点击、读ts原始值 */
        /* A(50, 50) */
        get_calibrate_point_data(50, 50, &a_ts_x, &a_ts_y);
    
        /* B(xres-50, 50) */
        get_calibrate_point_data(xres-50, 50, &b_ts_x, &b_ts_y);
    
        /* C(xres-50, yres-50) */
        get_calibrate_point_data(xres-50, yres-50, &c_ts_x, &c_ts_y);
    
        /* D(50, yres-50) */
        get_calibrate_point_data(50, yres-50, &d_ts_x, &d_ts_y);
        
        /* E(xres/2, yres/2) */
        get_calibrate_point_data(xres/2, yres/2, &e_ts_x, &e_ts_y);
    
        /* 确定触摸屏数据XY是否反转 */
        g_ts_xy_swap = is_ts_xy_swap(a_ts_x, a_ts_y, b_ts_x, b_ts_y);
    
        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_x - a_ts_x;
        ts_s2 = c_ts_x - d_ts_x;
        lcd_s = xres-50 - 50;
    
        ts_d1 = d_ts_y - a_ts_y;
        ts_d2 = c_ts_y - b_ts_y;
        lcd_d = yres-50-50;
    
        g_kx = ((double)(2*lcd_s)) / (ts_s1 + ts_s2);
        g_ky = ((double)(2*lcd_d)) / (ts_d1 + ts_d2);
    
        g_ts_xc = e_ts_x;
        g_ts_yc = e_ts_y;
    
        g_lcd_xc = xres/2;
        g_lcd_yc = yres/2;
    }

    这里还补充了一点,这里可以软件进行矫正触摸屏与LCD贴错位的情况导致x,y轴坐标反转的问题。这里用a,b两个点的触摸屏实际坐标进行比对,如果从a点到b点的x坐标变化明显,y坐标变化不明显,表示x,y方向没有贴反。反之则表示x,y方向贴反了,需要反转坐标轴。

    5. ts_read()读出校准后(期望)的坐标

    /*
     * 读TS原始数据, 转换为期望的坐标
     */
    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_x = g_kx * (ts_x - g_ts_xc) + g_lcd_xc;
      *lcd_y = g_ky * (ts_y - g_ts_yc) + g_lcd_yc;
    }

    二、测试

    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: 0xf800 */
    
        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;
    
        }
    }
    void touchscreen_test(void)
    {
        unsigned int fb_base;
        int xres, yres, bpp;
    
        int x, y, pressure;
    
        /* 获得LCD的参数: fb_base, xres, yres, bpp */
        get_lcd_params(&fb_base, &xres, &yres, &bpp);
    
        touchscreen_init();
    
        /* 清屏 */
        clear_screen(0);/*LCD章节有介绍*/
    
        /* 显示文字提示较准 */
        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)
        {
            if (ts_read(&x, &y) == 0)
            {
                printf(" x = %d, y = %d
    
    ", x, y);
                fb_put_pixel(x, y, 0xff00); //显示点
            }
        }
    }

    这里我只点击了A点,怎么一下修改子跳出5个十字架。这里由于我们是点击一下可能时间会很长,几十甚至几百毫秒,那么会产生很多次TS intterrupt和ADC中断,那么我们需要用户松开后才认为触摸动作完成。

  • 相关阅读:
    迭代器相关整理
    闭包的功能举例
    函数参数相关整理
    python中进制转换及IP地址转换
    dD Geometry Kernel ( Geometry Kernels) CGAL 4.13 -User Manual
    2D and 3D Linear Geometry Kernel ( Geometry Kernels) CGAL 4.13 -User Manual
    Monotone and Sorted Matrix Search ( Arithmetic and Algebra) CGAL 4.13 -User Manual
    Algebraic Kernel ( Arithmetic and Algebra) CGAL 4.13 -User Manual
    数论中的环概念
    QT的配置及目录结构
  • 原文地址:https://www.cnblogs.com/fuzidage/p/14913708.html
Copyright © 2011-2022 走看看