沙丁鱼介绍

首页 » 常识 » 问答 » 正点原子战舰V3第四十五章汉字显示实验
TUhjnbcbe - 2025/3/30 17:44:00

汉字显示在很多单片机系统都需要用到,少则几个字,多则整个汉字库的支持,更有甚者还要支持多国字库,那就更麻烦了。本章,我们将向大家介绍,如何用STM32F1控制LCD显示汉字。在本章中,我们将使用外部FLASH来存储字库,并可以通过SD卡更新字库。STM32F1读取存在FLASH里面的字库,然后将汉字显示在LCD上面。本章分为如下几个部分:

-45.1汉字显示原理简介

-45.2硬件设计

-45.3软件设计

-45.4下载验证

45.1汉字显示原理简介

常用的汉字内码系统有GB,GB,GBK,BIG5(繁体)等几种,其中GB支持的汉字仅有几千个,很多时候不够用,而GBK内码不仅完全兼容GB,还支持了繁体字,总汉字数有2万多个,完全能满足我们一般应用的要求。

本实例我们将制作三个GBK字库,制作好的字库放在SD卡里面,然后通过SD卡,将字库文件复制到外部FLASH芯片W25Q里,这样,W25Q就相当于一个汉字字库芯片了。

汉字在液晶上的显示原理与前面显示字符的是一样的。汉字在液晶上的显示其实就是一些点的显示与不显示,这就相当于我们的笔一样,有笔经过的地方就画出来,没经过的地方就不画。所以要显示汉字,我们首先要知道汉字的点阵数据,这些数据可以由专门的软件来生成。只要知道了一个汉字点阵的生成方法,那么我们在程序里面就可以把这个点阵数据解析成一个汉字。

知道显示了一个汉字,就可以推及整个汉字库了。汉字在各种文件里面的存储不是以点阵数据的形式存储的(否则那占用的空间就太大了),而是以内码的形式存储的,就是GB/GBK/BIG5等这几种的一种,每个汉字对应着一个内码,在知道了内码之后再去字库里面查找这个汉字的点阵数据,然后在液晶上显示出来。这个过程我们是看不到,但是计算机是要去执行的。

单片机要显示汉字也与此类似:汉字内码(GBK/GB)→查找点阵库→解析→显示。

所以只要我们有了整个汉字库的点阵,就可以把电脑上的文本信息在单片机上显示出来了。

这里我们要解决的最大问题就是制作一个与汉字内码对得上号的汉字点阵库。而且要方便单片机的查找。每个GBK码由2个字节组成,第一个字节为0X81~0XFE,第二个字节分为两部分,一是0X40~0X7E,二是0X80~0XFE。其中与GB相同的区域,字完全相同。

我们把第一个字节代表的意义称为区,那么GBK里面总共有个区(0XFE-0X81+1),每个区内有个汉字(0XFE-0X80+0X7E-0X40+2),总共就有*=个汉字。我们的点阵库只要按照这个编码规则从0X开始,逐一建立,每个区的点阵大小为每个汉字所用的字节数*。这样,我们就可以得到在这个字库里面定位汉字的方法:

当GBKL0X7F时:Hp=((GBKH-0x81)*+GBKL-0X40)*(size*2);

当GBKL0X80时:Hp=((GBKH-0x81)*+GBKL-0X41)*(size*2);

其中GBKH、GBKL分别代表GBK的第一个字节和第二个字节(也就是高位和低位),size代表汉字字体的大小(比如16字体,12字体等),Hp则为对应汉字点阵数据在字库里面的起始地址(假设是从0开始存放)。

这样我们只要得到了汉字的GBK码,就可以显示这个汉字了。从而实现汉字在液晶上的显示。

上一章,我们提到要用cc.c,以支持长文件名,但是cc.c文件里面的两个数组太大了(KB),直接刷在单片机里面,太占用flash了,所以我们必须把这两个数组存放在外部flash。cc里面包含的两个数组oem2uni和uni2oem存放unicode和gbk的互相转换对照表,这两个数组很大,这里我们利用ALIENTEK提供的一个C语言数组转BIN(二进制)的软件:C2B转换助手V1.1.exe,将这两个数组转为BIN文件,我们将这两个数组拷贝出来存放为一个新的文本文件,假设为UNIGBK.TXT,然后用C2B转换助手打开这个文本文件,如图45.1.1所示:

图45.1.1C2B转换助手

然后点击转换,就可以在当前目录下(文本文件所在目录下)得到一个UNIGBK.bin的文件。这样就完成将C语言数组转换为.bin文件,然后只需要将UNIGBK.bin保存到外部FLASH就实现了该数组的转移。

在cc.c里面,主要是通过ff_convert调用这两个数组,实现UNICODE和GBK的互转,该函数原代码如下:

WCHARff_convert(/*Convertedcode,0meansconversionerror*/

WCHARsrc,/*Charactercodetobeconverted*/

UINTdir/*0:UnicodetoOEMCP,1:OEMCPtoUnicode*/

constWCHAR*p;

WCHARc;

inti,n,li,hi;

if(src0x80){/*ASCII*/

c=src;

}else{

if(dir){/*OEMCPtounicode*/

p=oem2uni;

hi=sizeof(oem2uni)/4-1;

}else{/*UnicodetoOEMCP*/

p=uni2oem;

hi=sizeof(uni2oem)/4-1;

li=0;

for(n=16;n;n--){

i=li+(hi-li)/2;

if(src==p[i*2])break;

if(srcp[i*2])li=i;

elsehi=i;

c=n?p[i*2+1]:0;

returnc;

此段代码,通过二分法(16阶)在数组里面查找UNICODE(或GBK)码对应的GBK(或

UNICODE)码。当我们将数组存放在外部flash的时候,将该函数修改为:

WCHARff_convert(/*Convertedcode,0meansconversionerror*/

WCHARsrc,/*Charactercodetobeconverted*/

UINTdir/*0:UnicodetoOEMCP,1:OEMCPtoUnicode*/

WCHARt[2];

WCHARc;

u32i,li,hi;

u16n;

u32gbk2uni_offset=0;

if(src0x80)c=src;//ASCII,直接不用转换.

else

if(dir)gbk2uni_offset=ftinfo.ugbksize/2;//GBK2UNICODE

elsegbk2uni_offset=0;//UNICODE2GBK

/*UnicodetoOEMCP*/

hi=ftinfo.ugbksize/2;//对半开.

hi=hi/4-1;

li=0;

for(n=16;n;n--)

i=li+(hi-li)/2;

W25QXX_Read((u8*)t,ftinfo.ugbkaddr+i*4+gbk2uni_offset,4);//读出4个字节

if(src==t[0])break;

if(srct[0])li=i;

elsehi=i;

c=n?t[1]:0;

returnc;

代码中的ftinfo.ugbksize为我们刚刚生成的UNIGBK.bin的大小,而ftinfo.ugbkaddr是我们存放UNIGBK.bin文件的首地址。这里同样采用的是二分法查找,关于cc.c的修改,我们就介绍到这。

字库的生成,我们要用到一款软件,由易木雨软件工作室设计的点阵字库生成器V3.8。该软件可以在WINDOWS系统下生成任意点阵大小的ASCII,GB(简体中文)、GBK(简体中文)、BIG5(繁体中文)、HANGUL(韩文)、SJIS(日文)、Unicode以及泰文,越南文、俄文、乌克兰文,拉丁文,系列等共二十几种编码的字库,不但支持生成二进制文件格式的文件,也可以生成BDF文件,还支持生成图片功能,并支持横向,纵向等多种扫描方式,且扫描方式可以根据用户的需求进行增加。该软件的界面如图45.1.2所示:

图45.1.2点阵字库生成器默认界面

要生成16*16的GBK字库,则选择:中文PRCGBK,字宽和高均选择16,字体大小选择12,然后模式选择纵向取模方式二(字节高位在前,低位在后),最后点击创建,就可以开始生成我们需要的字库了(.DZK文件)。具体设置如图45.1.3所示:

图45.1.3生成GBK16*16字库的设置方

注意:电脑端的字体大小与我们生成点阵大小的关系为:

fsize=dsize*6/8

其中,fsize是电脑端字体大小,dsize是点阵大小(12、16、24等)。所以16*16点阵大小对应的是12字体。

生成完以后,我们把文件名和后缀改成:GBK16.FON(这里是手动修改后缀!!)。同样的方法,生成12*12的点阵库(GBK12.FON)和24*24的点阵库(GBK24.FON),总共制作3个字库

另外,该软件还可以生成其他很多字库,字体也可选,大家可以根据自己的需要按照上面的方法生成即可。该软件的详细介绍请看软件自带的《点阵字库生成器说明书》,关于汉字显示原理,我们就介绍到这。

45.2硬件设计

本章实验功能简介:开机的时候先检测W25Q中是否已经存在字库,如果存在,则按次序显示汉字(三种字体都显示)。如果没有,则检测SD卡和文件系统,并查找SYSTEM文件夹下的FONT文件夹,在该文件夹内查找UNIGBK.BIN、GBK12.FON、GBK16.FON和GBK24.FON(这几个文件的由来,我们前面已经介绍了)。在检测到这些文件之后,就开始更新字库,更新完毕才开始显示汉字。通过按按键KEY0,可以强制更新字库。同样我们也是用DS0来指示程序正在运行。

所要用到的硬件资源如下:

1)指示灯DS0

2)KEY0按键

3)串口

4)TFTLCD模块

5)SD卡

6)SPIFLASH这几部分分,在之前的实例中都介绍过了,我们在此就不介绍了。

45.3软件设计

打开上一章的工程,首先在HARDWARE文件夹所在的文件夹下新建一个TEXT的文件夹。在TEXT文件夹下新建fontupd.c、fontupd.h、text.c、text.h这4个文件。并将该文件夹加入头文件包含路径。

打开fontupd.c,在该文件内输入如下代码:

//字库区域占用的总扇区数大小(字库信息+unigbk表+3个字库=字节,约占

//个W25QXX扇区)

#defineFONTSECSIZE

//字库存放起始地址

#defineFONTINFOADDR**12

//战舰STM32F,是从12M地址以后开始存放字库,前面12M被fatfs占用了.

//12M以后紧跟3个字库+UNIGBK.BIN,总大小3.09M,被字库占用了,不能动!

//15.10M以后,用户可以自由使用.建议用最后的K字节比较好.

//用来保存字库基本信息,地址,大小等

_font_infoftinfo;

//字库存放在磁盘中的路径

u8*constGBK24_PATH=/SYSTEM/FONT/GBK24.FON;//GBK24的存放位置

u8*constGBK16_PATH=/SYSTEM/FONT/GBK16.FON;//GBK16的存放位置

u8*constGBK12_PATH=/SYSTEM/FONT/GBK12.FON;//GBK12的存放位置

u8*constUNIGBK_PATH=/SYSTEM/FONT/UNIGBK.BIN;//UNIGBK.BIN的存放位置

//显示当前字体更新进度

//x,y:坐标

//size:字体大小

//fsize:整个文件大小

//pos:当前文件指针位置

u32fupd_prog(u16x,u16y,u8size,u32fsize,u32pos)

……//此处省略代码

//更新某一个

//x,y:坐标

//size:字体大小

//fxpath:路径

//fx:更新的内容0,ungbk;1,gbk12;2,gbk16;3,gbk24;

//返回值:0,成功;其他,失败.

u8updata_fontx(u16x,u16y,u8size,u8*fxpath,u8fx)

u32flashaddr=0;

FIL*fftemp;

u8*tempbuf;

u8res;

u16bread;

u32offx=0;

u8rval=0;

fftemp=(FIL*)mymalloc(SRAMIN,sizeof(FIL));//分配内存

if(fftemp==NULL)rval=1;

tempbuf=mymalloc(SRAMIN,);//分配个字节空间

if(tempbuf==NULL)rval=1;

res=f_open(fftemp,(constTCHAR*)fxpath,FA_READ);

if(res)rval=2;//打开文件失败

if(rval==0)

switch(fx)

case0://更新UNIGBK.BIN

ftinfo.ugbkaddr=FONTINFOADDR+sizeof(ftinfo);//紧跟UNIGBK码表

ftinfo.ugbksize=fftemp-fsize;//UNIGBK大小

flashaddr=ftinfo.ugbkaddr;

break;

case1:

ftinfo.f12addr=ftinfo.ugbkaddr+ftinfo.ugbksize;//紧跟GBK12字库

ftinfo.gbk12size=fftemp-fsize;//GBK12字库大小

flashaddr=ftinfo.f12addr;//GBK12的起始地址

break;

case2:

ftinfo.f16addr=ftinfo.f12addr+ftinfo.gbk12size;//紧跟GBK16字库

ftinfo.gbk16size=fftemp-fsize;//GBK16字库大小

flashaddr=ftinfo.f16addr;//GBK16的起始地址

break;

case3:

ftinfo.f24addr=ftinfo.f16addr+ftinfo.gbk16size;//紧跟GBK24字库

ftinfo.gkb24size=fftemp-fsize;//GBK24字库大小

flashaddr=ftinfo.f24addr;//GBK24的起始地址

break;

}

while(res==FR_OK)//死循环执行

{

res=f_read(fftemp,tempbuf,,(UINT*)bread);//读取数据

if(res!=FR_OK)break;//执行错误

W25QXX_Write(tempbuf,offx+flashaddr,);//从0开始写个数据

offx+=bread;

fupd_prog(x,y,size,fftemp-fsize,offx);//进度显示

if(bread!=)break;//读完了.}

f_close(fftemp);

myfree(SRAMIN,fftemp);//释放内存

myfree(SRAMIN,tempbuf);//释放内存

returnres;

//更新字体文件,UNIGBK,GBK12,GBK16,GBK24一起更新

//x,y:提示信息的显示地址

//size:字体大小

//src:字库来源磁盘.0:,SD卡;1:,FLASH盘,2:,U盘.

//提示信息字体大小

//返回值:0,更新成功;

//其他,错误代码.

u8update_font(u16x,u16y,u8size,u8*src)

u8*pname;u8res=0;

u32*buf;

u16i,j;

FIL*fftemp;

u8rval=0;

res=0XFF;

ftinfo.fontok=0XFF;

pname=mymalloc(SRAMIN,);//申请字节内存

buf=mymalloc(SRAMIN,);//申请4K字节内存

fftemp=(FIL*)mymalloc(SRAMIN,sizeof(FIL));//分配内存

if(buf==NULL

pname==NULL

fftemp==NULL)

myfree(SRAMIN,fftemp);

myfree(SRAMIN,pname);

myfree(SRAMIN,buf);

return5;//内存申请失败

//先查找文件是否正常

strcpy((char*)pname,(char*)src);//copysrc内容到pname

strcat((char*)pname,(char*)UNIGBK_PATH);

res=f_open(fftemp,(constTCHAR*)pname,FA_READ);

if(res)rval

=14;//打开文件失败

strcpy((char*)pname,(char*)src);//copysrc内容到pname

strcat((char*)pname,(char*)GBK12_PATH);

res=f_open(fftemp,(constTCHAR*)pname,FA_READ);

if(res)rval

=15;//打开文件失败

strcpy((char*)pname,(char*)src);//copysrc内容到pname

strcat((char*)pname,(char*)GBK16_PATH);

res=f_open(fftemp,(constTCHAR*)pname,FA_READ);

if(res)rval

=16;//打开文件失败

strcpy((char*)pname,(char*)src);//copysrc内容到pname

strcat((char*)pname,(char*)GBK24_PATH);

res=f_open(fftemp,(constTCHAR*)pname,FA_READ);

if(res)rval

=17;//打开文件失败

myfree(SRAMIN,fftemp);//释放内存

if(rval==0)//字库文件都存在.

LCD_ShowString(x,y,,,size,Erasingsectors...);//提示正在擦除扇区

for(i=0;iFONTSECSIZE;i++)//先擦除字库区域,提高写入速度

fupd_prog(x+20*size/2,y,size,FONTSECSIZE,i);//进度显示

W25QXX_Read((u8*)buf,((FONTINFOADDR/)+i)*,);//读扇区

for(j=0;j;j++)//校验数据

if(buf[j]!=0XFFFFFFFF)break;//需要擦除

if(j!=)W25QXX_Erase_Sector((FONTINFOADDR/)+i);//要擦除扇区

myfree(SRAMIN,buf);

LCD_ShowString(x,y,,,size,UpdatingUNIGBK.BIN);

strcpy((char*)pname,(char*)src);//copysrc内容到pname

strcat((char*)pname,(char*)UNIGBK_PATH);

res=updata_fontx(x+20*size/2,y,size,pname,0);//更新UNIGBK.BIN

if(res){myfree(SRAMIN,pname);return1;}

LCD_ShowString(x,y,,,size,UpdatingGBK12.BIN);

strcpy((char*)pname,(char*)src);//copysrc内容到pname

strcat((char*)pname,(char*)GBK12_PATH);

res=updata_fontx(x+20*size/2,y,size,pname,1);//更新GBK12.FON

if(res){myfree(SRAMIN,pname);return2;}

LCD_ShowString(x,y,,,size,UpdatingGBK16.BIN);

strcpy((char*)pname,(char*)src);//copysrc内容到pname

strcat((char*)pname,(char*)GBK16_PATH);

res=updata_fontx(x+20*size/2,y,size,pname,2);//更新GBK16.FON

if(res){myfree(SRAMIN,pname);return3;}

LCD_ShowString(x,y,,,size,UpdatingGBK24.BIN);

strcpy((char*)pname,(char*)src);//copysrc内容到pname

strcat((char*)pname,(char*)GBK24_PATH);

res=updata_fontx(x+20*size/2,y,size,pname,3);//更新GBK24.FON

if(res){myfree(SRAMIN,pname);return4;}

//全部更新好了

ftinfo.fontok=0XAA;

W25QXX_Write((u8*)ftinfo,FONTINFOADDR,sizeof(ftinfo));//保存字库信息

myfree(SRAMIN,pname);//释放内存

myfree(SRAMIN,buf);

returnrval;//无错误.

//初始化字体

//返回值:0,字库完好.

//其他,字库丢失

u8font_init(void)

u8t=0;

W25QXX_Init();

while(t10)//连续读取10次,都是错误,说明确实是有问题,得更新字库了

t++;

W25QXX_Read((u8*)ftinfo,FONTINFOADDR,sizeof(ftinfo));//ftinfo结构体数据

if(ftinfo.fontok==0XAA)break;

delay_ms(20);

if(ftinfo.fontok!=0XAA)return1;

return0;

此部分代码主要用于字库的更新操作(包含UNIGBK的转换码表更新),其中ftinfo是我们在fontupd.h里面定义的一个结构体,用于记录字库首地址及字库大小等信息。因为我们将W25Q的前12M字节给FATFS管理(用做本地磁盘),随后,紧跟字库结构体、UNIGBK.bin、和三个字库,这部分内容首地址是:(*12)*,大小约3.09M,最后W25Q还剩下约0.9M给用户自己用。

保存该部分代码,并在工程里面新建一个TEXT的组,把fontupd.c加入到这个组里面,然后打开fontupd.h在该文件里面输入如下代码:

#ifndef__FONTUPD_H__

#define__FONTUPD_H__

#includestm32f10x.h

//字体信息保存地址,占33个字节,第1个字节用于标记字库是否存在.后续每8个字节一组,

//分别保存起始地址和文件大小

externu32FONTINFOADDR;

//字库信息结构体定义

//用来保存字库基本信息,地址,大小等

__packedtypedefstruct

{

u8fontok;//字库存在标志,0XAA,字库正常;其他,字库不存在

u32ugbkaddr;//unigbk的地址

u32ugbksize;//unigbk的大小

u32f12addr;//gbk12地址

u32gbk12size;//gbk12的大小

u32f16addr;//gbk16地址

u32gbk16size;//gbk16的大小

u32f24addr;//gbk24地址

u32gkb24size;//gbk24的大小

}_font_info;

extern_font_infoftinfo;//字库信息结构体

u32fupd_prog(u16x,u16y,u8size,u32fsize,u32pos);//显示更新进度

u8updata_fontx(u16x,u16y,u8size,u8*fxpath,u8fx);//更新指定字库

u8update_font(u16x,u16y,u8size,u8*src);//更新全部字库

u8font_init(void);//初始化字库

#endif

这里,我们可以看到ftinfo的结构体定义,总共占用33个字节,第一个字节用来标识字库

是否OK,其他的用来记录地址和文件大小。保存此部分代码,然后打开text.c文件,在该文件

里面输入如下代码:

//code字符指针开始

//从字库中查找出字模

//code字符串的开始地址,GBK码

//mat数据存放地址(size/8+((size%8)?1:0))*(size)bytes大小

//size:字体大小

voidGet_HzMat(unsignedchar*code,unsignedchar*mat,u8size)

unsignedcharqh,ql;

unsignedchari;

unsignedlongfoffset;

u8csize=(size/8+((size%8)?1:0))*(size);//得到一个字符对应点阵集所占的字节数

qh=*code;

ql=*(++code);

if(qh0x81

ql0x40

ql==0xff

qh==0xff)//非常用汉字

for(i=0;icsize;i++)*mat++=0x00;//填充满格

return;//结束访问

if(ql0x7f)ql-=0x40;//注意!

elseql-=0x41;

qh-=0x81;

foffset=((unsignedlong)*qh+ql)*csize;//得到字库中的字节偏移量

switch(size)

case12:W25QXX_Read(mat,foffset+ftinfo.f12addr,csize);break;

case16:W25QXX_Read(mat,foffset+ftinfo.f16addr,csize);break;

case24:W25QXX_Read(mat,foffset+ftinfo.f24addr,csize);break;

//显示一个指定大小的汉字

//x,y:汉字的坐标

//font:汉字GBK码

//size:字体大小

//mode:0,正常显示,1,叠加显示

voidShow_Font(u16x,u16y,u8*font,u8size,u8mode)

u8temp,t,t1;

u16y0=y;

u8dzk[72];

u8csize=(size/8+((size%8)?1:0))*(size);//得到一个字符对应点阵集所占的字节数

if(size!=12size!=16size!=24)return;//不支持的size

Get_HzMat(font,dzk,size);//得到相应大小的点阵数据

for(t=0;tcsize;t++)

temp=dzk[t];//得到点阵数据

for(t1=0;t18;t1++)

if(temp0x80)LCD_Fast_DrawPoint(x,y,POINT_COLOR);

elseif(mode==0)LCD_Fast_DrawPoint(x,y,BACK_COLOR);

temp=1;

y++;

if((y-y0)==size){y=y0;x++;break;}

//在指定位置开始显示一个字符串

//支持自动换行

//(x,y):起始坐标

//width,height:区域

//str:字符串

//size:字体大小

//mode:0,非叠加方式;1,叠加方式

voidShow_Str(u16x,u16y,u16width,u16height,u8*str,u8size,u8mode)

{

……//此处代码省略

}

//在指定宽度的中间显示字符串

//如果字符长度超过了len,则用Show_Str显示

//len:指定要显示的宽度

voidShow_Str_Mid(u16x,u16y,u8*str,u8size,u8len)

……//此处代码省略

此部分代码总共有4个函数,我们省略了两个函数(Show_Str_Mid和Show_Str)的代码,

另外两个函数,Get_HzMat函数用于获取GBK码对应的汉字字库,通过我们45.1节介绍的办

法,在外部flash查找字库,然后返回对应的字库点阵。Show_Font函数用于在指定地址显示一

个指定大小的汉字,采用的方法和LCD_ShowChar所采用的方法一样,都是画点显示,这里就

不细说了。保存此部分代码,并把text.c文件加入TEXT组下。text.h里面都是一些函数申明,

这里我们就不贴出来了,详见光盘本例程源码。

前面提到我们对cc.c文件做了修改,我们将其命名为mycc.c,并保存在exfuns文件

夹下,将工程FATFS组下的cc.c删除,然后重新添加mycc.c到FATFS组下,mycc.c

的源码就不贴出来了,其实就是在cc.c的基础上去掉了两个大数组,然后对ff_convert进行

了修改,详见本例程源码。

最后,我们在test.c里面修改main函数如下:

intmain(void)

u32fontcnt;u8i,j;u8key,t;

u8fontx[2];//gbk码

HAL_Init();//初始化HAL库

Stm32_Clock_Init(RCC_PLL_MUL9);//设置时钟,72M

delay_init(72);//初始化延时函数

uart_init();//初始化串口

usmart_dev.init(72);//初始化USMART

LED_Init();//初始化LED

KEY_Init();//初始化按键

LCD_Init();//初始化LCDFSMC接口

SRAM_Init();//初始化外部SRAM

my_mem_init(SRAMIN);//初始化内部内存池

my_mem_init(SRAMEX);//初始化外部内存池

exfuns_init();//为fatfs相关变量申请内存

f_mount(fs[0],0:,1);//挂载SD卡

f_mount(fs[1],1:,1);//挂载FLASH.

while(font_init())//检查字库

UPD:

LCD_Clear(WHITE);//清屏

POINT_COLOR=RED;//设置字体为红色

LCD_ShowString(30,50,,16,16,WarShipSTM32);

while(SD_Init())//检测SD卡

LCD_ShowString(30,70,,16,16,SDCardFailed!);

delay_ms();

LCD_Fill(30,70,+30,70+16,WHITE);

delay_ms();

LCD_howString(30,70,,16,16,SDCardOK);

LCD_ShowString(30,90,,16,16,FontUpdating...);

key=update_font(20,,16,0:);//更新字库

while(key)//更新失败

LCD_ShowString(30,,,16,16,FontUpdateFailed!);

delay_ms();

LCD_Fill(20,,+20,+16,WHITE);

delay_ms();

LCD_ShowString(30,,,16,16,FontUpdateSuccess!);

delay_ms();

LCD_Clear(WHITE);//清屏

POINT_COLOR=RED;

Show_Str(30,50,,16,战舰STM32F开发板,16,0);

Show_Str(30,70,,16,GBK字库测试程序,16,0);

Show_Str(30,90,,16,正点原子

ALIENTEK,16,0);

Show_Str(30,,,16,年9月28日,16,0);

Show_Str(30,,,16,按KEY0,更新字库,16,0);

POINT_COLOR=BLUE;

Show_Str(30,,,16,内码高字节:,16,0);

Show_Str(30,,,16,内码低字节:,16,0);

Show_Str(30,,,16,汉字计数器:,16,0);

Show_Str(30,,,24,对应汉字为:,24,0);

Show_Str(30,,,16,对应汉字(16*16)为:,16,0);

Show_Str(30,,,12,对应汉字(12*12)为:,12,0);

while(1)

fontcnt=0;

for(i=0x81;i0xff;i++)

fontx[0]=i;

LCD_ShowNum(,,i,3,16);//显示内码高字节

for(j=0x40;j0xfe;j++)

if(j==0x7f)continue;

fontcnt++;

LCD_ShowNum(,,j,3,16);//显示内码低字节

LCD_ShowNum(,,fontcnt,5,16);//汉字计数显示

fontx[1]=j;

Show_Font(30+,,fontx,24,0);

Show_Font(30+,,fontx,16,0);

Show_Font(30+,,fontx,12,0);

t=;

while(t--)//延时,同时扫描按键

delay_ms(1);

key=KEY_Scan(0);

if(key==KEY0_PRES)gotoUPD;

LED0=!LED0

此部分代码就实现了我们在硬件描述部分所描述的功能,至此整个软件设计就完成了。

45.4下载验证

在代码编译成功之后,我们通过下载代码到ALIENTEK战舰STM32F上,可以看到LCD开始显示汉字及汉字内码,如图45.4.1所示

图45.4.1汉字显示实验显示效果

一开始就显示汉字,是因为ALIENTEK战舰STM32F在出厂的时候都是测试过的,里面刷了综合测试程序,已经把字库写入到了W25Q里面,所以并不会提示更新字库。如果你想要更新字库,那么则必须先找一张SD卡,把:光盘\5,SD卡根目录文件文件夹下面的SYSTEM文件夹拷贝到SD卡根目录下,插入开发板,并按复位,之后,在显示汉字的时候,按下KEY0,就可以开始更新字库了。

字库更新界面如图45.4.2所示:

图45.4.2汉字字库更新界面

我们还可以通过USMART来测试该实验,将Show_Str函数加入USMART控制(方法前面已经讲了很多次了),就可以通过串口调用该函数,在屏幕上显示任何你想要显示的汉字了,有兴趣的朋友可以测试一下。

1
查看完整版本: 正点原子战舰V3第四十五章汉字显示实验