从一个例子看ASCII点阵字库的应用原理

本文详细介绍了Linux内核如何使用内置字库在Framebuffer上显示ASCII字符,重点解析了字体数据结构和fbcon配置,展示了字符绘制的代码示例,探讨了颜色处理和像素操作。同时,给出了一个在Framebuffer设备上绘制字符A的C语言程序,但程序结果显示字符为躺着的状态,原因未明。
摘要由CSDN通过智能技术生成

Linux内核中使用了内建的字库用于在framebuffer上显示ascii码字形信息,具体定义在文件

linux-stable/lib/fonts/fonts.c

通过fbcon=符号指定,

fbcon=font:VGA8x16

fbcon指定的信息在内核中会被以下函数解析:

内核的自形库数据组织结构:

 以其中的font_vga_8x16为例:

 其结构中内部指定了fontdata_8x16字库文件,字库文件中存储有字形信息:

下面以一个程序为例,来说明字形库的用法: 

Framebuffer书写字符A的代码:

#include <unistd.h>  
#include <stdio.h>  
#include <fcntl.h>  
#include <linux/fb.h>  
#include <sys/mman.h>  
#include <stdlib.h>  
#include <string.h>

#define RED    0xF800
#define YELLOW    0xFFE0
#define BLUE     0x001F
#define WHITE    0xFFFF 
#define BLACK    0x0000

struct fb_var_screeninfo vinfo;  
static const unsigned char fontdata_8x16[16] = {
0x00,
0x00,
0x10,
0x38,
0x6c,
0xc6,
0xc6,
0xfe,
0xc6,
0xc6,
0xc6,
0xc6,
0x00,
0x00,
0x00,
0x00,
};
unsigned char *fbmem;
/* color : 0x00RRGGBB */
void lcd_put_pixel(int x, int y, unsigned int color)
{
	unsigned char *pen_8 = fbmem+y*4 + x*vinfo.xres*4;
	//找到对应的像素在内存中的位置,后面向其(*pen_8)写颜色值。
	//通过pen_8来操作fbmem,实现LCD显示
	unsigned short *pen_16;	
	unsigned int *pen_32;	
 
	unsigned int red, green, blue;	
 
	pen_16 = (unsigned short *)pen_8;
	pen_32 = (unsigned int *)pen_8;
 
	switch (vinfo.bits_per_pixel)
	//不同的像素位数,颜色值格式不同。根据像素位数设置对应的颜色值格式,并写值。
	{
		case 8:
		{
			*pen_8 = color;//8位像素的话,颜色值直接赋给这个内存中即可。
			break;
		}
		case 16:
		{
			/* color : 0x00RRGGBB ,unsigned int 32位color的格式*/
			/* 565 */
			red   = (color >> 16) & 0xff;
			//右移16位后剩下高16位,再&0xff,又剩下低8位。即取出32位color的16-23位
			green = (color >> 8) & 0xff;//取出32color的8-15位
			blue  = (color >> 0) & 0xff;//取出32color的0-7位
			color = ((red >> 3) << 11) | ((green >> 2) << 5) | (blue >> 3);
			//取出对应的组成565
			*pen_16 = color;
			break;
		}
		case 32:
		{
			*pen_32 = color;//32位像素也直接写即可。
			break;
		}
		default:
		{
			printf("can't surport %dbpp\n", vinfo.bits_per_pixel);
			break;
		}
	}
}

void fill_color16(short *fb_addr, short bit_map, int psize)
{
    int i;
    for(i=0; i<psize; i++) {
        *fb_addr = bit_map;
        fb_addr++;
    }
}

void lcd_put_ascii(int x, int y, unsigned char c)
{
	c = 0;
	unsigned char *dots = (unsigned char *)&fontdata_8x16[c*16];
	//从fontdata_8x16[FONTDATAMAX]数组中获得点阵起始位置
	int i, b;
	unsigned char byte;
 
	for (i = 0; i < 16; i++)//点阵有16行
	{
		byte = dots[i];
		for (b = 7; b >= 0; b--)//点阵有8列
		{
			if (byte & (1<<b))//判断点阵中的各个点是否为1
			{
				/* show */
				lcd_put_pixel(x+7-b, y+i, 0xffff0000); /* 白 */
			}
			else
			{
				/* hide */
				lcd_put_pixel(x+7-b, y+i, 0); /* 黑 */
			}
		}
	}
}


int main ()   
{  
    int fp=0;  
    struct fb_fix_screeninfo finfo;  
    long screensize=0;  
    char *fbp = NULL, *test_fbp=NULL;    
    int x = 0, y = 0;  
    long location = 0;
    int i;
    int num = 5;
    int pix_size=0;

    fp = open("/dev/fb0", O_RDWR);  

    if(fp < 0) {  
        printf("Error : Can not open framebuffer device/n");  
        exit(1);  
    }  

    if(ioctl(fp, FBIOGET_FSCREENINFO, &finfo)){  
        printf("Error reading fixed information/n");  
        exit(2);  
    }  

    if(ioctl(fp, FBIOGET_VSCREENINFO, &vinfo)){  
        printf("Error reading variable information/n");  
        exit(3);  
    }  

    screensize = vinfo.xres * vinfo.yres * vinfo.bits_per_pixel / 8;  

    printf("The phy mem = 0x%lx, total size = %d(byte)\n", finfo.smem_start, finfo.smem_len);  
    printf("xres =  %d, yres =  %d, bits_per_pixel = %d\n", vinfo.xres, vinfo.yres, vinfo.bits_per_pixel);  
    printf("So the screensize = %ld(byte), using %ld frame\n", screensize, finfo.smem_len/screensize);
    printf("vinfo.xoffset = %d, vinfo.yoffset = %d\n", vinfo.xoffset, vinfo.yoffset);  
    printf("vinfo.vmode is :%d\n", vinfo.vmode);  
    printf("finfo.ypanstep is :%d\n", finfo.ypanstep);  
    printf("vinfo.red.offset=0x%x\n", vinfo.red.offset);
    printf("vinfo.red.length=0x%x\n", vinfo.red.length);
    printf("vinfo.green.offset=0x%x\n", vinfo.green.offset);
    printf("vinfo.green.length=0x%x\n", vinfo.green.length);
    printf("vinfo.blue.offset=0x%x\n", vinfo.blue.offset);
    printf("vinfo.blue.length=0x%x\n", vinfo.blue.length);
    printf("vinfo.transp.offset=0x%x\n", vinfo.transp.offset);
    printf("vinfo.transp.length=0x%x\n", vinfo.transp.length);
    

    fbp =(char *)mmap(0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED, fp,0);  
    if ((int)fbp == -1)  
    {    
        printf ("Error: failed to map framebuffer device to memory.\n");  
        exit (4);  
    }
    printf("Get virt mem = %p\n", fbp);  

	fbmem = fbp;

    pix_size = vinfo.xres * vinfo.yres;
    /* using first frame, for FBIOPAN_DISPLAY
     * 当刷新需要调用FBIOPAN_DISPLAY, 要告知驱动刷哪块帧, 用到下面两个参数
     * 如果使用第二帧buffer -> vinfo.xoffset = 0; vinfo.yoffset = vinfo.yres;
     */
    vinfo.xoffset = 0;
    vinfo.yoffset = 0;

    int xx = 0, yy = 0;
    int j = 10;

    while(j--)
    {
        lcd_put_ascii(xx, yy, 1);
	xx = xx + 32;
	yy = yy + 32;
    }

#if 0
    /* show color loop */
    while(num--) {
        printf("\ndrawing YELLOW......\n");
        fill_color16((short *)fbp, YELLOW, pix_size);
        //ioctl(fp, FBIOPAN_DISPLAY, &vinfo);
        sleep(3);

        printf("\ndrawing BLUE......\n");
        fill_color16((short *)fbp, BLUE, pix_size);
        //ioctl(fp, FBIOPAN_DISPLAY, &vinfo);
        sleep(3);
        
        printf("\ndrawing RED......\n");
        fill_color16((short *)fbp, RED, pix_size);
        //ioctl(fp, FBIOPAN_DISPLAY, &vinfo);
        sleep(3);
    }
#if 1
    /*这是你想画的点的位置坐标,(0,0)点在屏幕左上角*/    
    x = 10;  
    y = 10;  
    location = x * (vinfo.bits_per_pixel / 8) + y  *  finfo.line_length;  
    test_fbp = fbp + location;
    printf("draw line.......\n");
    for(i = 0; i < (vinfo.xres - x); i++)
        *test_fbp++ = i+30;

    //ioctl(fp, FBIOPAN_DISPLAY, &vinfo);
#endif
#endif

    munmap(fbp, screensize); /*解除映射*/  

    close (fp);
    return 0;
}

结果:

至于为什么是躺着的,还不清楚原因。

结束!

  • 7
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

papaofdoudou

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值