嵌入式学习(day26)frambuffer帧缓冲

发布于:2025-08-16 ⋅ 阅读:(18) ⋅ 点赞:(0)

一、UI技术: User interface

(1)framebuffer: 帧缓冲、帧缓存技术
Linux内核专门为图形化显示提供的一套应用程序接口。

流程如下:

1. 打开显示设备 (/dev/fb0)
2. 获取显示设备相关参数(分辨率,像素格式)---》ioctl
3. 建立显存空间和用户空间的内存映射
4. 向映射的用户空间写入RGB颜色值
5. 解除映射关系
6. 关闭显示设备

二、mmap(内存映射)函数使用:将显存映射到用户空间,方便直接读写:

void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
功能: 建立内存映射
参数:
    addr: 映射的用户空间首地址
        NULL: 让操作系统自己分配用户空间
    length: 要映射的空间大小
    prot: 操作权限
        PROT_READ Pages may be read.
        PROT_WRITE Pages may be written
    flag: MAP_SHARED
    fd: 显示设备文件描述符
    offset: 偏移量
        0: 从显存开头映射
返回值:
    成功: 映射的用户空间首地址
    失败: MAP_FAILED ((void *)-1)

三、练习:

1. 封装函数绘制横线
2. 封装函数绘制竖线
3. 封装函数绘制矩形
4. 封装函数绘制圆
5. 封装函数绘制bmp图片
6. 封装函数绘制文字

framebuffer.c

//framebuffer.c文件:

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <linux/fb.h>
#include <sys/mman.h>
#include "framebuffer.h"
#include <math.h>

void *pmem = NULL;
int fb;
struct fb_var_screeninfo vinfo;

int init_fb(char *devname)
{
    //1. 打开显示设备(/dev/fb0)
    fb = open(devname, O_RDWR);
    if (-1 == fb)
    {
        perror("open fb error");
        return -1;
    }

    //2. 获取显示设备相关参数(分辨率,像素格式)
   
    int ret = ioctl(fb, FBIOGET_VSCREENINFO, &vinfo);
    if (ret < 0)
    {
        perror("ioctl error");
        return -1;
    }

    printf("xres = %d, yres = %d\n", vinfo.xres, vinfo.yres);
    printf("xres_virtual = %d, yres_virtual = %d\n", vinfo.xres_virtual, vinfo.yres_virtual);
    printf("bits_per_pixel = %d\n", vinfo.bits_per_pixel);

    //3. 建立显存空间和用户空间的内存映射
    size_t len = vinfo.xres_virtual * vinfo.yres_virtual * vinfo.bits_per_pixel/8;
    pmem = mmap(NULL, len, PROT_READ|PROT_WRITE, MAP_SHARED, fb, 0);
    if (pmem == MAP_FAILED)
    {
        perror("mmap error");
        return -1;
    }

    return 0;
}

int uninit_fb()
{
    //5. 解除映射关系
    //6. 关闭显示设备
    size_t len = vinfo.xres_virtual * vinfo.yres_virtual * vinfo.bits_per_pixel/8;
    munmap(pmem, len);
    close(fb);

}

void draw_point(int x, int y, unsigned int col)
{
    if (x >= vinfo.xres || y >= vinfo.yres)
    {
        return ;
    }
    if (vinfo.bits_per_pixel == RGB_FMT_888)
    {
        unsigned int *p = pmem;
        *(p+vinfo.xres_virtual*y+x) = col;
    }
    else if (vinfo.bits_per_pixel == RGB_FMT_565)
    {
        unsigned short *p = pmem;
        *(p+vinfo.xres_virtual*y+x) = col;
    }
}

void draw_x_line(int x1,int x2,int y,unsigned int col)
{
    if(x1 >= vinfo.xres || x2 >= vinfo.xres || y >= vinfo.yres)
    {
        return;
    }
    for(int i = 0;i < x2 - x1;++i)
    {
        if(vinfo.bits_per_pixel == RGB_FMT_888)
        {
            unsigned int *p =pmem;
            *(p+vinfo.xres_virtual*y+(x1+i))= col;
        }
        else if(vinfo.bits_per_pixel == RGB_FMT_565)
        {
            unsigned short *p = pmem;
            *(p+vinfo.xres_virtual*y+(x1+i))=col;
        }
    }

}
void draw_y_line(int x,int y1,int y2,unsigned int col)
{
    if(x >= vinfo.xres || y1 >= vinfo.yres || y2 >=vinfo.yres)
    {
        return;
    }
    for(int i = 0;i < y2-y1;++i)
    {
        if(vinfo.bits_per_pixel == RGB_FMT_888)
        {
            unsigned int *p = pmem;
            *(p + vinfo.xres_virtual*(y1+i)+x) = col;
        }
        else if(vinfo.bits_per_pixel == RGB_FMT_565)
        {
            unsigned short *p =pmem;
            *(p+vinfo.xres_virtual*(y1+i)+x) = col;
        }
    }
}

void draw_rect(int x, int y, int w, int h, unsigned int col) 
{
    if (w <= 0 || h <= 0) return;  // 宽度或高度无效
    draw_x_line(x, x + w - 1, y, col);        // 上边
    draw_x_line(x, x + w - 1, y + h - 1, col);// 下边
    draw_y_line(x, y, y + h - 1, col);        // 左边
    draw_y_line(x + w - 1, y, y + h - 1, col);// 右边
}


void draw_circle(int x, int y, int r, unsigned int col)
{
    int x0 = 0;
    int y0 = 0;
    int si = 0;

    for (si = 0; si <= 360; si++)
    {
        x0 = r * sin(3.14 * 2 / 360 * si) + x; 
        y0 = r * cos(3.14 * 2 / 360 * si) + y;

        draw_point(x0, y0, col);
    }
}


int get_bmp_head_info(const char *bmpname, Bmp_file_head_t *pheadinfo, Bmp_info_t *pbmpinfo)
{
	FILE *fp = fopen(bmpname, "r");
	if (NULL == fp)
	{
		perror("fopen error");
		return -1;
	}
	

	fread(pheadinfo, sizeof(Bmp_file_head_t), 1, fp);
	fread(pbmpinfo, sizeof(Bmp_info_t), 1, fp);


	fclose(fp);

	return 0;
}

void draw_bmp(int x, int y, char *bmpname)
{
    Bmp_file_head_t headinfo;
	Bmp_info_t bmpinfo;
	
	get_bmp_head_info("./1.bmp", &headinfo, &bmpinfo);

    int fd = open(bmpname, O_RDONLY);
    if (-1 == fd)
    {
        perror("open bmp error");
        return ;
    }
    lseek(fd, 54, SEEK_SET);
    unsigned char *buff = malloc(bmpinfo.biHeight*bmpinfo.biWidth*bmpinfo.biBitCount/8);
    read(fd, buff, bmpinfo.biHeight*bmpinfo.biWidth*bmpinfo.biBitCount/8);
    close(fd);

    unsigned char *p = buff;
    unsigned char r, g, b;

    for (int j = bmpinfo.biHeight-1; j >= 0; j--)
    {
        for (int i = 0; i < bmpinfo.biWidth; i++)
        {
            b = *p;++p;
            g = *p;++p;
            r = *p;++p;
             if (vinfo.bits_per_pixel == RGB_FMT_888)
             {
                unsigned int col = (r << 16) | (g << 8) | (b << 0);
                draw_point(i+x, j+y, col);
             }
             else if  (vinfo.bits_per_pixel == RGB_FMT_565)
             {
                unsigned short col = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
                draw_point(i+x, j+y, col);
             }
        }

    }

    free(buff);

}


void draw_word(int x, int y, unsigned char *pword, int w, int h, unsigned int col)
{
    for (int j = 0; j < h; j++)
    {
        for (int i = 0; i < w; i++)
        {
            unsigned char tmp = pword[i+j*w];
            for (int k = 0; k < 8; k++)
            {
                if (tmp & 0x80)
                {
                    draw_point(x+i*8+k, y+j, col);
                }
                else
                {

                }
                tmp = tmp << 1;
            }
        }

    }
}
//framebuffer.h文件:


#ifndef __FRAMEBUFFER_H__
#define __FRAMEBUFFER_H__

#define RGB_FMT_888 32
#define RGB_FMT_565 16

#pragma pack(1)

//bmp文件相关信息
typedef struct tagBITMAPFILEHEADER {
    short    bfType;         // 文件类型标志
    int      bfSize;         // 文件大小,单位为字节
    short    bfReserved1;    // 保留字节
    short    bfReserved2;    // 保留字节
    int      bfOffBits;      // 数据偏移量,即实际图像数据开始的位置
}Bmp_file_head_t;
//bmp图像信息
typedef struct tagBITMAPINFOHEADER {
    int   biSize;         // BITMAPINFOHEADER的大小,单位为字节
    int    biWidth;        // 位图的宽度,单位为像素
    int    biHeight;       // 位图的高度,单位为像素
    short    biPlanes;       // 目标设备的位平面数,必须为1
    short    biBitCount;     // 每像素位数(颜色深度)
    int   biCompression;  // 图像压缩类型
    int   biSizeImage;    // 图像大小,单位为字节
    int    biXPelsPerMeter;// 水平分辨率,单位为像素/米
    int    biYPelsPerMeter;// 垂直分辨率,单位为像素/米
    int   biClrUsed;      // 实际使用颜色数
    int   biClrImportant; // 重要颜色数
}Bmp_info_t;
#pragma pack()


extern int init_fb(char *devname);
extern int uninit_fb();
extern void draw_point(int x,int y,unsigned int col);
extern void draw_x_line(int x1,int x2,int y,unsigned int col);
extern void draw_y_line(int x,int y1,int y2,unsigned int col);
extern void draw_rect(int x,int y,int w,int h,unsigned int col);
extern void draw_circle(int x, int y, int r, unsigned int col);
extern int get_bmp_head_info(const char *bmpname, Bmp_file_head_t *pheadinfo, Bmp_info_t *pbmpinfo);
extern void draw_bmp(int x, int y, char *bmpname);
extern void draw_word(int x, int y, unsigned char *pword, int w, int h, unsigned int col);


#endif
//main.c文件:



#include <stdio.h>
#include "framebuffer.h"

/*
1. 打开显示设备(/dev/fb0)
2. 获取显示设备相关参数(分辨率,像素格式)
3. 建立显存空间和用户空间的内存映射
4. 向映射的用户空间写入RGB颜色值
5. 解除映射关系
6. 关闭显示设备
*/

unsigned char D[2*33]={/*--  文字:  D  --*/
/*--  仿宋24;  此字体下对应的点阵为:宽x高=16x33   --*/
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x80,0xFF,0xE0,
0x38,0x78,0x38,0x3C,0x38,0x1C,0x38,0x1E,0x38,0x1E,0x38,0x1E,0x38,0x0E,0x38,0x0E,
0x38,0x0E,0x38,0x0E,0x38,0x0E,0x38,0x0E,0x38,0x1E,0x38,0x1E,0x38,0x1E,0x38,0x1C,
0x38,0x3C,0x38,0x78,0x38,0xF0,0xFF,0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00};



int main(void)
{
    
    int ret = init_fb("/dev/fb0");
    if (ret < 0)
    {
        return -1;
    }

    //4. 向映射的用户空间写入RGB颜色值

    //draw_point(400, 300, 0x00FF0000);
    draw_x_line(200,500,200,0xFF00FF00);
    draw_y_line(300,100,500,0xFFFFFFFF);
    draw_rect(100,100,200,150,0xFFFFFFFF);
    
    draw_circle(100, 100, 50, 0xFF0000); 
   // draw_bmp(0, 0, "./1.bmp");

    //draw_word(200, 300, D, 2, 33, 0x00FF0000);


    uninit_fb();

    return 0;
}


网站公告

今日签到

点亮在社区的每一天
去签到