通信原理课设(gec6818) 002:文件io+文件偏移+LCD+内存映射

目录

1、文件io

2、文件偏移

3、LCD屏幕

4、练习1

1、实现一个文件拷贝功能

2、  实现你的屏幕切屏、循环切颜色

5、内存映射


1、文件io

文件io分为两种:

系统io:系统提供给外面的一个接口,让程序员能通过这个接口去操作系统里面的文件,系统io意味着系统不一样,那么接口操作就会不一样。

标准io:由标准C库(第三方库)提供的接口函数,比如:fopen、fread、fwrite、scanf、printf...
 这个标准io只是针对于普通文件。由于标准io带缓冲区,因此它的效率要高一些,所以:普通文件建议使用标准io。

2、文件偏移

#include 
#include 
off_t lseek(int fd, off_t offset, int whence);

参数解释

fd:文件描述符
offset:偏移量 也就是你的光标要挪动多少个单位,单位是字节
            这个参数可正可负,正代表向后负代表向前
whence:基准定位
                 SEEK_SET    基于文件的开头,这个时候如果offset负数,表示继续往前,但是前面是没有数据,这个时候文件会留下空洞。从原来的文件结尾到新写入数据间的这段空间被成为文件空洞。有时候空洞是好事,但是会造成资源的浪费。
                 SEEK_CUR    基于光标的当前位置
                 SEEK_END    基于文件的末尾,这个时候如果offset正数,表示继续往后,注意后面是没有数据,这个时候文件会留下空洞

返回值:成功返回光标当前的位置到文件开头所有的字节数
              所以求文件大小:unsigned int filesize = lseek(fd,0x00,SEEK_END);
              失败返回-1,同时errno被设置。

3、LCD屏幕

        gec6918开发板上面的屏幕是800*480的点阵,每个点是3个颜色 --- rgb,每一个点是由一个uint(4个字节)型数据去表示。
        数据的表示是有严格的顺序的(argb):
            最高字节是透明度(a)
            次高字节是红色(r)
            次低字节是绿色(g)
            最低字节是蓝色(b)
        我们现在既不模拟3D 也不需要透明,所有这个透明度没有什么作用,随便你弄多少都可以,但是这个字节你还是不能丢。现在我们需要让我们的屏幕成为一个什么样子的颜色,我只需要往屏幕里面写入800 * 480个int值就可以了,用一个值来表示一个颜色 我们叫颜色的量化。

   unsigned int color[800 * 480];
    int i;
    for(i = 0;i < 800*480;i++)
    {
        color[i] = 0xff0000;
    }

LCD屏也是一个文件,只需要将color这个数组写入到这个屏幕文件即可。屏幕的文件为 /dev/fb0

4、练习1

1、实现一个文件拷贝功能
#include 
#include 
#include 
#include 
#include 
#include 
#include 

//写一个copy的功能函数
void copyfile(const char *from,const char * to)
{
    //from是必须要存在的
    int fd_from = open(from,O_RDONLY);
    if(-1 == fd_from)
    {
        perror("open from error");
        exit(1);
    }
    //to 是可能不存在的 如果不存在我需要创建  如果存在我需要截短
    int fd_to = open(to,O_WRONLY | O_CREAT | O_TRUNC,0664);
    if(-1 == fd_to)
    {
        perror("open to error");
        close(fd_from);
        exit(2);
    }

    //执行搬砖的任务  你需要一个小车
    //unsigned char buf[1024];
    unsigned char * ptr = malloc(1024);
    //memset(ptr,0,1024);
    //我们要一直搬砖  知道砖没有

    int r;
    int w;
    unsigned int filesize = lseek(fd_from,0x00,SEEK_END);//
    lseek(fd_from,0x00,SEEK_SET);//弄完需要回到开头 重新进行copy操作
    int sum = 0;
    while(1)
    {
        r = read(fd_from,ptr,1024);
        if(-1 == r)
        {
            perror("read error");
            break;
        }
        else if(0 == r)//你读成功了  但是读的字节是0  说明你弄完了
        {
            printf("copy over!!!\n");
            break;
        }
        else//这里就读到内容了
        {
            w = write(fd_to,ptr,r);
            sum += w;
            if(w < r)//丢字节了
            {
                perror("write error");
                break;
            }
            //求百分比  相当于文件拷贝的进度条
            printf("\r\033[K%d %%",(int)((double)sum / filesize * 100));
            fflush(stdout);
        }
    }

    close(fd_from);
    close(fd_to);
}

int main(int argc,char * argv[])
{
    if(argc < 3)
    {
        printf("参数不对,不能执行复制操作\n");
        return -1;
    }
    copyfile(argv[1],argv[2]);
    return 0;
}

2、  实现你的屏幕切屏、循环切颜色
#include 
#include 
#include 
#include 
#include 

int r, g, b;
int main()
{
    //1 打开文件
    int fd = open("/dev/fb0", O_RDWR);
    if (-1 == fd)
    {
        perror("lcd open error");
        return -1;
    }

    unsigned int red_color[800 * 480],green_color[800*480], bule_color[800 * 480];
    int i;
    for (i = 0; i < 800 * 480; i++)
    {
        red_color[i] = 0xff0000;
        green_color[i] = 0xff00;
        bule_color[i] = 0xff;
    }

    if (r != 800 * 480 * 4)
    {
        perror("write error");
    }
    if (g != 800 * 480 * 4)
    {
        perror("write error");
    }
    if (b != 800 * 480 * 4)
    {
        perror("write error");
    }

    while(1)
    {
        r = write(fd, green_color, 800 * 480 * 4);
        sleep(5);
        lseek(fd, 0x00, SEEK_SET);
        g = write(fd, red_color, 800 * 480 * 4);
        sleep(5);
        lseek(fd, 0x00, SEEK_SET);
        b = write(fd, bule_color, 800 * 480 * 4);
        sleep(5);
        lseek(fd, 0x00, SEEK_SET);
    }
    close(fd);
    return 0;
}

补充:延时 :sleep(1); -> 秒级延时;usleep() -> 微秒级延时

将该代码刷到gec6818板子上后,会发现LCD屏上有条纹状 ,这是因为(800*480)的数组复制了两遍,以及应用态和内核态之间的切换造成了效率低下,我们可以通过内存的映射来解决这个问题。

5、内存映射

#include 
void *mmap(void *addr, size_t length, int prot, int flags,int fd, off_t offset);
  • addr:你要将文件映射到内存的哪个地址,一般我们是难得去得到这个地址的,因此我们需要让操作系统给我指定 填NULL即可

  • length:长度 你要映射多大,单位是字节, 要以页为单位 1页 = 4K,800 * 480 * 4

  • prot:权限 一般要根据fd的权限 PROT_READ 可读

    PROT_WRITE 可写

    PROT_READ | PROT_WRITE 读写

  • flags:映射的标志

    MAP_SHARED 公有映射

    对于内存的操作可以直接影响文件,一般选这个

    MAP_PRIVATE 私有映射

    开辟一个内存你自己玩,不会直接影响文件

  • fd:你要映射哪个文件 就是一个文件描述符

  • offset:偏移量 单位是字节 但是以页为单位,填0表示不偏移
  • 返回值

    成功返回映射后的首地址,我们操作这个地址就可以直接去影响文件了(MAP_SHARED),失败返回MAP_FAILED ,同时errno被设置

操作完成之后,将内存归还系统:

  int munmap(void *addr, size_t length);
  • addr:你映射的那个首地址

  • length:你要解除多大,一般映射多大就解除多大

  • 返回值:成功返回0,失败返回-1,同时errno被设置

你可能感兴趣的:(gec6818,linux,c语言,嵌入式硬件)