2019年7月25日星期四(文件IO)

2019725日星期四

. linux系统IO应用实例  -> LCD液晶屏幕

1. linux下,一切都是文件。  -> LCD液晶屏幕都是文件。

   既然LCD液晶是文件,那么文件名是什么?  --> 硬件设备文件去/dev下寻找。

/dev/ttySAC0    -> 拓展外接串口1

/dev/ttySAC1    -> 拓展外接串口2

/dev/ttySAC2

/dev/ttySAC3

/dev/fb0    -> LCD液晶屏幕

/dev/input/event0  -> 触摸屏

2. 液晶LCD参数:

1)屏幕尺寸:7

2)分辨率:蓝色:800*480  黑色:1024*600

   什么是分辨率?  --> 指的就是屏幕中像素点的总个数。

3)每一个像素点都是由RGB组成,那么每一个像素点中有多少个字节?

[root@GEC6818 /]# cat /sys/class/graphics/fb0/bits_per_pixel  -> 32  -> 每一个像素点都是32位  -> 4字节

 像素点排布: ARGB

3. 举例子。

#include <sys/types.h>

#include <sys/stat.h>

#include <fcntl.h>

#include <stdio.h>

#include <unistd.h>

int main(int argc,char *argv[])

{

       //1. 打开LCD液晶屏幕

       int lcd = open("/dev/fb0",O_WRONLY);

       //2. 写入颜色到LCD中

       int color = 0x00FF00FF;

       write(lcd,&color,4);

       //3. 关闭文件

       close(lcd);

       return 0;

}

===========================================================

  练习1:显示全屏紫色。

#include <sys/types.h>

#include <sys/stat.h>

#include <fcntl.h>

#include <stdio.h>

#include <unistd.h>

int main(int argc,char *argv[])

{

       //1. 打开LCD液晶屏幕

       int lcd = open("/dev/fb0",O_WRONLY);

       //2. 写入颜色到LCD中

       int color = 0x00FF00FF;

       int i;

       for(i=0;i<800*480;i++)

       {

              write(lcd,&color,4);

       }

       //3. 关闭文件

       close(lcd);

       return 0;

}

或者

#include <sys/types.h>

#include <sys/stat.h>

#include <fcntl.h>

#include <stdio.h>

#include <unistd.h>

int main(int argc,char *argv[])

{

       //1. 打开LCD液晶屏幕

       int lcd = open("/dev/fb0",O_WRONLY);

       //2. 写入颜色到LCD中

       int color[800*480];

       int i;

       for(i=0;i<800*480;i++)

       {

              color[i] = 0x00FF00FF;

       }

       write(lcd,color,800*480*4);

       //3. 关闭文件

       close(lcd);

       return 0;

}

===========================================================

  练习2:横向彩虹。红黄蓝绿...

#include <sys/types.h>

#include <sys/stat.h>

#include <fcntl.h>

#include <stdio.h>

#include <unistd.h>

int main(int argc,char *argv[])

{

       //1. 打开LCD液晶屏幕

       int lcd = open("/dev/fb0",O_WRONLY);

       //2. 写入颜色到LCD中

       int color[800*480];

       int i;

       for(i=0;i<800*160;i++)

       {

              color[i] = 0x00FF0000;

       } //i=800*160

       for( ;i<800*320;i++)

       {

              color[i] = 0x0000FF00;

       }

       for( ;i<800*480;i++)

       {

              color[i] = 0x000000FF;

       }

       write(lcd,color,800*480*4);

       //3. 关闭文件

       close(lcd);

       return 0;

}

.文件IO的处理方式

write()  -> 访问文件,得到文件描述符fd   -> 往文件描述符中写入数据 write(fd);

内存映射  -> 访问文件,得到文件描述符fd  -> 根据文件描述符去内存空间中申请一片内存空间,得到地址p  -> 用户只需要操作地址p上的数据  -> 文件就会有相对应的变化

一般,对于LCD液晶屏幕,大多数都是使用内存映射方式来进行数据IO。

内存映射方式:

1. 根据文件申请文件描述符fd

   int fd = open("xxxx");

2. 如何根据文件描述符fd申请内存空间?  -> mmap()  -> man 2 mmap

功能: map files or devices into memory

使用格式:

       #include <sys/mman.h>

      void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);

       addr:

              NULL  -> 系统自动分配空间  99.99%

              不为NULL  -> 手动分配空间  0.01%

       length: 内存映射的空间的长度   -> 例如:lcd就填800*480*4

       prot: 保护权限

              PROT_EXEC  Pages may be executed.

              PROT_READ  Pages may be read.

              PROT_WRITE Pages may be written.

              PROT_NONE  Pages may not be accessed.

              如果有多个权限,则使用"|"连接在一起,例如: PROT_READ|PROT_WRITE    

       flags:

              MAP_SHARED -> 公开

              MAP_PRIVATE -> 私有

       fd: 进行映射的文件描述符

       offset: 文件的偏移量

       返回值:

              成功: 指向该内存空间的起始地址

              失败: (void *)-1

3. 拷贝数据到空间中   -> memcpy()  -> man 3 memcpy

NAME

memcpy - copy memory area  -> 拷贝数据到内存空间中

       #include <string.h>

       void *memcpy(void *dest, const void *src, size_t n);

       dest:目标地址  -> 地址上空间必须足够大。

       src:需要拷贝的东西

       n:需要拷贝的字节数

       返回值:

              成功: 指向dest的地址

              失败: NULL

4. 撤销映射  -> munmap()  ->  man 2 munmap

使用格式:

       #include <sys/mman.h>

    int munmap(void *addr, size_t length);

       addr:内存的起始地址

       length:需要撤销的映射长度

    返回值:

       成功:0

       失败:-1

   练习3:使用内存映射的方式显示满屏紫色。

#include <sys/types.h>

#include <sys/stat.h>

#include <fcntl.h>

#include <stdio.h>

#include <unistd.h>

#include <sys/mman.h>

#include <string.h>

int main(int argc,char*argv[])

{

       //1. 打开文件

       int lcd;

       lcd = open("/dev/fb0",O_RDWR);

       if(lcd < 0)

              printf("open lcd error!\n");

       //2. 申请内存映射

       char *p = mmap(NULL,800*480*4,PROT_READ|PROT_WRITE,MAP_SHARED,lcd,0);

       if(p == (void *)-1)

              printf("mmap error!\n");

       //3. 往内存空间中填充颜色

       int color = 0x00FF00FF;

       int i;

       for(i=0;i<800*480*4;i+=4)

       {

              memcpy(&p[i],&color,4);   等价于:  &p[i] = &*(p+i) = p+i

       }

       //4. 撤销映射

       munmap(p,800*480*4);

       //5. 关闭文件

       close(lcd);

       return 0;

}

  练习4:将char *修改为int *

char *p = mmap(NULL,800*480*4,PROT_READ|PROT_WRITE,MAP_SHARED,lcd,0);

if(p == (void *)-1)

       printf("mmap error!\n");

修改为:

int *p = (int *)mmap(NULL,800*480*4,PROT_READ|PROT_WRITE,MAP_SHARED,lcd,0);

if(p == (void *)-1)

       printf("mmap error!\n");

for(i=0;i<800*480*4;i+=4)

{

       memcpy(&p[i],&color,4);   等价于:  &p[i] = &*(p+i) = p+i

}

修改为:

for(i=0;i<800*480;i++)

{

       memcpy(p+i,&color,4);

}

  练习5: 使用内存映射方式来显示横向彩虹  红黄蓝绿...

#include <sys/types.h>

#include <sys/stat.h>

#include <fcntl.h>

#include <stdio.h>

#include <unistd.h>

#include <sys/mman.h>

#include <string.h>

int main(int argc,char*argv[])

{

       //1. 打开文件

       int lcd;

       lcd = open("/dev/fb0",O_RDWR);

       if(lcd < 0)

              printf("open lcd error!\n");

       //2. 申请内存映射

       int *p = (int *)mmap(NULL,800*480*4,PROT_READ|PROT_WRITE,MAP_SHARED,lcd,0);

       if(p == (void *)-1)

              printf("mmap error!\n");

       //3. 往内存空间中填充颜色

       int red_color = 0x00FF0000;

       int green_color = 0x0000FF00;

       int blue_color = 0x000000FF;

       int i;

       for(i=0;i<800*160;i++)

       {

              memcpy(p+i,&red_color,4);

       }

       for(;i<800*320;i++)

       {

              memcpy(p+i,&green_color,4);

       }

       for(;i<800*480;i++)

       {

              memcpy(p+i,&blue_color,4);

       }

       //4. 撤销映射

       munmap(p,800*480*4);

       //5. 关闭文件

       close(lcd);

       return 0;

}

. linux系统IO应用 ---> 触摸屏

1. linux下,一切都是文件。  -> 连触摸屏也是文件。

   触摸屏设备文件名字: /dev/input/event0

2. 熟悉两个关于触摸屏专业术语。

1)事件

当一些外接设备(鼠标、键盘、WIFI、触摸屏)接入到嵌入式平台时,这些外接设备的状态发生改变,例如:鼠标的左键按了一下,键盘的R键松开,WIFI有人连接进来,触摸屏被滑动了。这个动作就称之为事件。也就是点击鼠标10次,就发生了20次事件(按下/松开都是属于一个事件)

2)输入子系统

专门用于处理事件的值,当一些事件发生了,输入子系统就会把该事件的值计算出来。

3. 触摸屏原理

   见“触摸屏原理.jpg”

4. 分析读取触摸屏坐标/压力的过程。

1)访问设备,得到对应的文件描述符。

2)确定设备数据来源

   外部  -> 设备    -> write()   -> 例如: LCD液晶屏幕

   设备  -> 外部    -> read()    -> 例如: 触摸屏

3)确定读取出来的数据是什么类型?

   究竟是char?int?结构体?数组?指针?

4)分析处理数据

5)关闭设备文件,回收资源。

5. 写例子尝试读取坐标

#include <sys/types.h>

#include <sys/stat.h>

#include <fcntl.h>

#include <stdio.h>

#include <unistd.h>

int main(int argc,char *argv[])

{

       //1. 打开文件

       int fd;

       fd = open("/dev/input/event0",O_RDONLY);

       if(fd < 0)

              printf("open error!\n");

       //2. 读取文件数据

       char buf[50] = {0};

       while(1)

       {

              read(fd,buf,sizeof(buf));

              printf("%s\n",buf);

       }

       close(fd);

       return 0;

}

结果: 都是乱码!

. 究竟输入子系统从驱动发来的数据上计算出来的结果是什么样子?

其实是一个结构体来的,这个结构体专门是用于描述刚才发生事件的情况。这个结构体是被定义在一个头文件中:/usr/include/linux/input.h

 

struct input_event {

       struct timeval time;  -> 事件发生的时间  -> 一般不用!

       __u16 type;   -> 事件的类型

       __u16 code;   -> 事件的编码  -> 对事件类型做进一步的描述!

       __s32 value;  -> 事件的值

};

输入子系统中事件类型有哪些? -> Event types

#define EV_KEY    0x01   -> 键盘、触摸屏压力设备

#define EV_ABS    0x03   -> 触摸屏坐标

输入子系统压力编码:

#define BTN_TOUCH  0x14a -> 触摸屏压力事件

#define ABS_X         0x00  -> X轴坐标

#define ABS_Y         0x01  -> Y轴坐标

输入子系统值:

压力值:  按下:1  松开:0

X坐标: 0~800   0~1024

Y坐标: 0~480   0~600

  练习6: 当你的手点击屏幕松开时,就打印一句话"your hand leave lcd!"

#include <sys/stat.h>

#include <fcntl.h>

#include <stdio.h>

#include <unistd.h>

#include <linux/input.h>

int main(int argc,char *argv[])

{

       //1. 打开文件

       int fd;

       fd = open("/dev/input/event0",O_RDONLY);

       if(fd < 0)

              printf("open error!\n");

       //2. 读取文件数据

       struct input_event buf;

       while(1)

       {

              read(fd,&buf,sizeof(buf));  //如果手已经触摸屏幕,那么buf就会有内容!

              if(buf.type == EV_KEY && buf.code == BTN_TOUCH && buf.value == 0)

              {

                     printf("your hand leave lcd!\n");

              }

       }

       close(fd);

       return 0;

}

  练习7:当你的手在滑动时,把手的位置的坐标打印出来

(100,200)

(100,201)

(101,201)

...

#include <sys/types.h>

#include <sys/stat.h>

#include <fcntl.h>

#include <stdio.h>

#include <unistd.h>

#include <linux/input.h>

int main()

{

       int fd;

       struct input_event buf;

       int x,y

       fd = open("/dev/input/event0",O_RDONLY);

       while(1)

       {

              read(fd,&buf,sizeof(buf));

              if(buf.type == EV_ABS && buf.code == ABS_X)

              {

                     x = buf.value;

              }

              if(buf.type == EV_ABS && buf.code == ABS_Y)

              {

                     y = buf.value;

              }

              printf("(%d , %d)\n",x,y);

       }

       close(fd);

       return 0;

}

  练习8:点击屏幕左边松手,打印一次"left"!

        点击屏幕右边松手,打印一次"right"!

猜你喜欢

转载自www.cnblogs.com/zjlbk/p/11248465.html