在 Linux 系统中,/dev/fb0 是**帧缓冲设备(framebuffer device)**的默认节点,对应于第一个物理或虚拟的图形输出(通常是主显示器)。它提供了一个低级的、像素级的接口,允许用户空间程序直接读写屏幕上的像素数据,绕过 X11/Wayland 等高级图形栈。
关于fb的基本概念
帧缓冲(Framebuffer):一块内存区域,存储屏幕上每个像素的颜色值(如 RGB)。
/dev/fb0:第一个帧缓冲设备(第二个是 /dev/fb1,以此类推)。
颜色格式:通常为 RGB565、RGB888、ARGB8888 等(通过 fb_var_screeninfo 查询)。
一、关于fd的操作
停止 LightDM 显示管理器服务,从而关闭图形界面。运行fd demo时需要先执行此命令,保证LightDM释放fd设备。
service lightdm stop
确认fd设备存在
ls -l /dev/fb0

查看内核日志中的帧缓冲信息
dmesg | grep -i fb
显示当前分辨率、颜色深度等
fbset -fb /dev/fb0

二、lcd_demo
在官方的demo中提供了lcd_demo,运行起来大概是这样的:


在HDMI设备上显示彩色条纹
lcd_demo.c中提供了画点函数,就用这个函数,开始fd的学习吧
void drawPixel(char *fbp, unsigned long location, PIXEL *pixel, int bpp) {
unsigned short rgb = 0;
unsigned int r = 0, g = 0, b = 0;
switch (bpp) {
case 32:
*(fbp + location) = pixel->blue;
*(fbp + location + 1) = pixel->green;
*(fbp + location + 2) = pixel->red;
*(fbp + location + 3) = pixel->trans;
break;
case 24:
*(fbp + location) = pixel->blue;
*(fbp + location + 1) = pixel->green;
*(fbp + location + 2) = pixel->red;
break;
case 16:
r = (pixel->red * 0x1f) / 0xff;
g = (pixel->green * 0x3f) / 0xff;
b = (pixel->blue * 0x1f) / 0xff;
rgb = (r << 11) | (g << 5) | b;
*((unsigned short*)(fbp + location)) = rgb;
break;
default:
printf("Error: No fit bpp\n");
break;
}
}
三、fd设备编程
1、获取屏幕参数
#include <linux/fb.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <stdio.h>
int main() {
int fb = open("/dev/fb0", O_RDWR);
struct fb_var_screeninfo vinfo;
ioctl(fb, FBIOGET_VSCREENINFO, &vinfo);
printf("Resolution: %dx%d\n", vinfo.xres, vinfo.yres);
printf("Bits per pixel: %d\n", vinfo.bits_per_pixel);
close(fb);
return 0;
}

2、映射帧缓冲到内存
通过 mmap 将设备内存映射到用户空间
#include <sys/mman.h>
#include <unistd.h>
#include <stdint.h>
int fbp= open("/dev/fb0", O_RDWR);
struct fb_fix_screeninfo finfo;
ioctl(fbp, FBIOGET_FSCREENINFO, &finfo);
size_t screensize = vinfo.yres_virtual * finfo.line_length;
uint8_t *fbp= mmap(NULL, screensize, PROT_READ | PROT_WRITE, MAP_SHARED, fb, 0);
3、绘制矩形函数
此函数调用画点函数
void drawRectangle(char *fbp, int x, int y, int w, int h, PIXEL *pixel, int width,int height,int line_length,int bpp) {
for (int i = y; i < y + h; i++) {
for (int j = x; j < x + w; j++) {
long location = (width + j) * (bpp/8)+(i+height)*line_length;
drawPixel(fbp, location, pixel, bpp);
}
}
}
4、运行个例子
int main() {
int fb = open("/dev/fb0", O_RDWR);
struct fb_var_screeninfo vinfo;
struct fb_fix_screeninfo finfo;
ioctl(fb, FBIOGET_VSCREENINFO, &vinfo);
ioctl(fb, FBIOGET_FSCREENINFO, &finfo);
printf("Resolution: %dx%d\n", vinfo.xres, vinfo.yres);
printf("Bits per pixel: %d\n", vinfo.bits_per_pixel);
size_t screensize = vinfo.yres_virtual * finfo.line_length;
char *fbp = mmap(NULL, screensize, PROT_READ | PROT_WRITE, MAP_SHARED, fb, 0);
memset(fbp, 0xff000000, screensize);
for(int k=0;k<8;k++)
{
for(int i=0;i<4;i++)
{
for(int j=0;j<8;j++)
{
PIXEL pixel = { 0x00, 0x00, 0x00, 0x00 };
pixel.red = 0x00;
pixel.green = 0x00;
pixel.blue = 0xff;
pixel.trans = 0x00;
int x;
x=((j+k)%2==0)?0:1;
drawRectangle(fbp,i*200+x*100,j*100,100,100,&pixel, vinfo.xoffset,vinfo.yoffset,finfo.line_length,vinfo.bits_per_pixel);
pixel.red = 0xFF;
pixel.green = 0xff;
pixel.blue = 0xff;
pixel.trans = 0x00;
x=((j+k)%2==0)?1:0;
drawRectangle(fbp,i*200+x*100,j*100,100,100,&pixel, vinfo.xoffset,vinfo.yoffset,finfo.line_length,vinfo.bits_per_pixel);
}
}
usleep(500000);
}
munmap(fbp, screensize);
close(fb);
return 0;
}
typedef struct {
char red;
char green;
char blue;
char trans;
} PIXEL;

四、显示JPG图片
为了显示JPG图片,需要对jpg进行解码(硬件或软件解码),然后将解码后的文件绘制到屏幕上
1、JPG 硬件解码
int decode_jpeg(const char *filename, unsigned char **output,
int *width, int *height, int *bpp) {
struct jpeg_decompress_struct cinfo;
struct jpeg_error_mgr jerr;
FILE *infile;
JSAMPARRAY buffer;
int row_stride;
if ((infile = fopen(filename, "rb")) == NULL) {
fprintf(stderr, "Can't open %s\n", filename);
return -1;
}
cinfo.err = jpeg_std_error(&jerr);
jpeg_create_decompress(&cinfo);
jpeg_stdio_src(&cinfo, infile);
jpeg_read_header(&cinfo, TRUE);
jpeg_start_decompress(&cinfo);
*width = cinfo.output_width;
*height = cinfo.output_height;
*bpp = cinfo.output_components * 8;
*output = (unsigned char *)malloc(cinfo.output_width * cinfo.output_height * cinfo.output_components);
row_stride = cinfo.output_width * cinfo.output_components;
buffer = (*cinfo.mem->alloc_sarray)((j_common_ptr)&cinfo, JPOOL_IMAGE, row_stride, 1);
unsigned char *ptr = *output;
while (cinfo.output_scanline < cinfo.output_height) {
jpeg_read_scanlines(&cinfo, buffer, 1);
memcpy(ptr, buffer[0], row_stride);
ptr += row_stride;
}
jpeg_finish_decompress(&cinfo);
jpeg_destroy_decompress(&cinfo);
fclose(infile);
return 0;
}
2、JPG软件解码
int decode_jpeg_sw(const char *filename, unsigned char **output,
int *width, int *height, int *bpp) {
struct jpeg_decompress_struct cinfo;
struct my_error_mgr jerr;
FILE *infile;
JSAMPARRAY buffer;
int row_stride;
if ((infile = fopen(filename, "rb")) == NULL) {
fprintf(stderr, "Can't open %s\n", filename);
return -1;
}
cinfo.err = jpeg_std_error(&jerr.pub);
jerr.pub.error_exit = my_error_exit;
if (setjmp(jerr.setjmp_buffer)) {
jpeg_destroy_decompress(&cinfo);
fclose(infile);
return -1;
}
jpeg_create_decompress(&cinfo);
jpeg_stdio_src(&cinfo, infile);
jpeg_read_header(&cinfo, TRUE);
jpeg_start_decompress(&cinfo);
*width = cinfo.output_width;
*height = cinfo.output_height;
*bpp = cinfo.output_components * 8;
*output = (unsigned char *)malloc(cinfo.output_width * cinfo.output_height * cinfo.output_components);
if (!*output) {
fprintf(stderr, "Memory allocation failed\n");
jpeg_destroy_decompress(&cinfo);
fclose(infile);
return -1;
}
row_stride = cinfo.output_width * cinfo.output_components;
buffer = (*cinfo.mem->alloc_sarray)((j_common_ptr)&cinfo, JPOOL_IMAGE, row_stride, 1);
unsigned char *ptr = *output;
while (cinfo.output_scanline < cinfo.output_height) {
jpeg_read_scanlines(&cinfo, buffer, 1);
memcpy(ptr, buffer[0], row_stride);
ptr += row_stride;
}
jpeg_finish_decompress(&cinfo);
jpeg_destroy_decompress(&cinfo);
fclose(infile);
return 0;
}
3、显示JPG函数
void display_jpeg(char *fbp, const char *filename, int x, int y,
int screen_width, int screen_height, int bpp) {
unsigned char *jpeg_data = NULL;
int jpeg_width, jpeg_height, jpeg_bpp;
if (decode_jpeg(filename, &jpeg_data, &jpeg_width, &jpeg_height, &jpeg_bpp) != 0) {
if (decode_jpeg_sw(filename, &jpeg_data, &jpeg_width, &jpeg_height, &jpeg_bpp) != 0) {
fprintf(stderr, "Failed to decode JPEG image\n");
return;
}
}
int draw_width = (x + jpeg_width > screen_width) ? (screen_width - x) : jpeg_width;
int draw_height = (y + jpeg_height > screen_height) ? (screen_height - y) : jpeg_height;
for (int i = 0; i < draw_height; i++) {
for (int j = 0; j < draw_width; j++) {
unsigned long location = ((y + i) * screen_width + (x + j)) * (bpp / 8);
unsigned long jpeg_offset = (i * jpeg_width + j) * (jpeg_bpp / 8);
PIXEL pixel;
if (jpeg_bpp == 24) {
pixel.red = jpeg_data[jpeg_offset];
pixel.green = jpeg_data[jpeg_offset + 1];
pixel.blue = jpeg_data[jpeg_offset + 2];
pixel.trans = 0xFF;
} else if (jpeg_bpp == 32) {
memcpy(&pixel, jpeg_data + jpeg_offset, sizeof(PIXEL));
} else {
fprintf(stderr, "Unsupported JPEG format\n");
free(jpeg_data);
return;
}
4、运行个例子
int main(int argc, char *argv[]) {
int fbfd = 0;
char *fbp = NULL;
struct fb_var_screeninfo vinfo;
struct fb_fix_screeninfo finfo;
fbfd = open(DEFAULT_FB_DEV, O_RDWR);
if (!fbfd) {
printf("Error: cannot open framebuffer device.\n");
exit(INADEQUATE_CONDITIONS);
}
if (ioctl(fbfd, FBIOGET_FSCREENINFO, &finfo)) {
printf("Error reading fixed information.\n");
close(fbfd);
exit(INADEQUATE_CONDITIONS);
}
if (ioctl(fbfd, FBIOGET_VSCREENINFO, &vinfo)) {
printf("Error reading variable information.\n");
close(fbfd);
exit(INADEQUATE_CONDITIONS);
}
else
printf("%dx%d, %dbpp\n", vinfo.xres, vinfo.yres, vinfo.bits_per_pixel);
fbp = (char *)mmap(0, finfo.smem_len, PROT_READ | PROT_WRITE, MAP_SHARED, fbfd, 0);
if (fbp == MAP_FAILED) {
printf("Error: failed to map framebuffer device to memory.\n");
close(fbfd);
exit(INADEQUATE_CONDITIONS);
}
int screen_width = vinfo.xres;
int screen_height = vinfo.yres;
int bpp = vinfo.bits_per_pixel;
PIXEL pixel;
pixel.red = 0x00;
pixel.green = 0x00;
pixel.blue = 0x00;
pixel.trans = 0x00;
while (!g_quit) {
clearScreen(fbp,&pixel,screen_width, screen_height, bpp);
display_jpeg(fbp, "test1.jpg", 0, 0, screen_width, screen_height, bpp);
usleep(1500000);
clearScreen(fbp,&pixel,screen_width, screen_height, bpp);
display_jpeg(fbp, "test2.jpg", 0, 0, screen_width, screen_height, bpp);
clearScreen(fbp,&pixel,screen_width, screen_height, bpp);
display_jpeg(fbp, "test3.jpg", 0, 0, screen_width, screen_height, bpp);
usleep(1500000);
clearScreen(fbp,&pixel,screen_width, screen_height, bpp);
display_jpeg(fbp, "test4.jpg", 0, 0, screen_width, screen_height, bpp);
}
munmap(fbp, finfo.smem_len);
close(fbfd);
return 0;
}