知识点1-lcd点亮->frame buffer、字库
一、frame buff 帧缓冲
1、概念:
帧缓存(fps一秒多少帧)
是一种图形硬件抽象层,它将显示设备的显存映射到系统内存中,使得应用程序可以直接通过读写内存来控制屏幕上的像素显示。这段代码实现了打开帧缓冲设备、获取设备的相关参数(如分辨率、位深度等),并将显存映射到用户空间的功能。
2、相关概念:
- 分辨率:宽高(广泛理解)
- 例如:imx6ull 板子的分辨率为:800*480(4.3寸)
- 色深:颜色空间、颜色深度、位深度(位越高,颜色越细腻)
- 类型:RGB、yuv、HSV
- 例如:imx6ull 板子的色深:RGB,888,24bit(位越高,颜色越细腻)
- imx6ull 板子的触屏接I2C
- 类型:RGB、yuv、HSV
- 一秒三十帧画面
- 大小:34M =800*480*3(RGB)*30(一秒30帧)
- 太大,所以采用并行传输(距离不能太远、速度越快越受到干扰)
3、lcd绘制:
实际屏幕对应一块显存,内存映射过来是一个长条,应用不能直接操作硬件,linux,驱动,合法手段内存映射mmap;如图所示
4、代码实现
void *pmem; //存储显存映射到用户后的起始地址
struct fb_var_screeninfo vinf; //结构体:存储:设备分辨率、色深等..//打开字符串为devname的帧缓冲设备
int init_fb(char *devname)
{
//1. 以读写模式打开帧缓冲设备文件
int fd = open(devname, O_RDWR);
if (-1 == fd)
{
perror("fail open fb");
return -1;
}
//2、获取显示设备相关参数 分辨率 位深度
int ret = ioctl(fd, FBIOGET_VSCREENINFO, &vinf);
if (-1 ==ret)
{
perror("fail ioctl");
return -1;
}
printf("xres = %d, yres = %d\n", vinf.xres, vinf.yres);
printf("xres_virtual = %d, yres_virtual = %d\n", vinf.xres_virtual, vinf.yres_virtual);
printf("bits_per_pixel : %d\n", vinf.bits_per_pixel);size_t len = vinf.xres_virtual * vinf.yres_virtual * vinf.bits_per_pixel/8;
//3, 建立显存和用户空间的映射关系(将显存映射到用户空间)
pmem = mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
if ((void *)-1 == pmem)
{
perror("fail mmap");
return -1;
}
return fd;
}
表格总结
步骤 | 函数调用 | 作用 | i.MX6ULL 特殊考量 |
---|---|---|---|
1 | open("/dev/fb0", ...) | 打开帧缓冲设备文件 | 需确认设备节点为 /dev/fb0 或 /dev/fb1 |
2 | ioctl(FBIOGET_VSCREENINFO) | 获取屏幕参数(分辨率/色深) | 需匹配芯片的显示控制器(如 DCSS/EPDC) |
3 | mmap() | 将显存映射到用户空间 | 物理地址需对齐 MX6ULL 的 MMU 配置 |
4 | 返回文件描述符 | 供后续绘图操作使用 | 需保持打开状态直到程序结束 |
5、显示点
//显示点
//传入点的位置,以及颜色
void draw_point(int x, int y, unsigned int col)
{//若超出边界则直接返回
if (x >= vinf.xres || y >= vinf.yres)
{
return ;
}//若色深为RGB 888 执行以下画点
if (vinf.bits_per_pixel == RGB888_FMT)
{//定义指针
unsigned int *p = pmem;//指向点位置(高度*一行的像素点+宽度)
*(p + y * vinf.xres_virtual + x) = col;
}
else if (vinf.bits_per_pixel == RGB565_FMT)
{
unsigned short *p = pmem;
*(p + y * vinf.xres_virtual + x) = col;
}
return ;
}main.c调用
draw_point(400, 300, 0x00ff0000);
6、显示图片
//显示图片
- int x, int y, 图片位置
- char *picname,存放源图片的路径
- int w, int h 图片的长宽
void draw_bmp(int x, int y, char *picname, int w, int h)
{
int fd = open(picname, O_RDONLY);
if (-1 == fd)
{
perror("fail open bmp");
return ;
}
lseek(fd, 54, SEEK_SET);unsigned char r, g, b;
unsigned char *buff = malloc(w*h*3);
read(fd, buff, w*h*3);
unsigned char *p = buff;
for (int j = h-1; j >= 0; j--)
{
for (int i = 0; i < w; i++)
{b = *p; p++;
g = *p; p++;
r = *p; p++;
if (vinf.bits_per_pixel == RGB888_FMT)
{
unsigned int col = (r << 16) | (g << 8) | (b << 0);
draw_point(i+x, j+y, col);
}
else if (vinf.bits_per_pixel == RGB565_FMT)
{
unsigned short col = ((r >> 3) << 11) | ((g >> 2) << 5) | ((b >> 3) << 0);
draw_point(i+x, j+y, col);
}
}
}free(buff);
close(fd);
}main.c 调用
draw_bmp(0, 0, "./res/3.bmp", 800, 480);
- 显示的图片还需要进行预处理(在window绘图软件进行)
- 将图片的长宽尺寸转为板子的分辨率(长800;宽480)
- 将图片另存为bmp:bit map(原始像素存储:前54byte 照片属性(长宽高))
- 将图片复制进虚拟机内部,并给图片读写权限
- 右键进入Properties
- 将其内的Permissions 的Access权限打开为:Read and Write
- 即可调用函数实现
7、显示字
1)字模创建(软件如图):
2)构建数组
复制字模软件生成的取模点阵,按照下面格式写成数组
3)函数调用
4)代码实现
- //显示字
- //int x, int y, 在哪显示
- //unsigned char *word, 字体的字模
- //int w, int h, 字体大小
- //unsigned int col 字体颜色
void draw_word(int x, int y, unsigned char *word, int w, int h, unsigned int col)
{for (int j = 0; j < h; j++)
{
for (int i = 0; i < w; i++)
{
unsigned char tmp = word[i+j*w];
for (int k = 0; k < 8; k++)
{
if (tmp & 0x80)
{
draw_point(i*8+k+x, j+y, col);
}
else
{
//文字的背景色
}
tmp = tmp << 1;
}
}
}
}main.c 调用
draw_word(300, 300, dan, 24/8, 22, 0x00ff0000);
- 24/8 :
- 24->宽(最好是8的整数倍,一般字模软件生成会调整)
- 8 固定
- 22:高
8、显示一段话(字库)
一段话一直一个单个字取模很麻烦,所以引入字库;
linux:一个汉字、两个字节
1)创建字库(软件如图):
2)初始化字库
3)查看字库权限
4)调用函数
5)代码实现
//显示一段话
int draw_utf8_str(UTF8_INFO *info, int arg_x, int arg_y, char* zi, unsigned int col, unsigned int col1)
{
char* temp = zi;
unsigned int x = arg_x ;
unsigned int y = arg_y;while(*temp != '\0')
{
int ret = draw_utf8(info, x, y, temp, col, col1);
x += info->width;
if(x > vinf.xres)
{
x = 0;
y += info->height;
if(y > vinf.yres)
{
y = 0;
}
}temp += ret;
}
return 0;
}main.c 调用
//初始化utf8字库
UTF8_INFO utf8_info;
bzero(&utf8_info, sizeof(UTF8_INFO));
strcpy(utf8_info.path, ZIKUK_FILE_BIG);
utf8_info.width = 32;
utf8_info.height = 32;
init_utf8(&utf8_info);//调用
draw_utf8_str(&utf8_info, 100, 100, "2025年10月8号", 0x00ff0000, 0x00ffffff);