首页 > 代码库 > 第二十天:mmap内存映射

第二十天:mmap内存映射

    可以说,一天的时间都在了解内存映射mmap这个函数,冯诺依曼结构中表示运算器不能直接对硬盘上的文件进行操作。mmap函数的功能就是将文件映射到某一段内存中,然后操作内存就相当与操作文件。这样的话对文件操作更加方便。mamp函数的定义如下:void *mmap(void *start,size_t length,int prot,int flags,int fd,off_t offsize);一共有六个参数,参数算是比较多了。第一个表示映射内存的起始地址,如果为NULL,那么操作系统会自动的找到空闲的内存映射。第二个参数是映射长度,第三个是映射区域的保护方式,第四个是影响映射区域的各种特性第五个为文件描述符,第六个文件映射的偏移量,通常设置为0。下面看代码来理解这个函数:

 1 #include<stdio.h> 2 #include<fcntl.h> 3 #include<sys/mman.h> 4 #include<string.h> 5  6 int main() 7 { 8     int fd = 0; 9     int file_size = 0;10     void *add = NULL;11     12     fd = open("hello",O_RDWR|O_CREAT,0644);13     if(fd < 0){14         perror("open");15         return 1;16     }17     file_size = lseek(fd,0,SEEK_END);18     lseek(fd,0,SEEK_SET);19 20     add = mmap(NULL,file_size,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);21     if(add ==(void *)-1){22         perror("mmap");23         return 1;24     }25     strcpy(add,"linrong ");26     printf("%s\n",add);27     close(fd);28 }

 这个代码的作用就是将文件映射到add地址上,然后直接往内存中写内容,改变文件的值。

  后面花了比较多的时间来写三个函数,一个是用四个颜色将屏幕分成四份,一个是在屏幕中写“中”。还有一个是在屏幕中显示一张图片,还有作业为将rgb888转换成rgb565。

  直接贴出代码,就是对屏幕文件/dev/fb0进行操作。如果没有这个文件可以在/etc/grub.conf 的kernel最后中加入VGA=0x314。注意一点是:以下代码要在原始终端中运行才有效果,我的屏幕分辨率是1280*800 。如果不同要对代码里面的一些值进行更改。

 1 #include<stdio.h> 2 #include<fcntl.h> 3 #include<sys/mman.h> 4 #include<string.h> 5 #include<linux/fb.h>  6  7 void clean_srcean(unsigned long *add,int x,int y); 8 void drawline(unsigned long *add ,int x0,int y0,int x1 ,int y1,int color); 9 int main()10 {11     int fd = 0;12     int file_size = 0;13     void *add = NULL;14     15     fd = open("/dev/fb0",O_RDWR|O_CREAT,0644);16     if(fd < 0){17         perror("open");18         return 1;19     }20     struct fb_var_screeninfo info;21     int ret = ioctl(fd,FBIOGET_VSCREENINFO,&info);22     if(ret < 0){23         perror("loctl");24         return 1;25     }26     file_size = info.xres * info.yres * info.bits_per_pixel >> 3 ;27     printf("vga is %d * %d\n",info.xres,info.yres);28     printf("bits_per_pixel is %d\n",info.bits_per_pixel);29     add = mmap(NULL,file_size,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);30     if(add ==(void *)-1){31         perror("mmap");32         return 1;33     }34     clean_srcean(add,info.xres,info.yres);35     drawline(add,0,0,400,640,0x00ff0000);36     drawline(add,0,640,400,1280,0x000000ff);37     drawline(add,400,0,800,640,0x00ff00ff);38     drawline(add,400,640,800,1280,0x0000ff00);39     close(fd);40 }41 42 void clean_srcean(unsigned long *add,int x,int y){43     int i;44     for(i=0;i<x*y;i++)45         add[i] = 0x0000ff00;46 47 }48 void drawline(unsigned long *add ,int x0,int y0,int x1,int  y1,int color){49     int i,j;50     for(i =x0;i<x1;i++)51         for(j = y0;j<y1;j++)52             add[i*1280+j] = color;53 54 }
四颜色分屏

 

 1 #include<stdio.h> 2 #include<fcntl.h> 3 #include<sys/mman.h> 4 #include<string.h> 5 #include<linux/fb.h>  6  7 void clean_srcean(unsigned long *add,int x,int y); 8 void drawline(unsigned long *add ,int x0,int y0,int x1 ,int y1,unsigned long color); 9 int main()10 {11     int fd = 0;12     int file_size = 0;13     void *add = NULL;14     15     fd = open("/dev/fb0",O_RDWR|O_CREAT,0644);16     if(fd < 0){17         perror("open");18         return 1;19     }20     struct fb_var_screeninfo info;21     int ret = ioctl(fd,FBIOGET_VSCREENINFO,&info);22     if(ret < 0){23         perror("loctl");24         return 1;25     }26     file_size = info.xres * info.yres * info.bits_per_pixel >> 3 ;27     printf("vga is %d * %d\n",info.xres,info.yres);28     printf("bits_per_pixel is %d\n",info.bits_per_pixel);29     add = mmap(NULL,file_size,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);30     if(add ==(void *)-1){31         perror("mmap");32         return 1;33     }34     clean_srcean(add,info.xres,info.yres);35     drawline(add,50,600,750,610,0x00ff0000);36     drawline(add,200,300,210,900,0x00ff0000);37     drawline(add,600,300,610,900,0x00ff0000);38     drawline(add,200,300,600,310,0x00ff0000);39     drawline(add,200,900,610,910,0x00ff0000);40     close(fd);41 }42 43 void clean_srcean(unsigned long *add,int x,int y){44     int i ;45     for(i = 0;i<x*y;i++)    46         add[i] = 0x0000ff00;47 48 }49 void drawline(unsigned long *add ,int x0,int y0,int x1,int  y1,unsigned long color){50     int i,j;51     for(i =x0;i<x1;i++)52         for(j = y0;j<y1;j++)53             add[i*1280+j] = color;54 55 }
屏幕中写“中”

 

 1 #include<stdio.h> 2 #include<fcntl.h> 3 #include<sys/mman.h> 4 #include<string.h> 5 #include<linux/fb.h>  6  7 void clean_srcean(unsigned long *add,int x,int y); 8 int main() 9 {10     int fd = 0;11     int file_size = 0;12     void *add = NULL;13     14     fd = open("/dev/fb0",O_RDWR|O_CREAT,0644);15     if(fd < 0){16         perror("open");17         return 1;18     }19     struct fb_var_screeninfo info;20     int ret = ioctl(fd,FBIOGET_VSCREENINFO,&info);21     if(ret < 0){22         perror("loctl");23         return 1;24     }25     file_size = info.xres * info.yres * info.bits_per_pixel >> 3 ;26     add = mmap(NULL,file_size,PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);27     if(add ==(void *)-1){28         perror("mmap");29         return 1;30     }31     int fp = open("2.bmp",O_RDWR);32     if(fp < 0){33         perror("open");34         return 1;35     }36     lseek(fp,54,SEEK_SET);37     ret = read(fp,add,file_size);38     if(ret < 0){39         perror("read");40         return 1;41     }42     close(fp);43     close(fd);44 } 
显示图片

 

   前两个代码都是利用两点确定一个矩形来完成画线和区域划分。最后显示图片代码要注意一定要使用位图。显示的时候因为位图的前54个字节是保存图片信息的。所以显示的时候要偏移54个字节。

  rgb888转换成rgb565的思路是装换过程,取高位保存。涉及到位运算。底下代码还是有些错误。后面回来再改,先保存下。

 1 #include<stdio.h> 2 #include<sys/mman.h> 3 #include<fcntl.h> 4 #include<string.h> 5 void rgb888torgb565(char *rgb888,char *rgb565); 6 int main() 7 { 8     int oldpicture = 0; 9     oldpicture = open("old.bmp",O_RDWR);10     if(oldpicture < 0){11         perror("open");12          return 1;13     }14     int newpicture = 0;15     newpicture = open("new.bmp",O_RDWR|O_CREAT,0755);16     if(newpicture < 0){17         perror("open");18         return 1;19     }20     int old_size = lseek(oldpicture,0,SEEK_END);21     lseek(oldpicture,54,SEEK_SET);22     lseek(newpicture,54,SEEK_SET);23     printf("old_size is %d\n",old_size);24     25     char a[54] = {0};26     char rgb888[4] = {0};27     char rgb565[2] = {0};28 29     int ret = 0;30     int i  = 0;31     while(i < old_size - 54){32         ret=read(oldpicture,rgb888,4);33         if(ret < 0){34             perror("read");35             return 1;36         }37         rgb888torgb565(rgb888,rgb565);38         ret = write(newpicture,rgb565,2);39         if(ret < 0){40             perror("write");41             return 1;42         }43         i = i + 4;44 45     }46 47 48 void rgb888torgb565(char *rgb888,char *rgb565){49     50     rgb565[0] = (rgb888[1] & 0xf8) | ((rgb888[2] & 0xe0 >> 5));51     rgb565[1] = ((rgb888[2] & 0x1c) << 3) | ((rgb888[3] & 0xf1) >> 3);52 53 }
rgb888转rgb565

 

第二十天:mmap内存映射