zoukankan      html  css  js  c++  java
  • 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! ");

           //2. 申请内存映射

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

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

                  printf("mmap error! ");

           //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! ");

    修改为:

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

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

           printf("mmap error! ");

    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! ");

           //2. 申请内存映射

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

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

                  printf("mmap error! ");

           //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! ");

           //2. 读取文件数据

           char buf[50] = {0};

           while(1)

           {

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

                  printf("%s ",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! ");

           //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! ");

                  }

           }

           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) ",x,y);

           }

           close(fd);

           return 0;

    }

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

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

  • 相关阅读:
    argparse模块的使用
    tf.stack() /tf.unstack()
    什么是tensor
    tf.size()函数
    tf.nn.l2_loss()的用法
    CNN中的卷积
    tf.reverse()
    学习音视频编程技术 博客
    shell 批量计算MD5值
    线程池的实现
  • 原文地址:https://www.cnblogs.com/zjlbk/p/11248465.html
Copyright © 2011-2022 走看看