首页 » 通讯 » 「正点原子STM32Mini板资料连载」第三十五章 汉字显示实验_字库_汉字

「正点原子STM32Mini板资料连载」第三十五章 汉字显示实验_字库_汉字

神尊大人 2024-11-27 01:06:29 0

扫一扫用手机浏览

文章目录 [+]

第三十五章 汉字显示实验

汉字显示在很多单片机系统都须要用到,少则几个字,多则全体汉字库的支持,更有甚者

「正点原子STM32Mini板资料连载」第三十五章 汉字显示实验_字库_汉字 「正点原子STM32Mini板资料连载」第三十五章 汉字显示实验_字库_汉字 通讯

还要支持多国字库,那就更麻烦了。
本章,我们将向大家先容,如何用 STM32 掌握 LCD 显示

「正点原子STM32Mini板资料连载」第三十五章 汉字显示实验_字库_汉字 「正点原子STM32Mini板资料连载」第三十五章 汉字显示实验_字库_汉字 通讯
(图片来自网络侵删)

汉字。
在本章中,我们将利用外部 FLASH 来存储字库,并可以通过 SD 卡更新字库。
STM32

读取存在 FLASH 里面的字库,然后将汉字显示在 LCD 上面。
本章分为如下几个部分:

35.1 汉字显示事理简介

35.2 硬件设计

35.3 软件设计

35.4 下载验证

35.1 汉字显示事理简介

常用的汉字内码系统有 GB2312,GB13000,GBK,BIG5(繁体)等几种,个中 GB2312

支持的汉字仅有几千个,很多时候不足用,而 GBK 内码不仅完备兼容 GB2312,还支持了繁体

字,总汉字数有 2 万多个,完备能知足我们一样平常运用的哀求。

本实例我们将制作三个 GBK 字库,制作好的字库放在 SD 卡里面,然后通过 SD 卡,将字

库文件复制到外部 FLASH 芯片 W25Q64 里,这样,W25Q64 就相称于一个汉字字库芯片了。

汉字在液晶上的显示事理与前面显示字符的是一样的。
汉字在液晶上的显示实在便是一些

点的显示与不显示,这就相称于我们的笔一样,有笔经由的地方就画出来,没经由的地方就不

画。
以是要显示汉字,我们首先要知道汉字的点阵数据,这些数据可以由专门的软件来天生。

只要知道了一个汉字点阵的天生方法,那么我们在程序里面就可以把这个点阵数据解析成一个

汉字。

知道显示了一个汉字,就可以推及全体汉字库了。
汉字在各种文件里面的存储不因此点阵

数据的形式存储的(否则那占用的空间就太大了),而因此内码的形式存储的,便是

GB2312/GBK/BIG5 等这几种的一种,每个汉字对应着一个内码,在知道了内码之后再去字库

里面查找这个汉字的点阵数据,然后在液晶上显示出来。
这个过程我们是看不到,但是打算机

是要去实行的。

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

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

这里我们要办理的最大问题便是制作一个与汉字内码对得上号的汉字点阵库。
而且要方便单片

机的查找。
每个 GBK 码由 2 个字节组成,第一个字节为 0X81~0XFE,第二个字节分为两部分,

一是 0X40~0X7E,二是 0X80~0XFE。
个中与 GB2312 相同的区域,字完备相同。

我们把第一个字节代表的意义称为区,那么 GBK 里面统共有 126 个区(0XFE-0X81+1),

每个区内有 190 个汉字(0XFE-0X80+0X7E-0X40+2),统共就有 126190=23940 个汉字。

们的点阵库只要按照这个编码规则从 0X8140 开始,逐一建立,每个区的点阵大小为每个汉字

所用的字节数190。
这样,我们就可以得到在这个字库里面定位汉字的方法:

当 GBKL<0X7F 时:Hp=((GBKH-0x81)190+GBKL-0X40)csize;

当 GBKL>0X80 时:Hp=((GBKH-0x81)190+GBKL-0X41)csize;

个中 GBKH、GBKL 分别代表 GBK 的第一个字节和第二个字节(也便是高位和低位),Hp

为对应汉字点阵数据在字库里面的起始地址(假设是从 0 开始存放),csize 代表一个汉字点阵所

占的字节数。
假定采取与 15.3 节 ASCII 字库一样的提取方法(从上到下,从左到右),可以得

出字体大小与点阵所占字节数的对应关系为:

csize=(size/8+((size%8)?1:0))size;

size 为字体大小,比如 12(1212)、16(1616)、24(2424)等。

这样我们只要得到了汉字的 GBK 码,就可以得到该汉字点阵在点阵库里面的位置,从而

获取其点阵数据,显示这个汉字了。

上一章,我们提到要用 cc936.c,以支持长文件名,但是 cc936.c 文件里面的两个数组太大

了(172KB),直接刷在单片机里面,太占用 flash 了,以是我们必须把这两个数组存放在外部

flash。
cc936 里面包含的两个数组 oem2uni 和 uni2oem 存放 unicode 和 gbk 的相互转换对照表,

这两个数组很大,这里我们利用 ALIENTEK 供应的一个 C 措辞数组转 BIN(二进制)的软件:

C2B 转换助手 V1.1.exe,将这两个数组转为 BIN 文件,我们将这两个数组拷贝出来存放为一个

新的文本文件,假设为 UNIGBK.TXT,然后用 C2B 转换助手打开这个文本文件,如图 35.1.1

所示:

图 35.1.1 C2B 转换助手

然后点击转换,就可以在当前目录下(文本文件所在目录下)得到一个 UNIGBK.bin 的文

件。
这样就完成将 C 措辞数组转换为.bin 文件,然后只须要将 UNIGBK.bin 保存到外部 FLASH

就实现了该数组的转移。

在 cc936.c 里面,紧张是通过 ff_convert 调用这两个数组,实现 UNICODE 和 GBK 的互转,

该函数原代码如下:

WCHAR ff_convert ( / Converted code, 0 means conversion error /

WCHAR src, / Character code to be converted /

UINT

dir

/ 0: Unicode to OEMCP, 1: OEMCP to Unicode /

)

{

const WCHAR p;

WCHAR c;

int i, n, li, hi;

if (src < 0x80) {

/ ASCII /

c = src;

} else {

if (dir) {

/ OEMCP to unicode /

p = oem2uni;

hi = sizeof(oem2uni) / 4 - 1;

} else {

/ Unicode to OEMCP /

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 (src > p[i 2]) li = i;

else hi = i;

}

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

}

return c;

}

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

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

WCHAR ff_convert ( / Converted code, 0 means conversion error /

WCHAR src,

/ Character code to be converted /

UINT

dir

/ 0: Unicode to OEMCP, 1: OEMCP to Unicode /

)

{

WCHAR t[2];

WCHAR c;

u32 i, li, hi;

u16 n;

u32 gbk2uni_offset=0;

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

else

{

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

//GBK 2 UNICODE

else gbk2uni_offset=0;

//UNICODE 2 GBK

/ Unicode to OEMCP /

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

hi =hi / 4 - 1;

li = 0;

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

{

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

SPI_Flash_Read((u8)&t,ftinfo.ugbkaddr+i4+gbk2uni_offset,4);//读出 4 个字节

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

if (src > t[0])li = i;

else hi = i;

}

c = n ? t[1] : 0;

}

return c;

}

代码中的 ftinfo.ugbksize 为我们刚刚天生的 UNIGBK.bin 的大小,而 ftinfo.ugbkaddr 是我们

存放 UNIGBK.bin 文件的首地址。
这里同样采取的是二分法查找,关于 cc936.c 的修正,我们就

先容到这。

字库的天生,我们要用到一款软件,由易木雨软件事情室设计的点阵字库天生器 V3.8。

软件可以在 WINDOWS 系统下天生任意点阵大小的 ASCII,GB2312(简体中文)、GBK(简体中

文)、BIG5(繁体中文)、HANGUL(韩文)、SJIS(日文)、Unicode 以及泰文,越南文、俄文、乌克

兰文,拉丁文,8859 系列等共二十几种编码的字库,不但支持天生二进制文件格式的文件,也

可以天生 BDF 文件,还支持天生图片功能,并支持横向,纵向等多种扫描办法,且扫描办法

可以根据用户的需求进行增加。
该软件的界面如图 35.1.1 所示:

图 35.1.2 点阵字库天生器默认界面

本章,我们统共要天生 3 个字库:1212 字库、1616 字库和 2424 字库。
这里以 1616

字库为例进行先容,其他两个字库的制作方法类似。

要天生 1616 的 GBK 字库,则选择:936 中文 PRC GBK,字宽和高均选择 16,字体大小

选择 12,然后模式选择纵向取模办法二(字节高位在前,低位在后),末了点击创建,就可以

开始天生我们须要的字库了(.DZK 文件)。
详细设置如图 35.1.3 所示:

图 35.1.3 天生 GBK1616 字库的设置方法

把稳:电脑真个字体大小与我们天生点阵大小的关系为:

fsize=dsize6/8

个中,fsize 是电脑端字体大小,dsize 是点阵大小(12、16、24 等)。
以是 1616 点阵大小

对应的是 12 字体。

天生完往后,我们把文件名和后缀改成:GBK16.FON。
同样的方法,天生 1212 的点阵库

(GBK12.FON)和 2424 的点阵库(GBK24.FON),统共制作 3 个字库。

其余,该软件还可以天生其他很多字库,字体也可选,大家可以根据自己的须要按照上面

的方法天生即可。
该软件的详细先容请看软件自带的《点阵字库天生器解释书》,关于汉字显示

事理,我们就先容到这。

35.2 硬件设计

本章实验功能简介:开机的时候先检测 W25Q64 中是否已经存在字库,如果存在,则按次

序显示汉字(两种字体都显示)。
如果没有,则检测 SD 卡和文件系统,并查找 SYSTEM 文件夹

下的 FONT 文件夹,在该文件夹内查找 UNIGBK.BIN、GBK12.FON、GBK16.FON 和

GBK24.FON(这几个文件的由来,我们前面已经先容了)。
在检测到这些文件之后,就开始

更新字库,更新完毕才开始显示汉字。
通过按按键 KEY0,可以逼迫更新字库。
同样我们也是

用 DS0 来指示程序正在运行。

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

1) 指示灯 DS0

2) KEY0 按键

3) 串口

4) TFTLCD 模块

5) SD 卡

6) SPI FLASH

这几部分分,在之前的实例中都先容过了,我们在此就不先容了。

35.3 软件设计

打开上一章的工程,首先在 HARDWARE 文件夹所在的文件夹下新建一个 TEXT 的文件夹。

在 TEXT 文件夹下新建 fontupd.c、fontupd.h、text.c、text.h 这 4 个文件。
并将该文件夹加入头

文件包含路径。

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

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

//约占 791 个 W25QXX 扇区)

#define FONTSECSIZE

791

//字库存放起始地址

#define FONTINFOADDR 1024102412

//Explorer STM32F4 是从 12M 地址往后开始存放字库前面 12M 被 fatfs 占用了.

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

//15.10M 往后,用户可以自由利用.建议用末了的 100K 字节比较好.

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

_font_info ftinfo;

//字库存放在 sd 卡中的路径

const u8 GBK24_PATH="0:/SYSTEM/FONT/GBK24.FON"; //GBK24 的存放位置

const u8 GBK16_PATH="0:/SYSTEM/FONT/GBK16.FON"; //GBK16 的存放位置

const u8 GBK12_PATH="0:/SYSTEM/FONT/GBK12.FON"; //GBK12 的存放位置

const u8 UNIGBK_PATH="0:/SYSTEM/FONT/UNIGBK.BIN";//UNIGBK.BIN 的存放位置

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

//x,y:坐标

//size:字体大小

//fsize:全体文件大小

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

u32 fupd_prog(u16 x,u16 y,u8 size,u32 fsize,u32 pos)

{

float prog; u8 t=0XFF;

prog=(float)pos/fsize;

prog=100;

if(t!=prog)

{

LCD_ShowString(x+3size/2,y,240,320,size,"%");

t=prog;

if(t>100)t=100;

LCD_ShowNum(x,y,t,3,size);//显示数值

}

return 0;

}

//更新某一个

//x,y:坐标

//size:字体大小

//fxpath:路径

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

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

u8 updata_fontx(u16 x,u16 y,u8 size,u8 fxpath,u8 fx)

{

u32 flashaddr=0; u16 bread; u32 offx=0;

FIL fftemp;

u8 tempbuf; u8 res; u8 rval=0;

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

if(fftemp==NULL)rval=1;

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

if(tempbuf==NULL)rval=1;

res=f_open(fftemp,(const TCHAR)fxpath,FA_READ);

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

if(rval==0)

{

switch(fx)

{

case 0:

//更新 UNIGBK.BIN

ftinfo.ugbkaddr=FONTINFOADDR+sizeof(ftinfo);// UNIGBK 转换码表

ftinfo.ugbksize=fftemp->fsize;

//UNIGBK 大小

flashaddr=ftinfo.ugbkaddr;

break;

case 1:

ftinfo.f12addr=ftinfo.ugbkaddr+ftinfo.ugbksize; //GBK12 字库地址

ftinfo.gbk12size=fftemp->fsize;

//GBK12 字库大小

flashaddr=ftinfo.f12addr;

//GBK12 的起始地址

break;

case 2:

ftinfo.f16addr=ftinfo.f12addr+ftinfo.gbk12size; // GBK16 字库地址

ftinfo.gbk16size=fftemp->fsize;

//GBK16 字库大小

flashaddr=ftinfo.f16addr;

//GBK16 的起始地址

break;

case 3:

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,4096,(UINT )&bread); //读取数据

if(res!=FR_OK)break;

//实行缺点

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

offx+=bread;

fupd_prog(x,y,size,fftemp->fsize,offx);

//进度显示

if(bread!=4096)break;

//读完了.

}

f_close(fftemp);

}

myfree(fftemp);

//开释内存

myfree(tempbuf); //开释内存

return res;

}

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

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

//size:字体大小

//提示信息字体大小

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

//

其他,缺点代码.

u8 update_font(u16 x,u16 y,u8 size)

{

u8 gbk24_path=(u8)GBK24_PATH;

u8 gbk16_path=(u8)GBK16_PATH;

u8 gbk12_path=(u8)GBK12_PATH;

u8 unigbk_path=(u8)UNIGBK_PATH;

u8 res;

res=0XFF;

ftinfo.fontok=0XFF;

SPI_Flash_Write((u8)&ftinfo,FONTINFOADDR,sizeof(ftinfo));

//打消之前字库成功的标志.防止更新到一半重启,导致的字库部分数据丢失.

SPI_Flash_Read((u8)&ftinfo,FONTINFOADDR,sizeof(ftinfo));

//重新读出 ftinfo 构造体数据

LCD_ShowString(x,y,240,320,size,"Updating UNIGBK.BIN");

res=updata_fontx(x+20size/2,y,size,unigbk_path,0);

//更新 UNIGBK.BIN

if(res)return 1;

LCD_ShowString(x,y,240,320,size,"Updating GBK12.BIN ");

res=updata_fontx(x+20size/2,y,size,gbk12_path,1);

//更新 GBK12.FON

if(res)return 2;

LCD_ShowString(x,y,240,320,size,"Updating GBK16.BIN ");

res=updata_fontx(x+20size/2,y,size,gbk16_path,2);

//更新 GBK16.FON

if(res)return 3;

LCD_ShowString(x,y,240,320,size,"Updating GBK24.BIN ");

res=updata_fontx(x+20size/2,y,size,gbk24_path,3);

//更新 GBK24.FON

if(res)return 4;

ftinfo.fontok=0XAA; //全部更新好了

SPI_Flash_Write((u8)&ftinfo,FONTINFOADDR,sizeof(ftinfo));

//保存字库信息

return 0;//无缺点.

}

//初始化字体

//返回值:0,字库无缺.

//

其他,字库丢失

u8 font_init(void)

{

SPI_Flash_Init();

SPI_Flash_Read((u8)&ftinfo,FONTINFOADDR,sizeof(ftinfo));//读出 ftinfo 构造体数据

if(ftinfo.fontok!=0XAA)return 1;

//字库缺点.

return 0;

}

此部分代码紧张用于字库的更新操作(包含 UNIGBK 的转换码表更新),个中 ftinfo 是我

们在 fontupd.h 里面定义的一个构造体,用于记录字库首地址及字库大小等信息。
由于我们将

W25Q64 的前 4.8M 字节给 FATFS 管理(用做本地磁盘),然后又预留了 100K 字节给用户自己

利用,末了的 3.1M 字节(W25Q64 统共 8M 字节),才是 UNIGBK 码表和字库的存储空间,所

以,我们的存储地址是从(4916+100)1024 处开始的。
最开始的 33 个字节给 ftinfo 用,用于保

存 ftinfo 构造体数据,之后依次是:UNIGBK.BIN、GBK12.FON、GBK16.FON 和 GBK24.FON。

保存该部分代码,并在工程里面新建一个 TEXT 的组,把 fontupd.c 加入到这个组里面,然

后打开 fontupd.h 在该文件里面输入如下代码:

#ifndef __FONTUPD_H__

#define __FONTUPD_H__

#include <stm32f10x.h>

//前面 4.8M 被 fatfs 占用了.

//4.8M 往后紧跟的 100K 字节,用户可以随便用.

//4.8M+100K 字节往后的字节,被字库占用了,不能动!

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

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

extern u32 FONTINFOADDR;

//字库信息构造体定义

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

__packed typedef struct

{

u8 fontok;

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

u32 ugbkaddr;

//unigbk 的地址

u32 ugbksize;

//unigbk 的大小

u32 f12addr;

//gbk12 地址

u32 gbk12size;

//gbk12 的大小

u32 f16addr;

//gbk16 地址

u32 gbk16size;

//gbk16 的大小

u32 f24addr;

//gbk24 地址

u32 gkb24size;

//gbk24 的大小

}_font_info;

extern _font_info ftinfo; //字库信息构造体

u32 fupd_prog(u16 x,u16 y,u8 size,u32 fsize,u32 pos);

//显示更新进度

u8 updata_fontx(u16 x,u16 y,u8 size,u8 fxpath,u8 fx);

//更新指定字库

u8 update_font(u16 x,u16 y,u8 size);

//更新全部字库

u8 font_init(void);

#endif

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

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

里面输入如下代码:

#include "sys.h"

#include "fontupd.h"

#include "flash.h"

#include "lcd.h"

#include "text.h"

#include "string.h"

//code 字符指针开始

//从字库中查找出字模

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

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

//size:字体大小

void Get_HzMat(unsigned char code,unsigned char mat,u8 size)

{

unsigned char qh,ql;

unsigned char i;

unsigned long foffset;

u8 csize=(size/8+((size%8)?1:0))(size);//得到该字体一个汉字对应点阵集所占字节数

qh=code;

ql=(++code);

if(qh<0x81||ql<0x40||ql==0xff||qh==0xff)//非 常用汉字

{

for(i=0;i<csize;i++)mat++=0x00;//添补斥格

return; //结束访问

}

if(ql<0x7f)ql-=0x40;//把稳!

else ql-=0x41;

qh-=0x81;

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

switch(size)

{

case 12:SPI_Flash_Read(mat,foffset+ftinfo.f12addr,24);break;

case 16:SPI_Flash_Read(mat,foffset+ftinfo.f16addr,32);break;

case 24:SPI_Flash_Read(mat,foffset+ftinfo.f24addr,72);break;

}

}

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

//x,y :汉字的坐标

//font:汉字 GBK 码

//size:字体大小

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

void Show_Font(u16 x,u16 y,u8 font,u8 size,u8 mode)

{

u8 temp,t,t1;

u16 y0=y;

u8 dzk[72];

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

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

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

for(t=0;t<csize;t++)

{

temp=dzk[t];

//得到点阵数据

for(t1=0;t1<8;t1++)

{

if(temp&0x80)LCD_Fast_DrawPoint(x,y,POINT_COLOR);

else if(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,叠加办法

void Show_Str(u16 x,u16 y,u16 width,u16 height,u8str,u8 size,u8 mode)

{

……此处代码省略

}

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

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

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

void Show_Str_Mid(u16 x,u16 y,u8str,u8 size,u8 len)

{

……//此处代码省略

}

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

其余两个函数,Get_HzMat 函数用于获取 GBK 码对应的汉字字库,通过我们 35.1 节先容的办

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

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

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

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

前面提到我们队 cc936.c 文件做了修正,我们将其命名为 mycc936.c,并保存在 exfuns 文件

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

的源码就不贴出来了,实在便是在 cc936.c 的根本上去掉了两个大数组,然后对 ff_convert 进行

了修正,详见光盘本例程源码。

末了,我们在 main.c 里面修正 main 函数如下:

int main(void)

{

u32 fontcnt;

u8 i,j,key,t;

u8 fontx[2];//gbk 码

HAL_Init();

//初始化 HAL 库

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

delay_init(72);

//初始化延时函数

uart_init(115200);

//初始化串口

usmart_dev.init(84);

//初始化 USMART

LED_Init();

//初始化 LED

KEY_Init();

//初始化按键

LCD_Init();

//初始化 LCD

mem_init();

//初始化内存池

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(60,50,200,16,16,"Mini STM32");

while(SD_Initialize())

//检测 SD 卡

{

LCD_ShowString(60,70,200,16,16,"SD Card Failed!");

delay_ms(200);

LCD_Fill(60,70,200+60,70+16,WHITE);

delay_ms(200);

}

LCD_ShowString(60,70,200,16,16,"SD Card OK");

LCD_ShowString(60,90,200,16,16,"Font Updating...");

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

while(key)//更新失落败

{

LCD_ShowString(60,110,200,16,16,"Font Update Failed!"); delay_ms(200);

LCD_Fill(20,110,200+20,110+16,WHITE); delay_ms(200);

}

LCD_ShowString(60,110,200,16,16,"Font Update Success!");

delay_ms(1500);

LCD_Clear(WHITE);//清屏

}

POINT_COLOR=RED;

Show_Str(30,50,200,16,"Mini STM32 开拓板",16,0);

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

Show_Str(30,90,200,16,"正点原子@ALIENTEK",16,0);

Show_Str(30,110,200,16,"2019 年 11 月 18 日",16,0);

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

POINT_COLOR=BLUE;

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

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

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

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

Show_Str(30,244,200,16,"对应汉字(1616)为:",16,0);

Show_Str(30,260,200,12,"对应汉字(1212)为:",12,0);

while(1)

{

fontcnt=0;

for(i=0x81;i<0xff;i++)

{

fontx[0]=i;

LCD_ShowNum(148,150,i,3,16);

//显示内码高字节

for(j=0x40;j<0xfe;j++)

{

if(j==0x7f)continue;

fontcnt++;

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

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

fontx[1]=j;

Show_Font(60+132,220,fontx,24,0);

Show_Font(60+144,244,fontx,16,0);

Show_Font(60+108,260,fontx,12,0);

t=200;

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

{

delay_ms(1);

key=KEY_Scan(0);

if(key==KEY0_PRES)goto UPD;

}

LED0=!LED0;

}

}

}

}

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

35.4 下载验证

本例程支持 1212、1616 和 2424 等三种字体的显示,在代码编译成功之后,我们通过下

载代码到 ALIENTEK MiniSTM32 开拓板上,可以看到 LCD 开始显示三种大小的汉字及汉字内

码,如图 35.4.1 所示:

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

一开始就显示汉字,是由于 ALIENTEK MiniSTM32 开拓板在出厂的时候都是测试过的,

里面刷了综合测试程序,已经把字库写入到了 W25Q64 里面,以是并不会提示更新字库。
如果

你想要更新字库,那么则必须先找一张 SD 卡,把:光盘\5,SD 卡根目录文件 文件夹下面的

SYSTEM 文件夹拷贝到 SD 卡根目录下,插入开拓板,并按复位,之后,在显示汉字的时候,

按下 KEY0,就可以开始更新字库了。
字库更新界面如图 35.4.2 所示:

图 35.4.2 汉字字库更新界面

我们还可以通过 USMART 来测试该实验,我们可以通过 USMART 调用 Show_Str 函数,

来实现任意位置显示任何字符串,有兴趣的朋友可以测试一下。

标签:

相关文章

单线SPI的在线编程筹划_串口_单线

随着半导体行业的飞速发展,芯片集成度越来越高,随之研发设计出来的PCBA大小已经能和硬币比肩,功能却一点都没有受到影响,是如何做到...

通讯 2025-01-22 阅读0 评论0