嵌入式linux/鸿蒙开发板(IMX6ULL)开发(十五)输入系统应用编程(中)

本文涉及的产品
文本翻译,文本翻译 100万字符
图片翻译,图片翻译 100张
文档翻译,文档翻译 1千页
简介: 嵌入式linux/鸿蒙开发板(IMX6ULL)开发(十五)输入系统应用编程

1.3.4 查询方式


APP调用open函数时,传入“O_NONBLOCK”表示“非阻塞”。

APP调用read函数读取数据时,如果驱动程序中有数据,那么APP的read函数会返回数据,否则也会立刻返回错误。


1.3.5 休眠-唤醒方式


APP调用open函数时,不要传入“O_NONBLOCK”。

APP调用read函数读取数据时,如果驱动程序中有数据,那么APP的read函数会返回数据;否则APP就会在内核态休眠,当有数据时驱动程序会把APP唤醒,read函数恢复执行并返回数据给APP。

//打开设备节点ioctl
#include <linux/input>
/*./01_get_input_info     /dev/input/event0   noblock */  
#include <sys/types.h>
#include <fcntl.h>
#include <sys/stat.h>
int main(int argc, char **argv)
{
  int fd;
  int len;
  unsigned int evbit[2];
  char ev_names={
  "EV_SYN",
  "EV_KEY",
  "EV_REL",
  "EV_ABS",
  "EV_MSC",
  "EV_SW",
  "NULL",
  "NULL",
  "NULL",
  "NULL",
  "NULL",
  "NULL",
  "NULL",
  "NULL",
  "NULL",
  "NULL",
  "NULL",
  "EV_LED",
  "EV_SND",
  "EV_REP",
  "EV_FF",
  "EV_PWR",  
  };
  int bit;
  if(argc<2)
  {
  printf("Usage:%s<dev> [noblock]\n,argv[0]");//<>是必须有的 []是可以省略的
  return -1;
  }
  if(argc==3 && strcmp(argv[2],"noblock"))
  {
  fd=open(argv[1],O_RDWR|O_NONBLOCK);
  }
  else
  {
  fd=open(argv[1],O_RDWR);
  }
  //fd=open(argv[1],O_RDWR);
  if(fd<0)
  {
  printf("open %s err\n",argv[1]);
  return -1;
  }
  err = ioctl(fd,EVIOCGID,&id);
  if(err=0)
  {
  printf("bustype = 0x%x\n",id.bustype);
  printf("vendor = 0x%x\n",id.vendor);
  printf("product = 0x%x\n",id.product);
  printf("version = 0x%x\n",id.version);
  }
len =ioctl(fd,EVIOCGBIT(0,sizeof(evbit),&evbit));
if(len > 0&&len <= sizeof(evbit))
{
  for(i=0;i<len;i++)
  {
  byte=((unsigned char *)evbit)[i];
  for(bit=0;bit<8;bit++)
  {
    if(byte & (1<<bit)){
    printf("%s",ev_names[i*8+bit]);
    }
  }
  }
  printf("support ev_type:");
}
  while(1)
  {
  len=read(fd,&event,sizeof(event));
  if(len==sizeof(event))
  {
    printf("get event:type=0x%x,code=0x%x,value=0x%x\n",event.type,event.code,event.value);
  }
  else
  {
    printf("read err %d\n",len);
  }
  }
return 0
}


1.3.6 POLL/SELECT方式


1. 功能介绍

POLL机制、SELECT机制是完全一样的,只是APP接口函数不一样。

简单地说,它们就是“定个闹钟”:在调用poll、select函数时可以传入“超时时间”。在这段时间内,条件合适时(比如有数据可读、有空间可写)就会立刻返回,否则等到“超时时间”结束时返回错误。


用法如下。

APP先调用open函数时。

APP不是直接调用read函数,而是先调用poll或select函数,这2个函数中可以传入“超时时间”。它们的作用是:如果驱动程序中有数据,则立刻返回;否则就休眠。在休眠期间,如果有人操作了硬件,驱动程序获得数据后就会把APP唤醒,导致poll或select立刻返回;如果在“超时时间”内无人操作硬件,则时间到后poll或select函数也会返回。APP可以根据函数的返回值判断返回原因:有数据?无数据超时返回?

APP根据poll或select的返回值判断有数据之后,就调用read函数读取数据时,这时就会立刻获得数据。

poll/select函数可以监测多个文件,可以监测多种事件:

1670901855573.jpg

在调用poll函数时,要指明:

① 你要监测哪一个文件:哪一个fd

② 你想监测这个文件的哪种事件:是POLLIN、还是POLLOUT

最后,在poll函数返回时,要判断状态。


应用程序代码如下:

struct pollfd fds[1];
int timeout_ms = 5000;
int ret;
fds[0].fd = fd;
fds[0].events = POLLIN;
ret = poll(fds, 1, timeout_ms);
if ((ret == 1) && (fds[0].revents & POLLIN))
{
  read(fd, &val, 4);
  printf("get button : 0x%x\n", val);
}


1.3.7 异步通知方式


功能介绍

所谓同步,就是“你慢我等你”。

那么异步就是:你慢那你就自己玩,我做自己的事去了,有情况再通知我。

所谓异步通知,就是APP可以忙自己的事,当驱动程序用数据时它会主动给APP发信号,这会导致APP执行信号处理函数。

仔细想想“发信号”,这只有3个字,却可以引发很多问题:

① 谁发:驱动程序发

② 发什么:信号

③ 发什么信号:SIGIO

④ 怎么发:内核里提供有函数

⑤ 发给谁:APP,APP要把自己告诉驱动

⑥ APP收到后做什么:执行信号处理函数

⑦ 信号处理函数和信号,之间怎么挂钩:APP注册信号处理函数

小孩通知妈妈的事情有很多:饿了、渴了、想找人玩。

Linux系统中也有很多信号,在Linux内核源文件include\uapi\asm-generic\signal.h中,有很多信号的宏定义:

1670901901243.jpg

驱动程序通知APP时,它会发出“SIGIO”这个信号,表示有“IO事件”要处理。

就APP而言,你想处理SIGIO信息,那么需要提供信号处理函数,并且要跟SIGIO挂钩。这可以通过一个signal函数来“给某个信号注册处理函数”,用法如下:

1670901914892.jpg

除了注册SIGIO的处理函数,APP还要做什么事?想想这几个问题:

① 内核里有那么多驱动,你想让哪一个驱动给你发SIGIO信号?

APP要打开驱动程序的设备节点。

② 驱动程序怎么知道要发信号给你而不是别人?

APP要把自己的进程ID告诉驱动程序。

③ APP有时候想收到信号,有时候又不想收到信号:

应该可以把APP的意愿告诉驱动:设置Flag里面的FASYNC位为1,使能“异步通知”。


应用编程

应用程序要做的事情有这几件:

① 编写信号处理函数:

static void sig_func(int sig)
{
  int val;
  read(fd, &val, 4);
  printf("get button : 0x%x\n", val);
}


② 注册信号处理函数:

signal(SIGIO, sig_func);

③ 打开驱动:

fd = open(argv[1], O_RDWR);

④ 把进程ID告诉驱动:

fcntl(fd, F_SETOWN, getpid());

⑤ 使能驱动的FASYNC功能:

flags = fcntl(fd, F_GETFL);
fcntl(fd, F_SETFL, flags | FASYNC);


1.4 电阻屏和电容屏


触摸屏分为电阻屏、电容屏。电阻屏结构简单,在以前很流行;电容屏支持多点触摸,现在的手机基本都是使用电容屏。

注意:LCD、触摸屏不是一回事,LCD是输出设备,触摸屏是输入设备。制作触摸屏时特意把它的尺寸做得跟LCD一模一样,并且把触摸屏覆盖在LCD上。


1.4.1 电阻屏


1. 复习一下欧姆定律

1670901976084.jpg

上图中的电阻假设是均匀的,就是长度和阻值成正比关系。电阻长度为L,阻值为R,在两端施加3.3V电压。在某点测得电压为V,求上图中长度X。

根据欧姆定律:3.3/R = V/Rx,

因为长度和阻值成正比关系,上述公式转换为:3.3∕L = V/X,所以X=LV/3.3。


2. 电阻屏原理

电阻屏就是基于欧姆定律制作的,它有上下两层薄膜,这两层薄膜就是两个电阻,如下图所示:

1670901985194.jpg

平时上下两层薄膜无触触,当点击触摸屏时,上下两层薄膜接触:这时就可以测量触点电压。过程如下:

① 测量X坐标:

在xp、xm两端施加3.3V电压,yp和ym不施加电压(yp就相当于探针),测量yp电压值。该电压值就跟X坐标成正比关系,假设:

② 测量Y坐标:

在yp、ym两端施加3.3V电压,xp和xm不施加电压(xp就相当于探针),测量xp电压值。该电压值就跟Y坐标成正比关系,假设:

1670901995971.jpg

在实际使用时,电阻屏的Xmax、Ymax无从得知,所以使用之前要先较准:依次点击触摸屏的四个角和中心点,推算出X、Y坐标的公式:

1670902007843.jpg


3. 电阻屏数据

Linux驱动程序中,会上报触点的X、Y数据,注意:这不是LCD的坐标值,需要APP再次处理才能转换为LCD坐标值。

对应的input_event结构体中,“type、code、value”如下:

按下时:
EV_KEY   BTN_TOUCH     1        /* 按下 */
EV_ABS   ABS_PRESSURE  1        /* 压力值,可以上报,也可以不报,可以是其他压力值 */
EV_ABS   ABS_X         x_value  /* X坐标 */
EV_ABS   ABS_Y         y_value  /* Y坐标 */
EV_SYNC  0             0        /* 同步事件 */
松开时:
EV_KEY   BTN_TOUCH     0        /* 松开 */
EV_ABS   ABS_PRESSURE  0        /* 压力值,可以上报,也可以不报 */
EV_SYNC  0             0        /* 同步事件 */


1.4.2 电容屏


1. 原理

原理如下图所示:

1670902038969.jpg

电容屏中有一个控制芯片,它会周期性产生驱动信号,接收电极接收到信号,并可测量电荷大小。当电容屏被按下时,相当于引入了新的电容,从而影响了接收电极接收到的电荷大小。主控芯片根据电荷大小即可计算出触点位置。

怎么通过电荷计算出触点位置?这由控制芯片实现,这类芯片一般是I2C接口。

我们只需要编写程序,通过I2C读取芯片寄存器即可得到这些数据。


2. 电容屏数据

参考文档:Linux内核Documentation\input\multi-touch-protocol.rst。

电容屏可以支持多点触摸(Multi touch),驱动程序上报的数据中怎么分辨触点?

这有两种方法:Type A、Type B,这也对应两种类型的触摸屏:

① Type A

该类型的触摸屏不能分辨是哪一个触点,它只是把所有触点的坐标一股脑地上报,由软件来分辨这些数据分别属于哪一个触点。

Type A已经过时,Linux内核中都没有Type A的源码了。


② Type B

该类型的触摸屏能分辨是哪一个触点,上报数据时会先上报触点ID,再上报它的数据。

具体例子如下,这是最简单的示例,使用场景分析来看看它上报的数据。

当有2个触点时(type, code, value):

EV_ABS   ABS_MT_SLOT 0                  // 这表示“我要上报一个触点信息了”,用来分隔触点信息
EV_ABS   ABS_MT_TRACKING_ID 45          // 这个触点的ID是45
EV_ABS   ABS_MT_POSITION_X x[0]         // 触点X坐标
EV_ABS   ABS_MT_POSITION_Y y[0]         // 触点Y坐标
EV_ABS   ABS_MT_SLOT 1                  // 这表示“我要上报一个触点信息了”,用来分隔触点信息
EV_ABS   ABS_MT_TRACKING_ID 46          // 这个触点的ID是46
EV_ABS   ABS_MT_POSITION_X x[1]         // 触点X坐标
EV_ABS   ABS_MT_POSITION_Y y[1]         // 触点Y坐标
EV_SYNC  SYN_REPORT        0            // 全部数据上报完毕


当ID为45的触点正在移动时:

EV_ABS   ABS_MT_SLOT 0   // 这表示“我要上报一个触点信息了”,之前上报过ID,就不用再上报ID了
EV_ABS   ABS_MT_POSITION_X x[0]   // 触点X坐标
EV_SYNC  SYN_REPORT         0     // 全部数据上报完毕


松开ID为45的触点时(在前面slot已经被设置为0,这里这需要再重新设置slot,slot就像一个全局变量一样:如果它没变化的话,就无需再次设置):

// 刚刚设置了ABS_MT_SLOT为0,它对应ID为45,这里设置ID为-1就表示ID为45的触点被松开了
EV_ABS   ABS_MT_TRACKING_ID -1   
EV_SYNC  SYN_REPORT         0    // 全部数据上报完毕


最后,松开ID为46的触点:

EV_ABS   ABS_MT_SLOT 1       // 这表示“我要上报一个触点信息了”,在前面设置过slot 1的ID为46
EV_ABS   ABS_MT_TRACKING_ID -1  // ID为-1,表示slot 1被松开,即ID为46的触点被松开
EV_SYNC  SYN_REPORT             // 全部数据上报完毕
相关文章
|
24天前
|
JavaScript 前端开发 物联网
「Mac畅玩鸿蒙与硬件1」鸿蒙开发环境配置篇1 - 认识鸿蒙系统与开发工具
本篇将介绍鸿蒙操作系统(HarmonyOS)的基本概念以及在 Mac 环境下进行鸿蒙开发所需的工具。通过了解鸿蒙系统和开发工具的特点,为后续的学习和实践奠定基础。
72 1
「Mac畅玩鸿蒙与硬件1」鸿蒙开发环境配置篇1 - 认识鸿蒙系统与开发工具
|
28天前
|
运维 监控 Shell
深入理解Linux系统下的Shell脚本编程
【10月更文挑战第24天】本文将深入浅出地介绍Linux系统中Shell脚本的基础知识和实用技巧,帮助读者从零开始学习编写Shell脚本。通过本文的学习,你将能够掌握Shell脚本的基本语法、变量使用、流程控制以及函数定义等核心概念,并学会如何将这些知识应用于实际问题解决中。文章还将展示几个实用的Shell脚本例子,以加深对知识点的理解和应用。无论你是运维人员还是软件开发者,这篇文章都将为你提供强大的Linux自动化工具。
|
2月前
|
存储 数据管理 调度
HarmonyOS架构理解:揭开鸿蒙系统的神秘面纱
【10月更文挑战第21天】华为的鸿蒙系统(HarmonyOS)以其独特的分布式架构备受关注。该架构包括分布式软总线、分布式数据管理和分布式任务调度。分布式软总线实现设备间的无缝连接;分布式数据管理支持跨设备数据共享;分布式任务调度则实现跨设备任务协同。这些特性为开发者提供了强大的工具,助力智能设备的未来发展。
91 1
|
2月前
|
安全 物联网 大数据
基于开元鸿蒙(OpenHarmony)的【智能药房与药品管理综合应用系统
基于开元鸿蒙(OpenHarmony)的【智能药房与药品管理综合应用系统
85 8
|
2月前
|
传感器 监控 算法
基于开源鸿蒙(OpenHarmony)的【智能家居综合应用】系统
基于开源鸿蒙(OpenHarmony)的【智能家居综合应用】系统
104 6
|
2月前
|
传感器 人工智能 监控
【基于开源鸿蒙(OpenHarmony)的智慧农业综合应用系统】
【基于开源鸿蒙(OpenHarmony)的智慧农业综合应用系统】
124 6
|
2月前
|
搜索推荐 物联网 开发工具
基于OpenHarmony(开源鸿蒙)的智慧医疗综合应用系统
基于OpenHarmony(开源鸿蒙)的智慧医疗综合应用系统
93 5
|
3月前
|
Shell Linux
Linux shell编程学习笔记82:w命令——一览无余
Linux shell编程学习笔记82:w命令——一览无余
|
移动开发 Ubuntu 网络协议
嵌入式linux/鸿蒙开发板(IMX6ULL)开发 (二)Ubuntu操作入门与Linux常用命令(中)
嵌入式linux/鸿蒙开发板(IMX6ULL)开发 (二)Ubuntu操作入门与Linux常用命令
172 1
嵌入式linux/鸿蒙开发板(IMX6ULL)开发 (二)Ubuntu操作入门与Linux常用命令(中)
|
XML Web App开发 开发框架
鸿蒙开发入门 | 开发第一个鸿蒙应用+页面跳转
准备好鸿蒙开发环境后,接下来就需要创建鸿蒙项目,掌握项目的创建过程以及配置。项目创建好后,需要把项目运行在模拟器上,鸿蒙的模拟和安卓模拟器有些不同,鸿蒙提供远程模拟器和本地模拟器,通过登录华为账号登录在线模拟器,使用DevEco Studio可将项目部署到远程模拟器中。
1273 1
鸿蒙开发入门 | 开发第一个鸿蒙应用+页面跳转
下一篇
无影云桌面