framebuffer编程

来源:互联网 发布:淘宝开店在哪交保证金 编辑:程序博客网 时间:2024/05/22 04:46

博客迁移,163真不能用

解决问题:

编程时候发现,如果使用/dev/fb0来编写应用程序图片导入,当800*480大图片整屏刷新的时候,会发现图像不是一下子就出现的,而像是一卡一卡的刷新出来,如何解决该问题?

使用:

fbfd = open("/dev/fb0", O_RDWR);//打开视频驱动显示模块,以读写的方式

ioctl(fbfd, FBIOGET_FSCREENINFO, &finfo)  //

ioctl(fbfd, FBIOGET_VSCREENINFO, &vinfo) //获得屏幕信息,800 480 ,以及像素bit=16bit RGB565

然后

fbp = (char *)mmap(0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED,
                       fbfd, 0);
这个命令可以创建一个screensize大小的显存,映射到驱动下的直接显存,可读,可写,MAP_SHARED表示直接显示。

因此我们可以对该fbp地址起始位置的内存,进行屏幕显存操作,fbp表示第一个像素地址,例如,如果我们要在800*480上的屏幕全部刷黑,我们可以用

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

                     *((unsigned short int *)fbp+i)=0x0000;   //这个是用short int ,16bit的数据刷

或者                for(i=0;i<800*480*2;i++)    *((unsigned char *)fbp+i)=0x00;  //这个用8bit 的数据刷

上面两个效果都是一样的,并且刷新屏幕的时候,屏幕图形变化非常快,但是后面这个需要注意,char的话,第一个刷的是高8位,第二个刷的是低八位。否则会出错.

如果不是复杂的数据量如:刷新屏是白、黑、红、蓝...单色,单一图像,那么使用

memset(fbp, 0xFF,screensize);  //全部刷白,注意screensize=800*480*2,因为数据0xFF是char 格式的

或者和上面一样,刷单色简单数据

这样的话,屏幕变化是很快的

 问题来了

如果说我要更新一张很大的图片,屏幕该如何的快速刷新呢?

方法一:

先将图片转化为const unsigned char gImage_data[]={0xFF,0xFF....};格式

然后利用循环

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

                     *((unsigned char*)fbp+i)=gImage_data[i];来刷新

这样是很慢的。因为该图片是从flash程序的code data区,先将gImage_data读取出来,然后再输出显示到屏幕内存中,并且中间的内存块传递空间不是一整块code data的大小,即800*480*2,所以只能一块块的显示屏幕上,所以有一卡一卡的现象

方法二:

先开一个内存buf_temp[800*480*2];  注意该块是运行的内存块,速度很快

fdfd_tu=open("./bizi.bin", O_RDONLY);    //打开一个bin格式的图片
   //注意:这里第一次打开图片的时候,可能会有点慢,但是开机仅此一次比较慢,后面就快了。                                                                             
        fdfd_long=read(fdfd_tu,buf_temp,800*480*2); //然后读取数据到buf_temp中
        memcpy(fbp,buf_temp,800*480*2);   //利用memcpy拷贝内存函数,整块进行拷贝

这样速度最快。和利用命令cp ./bizi.bin /dev/fb0效果一样。

 

总结:

     所以,如果你的内存空间足够,那么你在程序中最好开辟一块整屏大小的内存块,然后再在该内存块上进行操作,那么肯定就不会有卡的问题了,不管是用什么方法,for(),do{}while(); memset() memcpy(),都可以。只要*(unsigned char *)fbp= 指定开辟了的内存数据存放地址。

小块图片可以用const 定义的for()循环进行拷贝,不会很影响速度。

如何解决上面的开机第一次比较慢的问题:

比较两个方法:

方法一:利用open,write的正常方法                                                                          
        UWord8 frame_buffer[JK_LCDScreenBuffer];
        UWord32 fbfd=0; Word8 *fbp = NULL;
                                                                                                          
        UWord32 fbfd_tu=0,fbfd_long=0;
        fbfd = open(JK_LCD_DEV, O_RDWR);
        if (fbfd < 0)
        {
                printf("Error: cannot open framebuffer device.\n");
                exit(1);
        }
        else
                printf("Open framebuffer device /dev/fb0 successfully\n");
                                                                                                          
        fbp = (char *)mmap(NULL,(size_t)JK_LCDScreenBuffer,(int)(PROT_READ | PROT_WRITE),(int)MAP_SHARED,(int)fbfd,(off_t)0);
                                                                                                          
                                                                                                          
        memset(fbp, 0xFF,JK_LCDScreenBuffer);
                                                                                                          
        fbfd_tu=open(JK_DiskFileNname, O_RDONLY);
        fbfd_long=read(fbfd_tu,frame_buffer,JK_LCDScreenBuffer);
        memcpy(fbp,frame_buffer,JK_LCDScreenBuffer);
                                                                                                          
        close(fbfd_long);
        close(fbfd_tu);
        close(fbfd);

方法二:利用FILE文件流格式,结果同上面的一样,就是第一次打开卡,后面就不卡了。

     FILE *fp_image;
        FILE *fp_device;
        Word8 buffer[JK_LCDScreenBuffer];
        size_t len;
                                                                                                          
        if ((fp_image = fopen(JK_DiskFileNname, "rb")) == NULL)
        {
            printf("Error: failed to open '%s'\n", JK_DiskFileNname);
            return UA_ERROR;
        }
                                                                                                          
        if ((fp_device = fopen(JK_LCD_DEV,"wb")) == NULL)
        {
                                                                                                          
            printf("Error: failed to open %s\n",LCD_DEVICE_FILENAME);
                                                                                                          
            fclose(fp_image);
                                                                                                          
            return UA_ERROR;
        }
                                                                                                          
        while(!feof(fp_image))
        {
            len = fread(buffer, sizeof(Word8), JK_LCDScreenBuffer, fp_image);
                                                                                                          
            fwrite(buffer, sizeof(Word8), len, fp_device);
        }
     fclose(fp_image);
        fclose(fp_device);

结论:该问题不太容易解决,可以参考内核显示logo的办法,内核显示logo非常快,一开始以为是用数据.c的结构进行写入,但是发现不是,

                                           

 如何在特定的位置,显示特定的小图片?

主要弄清楚,

1.你的屏是多少位的,RGB565,或RGB666,都可以使用16bit来显示一个像素的内容。

2.数据是bin 文件,还是*.c数据文件,文件的大小其实是一样的,如果从编程的角度看,还是转化为*.c来的划算,因为毕竟bin文件放在flash中占用空间要稍微大一点,不像*.c是纯数据格式编进运行文件中,但是这样也有缺点,就是最后编译的工程会增大很多。我的意思是大图片不要编译进去,但是小图片可以。

但是从方便的角度来看,还是用*.bin的格式好用,推荐!

3.open 一个bin 文件,如果你的buffer是char形式的,那么读取的就是安装char格式,一个个的读出,和定义了unsigned char 格式的*.c数据是一样的,这样就可以一对一的进行赋值了。

 

 下面是我的一个小程序:

UWord32 JKOpenImage(Word8 *FileName,UWord32 image_w,UWord32 image_h,UWord32 Display_x,UWord32 Display_y)

要打开的图标文件名FileName, e.g "image.bin" ,该图标的像素宽度image_w,该图标的像素高度image_h

例如:48*48的图片,还有后面是要在屏幕上显示的起始位置(x,y),注意该位置相对应的原点坐标是(0,0),也即左上角位置
{
                                                                                                          
        UWord8 frame_buffer[JK_LCDScreenBuffer];   //直接申请一块屏幕大小的显存,800*480*2
        UWord32 fbfd=0; Word8 *fbp = NULL;
                                                                                                          
        UWord32 fbfd_tu=0;
        UWord32 i=0,j=0;
        UWord32 image_size=0;
        UWord32 image_start=0;
                                                                                                          
  fbfd = open(JK_LCD_DEV, O_RDWR);
        if (fbfd < 0)
        {
                printf("Error: cannot open framebuffer device.\n");
                exit(1);
        }
                                                                                                          
        fbp = (char *)mmap(NULL,(size_t)JK_LCDScreenBuffer,(int)(PROT_READ | PROT_WRITE),(int)MAP_SHARED,(int)fbfd,(off_t)0);
                                                                                                          
        //If the LCD is 16bits,RGB565,then the real data in frame_buffer size is image_w*image_h*2(words) ,这句话的意思,真正只使用了的image_size大小的frame_buffer。
        image_size=image_h*image_w*2;
        image_start=(Display_x+Display_y*800)*2;

//建立一个外部变量,保存本地原来的图像

//save the local image
        for(j=0;j<image_h;j++)
                for(i=0;i<image_w*2;i++)
                {
                        *(frame_save+i+2*j*image_w)=*((Word8 *)fbp+image_start+i+2*j*800);
                }

-----------利用上面这句就可以保存原来的图片。其中frame_save是外部定义个一个char 变量.

 

//打开小图片进行显示
        fbfd_tu=open(FileName,O_RDWR);
        if (fbfd_tu < 0)
        {
                printf("Error: cannot open framebuffer device.\n");
                exit(1);
        }
        read(fbfd_tu,frame_buffer,image_size);  将该小图片的数据读取出来,成char格式


 for(j=0;j<image_h;j++)
                for(i=0;i<image_w*2;i++){
                        *((Word8 *)fbp+image_start+2*j*800+i)=*(frame_buffer+i+2*j*image_w);

//上面的这个绝对不能有错,否则图片显示就有问题了,image_start是利用Display_x,Display_y计算出来的起始位置, 然后i没循环到一行图片数据结束,就换行,但是记住:后面的数据一定要加上2*j*image_w,数据也一定要跟上。

 

                        //*((Word8 *)fbp+image_start+2*j*800+i)=gImage_image1[i+2*j*image_w];  这个是用*.c数据时候的用法
                        }
                                                                                                          
                                                                                                          
        close(fbfd_tu);
        close(fbfd);
                                                                                                          
                                                                                                          
        return 0;
                                                                                                          
}

 可以利用上面保存的frame_save变量,将我们的图片还原。

UWord32 JKReturnImage(UWord32 image_w,UWord32 image_h,UWord32 Display_x,UWord32 Display_y)
{
                                                                                                          
        UWord32 fbfd=0; Word8 *fbp = NULL;
                                                                                                          
        UWord32 i=0,j=0;
        UWord32 image_start;
                                                                                                          
        fbfd = open(JK_LCD_DEV, O_RDWR);
        if (fbfd < 0)
        {
                printf("Error: cannot open framebuffer device.\n");
                exit(1);
        }
                                                                                                          
        fbp = (char *)mmap(NULL,(size_t)JK_LCDScreenBuffer,(int)(PROT_READ | PROT_WRITE),(int)MAP_SHARED,(int)fbfd,(off_t)0);
                                                                                                          
        image_start=(Display_x+Display_y*800)*2;
                                                                                                          
        for(j=0;j<image_h;j++)
                for(i=0;i<image_w*2;i++){
                        *((Word8 *)fbp+image_start+2*j*800+i)=*(frame_save+i+2*j*image_w);
                        }

        memset(frame_save,0,800*480);
        close(fbfd);
                                                                                                          
        return 0;
}
                                    



原创粉丝点击