linux嵌入式开发:基于linux的语音机器人(六)|触摸屏|相册设计

在本篇介绍这个项目的相册功能,实现点击开发板屏幕就可完成对相册的浏览。其中涉及到触摸屏读取点击屏幕的坐标信息,

触摸屏读取的结构体信息

相册的设计就要用到触摸屏,依靠点击屏幕来进行图片的浏览

在终端命令行中可以通过输入 [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频繁更改 ,一定需要细心操作

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值