2026/08/17 linux嵌入式系统的触摸屏

触摸屏的原理与应用

基本概念

项目实现过程中为了提高用户体验,一般都需要实现人机交互,常见的人机交互的方式有触摸按键、触摸屏、语音识别等方案,其中最常用的就是触摸屏。

在Linux系统下连接操作系统的输入设备不止一种,可能是一个键盘、一个 USB 鼠标或者是一块触摸屏,甚至是一个游戏机摇杆,Linux在处理这些复杂多样的输入设备时,采用的办法就是用中间层来屏蔽各种细节,所以就设计出输入子系统(输入设备的集合)来管理这些输入设备。
image

驱动原理

在Linux内核中,对输入设备的使用,实际上运用了3大块来管理,它们分别是所谓的输入设备驱动层、输入子系统核心层,以及事件触发层。

(1)设备驱动层提供对硬件各寄存器的读写访问和将底层硬件对用户输入访问的响应转换为标准的输入事件,再通过核心层提交给事件处理层。
(2)子系统核心层对下提供了设备驱动层的编程接口,对上又提供了事件处理层的编程接口。
(3)事件处理层就为我们用户空间的应用程序提供了统一访问设备的接口和驱动层提交来的事件处理。所以这使得我们输入设备的驱动部分不在用关心对设备文件的操作,而是要关心对各硬件寄存器的操作和提交的输入事件。
image

举例:当手指在屏幕上滑动的时候,驱动层中的触摸屏驱动会源源不断地产生触摸屏相关数据,并向上递送给内核输入子系统,输入子系统进一步将这些信息规整为统一的结构体,并借助事件触发层发往对应的设备节点文件,至此,应用程序即可从这些设备节点文件读取相关信息。
注意:底层驱动产生的设备数据与上层应用读取设备数据是两个完全异步的过程,彼此之间是没有耦合和约束的,例如:当底层驱动产生的触摸屏坐标信息比应用层读取的速度要快时,应用程序将会丢失一部分坐标信息。

硬件信息
在最靠近应用程序的事件触发层上内核所获知的各类输入事件,比如键盘被按了一下、触摸屏被滑了一下等,都将被统一封装在一个叫做input_event的输入信息结构体当中,该结构体在名字叫做input.h的头文件中定义,头文件路径为/usr/inlucde/linux/input.h。
image
image
image

(1)type
image

(2)code
用于对事件的类型作进一步的描述。比如:当发生EV_KEY事件时,则可能是键盘被按下了,那么究竟是哪个按键被按下了呢?此时查看code就知道了。当发生EV_REL事件时,也许是鼠标动了,也许是滚轮动了。这时可以用code的值来加以区分。
image

(3)value
当code都不足以区分事件的性质的时候,可以用value来确认。比如由EV_REL和REL_WHEEL确认发生了鼠标滚轮的动作,但是究竟是向上滚还是向下滚呢?再比如由由EV_KEY和KEY_F确认了发生键盘上F键的动作,但究竟是按下呢还是弹起呢?这时都可以用value值来进一步判断。
image

设备文件
触摸屏属于字符设备,所以在开发板的Linux系统已经默认把触摸屏的驱动程序安装在Linux内核中,当触摸屏的驱动安装完成后,系统内核会自动在开发板的Linux系统的 /dev目录生成对应的设备文件,所以触摸屏的设备文件的路径:/dev/input/event0
image

程序设计
image

注意:当前的开发板的触摸屏的坐标范围是 X轴:0 ~ 1023 Y轴: 0 ~ 599 所以也就是触摸屏的坐标范围是(1024,600),所以需要等比例缩小为LCD屏的(800,480)大小。
image

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <linux/input.h>
#include <stdio.h>

int cnt=0;
int x,y;

int main(int argc, char const *argv[])
{
    //1.打开触摸屏文件
    int ts_fd = open("/dev/input/event0",O_RDWR);
    //2.读取输入设备的信息
    struct input_event ts_event;

    while(1)
	{
		read(ts_fd,&ts_event,sizeof(ts_event));

		//3.分析读取的设备信息 (type + code + value)
		if (ts_event.type == EV_ABS) //说明是触摸屏
		{
			if (ts_event.code ==  ABS_X) //说明是X轴
			{
				cnt++;
				x = ts_event.value * 800 / 1024;
			}
			if (ts_event.code ==  ABS_Y) //说明是Y轴
			{
				cnt++;
				y = ts_event.value * 480 / 600;
			}

			if(cnt >= 2)
			{
				printf("x = %d\t", x); //输出X轴坐标
				printf("y = %d\n", y); //输出Y轴坐标
				cnt=0;
			}
		}
	}
	

	
	//4.关闭触摸屏
	close(ts_fd);
    return 0;
}

练习:设计一个程序,该程序在运行之后自动播放一段开机动画,开机动画结束后可以调转到登录界面,登录界面有2个按钮,分别是登录和退出,点击登录之后可以显示系统主界面,主界面自拟,要求主界面有一个返回按钮,点击返回按钮可以回到登录界面。要求:不可以使用goto语句。
主要代码:

int main(int argc, char const *argv[])
{
  //1.打开触摸屏文件
  int ts_fd = open("/dev/input/event0",O_RDWR);
  int cnt=0;
  //2.读取输入设备的信息
  struct input_event ts_event;
	//3.打开LCD   open  
	int lcd_fd = open("/dev/fb0",O_RDWR);
  
  int flag = 0;
	//4.对LCD进行内存映射  mmap
	lcd_mp = (int *)mmap(NULL,800*480*4,PROT_READ|PROT_WRITE,MAP_SHARED,lcd_fd,0);

	//5.显示开机动画
	char gif_path[128] ={0}; 

  for (int i = 0; i < 59; ++i)
		{
			sprintf(gif_path,"./gif/Frame%d.jpg",i);  //构造jpg图片的路径
			read_JPEG_file (gif_path,0,0);			  //在LCD上显示
			usleep(1000*20);						  //FPS = 50HZ
		}	

		sprintf(gif_path,"./pic/denglu.jpg");  //构造jpg图片的路径
		read_JPEG_file (gif_path,0,0);			  //在LCD上显示

  while(1)
  {
		read(ts_fd,&ts_event,sizeof(ts_event));

		//3.分析读取的设备信息 (type + code + value)
		if (ts_event.type == EV_ABS) //说明是触摸屏
		{
			if (ts_event.code ==  ABS_X) //说明是X轴
			{
				cnt++;
				x = ts_event.value * 800 / 1024;
			}
			if (ts_event.code ==  ABS_Y) //说明是Y轴
			{
				cnt++;
				y = ts_event.value * 480 / 600;
			}

			if(cnt >= 2)
			{
				printf("x = %d\t", x); //输出X轴坐标
				printf("y = %d\n", y); //输出Y轴坐标
				cnt=0;
			}
    }
    if (x < 200 && y > 430 && flag == 0)
    {
        sprintf(gif_path,"./pic/xit.jpg");  //构造jpg图片的路径
		    read_JPEG_file (gif_path,0,0);			  //在LCD上显示
        flag = 1;
    }
    
    if (x > 650 && y < 50 && flag ==1)
    {
        sprintf(gif_path,"./pic/denglu.jpg");  //构造jpg图片的路径
		    read_JPEG_file (gif_path,0,0);			  //在LCD上显示
        flag =0;
    }
  

	}
	return 0;
}
posted @ 2026-08-17 21:36  !城北徐公.!  阅读(7)  评论(0)    收藏  举报