LCD显示汉字原理和显示字符一样,设置区域初始点,把汉字字模写入显存。但是汉字的数量比较多,以GB2312为例,GB2312 收录简化汉字及符号、字母、日文假名等共 7445 个图形字符,其中汉字占 6763 个,与ASCII的总数量128不是在同一个数量级上。如果把汉字字模像ASCII一样作为常量保存起来,那将会占用大量的CPU内存。为了节省CPU,这里把汉字字模存入flash中。
对于这么多的汉字,如果按照GB2312的表格来写入字模生成器就比较麻烦了,所以这里用另一个取模软件ts3,可以直接生成整个GB2312的字库。
打开ts3,生成字库步骤和之前生成单个字模的软件类似,这里不再介绍。
对于那么多的汉字,生成字库时间可能会比较长。
生成一个16号字体和一个24号字体的GB2312字库,然后把这两个文件通过双缓冲区接收文件的程序写入flash不常用的地址。flash一共8M,所以把两个文件放在比较靠后的7M地址处,先存储hz_16.DZK文件,hz_16.DZK文件一共255Kb,所以直接分配一个扇区给它;hz_24.DZK文件在下一扇区首地址处开始写入,也就是7M+256Kb处。
字库文件成功保存到flash后,开始编写显示汉字函数。
编写函数,有必要了解下GB2312的编码规则:
GB2312 规定<对任意一个图形字符都采用两个字节表示,每个字节均采用七位编码表示>,习惯上称第一个字节为<高字节>,第二个字节为<低字节>。GB2312-80 包含了大部分常用的一、二级汉字,和 9 区的符号。该字符集是几乎所有的中文系统和国际化的软件都支持的中文字符集,这也是最基本的中文字符集。其编码范围是高位0xa1-0xfe,低位也是0xa1-0xfe;汉字从0xb0a1开始,结束于 0xf7fe。
GB2312 将代码表分为 94 个区,对应第一字节(0xa1-0xfe);每个区 94 个位(0xa1-0xfe),对应第二字节,两个字节的值分别为区号值和位号值加 32(2OH),因此也称为区位码。01-09 区为符号、数字区,16-87 区为汉字区(0xb0-0xf7),10-15 区、88-94 区是有待进一步标准化的空白区。GB2312 将收录的汉字分成两级:第一级是常用汉字计 3755 个,置于 16-55 区,按汉语拼音字母/笔形顺序排列;第二级汉字是次常用汉字计 3008 个,置于 56-87 区,按部首/笔画顺序排列。故而 GB2312 最多能表示 6763 个汉字。
所以只要有汉字的第一和第二个字节,就能得到所要的汉字在GB2312中的对应区位,然后找到flash中存放地址偏移字模对应区位的地址,读取出字模,就可以了。
//LCD显示16号汉字
//ch:要写的汉字
//pencolor:字符颜色
//bcolor:背景色
//mode: 0:填充背景色
// 1:不填充背景色
void LCD_ShowChinese_16(u8 x,u8 y,u8 *ch,u16 pencolor,u16 bcolor,u8 mode)
{
u8 buf[32]={0};
u32 add = 7*1024*1024; //16号汉字存放首地址
u8 i = 0,j = 0;
u8 temp = 0;
add += 32*(ch[0] - 0xa1)*94 + 32*(ch[1] - 0xa1); //对应汉字字模地址
W25Q64_ReadBytes(add,buf,32); //从flash读取汉字的字模
for(i=0;i< 16;i++)
{
temp = buf[2*i];
for(j=0;j< 8;j++) //写左半部分
{
if(temp & 0x80)
{
LCD_DrawPoint(x,y,pencolor);
}
else
{
if(mode == 1)
LCD_DrawPoint(x,y,bcolor);
}
x++;
temp < <=1;
}
temp = buf[2*i+1];
for(j=0;j< 8;j++) //写入右半部分
{
if(temp & 0x80)
{
LCD_DrawPoint(x,y,pencolor);
}
else
{
if(mode == 1)
LCD_DrawPoint(x,y,bcolor);
}
x++;
temp < <=1;
}
x -= 16;
y++;
}
}
显示16号汉字函数只要在显示24号ASCII值 的基础上,添加读取flash中字模部分就可以实现了。
主函数
#include "stm32f4xx.h"
#include "core_cm4.h"
#include "ili9341.h"
#include "lcd.h"
#include "stdio.h"
int main()
{
W25Q64_Init();
LCD_Init(); //初始化LCD
LCD_ShowChinese_16(100,100,(u8 *)"郭",RED,WHITE,1);
while(1);
}
屏幕显示如下
24号汉字函数
//LCD显示24号汉字
//ch:要写的汉字
//pencolor:字符颜色
//bcolor:背景色
//mode: 0:填充背景色
// 1:不填充背景色
void LCD_ShowChinese_24(u8 x,u8 y,u8 *ch,u16 pencolor,u16 bcolor,u8 mode)
{
u8 buf[72] = {0};
u32 add = 7*1024*1024 + 256*1024; //24号汉字存放地址
u8 i,j;
u8 temp = 0;
add += 72*(ch[0] - 0xa1)*94 + 72*(ch[1] - 0xa1); //对应汉字字模地址
W25Q64_ReadBytes(add,buf,72); //从flash读取汉字的字模
for(i=0;i< 24;i++)
{
temp = buf[3*i];
for(j=0;j< 8;j++) //写入左半部分
{
if(temp & 0x80)
{
LCD_DrawPoint(x,y,pencolor);
}
else
{
if(mode == 1)
LCD_DrawPoint(x,y,bcolor);
}
x++;
temp < <=1;
}
temp = buf[3*i+1];
for(j=0;j< 8;j++) //写入中半部分
{
if(temp & 0x80)
{
LCD_DrawPoint(x,y,pencolor);
}
else
{
if(mode == 1)
LCD_DrawPoint(x,y,bcolor);
}
x++;
temp < <=1;
}
temp = buf[3*i+2];
for(j=0;j< 8;j++) //写入右半部分
{
if(temp & 0x80)
{
LCD_DrawPoint(x,y,pencolor);
}
else
{
if(mode == 1)
LCD_DrawPoint(x,y,bcolor);
}
x++;
temp < <=1;
}
x -= 24;
y++;
}
}
主函数
#include "stm32f4xx.h"
#include "core_cm4.h"
#include "ili9341.h"
#include "lcd.h"
#include "stdio.h"
int main()
{
W25Q64_Init();
LCD_Init(); //初始化LCD
LCD_ShowChinese_16(100,100,(u8 *)"郭",RED,WHITE,1);
LCD_ShowChinese_24(90,130,(u8 *)"舜",RED,WHITE,1);
LCD_ShowChinese_24(105,160,(u8 *)"贤",RED,WHITE,1);
while(1);
}
屏幕显示如下
24号汉字的显示函数编写与16号汉字显示区别不大,这里就不再介绍了。