×
单片机 > 单片机程序设计 > 详情

STM32自带GB2312字库显示汉字

发布时间:2020-06-09 发布时间:
|

  本文介绍如何把字库文件写入单片机的flash中,然后无需再提取字模,即可实现单片机显示中文字符的功能。


下载字库到单片机flash中的指定位置

  在上一篇博客中,最后留了一个想法,让单片机自带字库。现在就来实现这个想法。

我把用到的编译过的字符放在这里

  我们借助J-Flash软件把bin文件放在单片机flash中的指定位置。

  首先要新建工程,然后根据自己的板子选择型号


  然后打开数据文件,找到刚刚下载的bin文件



  根据自己单片机的flash大小输入地址,注意这个地址要与代码中的“基地址”一致

  设置好以后按下快捷键F7

  成功烧录以后,代码不可以在使用此区域。——一般情况下,你的工程代码也不会大到可以覆盖这个区域。


编写字库显示函数

  函数编写过程就不讲述了,原理都在代码里。有需要的可以自行研究。有一些没有提到的函数,可以参考上一篇博客。

  这是显示字符串的函数


/**

  * @brief 输出12*12的汉字或6*12的字符,函数可以自动识别是中文字符还是ASCII

  * @param 第一个字符的坐标,汉字颜色,背景颜色,需要显示的字符串。背景颜色为0表示不画背景

  * @Note  汉字字模来自于字库,字库是编译好的bin文件,在_DEF_FONT_CH字库的基地址中

  * @retval None

  */

void LCD_DrawFont_GBK12(u16 x, u16 y, u16 fc, u16 bc, char *pStr)

{

unsigned char xNow,temp_width;

const u8 *FontModel;

char ch[2];

xNow = x;

while(*pStr)

{

ch[0] = *pStr;

pStr++;

ch[1] = *pStr;

if(ch[0] == 10)

{

x = xNow;

y += 12;

}

else if(ch[0] < 128)

{

temp_width = Get_Model(ch,&FontModel);

if(x < 128)

DrawFontModel(x,y,temp_width,FontModel,fc,bc);

x += temp_width;//下一个字符的横坐标

}

else if((ch[0] > 160) && (ch[1] > 160)) //中文

{

ch[1] = *pStr;

temp_width = Get_Model(ch,&FontModel);

if(x < 128)

DrawFontModel(x,y,temp_width,FontModel,fc,bc);

x += temp_width;//下一个字符的横坐标

pStr++;

}

}

}


  这个函数用于显示单个字符


/**

  * @brief 根据传入的参数显示一个字符,可以自动识别是中文还是英文

  * @param 第一个字符的坐标,字符的宽度(中文12英文6),颜色,背景颜色,需要显示的字符串。背景颜色为0表示不画背景

  * @Note  汉字字模来自于字库,字库是编译好的bin文件,在_DEF_FONT_CH字库的基地址中

  *         返回值并不是字库的地址,字库地址是通过指针传递的,也就是说,参数FontModel本身也是返回值

  * @retval None

  */

static void DrawFontModel(u8 xNow,u8 yNow,u8 width,const u8 *FontModel,u16 fc, u16 bc )

{

u8 bit = 0;

u8 m = 0xff;

if(FontModel)//字母为空处理

m = *FontModel;

for (u8 y = yNow; y < yNow + 12; y++)//竖着显示,先判断y坐标。

{

for(u8 x = xNow; x < xNow + width; x++)//再判断横坐标

{

if(x < 128)

{

if((m&0x01) == 0x01)

{

LCD_DrawPoint(x,y,fc);

}

else

{

if ((bc!=0)&&(fc!=bc)) LCD_DrawPoint(x,y,bc);

}

}

bit++;

m >>= 1;//字符循环右移

if(bit == 8)//一个字节显示完毕,则显示下一个字节

{

bit = 0;

if(FontModel)//空字模处理

{

FontModel ++;

          m = *FontModel;

}

else

{

m = 0xff;

}

}

}

}

}


  这是根据字符的标号,从flash中找到对应字符数组的 函数


/**

  * @brief 获取字模数组的 地址

  * @param 第一个字符的坐标,字符的宽度(中文12英文6),颜色,背景颜色,需要显示的字符串。背景颜色为0表示不画背景

  * @Note  汉字字模来自于字库,字库是编译好的bin文件,在_DEF_FONT_CH字库的基地址中

  * @retval 字模的宽度

  */

static char Get_Model(const char *ch,const u8 **FontModel)

{

if((ch[0] > 0xA0) && (ch[1] > 0xA0))//中文

{

*FontModel = _DEF_FONT_CH + 18 * ((ch[0] - 161) * 94 + ch[1] - 161);//获取此字模的地址

return 12;

}

if(*ch >= 0x20)//英文

{

*FontModel = _DEF_FONT_EN + 9 * (ch[0] - 0x20);

return 6;

}

*FontModel = _DEF_FONT_EN;//无法匹配,显示空白

return 0;

}


  GB2312的字符计算是怎么算的?GB2312的编号可以帮助我们找到字符,简单来说,就是GB2312规定对收录的每个字符采用两个字节表示,第一个字节为“高字节”,对应94个区;第二个字节为“低字节”,对应94个位。所以它的区位码范围是:0101-9494。区号和位号分别加上0xA0就是GB2312编码。例如最后一个码位是9494,区号和位号分别转换成十六进制是5E5E,0x5E+0xA0=0xFE,所以该码位的GB2312编码是FEFE。

  这也就是为什么我们的代码中要乘以94了。

  关于GB2312的详细资料可以参考这篇博客

  在主函数中我调用了显示函数:


ST7735S_CPT144_Initial();

LCD_BG_Color(GREEN);


LCD_DrawFont_GBK12(0,0,BLACK,GREEN,"来自geekYatao的博客");

LCD_DrawFont_GBK12(0,12,BLACK,GREEN,"ABCabc123,.?《》");

LCD_DrawFont_GBK12(0,24,BLACK,GREEN,"犇鱻羴显示不出来");


  另外我还定义了汉字字符的基地址,与英文字符的数组


extern const u8 _FontLibEn612[];

#define _DEF_FONT_CH     (const u8*)(0x080DC000)  //字库的基地址

#define _DEF_FONT_EN            _FontLibEn612


extern const u8 _FontLibEn612[] = { 0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0, // 0x20  

                        0x0,0x40,0x10,0x4,0x41,0x10,0x0,0x1,0x0, // 0x21 !

                        0x0,0xA5,0x28,0x0,0x0,0x0,0x0,0x0,0x0, // 0x22 "

                        0x0,0x40,0x51,0x3F,0xA5,0xFC,0x8A,0x2,0x0, // 0x23 #

                        0x0,0xE1,0x55,0x85,0xC1,0x50,0xD5,0x43,0x0, // 0x24 $

                        0x0,0x20,0x55,0x8D,0x42,0xB1,0xAA,0x4,0x0, // 0x25 %

                        0x0,0x40,0x28,0x8A,0x57,0x55,0x89,0xD,0x0, // 0x26 &

                        0x80,0x20,0x4,0x0,0x0,0x0,0x0,0x0,0x0, // 0x27 '

                        0x0,0x8,0x21,0x8,0x82,0x20,0x8,0x4,0x2, // 0x28 (

                        0x80,0x40,0x20,0x8,0x82,0x20,0x8,0x21,0x0, // 0x29 )

                        0x0,0x0,0x10,0x95,0xE3,0x54,0x4,0x0,0x0, // 0x2A *

                        0x0,0x40,0x10,0xC4,0x47,0x10,0x4,0x0,0x0, // 0x2B +

                        0x0,0x0,0x0,0x0,0x0,0x0,0x80,0x20,0x4, // 0x2C ,

                        0x0,0x0,0x0,0xC0,0x7,0x0,0x0,0x0,0x0, // 0x2D -

                        0x0,0x0,0x0,0x0,0x0,0x0,0x80,0x0,0x0, // 0x2E .

                        0x0,0x84,0x20,0x8,0x41,0x8,0x82,0x10,0x0, // 0x2F /

                        0x0,0xE0,0x44,0x51,0x14,0x45,0x91,0x3,0x0, // 0x30 0

                        0x0,0x40,0x18,0x4,0x41,0x10,0x84,0x3,0x0, // 0x31 1

                        0x0,0xE0,0x44,0x11,0x42,0x8,0xC1,0x7,0x0, // 0x32 2

                        0x0,0xE0,0x44,0x10,0x3,0x41,0x91,0x3,0x0, // 0x33 3

                        0x0,0x80,0x30,0x8A,0x92,0x78,0x8,0x6,0x0, // 0x34 4

                        0x0,0xF0,0x5,0xC1,0x3,0x41,0x91,0x3,0x0, // 0x35 5

                        0x0,0xE0,0x24,0xC1,0x13,0x45,0x91,0x3,0x0, // 0x36 6

                        0x0,0xF0,0x25,0x8,0x41,0x10,0x4,0x1,0x0, // 0x37 7

                        0x0,0xE0,0x44,0x91,0x13,0x45,0x91,0x3,0x0, // 0x38 8

                        0x0,0xE0,0x44,0x51,0xE4,0x41,0x92,0x3,0x0, // 0x39 9

                        0x0,0x0,0x0,0x4,0x0,0x0,0x0,0x1,0x0, // 0x3A :

                        0x0,0x0,0x0,0x0,0x1,0x0,0x0,0x41,0x0, // 0x3B ;

                        0x0,0x8,0x21,0x84,0x40,0x20,0x10,0x8,0x0, // 0x3C <

                        0x0,0x0,0x0,0x1F,0x0,0x7C,0x0,0x0,0x0, // 0x3D =

                        0x80,0x40,0x20,0x10,0x8,0x21,0x84,0x0,0x0, // 0x3E >

                        0x0,0xE0,0x44,0x11,0x42,0x10,0x0,0x1,0x0, // 0x3F ?

0x0,0xE0,0x44,0x


『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多
8051单片机的函数发生器的设计