1、开发板显示颜色
开发板大小为800*480,采用32位色深,Argb真彩色。,要显示颜色,只需要将每个像素点填充颜色。首先显示屏设备目录是:"/dev/fb0",先用函数open打开设备文件,然后将数据写到LCD。
int lcd_fd = open("/dev/fb0", O_RDWR);
if(lcd_fd == -1)
{
perror("lcd_fd");
return -1;
}
unsigned int red = 0xff0000;
for (int y = 0; y < 480 ; ++y)
{
for (int x = 0; x < 800; ++x)
{
write(lcd_fd, &red, 4);
}
}
close(lcd_fd);
这种方式要调用write 800*480次,屏幕显示也会有延时。所以我们需采用映射的方式,mmap函数可以将LCD映射到一个虚拟内存,这样我们对这个内存空间操作将会实时显示到LCD。
#include <sys/mman.h>
void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
参数列表: addr:内存映射起始的地址,若为NULL:系统自动分配 。
length:要映射的内存大小。
prot:PROT_READ:可读 PROT_WRITE:可写 ......
flags:多个进程在访问的时候,是否让其他进程可见,MAP_SHARED,允许其他进程可见,MAP_PRIVATE,跟MAP_SHARED相反......
fd:LCD屏的文件描述符
offset:偏移量
返回值: 成功:映射内存的起始地址 失败:(void *)-1
解除内存映射
int munmap(void *addr, size_t length);
addr:解除内存映射的地址
length:内存映射的大小
练习:在自定义位置显示一个红色的长方形
#include <sys/mman.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
int main(int argc, char const *argv[])
{
int lcd_fd = open("/dev/fb0", O_RDWR);
if(lcd_fd == -1)
{
perror("lcd_fd");
return -1;
}
unsigned int white = 0xffffff;
unsigned int red = 0xff0000;
int *p = mmap(NULL, 800*480*4, PROT_WRITE | PROT_READ, MAP_SHARED, lcd_fd, 0);
if(p == (void *)-1)
{
perror("mmap");
return -1;
}
//先将屏幕全部填充为白色背景
for (int y = 0; y < 480 ; ++y)
{
for (int x = 0; x < 800; ++x)
{
*(p+x+y*800) = white;
}
}
//在坐标(500,100)位置填充红色
for (int y = 100; y <= 150; ++y)
{
for (int x = 500; x <= 600 ; ++x)
{
*(p+x+y*800) = red;
}
}
close(lcd_fd);
munmap(p,800*480*4);
效果图:
2、开发板显示bmp格式图片
图片格式有bmp,jpg,png...... jpg和png格式的图片都经过了压缩,需要解压。而bmp没有压缩。可以直接读取数据。bmp图片文件头占14字节,位图信息头占40字节,之后的才是颜色数据。所以在读取图片信息时要跳过前面54字节。
bmp图像采用24位色深bgr,而LCD存储方式是32位rgb,则需要将数据转换成RGB在进行填充。由于显示屏是从上往下显示,而bmp图片数据是从下往上存储。所以我们在填充数据时要反向填充。
练习:显示图片
#include <sys/mman.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int main(int argc, char const *argv[])
{
int lcd_fd = open("/dev/fb0", O_RDWR);
if(lcd_fd == -1)
{
perror("lcd_fd");
return -1;
}
int *p = mmap(NULL, 800*480*4, PROT_WRITE | PROT_READ, MAP_SHARED, lcd_fd, 0);
if(p == (void *)-1)
{
perror("mmap");
return -1;
}
//打开图片
int bmp_fd = open("./1.bmp", O_RDWR);
if(bmp_fd == -1)
{
perror("bmp_fd");
return -1;
}
char buf1[800*480*3];
int buf[800*480];
read(lcd_bmp, buf1, 800*480*3); //读取数据
for (int i = 0; i < 800*480; ++i)
{
// b g r
buf[i] = buf1[3*i] | buf1[3*i+1] <<8 | buf1[3*i+2] << 16 | 0xff << 24; //拼接成rgb
}
for (int y = 0; y < 480; ++y)
{
for (int x = 0; x < 800; ++x)
{
p[x+(479-y)*800] = buf[y*800+x]; //反向填充
}
close(lcd_fd);
munmap(p,800*480*4);
return 0;
}
效果图:
如果图片尺寸小于800*480,我们需要获取图片宽度和高度如何去计算坐标,显示在任意位置。由于计算机读取数据是按固定字长如32位CPU一次读4字节。图片宽的字节数必须为4的倍数。不满足4的倍数计算机会自动补齐空白字节。
如下图 401240的bmp图片存储大小是401240*3+240(补齐的空白字节)
所以在读取是需要跳过空白字节
switch(width%4)
{
case 1:
for (int i = 0; i < height; ++i)
{
read(bmp_fd, buf+i*width*3, width*3);// 401*3= 1203 * 240
lseek(bmp_fd, 1, SEEK_CUR);
}break;
case 2:
for (int i = 0; i < height; ++i)
{
read(bmp_fd, buf+i*width*3, width*3);//402
lseek(bmp_fd, 2, SEEK_CUR);
}break;
case 3:
for (int i = 0; i < height; ++i)
{
read(bmp_fd, buf+i*width*3, width*3);//403
lseek(bmp_fd, 3, SEEK_CUR);
}break;
case 0:read(bmp_fd, buf, width*height*3); //若为0满足是4的倍数,不需要偏移,可直接读取。
}
练习:在中间显示图片400*240
首先读取宽度高度,可以定义一个结构体,也可以读取54字节然后取出宽和高对应位的数据。
1、读取54字节
char head[54];
read(bmp_fd, head, 54);
int width = head[18]| head[19]<<8| head[20]<<16| head[21]<<24;
int height = head[22]| head[23]<<8| head[24]<<16| head[25]<<24;
printf("width = %d\n", width);
printf("hight = %d\n", height);
2、定义结构体
typedef unsigned int u32;
typedef unsigned short u16;
typedef unsigned char u8;
#pragma pack(1) /* 取消字节对齐 */
typedef struct { /* bmp图片文件头信息封装 */
/* 位图文件头-14Byte */
u8 bit_file_type[2]; /* 位图文件类型:'BM'->0x4d42 */
u32 file_size; /* 整个文件大小 */
u16 reserved1; /* 保留字1 */
u16 reserved2; /* 保留字2 */
u32 offset; /* 文件头到位图数据之间的偏移量 */
/* 位图信息头-40Byte */
u32 head_size; /* 位图信息头长度 */
u32 width; /* 位图宽度 */ //19~22
u32 height; /* 位图高度 */ //23~26
u16 bit_planes; /* 位图位面数 */
u16 bits_per_pixel; /* 每个像素的位数 */
u32 compression; /* 压缩说明 */
u32 image_size; /* 位图数据大小 */
u32 h_res; /* 水平分辨率 */
u32 v_res; /* 垂直分辨率 */
u32 color_palette; /* 位图使用的颜色索引数 */
u32 vip_color; /* 重要的颜色索引数目 */
}bmp_head;
#pragma pack() /* 恢复字节对齐 */
bmp_head head; //定义一个结构体
read(lcd_bmp, &head, 54);
printf("宽:%d\n", head.width);
printf("高:%d\n", head.height);
显示图片:
#include <sys/mman.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int main(int argc, char const *argv[])
{
//采用传参方式
if(argc != 2)
{
printf("./bmp <filename>\n");
return 0;
}
int lcd_fd = open("/dev/fb0", O_RDWR);
if(lcd_fd == -1)
{
perror("lcd_fd");
return -1;
}
int *p = mmap(NULL, 800*480*4, PROT_WRITE | PROT_READ, MAP_SHARED, lcd_fd, 0);
if(p == (void *)-1)
{
perror("mmap");
return -1;
}
int bmp_fd = open(argv[1], O_RDWR);
if(bmp_fd == -1)
{
perror("lcd_bmp");
return -1;
}
unsigned char b, g, r;
char head[54];
read(bmp_fd, head, 54);
int width = head[18]| head[19]<<8| head[20]<<16| head[21]<<24;
int height = head[22]| head[23]<<8| head[24]<<16| head[25]<<24;
char buf1[width*height*3];
int st_x = (800-width) / 2;
int st_y = (480-height) / 2;
read(bmp_fd, buf1, width*height*3);
int i = 0;
for (int y = 0; y < height; ++y)
{
for (int x = 0; x < width; ++x)
{
b = buf1[i++];
g = buf1[i++];
r = buf1[i++];
p[st_x+x+(479-st_y-y)*800] = b | g <<8 | r <<16; //倒转填充
}
}
close(lcd_fd);
munmap(p,800*480*4);
return 0;
}
效果图: