首页 > 代码库 > 第二十天: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 }
第二十天:mmap内存映射