Linux嵌入式学习——字符显示代码

该文详细介绍了如何在基于I.MX6ULL芯片的系统上,利用Linaro的交叉编译工具链操作framebuffer,包括按像素绘制图像和显示ASCII及汉字的方法。代码示例展示了如何打开framebuffer设备,获取LCD参数,映射内存以及实现不同颜色深度的点、线和字符绘制功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、环境

板子:I.MX6ULL

交叉编译链:Linaro 的交叉编译器

二、代码

1.按pixel绘制图像

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <linux/fb.h>
#include <sys/mman.h>
#include <string.h>

int line_width;
int pixel_width;
int screen_size;
unsigned char* fb_base;
static struct fb_var_screeninfo var;

//描点函数
void lcd_put_pixel(int x,int y,unsigned int color)
{
        unsigned char* pen_8 = fb_base + y*line_width + x*pixel_width;
        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(var.bits_per_pixel)
        {
                case 8:
                        *pen_8 = color;
                        break;
                case 16:
                        {
                                /*565*/
                                red = color>>16 & 0xff;
                                green = color>>8 & 0xff;
                                blue = color & 0xff;
                                color = ((red>>3)<<11) | ((green>>2)<<5) | (blue>>3);
                                *pen_16 = color;
                        }
                        break;
                case 32:
                        *pen_32 = color;
                        break;
                default:
                        printf("can not support %d bpp\n",var.bits_per_pixel);
                        break; 
        }
}

int main(int argc,char* argv[])
{
        int fd_fb;

        //1.打开设备节点
        fd_fb = open("/dev/fb0",O_RDWR);
        if(fd_fb < 0)
        {
                printf("can not open /dev/fb0 \n");
                return -1;
        }

        //2.获取LCD参数
        if(ioctl(fd_fb,FBIOGET_VSCREENINFO,&var))
        {
                printf("can not get var screen info\n");
                return -1;
        }

        //3.映射framebuffer
        line_width = var.xres * var.bits_per_pixel / 8;
        pixel_width = var.bits_per_pixel / 8;
        screen_size = var.xres * var.yres * pixel_width;

        fb_base = (unsigned char*)mmap(NULL,screen_size,PROT_READ | PROT_WRITE,MAP_SHARED,fd_fb,0);
        if(fb_base == (unsigned char *) -1)
        {
                printf("can not mmap framebuffer\n");
                return -1;
        }

        //4.绘画
        /* 清屏:全部设为0xff */
        memset(fb_base,0xff,screen_size);

        /* 绘制一条红色直线 */
        int i;
        for(i=0;i<100;++i)
                lcd_put_pixel(var.xres/2+i,var.yres/2,0xff0000);

        munmap(fb_base,screen_size);
        close(fd_fb);
        return 0;
}

                           

2.绘制字符

2.1 ascii

其中,font_8x16.h是从网上下载的字体文件,稍作修改之后用的。

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <string.h>
#include <linux/fb.h>
#include "font_8x16.h"

int line_width;
int pixel_width;
int screen_size;
unsigned char * fb_base;
static struct fb_var_screeninfo var;


//描点函数
void lcd_put_pixel(int x,int y,int color)
{
        unsigned char * pen_8 = fb_base + y*line_width + x*pixel_width;
        unsigned short *pen_16;
        unsigned int * pen_32;

        int red,green,blue;
        pen_16 = (unsigned short *)pen_8;
        pen_32 = (unsigned int *)pen_8;

        switch(var.bits_per_pixel)
        {
                case 8:
                        *pen_8 = color;
                        break;
                case 16:
                        {
                                /* 565 */
                                red = (color>>16) & 0xff;
                                green = (color>>8) & 0xff;
                                blue = color & 0xff;
                                color = ((red>>3)<<11) | ((green>>2)<<5) | (blue>>3);
                                *pen_16 = color;
                        }
                        break;
                case 32:
                        *pen_32 = color;
                        break;
                default:
                        printf("can not support %d bpp\n",var.bits_per_pixel);
                        break;
        }
}

//绘制ascii
void lcd_put_ascii(int x,int y,unsigned char c)
{
        unsigned char *dot = (unsigned char*)&fontdata_8x16[c*16];
        int i,b;
        unsigned char byte;

        for(i=0;i<16;++i)
        {
                byte = dot[i];
                for(b=7;b>=0;--b)
                {
                        if(byte & (1<<b))
                                lcd_put_pixel(x+7-b,y+i,0xffffff);
                        else
                                lcd_put_pixel(x+7-b,y+i,0);
                }
        }
}

//绘制字符串
void lcd_put_str(int x,int y,char s[])
{
        int i;
        int len = strlen(s);
        printf("str length = %d\n",len);
        int tempx = x;

        for(i=0;i<len;++i)
        {
                if(s[i] == '\n')
                {
                        //换行
                        y += 16;
                        x = tempx;
                }
                else
                {
                        lcd_put_ascii(x,y,s[i]);
                        x += 8;
                }
        }
}

int main(int argc,char* argv[])
{
        int fd_fb;

        // 1.打开framebuffer设备结点
        fd_fb = open("/dev/fb0",O_RDWR);
        if(fd_fb < 0)
        {
                printf("can not open /dev/fb0\n");
                return -1;
        }

        // 2.获取framebuffer 数据
        if(ioctl(fd_fb,FBIOGET_VSCREENINFO,&var))
        {
                printf("can not get var\n");
                return -1;
        }

        // 3.将framebuffer 映射到内存
        line_width = var.xres * var.bits_per_pixel / 8;
        pixel_width = var.bits_per_pixel / 8;
        screen_size = var.xres * var.yres * pixel_width;

        fb_base = (unsigned char*)mmap(NULL,screen_size,PROT_READ | PROT_WRITE,MAP_SHARED,fd_fb,0);
        if(fb_base == (unsigned char*)-1)
        {
                printf("can not mmap\n");
                return -1;
        }

        // 4.绘画
        /* 清屏:全部赋值0xff */
        memset(fb_base,0,screen_size);
        //lcd_put_ascii(var.xres/2,var.yres/2,'A');
        lcd_put_str(var.xres/2,var.yres/2,argv[1]);

        munmap(fb_base,screen_size);
        close(fd_fb);

        return 0;
}

2.2 汉字

注意:需要字体库HZK16文件,编译和运行阶段都需要,所以在开发板上运行时,需要将字体库文件HZK16加到当前目录中。

HZK16文件资源:https://download.csdn.net/download/weixin_42638731/87603904

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/fb.h>
#include <sys/mman.h>
#include <string.h>
#include "font_8x16.h" 
#include <unistd.h>


static struct fb_var_screeninfo var;
int pixel_width;
int line_width;
int screen_size;
unsigned char* fb_mem;

struct stat statbuf;
unsigned char* hzk16_mem;

//描点函数
void lcd_put_pixel(int x,int y,int color);
//显示ASCII码字符
void lcd_put_ascii(int x,int y,char c);
//显示ASCII码字符串
void lcd_put_str(int x,int y, char *s);
//显示中文字符
void lcd_put_chinese(int x,int y,char * s);

int main(int argc,char *argv[])
{
	//1.打开framebuffer设备
	int fd_fb = open("/dev/fb0",O_RDWR);
	if(fd_fb == -1)
	{
		printf("can not open /dev/fb0 \n");
		return -1;
	}

	//2.获取framebuffer参数
	if(ioctl(fd_fb,FBIOGET_VSCREENINFO,&var))
	{
		printf("can not get fb var\n");
		return -1;
	}
	pixel_width = var.bits_per_pixel / 8;
	line_width = pixel_width * var.xres;
	screen_size = line_width * var.yres;

	//3.将framebuffer映射到内存
	fb_mem = (unsigned char*)mmap(NULL,screen_size,PROT_READ | PROT_WRITE,MAP_SHARED,fd_fb,0);
	if(fb_mem == (unsigned char*) -1)
	{
		printf("can not mmap\n");
		return -1;
	}

	//4.绘制
	/* 清屏 */
	memset(fb_mem,0xff,screen_size);
 	
	//描点函数
	int i;
 	for(i=0;i<100;++i)
	{
		lcd_put_pixel(var.xres/5 + i,var.yres/5,0xff0000);
	}
	
	//显示ASCII码字符
	lcd_put_ascii(var.xres/3,var.yres/3,'1');
	
	//显示ASCII码字符串
 	//lcd_put_str(var.xres/2,var.yres/2,"ASD123");
	
	//显示中文字符串
	//1.打开HZK16文件
	int fd_hzk16=open("HZK16",O_RDONLY);
	if(fd_hzk16 < 0)
	{
		printf("can not open HZK16\n");
		return -1;
	}

	//2.计算HZK16文件大小
	if(fstat(fd_hzk16,&statbuf))
	{
		printf("can not get stat\n");
		return -1;
	}
	

	//3.将HZK16文件映射到内存
	hzk16_mem =(unsigned char*) mmap(NULL,statbuf.st_size,PROT_READ,MAP_SHARED,fd_hzk16,0);
	if(hzk16_mem == (unsigned char*)-1)
	{
		printf("can not map hzk16\n");
		return -1;
	}
	
	//4.显示中文字符
	unsigned char str[]="中";
	lcd_put_chinese(var.xres*3/5,var.yres*2/5,str);
	
	//5.显示混合字符串
	lcd_put_str(var.xres/2,var.yres/2,"中国加油\nfighting");	
	return 0;
}

//描点函数
void lcd_put_pixel(int x,int y,int color)
{
	unsigned char *pen_8 = fb_mem + line_width * y + pixel_width * x;
	unsigned short *pen_16;
	unsigned int *pen_32;

	int red,green,blue;
	pen_16 = (unsigned short*)pen_8;
	pen_32 = (unsigned int*)pen_8;

	switch(var.bits_per_pixel)
	{
		case 8:
			*pen_8 = color;
			break;
		case 16:
			{
				/* 565 */
				red = (color>>16) & 0xff;
				green = (color>>8) & 0xff;
				blue = (color>>0) & 0xff;

				*pen_16 = ((red>>3)<<11) | ((green>>2)<<5) | (blue>>3);
			}
			break;
		case 32:
			*pen_32 = color;
			break;
		default:
			printf("can not support %d bpp\n",var.bits_per_pixel);
			break;
	}
}

//显示ASCII码字符
void lcd_put_ascii(int x,int y,char c)
{
	unsigned char* fontdata = (unsigned char*)&fontdata_8x16[c*16];
	unsigned char byte;

	int i,j;
	for(i=0;i<16;++i)
	{
		byte = fontdata[i];

		for(j=7;j>=0;--j)
		{
			if(byte & (1<<j))
				lcd_put_pixel(x+7-j,y+i,0xffffff);  //白
			else
				lcd_put_pixel(x+7-j,y+i,0);  //黑
		}
	}
}

//显示ASCII码字符串
void lcd_put_str(int x,int y, char *s)
{
	int len = strlen(s);
	int i;
	int tempx = x;

	for(i=0;i<len;)
	{
		if(s[i] == '\n')
		{
			x = tempx;
			y += 16;
			printf("huan hang\n");
			i += 1;
		}
		else
		{
			if(((unsigned char)s[i]) < 0x80)
			{
				lcd_put_ascii(x,y,s[i]);
				x += 8;
				i += 1;
			}
			else
			{
				lcd_put_chinese(x,y,&s[i]);
				x += 16;
				i += 2;
			}
		}
	}
}


//显示中文字符
void lcd_put_chinese(int x,int y,char * s)
{
	unsigned int area = s[0] - 0xA1;
	unsigned int where = s[1] - 0xA1;
	unsigned char * dots = hzk16_mem +(area*94+where)*32;

	int i,j,k;
	unsigned char byte;
	for(i=0;i<16;++i)
	{
		for(j=0;j<2;++j)
		{
			byte = dots[i*2+j];
			for(k=7;k>=0;--k)
			{
				if(byte & (1<<k))
					lcd_put_pixel(x+8*j+7-k,y+i,0xffffff);
				else
					lcd_put_pixel(x+8*j+7-k,y+i,0);
			}
		}
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值