触摸屏工作原理(输入子系统)
如上图所示,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;
}