触摸屏(应用层)

触摸屏工作原理(输入子系统)


 如上图所示,Linux在处理这些纷繁各异的输入设备的时候,采用的办法是找中间层来屏蔽各种细节。硬件设备通过输入子系统接入到系统中去,当硬件设备产生脉冲信号的时候,会将信号传递到驱动层,驱动层将此信号转换成数字信号,并这些数字信号转换成一个结构体,输入子系统则分辨出是哪个硬件设备产生的数据后,将数据发送到数据触发层,最后由该层将数据发送到指定驱动文件中去,用户就可以根据相关结构体的格式读取相关文件的数据了。

如何操作触摸屏

 使用命令cat /input/event0(触摸屏设备文件)后,点击触摸屏看是否有数据产生(乱码),确保触摸屏没有问题。
  1.打卡触摸屏对应的设备文件;
  2.用相关结构体格式去读取文件的内容;
  3.根据触摸屏数据去做一些操作;
  4.关闭文件。

输入子系统头文件分析

/usr/include/linux/input.h
struct input_event {
    struct timeval time; // 用于描述事件发生的时间
    __u16 type;       // 用来区分不同类型的硬件,比如键盘/鼠标/蓝牙/游戏遥感/触摸屏等等
    __u16 code;      // 用来区分不同硬件中的具体事件, 比如键盘的某个按键、鼠标中的某个按键、触摸屏的X/Y
    __s32 value;     // 用来表示具体的值,比如某个按键的状态(安下/松开) 触摸屏中具体的数值
};
</usr/include/linux/input-event-codes.h>//该文件包含了输入子系统中所要用到的宏
/*
 * Event types
 */
#define EV_SYN          0x00   // 事件分割标志
#define EV_KEY          0x01   // 键盘事件
#define EV_REL          0x02   // 相对位移事件
#define EV_ABS          0x03   // 绝对位移事件 


 /*
 * Keys and buttons
 */
 #define BTN_TOUCH       0x14a    // 按键被触摸


/*
 * Absolute axes
 */
#define ABS_X           0x00   // X轴
#define ABS_Y           0x01   // Y轴

实验程序1

 在开发板中执行下面程序,点击触摸屏将产生数据。

#define     TS_PATH     "/dev/input/event0"

int main(int argc, char const *argv[])
{
    //打开触摸屏
    int fd_ts = open( TS_PATH , O_RDWR);
    if (fd_ts < 0 )
    {
        perror("open event0 error");
        return -1 ;
    }
    

    //读取文件的内容
    struct input_event ts_event ;

    while(1)
    {
        read( fd_ts , &ts_event , sizeof(struct input_event));


        //分析数据

        //为所欲为
        printf("Time:%d.%d	Type:%d	Code:%d	Value:%d
",
                ts_event.time.tv_sec,
                ts_event.time.tv_usec,
                ts_event.type,
                ts_event.code,
                ts_event.value);
    }
    //关闭文件  
    close(fd_ts);

    return 0;
}

输出:
。。。
Time:1420087593.789776  Type:3  Code:0    Value:546
Time:1420087593.789781  Type:3  Code:1    Value:202
Time:1420087593.789785  Type:1  Code:330  Value:1  //按下
Time:1420087593.789789  Type:0  Code:0    Value:0 //事件分割标志
Time:1420087593.873062  Type:1  Code:330  Value:0  //松开
Time:1420087593.873067  Type:0  Code:0    Value:0
。。。

备注:
此程序不支持滑屏

实验程序2

 下面程序将在开发板的LCD显示出一个十字架,十字架的坐标便是触摸屏上被触摸的坐标。

#define     CYAN        0x00FFFF
#define     PPuff       0xFFDAB9
#define     RED         0xFF0000
#define     YELLOW      0XFFFF00
#define     BLUE        0x0000FF
#define     INRED       0xEE6363
#define     SNOW        0xFFFAFA
#define     PURPLE      0xA020F0

#define  TS_PATH    "/dev/input/event0"
#define     LCD_PATH    "/dev/fb0"
#define     LCD_W       800
#define     LCD_H       480
#define     LCD_SIZE    LCD_W*LCD_H*4

bool draw_point(int *address, int color, int x, int y)
{
    if (MAP_FAILED  == address)
    {
        printf("draw_point msg:%s
", strerror(errno));  
        return false;
    }

    *(address + (x + (y*800))) = color; 

    return true;
}

bool draw_Hline(int *address, int color, int len, int x, int y)
{
    if (MAP_FAILED == address)
    {
        printf("draw_line msg:%s
", strerror(errno));        
        return false;
    }
    int wide = LCD_W - 10;
    while (wide--)
    {
        draw_point(address, color, wide, y);

    }
    return true;
}

bool draw_Vline(int *address, int color, int len, int x, int y)
{
    if (MAP_FAILED == address)
    {
        printf("draw_line msg:%s
", strerror(errno));        
        return false;
    }
    int high = LCD_H - 10;
    while (high--)
    {
        //address = address + LCD_W;
        draw_point(address, color, x, high);
    }
    return true;
}

bool touch_screen_pos(int fd, int *x, int *y)
{
    int tmp_x = 0; 
    int tmp_y = 0;
    int cnt = 0;

    while (1)
    {
        
        int ret = read(fd, &ts_event, sizeof(struct input_event));
        if(0 == ret)
        {   
            return false;
        }
        if (ts_event.type == EV_ABS)
        {
            if (ABS_X == ts_event.code )
            {
                tmp_x = (ts_event.value*800)/1024; //LCD与触摸屏的坐标转换
                cnt++;
            }
            if (ABS_Y == ts_event.code)
            {
                tmp_y = (ts_event.value*480)/600; //LCD与触摸屏的坐标转换
                cnt++;
            }
        }
        //得到完整数据便返回成功
        if (2 == cnt)
        {
            *x = tmp_x;
            *y = tmp_y;
            return true;
        }
    }
}

int main(int argc, char const *argv[])
{
    // 打开lcd设备文件  /dev/fb0  --》 由驱动工程师完成
    int fd  = open(LCD_PATH , O_RDWR);
    if (fd < 0 )
    {
       perror("open lcd error");
       return -1 ;
    }
   
    // 内存映射
    int * lcd_p = (int *)mmap(NULL ,   // 指向欲对应的内存起始地址, 通常设为 NULL, 代表让系统自动选定地址
                            LCD_SIZE,  // 显示器的大小
                            PROT_READ | PROT_WRITE,  // 配置内存区可读, 可写
                            MAP_SHARED,    // 设置内存区为共享*(对内存的任何操作都会被复制到文件中)
                            fd,        // 需要映射的文件
                            0);        // 偏移量
    if (MAP_FAILED ==  lcd_p)
    {
        perror("mmap error ");
        return -1 ;
    }
    
    int fd_ts = open(TS_PATH, O_RDWR);
    if (fd_ts < 0)
    {
        perror("open event0 error
");
        return -1;
    }

    int x = 0;
    int y = 0;
    int cnt = 0;
    while (1)
    {   
        touch_screen_pos(fd_ts, &x, &y);
        printf("(%d,%d)
",x,y);

         int i ;
         //得到触摸数据后刷新屏幕,将LCD上一次的内容刷掉
         for ( i = 0; i < 800*480; i++)
         {
              *(lcd_p+i) = SNOW ;
 
         }
        
        //打印十字架
        draw_Vline(lcd_p, CYAN, 500, x, y);
        draw_Hline(lcd_p, CYAN, 400, x, y);

    }

    close(fd);
    close(fd_ts);
    munmap(lcd_p, LCD_SIZE);
    
    return 0;
}

原文地址:https://www.cnblogs.com/ding-ding-light/p/14166008.html