使用之前首先要了解一下,所使用的开发板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++)//行循环
{
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);
//通过行列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:是想取消的内存大小。
所以 赋值操作应该是 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;
}