一、触摸屏(touch screen =TS)
1.分类
电阻触摸屏:压力感应 x+ x- y+ y-
电容触摸屏:电压感应 vcc gnd int(中断) rst(复位) scl(i2c的时钟) sda(i2c的数据)
2.触摸屏的文件路径名
/dev/input/event0
3.触摸屏有哪些信息
1)需要读取触摸屏的设备文件信息
2)设备文件信息包含3个信息 type\code\value
4.设备文件信息
gec@ubuntu:/mnt/hgfs/GZ2264/6_文件IO/05/code/zuoye$ vi /usr/include/linux/input.h
23 struct input_event {
24 struct timeval time;
25 __u16 type;
26 __u16 code;
27 __s32 value;
28 };
说明(头文件的使用方法):
gec@ubuntu:/mnt/hgfs/GZ2264/6_文件IO/06/code$ ls /usr/include/stdio.h
/usr/include/stdio.h ----->#include <stdio.h>
gec@ubuntu:/mnt/hgfs/GZ2264/6_文件IO/06/code$ ls /usr/include/linux/input.h
/usr/include/linux/input.h ----->#include <linux/input.h>
5.怎样读取触摸屏的设备文件
struct input_event ts;
read(fd,&ts,sizeof(struct input_event));
练习1:
通过指针传参来取值---指针的高级用法1
int get_value(int *x,int *y)
{
*x = 100;
*y = 250;
return 0;//不用通过返回值就可以从子函数中取值
}
int main()
{
int num1=0,num2=0; //注意这里不要定义成int *num1与int *num2
get_value(&num1,&num2);
printf("num1=%d num2=%d\n",num1,num2);
return 0;
}
6.分析触摸屏读取的type\code\value的值
练习2:(代码要在开发板上面执行)
1)读取一遍 type\code\value的值是什么?
//打开触摸屏int fd;fd = open("/dev/input/event0",O_RDWR);//要用系统IO open函数打开硬件设备文件if(fd < 0){perror("open ts fail");return 0;}//定义一个存储触摸屏信息的结构体,将读取的设备文件信息存储在ts中struct input_event ts;while(1){ //读触摸屏信息--阻塞函数(点击触摸屏之后才会往下执行)read(fd,&ts,sizeof(struct input_event));if(ts.type == EV_ABS &&ts.code == ABS_X){//printf("x=%d ",(int)(ts.value*0.78)); //黑色板x轴的坐标值printf("x=%d ",ts.value*800/1024); //黑色板x轴的坐标值//printf("x=%d ",ts.value); //蓝色板x轴的坐标值}if(ts.type == EV_ABS &&ts.code == ABS_Y){//printf("y=%d\n",(int)(ts.value*0.8)); //黑色板y轴的坐标值printf("y=%d\n",ts.value*480/600); //黑色板y轴的坐标值//printf("y=%d\n",ts.value); //蓝色板y轴的坐标值}} //关闭触摸屏close(fd);
2)死循环读取type\code\value的值是什么,观察规律?
ts.type=3
ts.code=0
ts.value=493 //触摸屏x轴的坐标
ts.type=3
ts.code=1
ts.value=286 //触摸屏y轴的坐标
ts.type=1
ts.code=330
ts.value=1 //按键按下去
ts.type=1
ts.code=330
ts.value=0 //按键松手后
说明:
黑色的板触摸屏分辨率:1024*460;如果是这种,它的分辨率和LCD不一致,需要软件转换
蓝色的板触摸屏分辨率:800*480;如果是这种,它的分辨率和LCD一致,不需要软件转换
7.如何获取触摸屏里面的x轴和y轴的值
//读触摸屏信息--阻塞函数(点击触摸屏之后才会往下执行)
read(fd,&ts,sizeof(struct input_event));
if(ts.type == 3 &&ts.code == 0)
printf("x=%d ",ts.value); //x轴的坐标值
if(ts.type == 3 &&ts.code == 1)
printf("y=%d\n",ts.value); //y轴的坐标值
练习3:用代码分别获取触摸屏5个点的坐标(4个边角点和1个中心点)
8.type、code、value的含义
type:输入事件的类型
code:输入事件的编码
value:输入事件的值(也是我们开发人员需要拿到的值)
type:
#define EV_ABS 0x3 //触摸屏事件类型
#define EV_KEY 0x1 //按键事件类型
code:
#define ABS_X 0x0 //x轴编码
#define ABS_Y 0x1 //y轴编码
#define BTN_TOUCH 0x14a //按键编码
搜索指令grep
gec@ubuntu:/usr/include/linux$ grep -rn "EV_ABS" //搜索字符串"EV_ABS"
input-event-codes.h:40:#define EV_ABS 0x03
gec@ubuntu:/usr/include/linux$ vi input-event-codes.h +40 //打开这个文件 直接跳到第30行
思考问题:
1)为什么有时候一直打印x轴的值
当你横着滑动屏幕的时候,此时y轴的值没有产生变化,输入子系统认为你y轴的编码事件没有变化,不打印y轴值
2)为什么有时候一直打印y轴的值
当你竖着滑动屏幕的时候,此时x轴的值没有产生变化,输入子系统认为你x轴的编码事件没有变化,不打印x轴值
3)怎样点击触摸屏让它x和y轴的值成对出现
当你斜着滑动屏幕的时候,输入子系统认为你x轴和y轴的编码事件都有变化,都打印。
9.如何将触摸屏的分辨率转换成LCD的分辨率一模一样(强制类型转换)
//printf("x=%d ",(int)(ts.value*0.78)); //黑色板x轴的坐标值
printf("x=%d ",ts.value*800/1024); //黑色板x轴的坐标值
//printf("y=%d\n",(int)(ts.value*0.8)); //黑色板y轴的坐标值
printf("y=%d\n",ts.value*480/600); //黑色板y轴的坐标值
10.按下去和松手后的操作识别(如何避免点下去的时候出现好几次打印)
1)单片机:
按键消抖:按下去的时候延时一会儿,再检测电平
松手检测:松手的时候延时一会儿,再检测电平
2)linux:
这里没有按键消抖和松手检测这个概念,它将按下去和松手后封装成两个事件
按下去的事件
if(ts.type==EV_KEY && ts.code==BTN_TOUCH && ts.value == 1)//按下去
{
printf("按下去 x=%d y=%d\n",x,y);
}
松手后的事件
if(ts.type==EV_KEY && ts.code==BTN_TOUCH && ts.value == 0)//松手
{
printf("松手 x=%d y=%d\n",x,y);
}
练习4:
点击屏幕左边显示left 点击屏幕右边显示right
//打开触摸屏int fd;fd = open("/dev/input/event0",O_RDWR);//要用系统IO open函数打开硬件设备文件if(fd < 0){perror("open ts fail");return 0;}//定义一个存储触摸屏信息的结构体,将读取的设备文件信息存储在ts中struct input_event ts;int x=0,y=0;while(1){ //读触摸屏信息--阻塞函数(点击触摸屏之后才会往下执行)read(fd,&ts,sizeof(struct input_event));if(ts.type == EV_ABS &&ts.code == ABS_X){printf("x=%d ",ts.value*800/1024); //黑色板x轴的坐标值//printf("x=%d ",ts.value); //蓝色板x轴的坐标值}if(ts.type == EV_ABS &&ts.code == ABS_Y){printf("y=%d\n",ts.value*480/600); //黑色板y轴的坐标值//printf("y=%d\n",ts.value); //蓝色板y轴的坐标值}/* //方法一:if(x<400) //有可能会出现多次打印left或right的情况printf("left\n");if(x>400)printf("right\n"); */if(ts.type==EV_KEY && ts.code==BTN_TOUCH && ts.value == 1)//按下去{//方法二printf("按下去 x=%d y=%d\n",x,y);if(x<400) printf("left\n");if(x>400)printf("right\n");} } //关闭触摸屏close(fd);
10.滑动的原理
左右滑动:按下和松手后x轴的坐标差值
上下滑动:按下和松手后y轴的坐标差值
1)抓取按下的坐标值
while(1)
{
//读触摸屏信息--阻塞函数(点击触摸屏之后才会往下执行)
read(fd,&ts,sizeof(struct input_event));
if(ts.type == EV_ABS &&ts.code == ABS_X)
{
//printf("x=%d ",ts.value*800/1024); //黑色板x轴的坐标值
x = ts.value*800/1024;
}
if(ts.type == EV_ABS &&ts.code == ABS_Y)
{
//printf("y=%d\n",ts.value*480/600); //黑色板y轴的坐标值
y = ts.value*480/600;
}
//按下去的时刻或者松手后的时刻
if(ts.type==EV_KEY && ts.code==BTN_TOUCH && ts.value == 1)//按下去
{
printf("按下去 x=%d y=%d\n",x,y);
break;
}
}
2)抓取松手后的坐标值
while(1)
{
//读触摸屏信息--阻塞函数(点击触摸屏之后才会往下执行)
read(fd,&ts,sizeof(struct input_event));
if(ts.type == EV_ABS &&ts.code == ABS_X)
{
//printf("x=%d ",ts.value*800/1024); //黑色板x轴的坐标值
x1 = ts.value*800/1024;
}
if(ts.type == EV_ABS &&ts.code == ABS_Y)
{
//printf("y=%d\n",ts.value*480/600); //黑色板y轴的坐标值
y1 = ts.value*480/600;
}
if(ts.type==EV_KEY && ts.code==BTN_TOUCH && ts.value == 0)//松手
{
printf("松手 x1=%d y1=%d\n",x1,y1);
break;
}
}
练习5:
将点击的代码和滑动合在一起
#include "my_head.h"enum SLIDE{left,right,up,down};
enum TOUCH{left_area,right_area};int fd;
//获取点击区域位置
int touch()
{//定义一个存储触摸屏信息的结构体,将读取的设备文件信息存储到ts中struct input_event ts;//读触摸屏信息--阻塞函数(点击触摸屏之后才会往下执行)int x,y;while(1){read(fd,&ts,sizeof(struct input_event));if(ts.type == EV_ABS && ts.code == ABS_X){x = ts.value*800/1024;//x轴坐标}if(ts.type == EV_ABS && ts.code == ABS_Y){y = ts.value*480/600;//y轴坐标}//按下去的时刻或者松手后的时刻if(ts.type == EV_KEY && ts.code == BTN_TOUCH && ts.value == 0)//松手后{if(x <400)return left;elsereturn right;}}
}//拿去上下左右滑动状态
int slide()
{//定义一个存储触摸屏信息的结构体,将读取的设备文件信息存储到ts中struct input_event ts;int x,y,x1,y1;while(1){while(1){read(fd,&ts,sizeof(struct input_event));if(ts.type == EV_ABS && ts.code == ABS_X){x = ts.value*800/1024;}if(ts.type == EV_ABS && ts.code == ABS_Y){y = ts.value*480/600;}//按下去的时刻或者松手后的时刻if(ts.type == EV_KEY && ts.code == BTN_TOUCH && ts.value == 1)//按下去{printf("按下去 (%d,%d)\n",x,y);break;}}//读触摸屏信息--阻塞函数(点击触摸屏之后才会往下执行)while(1){read(fd,&ts,sizeof(struct input_event));if(ts.type == EV_ABS && ts.code == ABS_X){x1 = ts.value*800/1024;}if(ts.type == EV_ABS && ts.code == ABS_Y){y1 = ts.value*480/600;}if(ts.type == EV_KEY && ts.code == BTN_TOUCH && ts.value == 0)//松手{printf("松手后 (%d,%d)\n",x1,y1);break;}}if(x1-x > 100)return right;if(x1-x < -100)return left;if(y1-y > 100)return down;if(y1-y < -100)return up;}return 0;
}int main(int argc,char *argv[])
{//打开触摸屏fd = open("/dev/input/event0",O_RDWR);if(fd < 0){perror("open fd error!\n");return 0;}while(1){//点击switch(touch()){case left:printf("touch left!\n");break;case right:printf("touch right!\n");break;}//滑动switch(slide()){case up:printf("up slide!\n");break;case down:printf("down slide!\n");break;case left:printf("left slide!\n");break;case right:printf("right slide!\n");break;}}//关闭触摸屏close(fd);return 0;
}
练习6:
使用滑动来切换图片
#include "my_head.h"enum SLIDE{left,right,up,down};
int fd,fd_lcd;int show_pic(int *p,char *bmp_path)
{//打开bmp图片int bmp = open(bmp_path,O_RDWR);if(bmp < 0){printf("open bmp fail!\n");return -1;}//去除掉头54个字节lseek(bmp,54,SEEK_SET);//存储bmp图片的buffer:800*480*3char buf[800*480*3] = {0};int ret1 = read(bmp,buf,800*480*3); sleep(1);//读bmp图片//将buf数据通过指针p填充到LCD中int x;//x表示横轴int y;//y表示纵轴for(y=0;y<480;y++){for(x=0;x<800;x++){*(p+((479-y)*800+x)) = (buf[3*(y*800+x)+0]) | (buf[3*(y*800+x)+1]<<8) | (buf[3*(y*800+x)+2]<<16);}}close(bmp);return 0;
}//拿去上下左右滑动状态
int slide()
{//定义一个存储触摸屏信息的结构体,将读取的设备文件信息存储到ts中struct input_event ts;int x,y,x1,y1;while(1){while(1){read(fd,&ts,sizeof(struct input_event));if(ts.type == EV_ABS && ts.code == ABS_X){x = ts.value*800/1024;}if(ts.type == EV_ABS && ts.code == ABS_Y){y = ts.value*480/600;}//按下去的时刻或者松手后的时刻if(ts.type == EV_KEY && ts.code == BTN_TOUCH && ts.value == 1)//按下去{printf("按下去 (%d,%d)\n",x,y);break;}}//读触摸屏信息--阻塞函数(点击触摸屏之后才会往下执行)while(1){read(fd,&ts,sizeof(struct input_event));if(ts.type == EV_ABS && ts.code == ABS_X){x1 = ts.value*800/1024;}if(ts.type == EV_ABS && ts.code == ABS_Y){y1 = ts.value*480/600;}if(ts.type == EV_KEY && ts.code == BTN_TOUCH && ts.value == 0)//松手{printf("松手后 (%d,%d)\n",x1,y1);break;}}if(x1-x > 100)return right;if(x1-x < -100)return left;if(y1-y > 100)return down;if(y1-y < -100)return up;}return 0;
}int main(int argc,char *argv[])
{//打开触摸屏fd = open("/dev/input/event0",O_RDWR);if(fd < 0){perror("open fd error!\n");return 0;}//打开lcdfd_lcd = open("/dev/fb0",O_RDWR);if(fd_lcd < 0){printf("open fd_lcd error!\n");return 0;}//lcd映射//指针指向一个像素点int *p = mmap(NULL,800*480*4,PROT_READ|PROT_WRITE,MAP_SHARED,fd_lcd,0);if(p == NULL){perror("mmap fail!\n");return -1;}while(1){//指针数组存储字符串char *bmp_path[] = {"james.bmp","wade.bmp"};int i=0;//滑动switch(slide()){case up:printf("up slide!\n");show_pic(p,bmp_path[0]);break;case down:printf("down slide!\n");show_pic(p,bmp_path[1]);break;case left:printf("left slide!\n");show_pic(p,bmp_path[0]);break;case right:printf("right slide!\n");show_pic(p,bmp_path[1]);break;}}//lcd映射释放munmap(p,800*480*4);//关闭触摸屏close(fd);return 0;
}
作业1:
点击左边显示一张bmp 点击右边显示一张jpg
//打开lcdint fd_lcd = open("/dev/fb0",O_RDWR);if(fd_lcd < 0){printf("open fd_lcd error!\n");return 0;}//lcd映射//指针指向一个像素点int *p = mmap(NULL,800*480*4,PROT_READ|PROT_WRITE,MAP_SHARED,fd_lcd,0);if(p == NULL){perror("mmap fail!\n");return -1;}//打开触摸屏int fd_ts = open("/dev/input/event0",O_RDWR);if(fd_ts < 0){printf("open fd_ts error!\n");return 0;}//定义一个存储触摸屏信息的结构体,将读取的设备文件信息存储到ts中struct input_event ts;//读触摸屏信息--阻塞函数(点击触摸屏之后才会往下执行)int x,y;while(1){//指针数组存储字符串char *bmp_path[] = {"james.bmp","wade.bmp"};int i;read(fd_ts,&ts,sizeof(struct input_event));if(ts.type == EV_ABS && ts.code == ABS_X){x = ts.value*800/1024;//x轴坐标}if(ts.type == EV_ABS && ts.code == ABS_Y){y = ts.value*480/600;//y轴坐标}//按下去的时刻或者松手后的时刻if(ts.type == EV_KEY && ts.code == BTN_TOUCH && ts.value == 1)//按下去{if(x <400){if(i<2){printf("left!\n");printf("show[%d]\n",i+1); show_pic(p,bmp_path[i]); i++;}// else// {// i=0;// show_pic(p,bmp_path[i]);// }}else if(x > 400){printf("right!\n");if(i==2){i=0;show_pic(p,bmp_path[i]);}else{lcd_draw_jpg(0,0,"./jr.jpg",NULL,0,0);}} }}//lcd映射释放munmap(p,800*480*4);//关闭lcd\bmp\tsclose(fd_lcd);close(fd_ts);
附加题:
//触摸屏的函数封装如下
int get_xy(int *x,int *y)
{
}
int main()
{
int x,y;
get_xy(&x,&y); //通过调用get_xy来获取x和y轴的坐标值
printf("x=%d y=%d\n",x,y);
return 0;
}
#include "my_head.h"int get_xy(int *x,int *y)
{//打开触摸屏int fd;fd = open("/dev/input/event0",O_RDWR);if(fd < 0){perror("open fd error!\n");return 0;} //定义一个存储触摸屏信息的结构体,将读取的设备文件信息存储到ts中struct input_event ts;while(1){//读触摸屏信息--阻塞函数(点击触摸屏之后才会往下执行)read(fd,&ts,sizeof(ts));//3. 判断事件 xif(ts.type == EV_ABS && ts.code == ABS_X){*x = ts.value*800/1024;//x轴坐标}if(ts.type == EV_ABS && ts.code == ABS_Y){*y = ts.value*480/600;//y轴坐标}if(ts.type == EV_KEY && ts.code == BTN_TOUCH && ts.value == 0)//松手后break;}//关闭触摸屏close(fd);}int main(int argc,char *argv[])
{int x,y;get_xy(&x,&y); //通过调用get_xy来获取x和y轴的坐标值printf("(%d , %d)\n",x,y);return 0;
}