嵌入式学习小组
直播中

孔妞妞

11年用户 481经验值
私信 关注

如何使用嵌入式开发板LCD?

如何使用嵌入式开发板LCD?

回帖(1)

王萍

2021-12-27 11:32:26
一、了解
使用之前首先要了解一下,所使用的开发板LCD设备文件的位置。(我的开发板位置: /dev/fb0)


文件 IO ——对 LCD设备文件的操作


控制LCD输出设备,就是往里面写像数数据;因此要知道所用的LCD屏的分辨率是多少。


我用的是7寸LCD屏,分辨率为: 800*480


一张图片是以光的三原色(RGB): red(0 ~ 255)green(0 ~ 255) blue(0 ~ 255)


而我们屏幕显示不止RGB三种,还有一个透明度,因此构成分辨率的是 ARGB ,而A透明度:是一种算法  不是颜色分量  范围依然是 0~255; 虽然不是颜色分量   但显存fb0 依然会将该分量计算在内


0x00 00 00 00 (以 A R G B 表示)A不用去管,填FF和00 没什么区别。


unsigned int color = 0x00FF0000;//红色


unsigned int color = 0x0000FF00;//绿色


unsigned int color = 0x000000FF;//蓝色


以上可知,写入fb0 显存的数据ARGB 是占4个字节为一个像数点,总的有800*480个像数点,因此写入显存的真正大小是:800*480*4


下面以一个简单的例子,熟悉一下


要求在 屏幕 显示单颜色绿色:


#include
#include
#include
#include
#include //read

int main()
{
        int i;//
        int fb0_fd;//lcd文件描述符
        unsigned int color = 0x0000FF00;//绿色
       
        fb0_fd = open("/dev/fb0",O_WRONLY);//只写
        if(-1 == fb0_fd)
        {
                perror("open fb0 fail");
        }
       
        //int i;
        for(i=0;i<800*480;i++)
        {
                write(fb0_fd,&color,4);
        }
       
        close(fb0_fd);
       
        return 0;
}







图片每一个像素点RGB分量都不一致,导致无法以上述那种简单的方式去显示一张五颜六色的图片,因此我们需要拿别人的RGB信息(搬运)。


bmp 格式的图片: 800*480*3 == 1152000字节 = 1.098M


而一张图片的实际大小是 1,152,054 字节






多出的54 字节是,bmp的文件头(位图文件头:14字节,位图信息头:40字节)


#include
#include
#include
#include
#include //read
#include

int main()
{
        int i;//
        int j;//循环计数值
        int fb0_fd;//lcd文件描述符
        int bmp_fd;//打开图片的描述符
        char bmp_buf[800*480*3]={0};
        char bmp4_buf[800*480*4]={0};//转换处理后4自己包含A

/*****************打开lcd设备文件******************************/
        fb0_fd = open("/dev/fb0",O_RDWR);//
        if(-1 == fb0_fd)
        {
                perror("open fb0 fail");
                return 0;
        }

/*************************打开图像文件*************************/
        bmp_fd = open("./1.bmp", O_RDONLY);
        if(-1 == bmp_fd)
        {
                perror(" open bmp fail");
                return 0;
        }

/*******************先跳过54字节bmp文件信息头*******************/

        lseek(bmp_fd,54,SEEK_SET);

/***********************处理图像信息************************/       
        read(bmp_fd, bmp_buf, 800*480*3);
        for(i=0,j=0;i<800*480*4;i+=4,j+=3)
        {        //B G R A      B G R
                bmp4_buf[i+2] = bmp_buf[j+2];
                bmp4_buf[i+1] = bmp_buf[j+1];
                bmp4_buf[i+0] = bmp_buf[j+0];
        }
/***********************写到LCD************************/       
        write(fb0_fd,bmp4_buf,800*480*4);
       
        close(fb0_fd);
        close(bmp_fd);

        return 0;
}

问题:会出现翻转问题(上下,左右,镜像翻转)
如果使用单循环(800*480)---循环式连续性 不分行列 需要判断if才能行列翻转很麻烦
                使用循环嵌套解决行列处理:
                    for(y=0,j=0;y<480;y++)//行循环
                    {undefined
                        for(x=0;x<800;x++,j+=3)//列循环
                        {undefined
                            //                                                 B                          G                             R
                            *(pfb0+(479-y)*800+ x) = (bmp_buf[j]<<0) | (bmp_buf[j+1]<<8) | (bmp_buf[j+2]<<16);
                            //通过行列xy的组合公式访问对应的显存映射空间  再赋值
                        }
                    }
                    
翻转现在只要处理 y  或 x 即可     (479-y)是上下翻转  (799-x)是左右翻转



利用显存映射 来显示图片:
内存映射技术(内核)


mmap:
    函数功能:映射一个文件(设备文件或其它文件--要用write)的空间到内存(可以直接赋值)


需要用到的头文件:#include #include


        void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
            参数1:addr  你指定的映射后内存中空间的首地址  我们一般不指定---NULL  空间由系统自动分配
            参数2:length  分配空间的大小  800*480*4
            参数3:prot  映射后空间的 权限 PROT_READ 、  PROT_WRITE 、 PROT_NONE(不能存取)
                        PROT_READ | PROT_WRITE  (读写权限)
            参数4:flags    空间属性 MAP_SHARED(空间共享属性)   MAP_PRIVATE(私有属性)   
            参数5:fd    你需要映射的文件  fb0_fd
            参数6: offset  偏移(必须分页大小的整数倍)     0 (不偏移)
               
            返回值:如果addr是NULL  那返回值就是映射后空间的首地址
                        失败:返回MAP_FAILED(-1)
            


解除映内存射


int munmap(void *addr, size_t length);


参数1:用来取消addr所指的映射内存起始地址。


参数2:是想取消的内存大小。


ARGB(这个是显存映射到内存后的RGB顺序 和之前内存定义数组的顺序BGRA不一致)
所以  赋值操作应该是  BGR ---> BGRA     BGRA = (B<<0) | (G<<8) | (R<<16)


程序如下:


#include
#include
#include
#include
#include //read
#include //mmap

#define MMAP_LENTH 800*480*4

int main()
{
        int x,y;//循环嵌套赋值显存数据的行列计数值
        int j;//循环计数值
               
        int fb0_fd;//lcd文件描述符
        int bmp_fd;
        char bmp_buf[800*480*3]={0};
        char bmp4_buf[800*480*4]={0};//转换处理后4自己包含A
       
        unsigned int *pfb0;
       
        //打开lcd设备文件
        fb0_fd = open("/dev/fb0",O_RDWR);//只写
        if(-1 == fb0_fd)
        {
                perror("open fb0 fail");
        }
       
        //映射
        pfb0 = mmap(NULL,MMAP_LENTH,PROT_READ | PROT_WRITE,MAP_SHARED,fb0_fd,0);
        if ( pfb0 == MAP_FAILED)
        {
                perror("mmap fail");
                return 0;
        }
       
        //打开图像文件
        bmp_fd = open("/workspace/1.bmp",O_RDONLY);
        if( -1 == bmp_fd )
        {
                perror("open bmp fail");
        }
       
        //先跳过54字节bmp文件信息头
        lseek(bmp_fd,54,SEEK_SET);
        //再读出所有像素点数据
        read(bmp_fd,bmp_buf,800*480*3);

       
        for(y=0,j=0;y<480;y++)
        {
                for(x=0;x<800;x++,j+=3)
                {
                    //                               B                G                    R
                *(pfb0+(479-y)*800+ x) = (bmp_buf[j]<<0) | (bmp_buf[j+1]<<8) | (bmp_buf[j+2]<<16);
                }
        }
       
        close(fb0_fd);
        close(bmp_fd);
        munmap(pfb0,MMAP_LENTH);
        return 0;
}
举报

更多回帖

发帖
×
20
完善资料,
赚取积分