在本篇介绍这个项目的相册功能,实现点击开发板屏幕就可完成对相册的浏览。其中涉及到触摸屏读取点击屏幕的坐标信息,
触摸屏读取的结构体信息
相册的设计就要用到触摸屏,依靠点击屏幕来进行图片的浏览
在终端命令行中可以通过输入 [root @GRE6818]#cat /dev//input/event0 来获取触摸屏底层驱动,但获取的信息是乱码的,那如何从乱码中获取坐标的有效信息呢,答案是无法获取的,那么如何获取触摸屏有效的信息呢?我们可以通过去编程来获取坐标信息,即经过筛选信息,来获取坐标值
软件设计
程序基本步骤如下所示:
Step1:打开触摸屏(open)---- “/dev/input/event0"
Step2:读取应用层input_event结构体的信息,并打印出来(read)
Step3:关闭触摸屏(close)
在这里涉及到linux系统下的一个结构体,需要用头文件 #include<linux/input.h>,该头文件可在linux系统中,通过下面的命令可找到该文件
gec@ubuntu:~$ vi /usr/include/linux/input.h
将该头文件文件复制到程序的共享文件夹中,使用之前的linux复制命令 cp
gec@ubuntu:~$ cp /usr/include/linux/input.h /mnt/hgfs/share1/
通过该命令,该头文件就在share1文件夹中了,我们需要的结构体就是下面这个
struct input_event {
struct timeval time; //获取的触摸的时间
__u16 type; //点击的事件类型:按压事件(1)、绝对坐标事件(3)、相对坐标事件(2)、同步事件(0)
__u16 code; //事件类型的属性:X坐标属性,Y坐标属性,(在一个事件下具有很多的属性……
__s32 value; //对应属性的数值:X坐标值,Y坐标值
};
编辑代码
#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<unistd.h> //write、close函数的头文件
#include<linux/input.h> //linux系统中/usr/inlcude/linux/input.h文件,已经在程序的目录下
int main(int argc,char *argv[])
{
//1、使用open函数打开触摸屏
int fd_event0=open("/dev/input/event0",O_RDWR); //打开触摸屏,保存文件描述符
if(-1==fd_event0){
printf("触摸屏打开失败\n");
}
else{
printf("触摸屏打开成功,文件描述符的数值:%d\n",fd_event0);
}
//2、读取应用层input_event结构体的信息,并打印出来
struct input_event ev; //定义结构体变量
//点击触摸屏,会获取很多信息,一次读取是不够的,我们需要多次读取
while(1)
{
read( fd_event0, &ev, sizeof(ev));
//打印结构体中的信息
printf("type:%d,code:%d, value:%d\n",ev.type,ev.code,ev.value);
}
// type:1,code:330, value:1 //手指按在触摸屏上
// type:1,code:330, value:0 //手指离开触摸屏
//3、关闭触摸屏
close(fd_event0);
return 0;
}
系统调试
在这里讲解一下输出的信息
type:3,code:0,value:455 //3表示绝对坐标事件,0表示x轴坐标属性,455表示手指在离开的那一刻的所在的x坐标值是455
type:3, code:1, value:275 //3表示绝对坐标事件,1表示y轴坐标属性,275表示手指在离开的那一刻的所在的y坐标值是275
type:1, code:330,value:1 //表示手指按在触摸屏上
type:0,code:0,value:0 //
type:1, code:330, value:0 //表示手指离开触摸屏
type:0, code:0,value:0 //
//type为3时,表示code属性下的值value
触摸屏读取的坐标
编辑代码
由上文的讲解可以知道坐标值的输出类型,因此可以由if条件筛选出以输出坐标
由
#include<stdio.h>//printf
#include <sys/types.h>//open
#include <sys/stat.h>//open
#include <fcntl.h>//open
#include <unistd.h>//write,close
#include <linux/input.h>
int main(int argc, char *argv[])
{
//Step1:打开触摸屏。(open)---- “/dev/input/event0"
int fd_event0 = open("/dev/input/event0", O_RDWR);
if(-1 == fd_event0)
{
printf("打开触摸屏失败\n");
}else{
printf("打开触摸屏成功,文件描述符的数值:%d\n", fd_event0);
}
//Step2:读取应用层input_event结构体的信息,并打印出来。read
struct input_event ev; //定义结构体变量
int ts_x=-1, ts_y=-1; //定义两个坐标变量
while(1) //进行多次循环,读取触摸屏信息
{
//一旦进入,重复读
read(fd_event0, &ev, sizeof(ev));
// type:1,code:330, value:1 //手指按在触摸屏上
// type:1,code:330, value:0 //手指离开触摸屏
#if 0
//开发板的边框是蓝色边框 触摸屏分辨率是800*480
//不用转换分辨率,直接由信息获取x、y坐标到ts_x、ts_y
if(ev.type==3 && ev.code==0)//X坐标
{
ts_x = ev.value;
}
if(ev.type==3 && ev.code==1)//Y坐标
{
ts_y = ev.value;
}
#endif
#if 1 //开发板的边框是黑边框,触摸屏分辨率是1024*600
//需要转换分辨率为800*400,获取x、y坐标到ts_x、ts_y
if(ev.type==3 && ev.code==0)//X坐标
{
ts_x = ev.value*800/1024;
}
if(ev.type==3 && ev.code==1)//Y坐标
{
ts_y = ev.value*480/600;
}
#endif
//若手指离开触摸屏就退出循环,不在读取数据,即一次只能触摸一次读取坐标
if(ev.type==1 && ev.code==330 && ev.value==0)
{
break;
}
}
//输出点击屏幕的坐标
printf("(x,y):(%d,%d)\n", ts_x, ts_y);
//Step3:关闭触摸屏。(close)
close(fd_event0);
}
相册功能
软件设计
1.进入界面先显示主界面,主界面中有相册控件
2.点击相册控件可进入相册功能
3.进入后默认显示1.bmp图片
4.
点击左侧区域(X:0-300;Y:0-480),浏览上一张图片
点击右侧区域(X:500-800;Y:0-480),浏览下一张图片
点击中间区域(X:300-500;Y:0-480),退出图片浏览
编辑代码
#include<stdio.h>//printf
#include <sys/types.h>//open
#include <sys/stat.h>//open
#include <fcntl.h>//open
#include <unistd.h>//write,close
#include <linux/input.h>
int fd_event0 = -1;//全局变量
//函数定义
int show_bmp(char *pathname); //显示相册功能,其中包括打开图片、LCD设备,关闭图片、LCD设备,"./image/1.bmp",相册路径
int open_ts(void); //打开触摸屏函数
int read_ts(int *p_ts_x, int *p_ts_y); //读取触摸屏信息,返回x、y坐标,参数为指针类型,可直接赋值改变
int close_ts(void); //关闭触摸屏函数
int main(int argc, char *argv[])
{
//1.先打开触摸屏函数
open_ts();
int ts_x=-1, ts_y=-1; //初始化
int i = 0; //i的范围0~2,用来控制浏览哪张相册
char bmp_path[3][48] = {
"./image/1.bmp",//bmp_path[0]
"./image/2.bmp",//bmp_path[1]
"./image/3.bmp" //bmp_path[2]
};
while(1)
{
//2.进入开发板后先显示主界面
//显示main.bmp,主界面显示控件的图片
show_bmp("./image/main.bmp");
//3.调用函数读取点击的坐标信息,并打印出来
read_ts(&ts_x, &ts_y); //注意函数的参数类型为指针,所以需要取地址
printf("(x,y):(%d,%d)\n", ts_x, ts_y); //将坐标地址打印出来
//4.条件是点击的是相册控件,则进入相册
if(ts_x>100 && ts_x<200 && ts_y>100 && ts_y<200)
{ //首先显示1.bmp
show_bmp("./image/1.bmp");//显示1.bmp
//默认显示1.bmp后,需要读取后面点击的坐标,以判断是上一张、下一张和退出操作
while(1)
{
read_ts(&ts_x, &ts_y);
printf("(x,y):(%d,%d)\n", ts_x, ts_y);
//1)手指点击左侧(X:0~300;Y:0~480)区域,浏览上一张图片
if(ts_x>0 && ts_x<300 && ts_y>0 && ts_y<480)
{ //用i来控制浏览哪张图片,i的取值只和相册的数量有关,这里有三张图片,所以i为2--->0,0---->2
i--;
if(i == -1)
{
i = 2; //当从第一张浏览上一张时,即要跳到最后一张
}
show_bmp(bmp_path[i]);
printf("显示的图片是%s\n", bmp_path[i]);
}
//2)手指点击右侧(X:500~800;Y:0~480)区域,浏览下一张图片
if(ts_x>500 && ts_x<800 && ts_y>0 && ts_y<480)
{
i++;
if(i == 3)
{
i = 0; //当从最后一张浏览下一张时,即要跳到第一张
}
show_bmp(bmp_path[i]);
printf("显示的图片是%s\n", bmp_path[i]);
}
//3)手指点击中间(X:300~500;Y:0~480)区域,退出图片浏览
if(ts_x>300 && ts_x<500 && ts_y>0 && ts_y<480)
{
break;
}
//5.当退出相册功能后,由于外面是个while循环,则重新返回主界面,可以再次点击各种控件进入其功能
}
}
}
//6.关闭触摸屏
close_ts();
}
//open_ts函数定义
int open_ts(void)
{
//Step1:打开触摸屏。(open)---- “/dev/input/event0"
fd_event0= open("/dev/input/event0", O_RDWR);
if(-1 == fd_event0)
{
printf("打开文件失败\n");
}else{
printf("打开文件成功,文件描述符的数值:%d\n", fd_event0);
}
return 0;
}
//在讲解触摸屏时说过的读取坐标,在这里再次复习一下
//①.在函数里面定义结构体变量后,在while函数中进行重复读操作
//②.根据之前解析的坐标内容,对x、y坐标进行赋值
//③.在手指离开触摸屏时,退出读操作
//在推出后,已经获得了点击的x、y坐标值
int read_ts(int *p_ts_x, int *p_ts_y)
{
struct input_event ev;
while(1)
{
read(fd_event0, &ev, sizeof(ev));
#if 0 //开发板的边框是蓝色边框 触摸屏分辨率是800*480
if(ev.type==3 && ev.code==0)//X坐标
{
*p_ts_x = ev.value;
}
if(ev.type==3 && ev.code==1)//Y坐标
{
*p_ts_y = ev.value;
}
#endif
#if 1 //开发板的边框是黑边框 1024*600
if(ev.type==3 && ev.code==0)//X坐标
{
*p_ts_x = ev.value*800/1024;
}
if(ev.type==3 && ev.code==1)//Y坐标
{
*p_ts_y = ev.value*480/600;
}
#endif //手指离开触摸屏的参数信息作为退出循环的条件
if(ev.type==1 && ev.code==330 && ev.value==0)
{
break;
}
}
return 0;
}
int close_ts(void)
{
//Step3:关闭触摸屏。(close)
close(fd_event0);
return 0;
}
int show_bmp(char *pathname)//"./image/1.bmp"
{
//1、首先需要一张 分辨率为800*480大小的且位深度为24位的.bmp格式的图片
//2、使用open函数打开bmp图片
int fd_bmp = open(pathname, O_RDWR);
if(-1 == fd_bmp)
{
printf("打开图片:%s失败\n", "./image/1.bmp");
}else{
printf("打开图片成功,文件描述符的数值:%d\n", fd_bmp);
}
//3、使用open函数打开LCD设备文件
int fd_fb0 = open("/dev/fb0", O_RDWR);
if(-1 == fd_fb0)
{
printf("打开文件失败\n");
}else{
printf("打开文件成功,文件描述符的数值:%d\n", fd_fb0);
}
//4、跳过bmp格式特有的54字节
lseek(fd_bmp, 54, SEEK_SET);
//5、把bmp格式的RGB数据读取到一个buf中
unsigned char bmp_buf[800*480*3] = {0};
read(fd_bmp, bmp_buf, sizeof(bmp_buf));
//6、通过24位转32位的方法进行数据转换
int i = 0;
unsigned int lcd_buf[800*480];//存储转换后的显示器数据
for(i=0; i<800*480; i++)
{
lcd_buf[i] =bmp_buf[i*3+0]<<0|bmp_buf[i*3+1]<<8|bmp_buf[i*3+2]<<16;
}
//7、由于扫描方式不同,需要进行翻转
int tmp_buffer[800*480];
int x=-1,y=-1;
for(y=0;y<480;y++)
{
for(x=0;x<800;x++)
{
tmp_buffer[(479-y)*800+x] = lcd_buf[y*800+x];
}
}
//8、把最后的数据写入到LCD中
lseek(fd_fb0, 0, SEEK_SET);
for(i=0; i<800*480; i++)
write(fd_fb0, &(tmp_buffer[i]), 4);
//9、关闭对应的设备文件
close(fd_bmp);
close(fd_fb0);
return 0;
}
系统调试
⭐️需要注意,在编辑好程序,下载程序到目标板后,需要将对应照片格式的文件放到程序中所在的文件中,注意也需要在开发板中下载该文件夹,在下载图片到开发板时也要进入该文件夹后再进行下载,否则开发板运行程序时将会找不到照片。该操作设计对 TFTP频繁更改 ,一定需要细心操作