韦东山 数码相框 项目学习(二)在LCD上显示中文字符

韦东山 数码相框 项目学习(二)在LCD上显示中文字符

和在LCD上显示ASCII字符一样,在LCD上显示中文字符也可以沿用之前的代码。只不过,中文点阵会放在一个汉字库文件HZK16里面,我们可以通过打开这个文件,并且使用mmap函数把它映射到我们的内存中,就可以使用内存操作来访问里面的点阵数据。
我们要完成的事情和在LCD上显示ASCII字符一样,只不过在细节处理上有些许差异,总体上还是一样的。

一、打开汉字库文件

第一步还是打开文件,在原来的基础上,我们要多打开一个汉字库文件HZK16,里面保存着汉字的点阵信息。

int fd_hzk16 = 0;
fd_hzk16 = open("HZK16", O_RDONLY);

我们只需要从中读取汉字的点阵数据就可以了,所以这里的权限设置为只读

二、把汉字库文件映射到内存

unsigned char *hzk_mem = NULL;
struct stat str_chinese_stat;
fstat(fd_hzk16, &str_chinese_stat);
hzk_mem = (unsigned char *)mmap(NULL, 
	str_chinese_stat.st_size, 
	PROT_READ, MAP_SHARED, fd_hzk16, 0);

在映射之前,我们需要获得文件的大小信息,通过fstat函数可以很便携的获取打开的文件的大小信息,然后就能够通过mmap函数进行内存映射了

三、读取汉字点阵信息

我们使用的HZK16,里面的汉字点阵信息是16x16大小的,在输出到LCD时就和输出ASCII字符一样。唯一一点需要注意的是,这个文件只支持GBK编码,所以我们需要在编译时指定可执行文件的编码格式为GBK,而GBK编码是以两个字节来存储一个汉字的,第一个字节保存的是区码,第二个字节保存的是位码,HZK16就是根据区码和位码来匹配到正确的汉字点阵数据的。

void lcd_put_chinese(int x, int y, unsigned char *str)
{
	printf("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);
	int area = str[0] - 0xA1;
	int where = str[1] - 0xA1;
	unsigned char *dots = hzk_mem + (area * 94 + where) * 32;
	unsigned char byte;

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

四、完整代码

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


struct fb_var_screeninfo var;
int screen_size = 0;
int screen_xres = 0;
int screen_yres = 0;
int line_width = 0;
int pixel_width = 0;

unsigned char *fbmem = NULL;
unsigned char *hzk_mem = NULL;

void lcd_put_pixel(int x, int y, unsigned int color)
{
	unsigned char *pen_8 = (unsigned char *)fbmem + y * line_width + x * pixel_width;
	unsigned short *pen_16 = (unsigned short *)pen_8;
	unsigned int *pen_32 = (unsigned int *)pen_8;

	unsigned char red, green, blue;
	

	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;
			color = (red >> 3) << 11 | (green >> 2) << 5 | (blue >> 3) << 0;
			*pen_16 = color;
			break;
		}

		case 32:
		{
			*pen_32 = color;
			break;
		}

		default:
		{
			printf("can't support this bits_per_pixel\n");
			break;
		}
	}

}

void lcd_put_chinese(int x, int y, unsigned char *str)
{
	printf("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);
	int area = str[0] - 0xA1;
	int where = str[1] - 0xA1;
	unsigned char *dots = hzk_mem + (area * 94 + where) * 32;
	unsigned char byte;

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

int main(int argc, char **argv)
{

	printf("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);

	int fd_fb = 0;
	int fd_hzk16 = 0;
	int ret = 0;
	char *str_chinese = "你好,世界";
	struct stat str_chinese_stat;

	
	/* 打开fb0 */
	fd_fb = open("/dev/fb0", O_RDWR);
	if(fd_fb < 0)
	{
		printf("can't open /dev/fb0");
		return -1;
	}

	
	/* 获取参数 */
	if(ioctl(fd_fb, FBIOGET_VSCREENINFO, &var))
	{
		printf("can't get screen var\n");
		ret = -1;
		goto fail_get_var;
	}

	screen_xres = var.xres;
	screen_yres = var.yres;
	screen_size = var.xres * var.yres * var.bits_per_pixel / 8;
	line_width = var.xres * var.bits_per_pixel / 8;
	pixel_width = var.bits_per_pixel / 8;

	printf("screen_xres: %d\n", screen_xres);
	printf("screen_yres: %d\n", screen_yres);
	printf("screen_size: %d\n", screen_size);
	printf("line_width:  %d\n", line_width);
	printf("pixel_width: %d\n", pixel_width);


	/* 映射内存 */
	fbmem = (unsigned char *)mmap(NULL, screen_size, PROT_WRITE | PROT_READ, MAP_SHARED,
                  fd_fb, 0);

    if(fbmem == (unsigned char *)-1)
    {
		printf("can't mmap to fbmem\n");
		ret = -1;
		goto fail_mmap_fb0;
    }

    /* 清屏 */
    memset(fbmem, 0, screen_size);

    /* 显示中文字符 */
	fd_hzk16 = open("HZK16", O_RDONLY);
	if(fd_hzk16 < 0)
	{
		printf("can't open HZK16\n");
		ret = -1;
		goto fail_open_HZK16;
	}

	/* 获取文件大小 */
	if(fstat(fd_hzk16, &str_chinese_stat))
	{
		printf("fstat failed!\n");
		ret = -1;
		goto fail_fstat;
	}
	printf("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);

	hzk_mem = (unsigned char *)mmap(NULL, str_chinese_stat.st_size, PROT_READ, MAP_SHARED, fd_hzk16, 0);
	printf("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);
    if(hzk_mem == (unsigned char *)-1)
    {
		printf("can't mmap HZK16\n");
		ret = -1;
		goto fail_mmap_HZK16;
    }

	i = 0;
	while(str_chinese[i])
	{
		lcd_put_chinese(screen_xres / 2 + i * 16, screen_yres / 2 + 16, str_chinese + i);
		i += 2;
	}
	
    
    munmap(hzk_mem, str_chinese_stat.st_size);
fail_mmap_HZK16:
fail_fstat:
	close(fd_hzk16);
fail_open_HZK16:
	munmap(fbmem, screen_size);
fail_mmap_fb0:
fail_get_var:
	close(fd_fb);
	return ret;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值