最新教程下载:http://www.armbbs.cn/forum.php?mod=viewthread&tid=93255

本章教程为大家讲解汉字小字库和全字库的制作方式,实际项目中用到的地方比较多。

43.1 初学者重要提示

43.2 使用MakeDot小软件生成C文件格式小字库方法

43.3 使用MakeDot小软件生成C文件格式全字库方法

43.4 C文件格式汉字使用方法

43.5 汉字显示方法解析

43.6 LCD驱动移植和使用

43.7 实验例程设计框架

43.8 实验例程说明(MDK)

43.9 实验例程说明(IAR)

43.10 总结

 

 

43.1 初学者重要提示

  1.   学习本章节前,务必优先学习第42章,需要对点阵字体字符编码有个认识。
  2.   LTDC驱动设计和相关问题在第41章有详细说明。
  3.   本章节为大家讲解的小字库和全字库方法,简单易用,是直接以C文件格式存储到内部Flash的。支持12点阵,16点阵,24点阵和32点阵的ASCII以及GB2312编码汉字显示。
  4.   本章节用到的字库软件下载:http://www.armbbs.cn/forum.php?mod=viewthread&tid=202

43.2 使用MakeDot小软件生成C文件格式小字库方法

生成方法比较简单,这里做个介绍:

43.2.1 第1步,准备好显示的字符

比如要显示如下字符,采用16点阵格式:

安富莱电子,www.armfly.com
故人西辞黄鹤楼,烟花三月下扬州。
孤帆远影碧空尽,唯见长江天际流。

43.2.2 第2步,复制要显示的字符到MakeDot小软件

选择16点阵,并将要显示的字符复制到输入窗口:

【STM32F429开发板用户手册】第43章       STM32F429的LTDC应用之汉字小字库和全字库制作 

点击生成数组按钮后的效果如下:

【STM32F429开发板用户手册】第43章       STM32F429的LTDC应用之汉字小字库和全字库制作 

43.2.3 第3步,复制生成的数组到工程中

在输出窗口鼠标右击,选择“全选”,然后再次鼠标右击选择复制。

【STM32F429开发板用户手册】第43章       STM32F429的LTDC应用之汉字小字库和全字库制作 

这样就可以粘贴到工程的hz.c文件里面:

【STM32F429开发板用户手册】第43章       STM32F429的LTDC应用之汉字小字库和全字库制作 

将点阵数据放在相应的文件里面时要注意加上两个0XFF。hz.c文件的内容如下:

/*
    FLASH中内嵌小字库,只包括本程序用到的汉字点阵
    每行点阵数据,头2字节是汉子的内码,后面是16点阵汉子的字模数据。
*/

#ifdef USE_SMALL_FONT

unsigned char const g_Hz16[] = {

0xA1,0xA3, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,////
           0x00,0x00,0x00,0x00,0x18,0x00,0x24,0x00,0x24,0x00,0x18,0x00,0x00,0x00,0x00,0x00,

           
0xA3,0xAC, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,////
           0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x00,0x30,0x00,0x10,0x00,0x20,0x00,0x00,0x00,

           
0xB0,0xB2, 0x02,0x00,0x01,0x00,0x3F,0xFC,0x20,0x04,0x42,0x08,0x02,0x00,0x02,0x00,0xFF,0xFE,////
           0x04,0x20,0x08,0x20,0x18,0x40,0x06,0x40,0x01,0x80,0x02,0x60,0x0C,0x10,0x70,0x08,

 /* 中间部分省略未写 */
           
0xD7,0xD3, 0x00,0x00,0x7F,0xF8,0x00,0x10,0x00,0x20,0x00,0x40,0x01,0x80,0x01,0x00,0xFF,0xFE,////
           0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x05,0x00,0x02,0x00,

          
/* 最后一行必须用0xFF,0xFF结束,这是字库数组结束标志 */
0xFF,0xFF

};

#else
    unsigned char const g_Hz16[] = {0xFF, 0xFF};
#endif

添加完毕点阵数据后,在font.h文件里面使能使用小字库:

#define USE_SMALL_FONT     /* 定义此行表示使用小字库, 这个宏只在bsp_tft+lcd.c中使用 */

至此就完成了小字库的汉字添加,用户就可以在使用16点阵时显示第1步中转换的字符了。

43.3 使用MakeDot小软件生成C文件格式全字库方法

生成方法比较简单,这里做个介绍:

43.3.1 第1步,准备好GB2312字符集

GB2312字符集已经在MakeDot小软件里面存好,点击汉字编码按钮可以看到:

【STM32F429开发板用户手册】第43章       STM32F429的LTDC应用之汉字小字库和全字库制作 

43.3.2 第2步,复制GB2312全部字符到MakeDot小软件

复制MakeDot小软件中GB2312所有字符到“输入窗口区”(在GB2312字符显示区,鼠标右击选择全选,之后就可以复制了),

 【STM32F429开发板用户手册】第43章       STM32F429的LTDC应用之汉字小字库和全字库制作

点击生成数组按钮后的效果如下:

【STM32F429开发板用户手册】第43章       STM32F429的LTDC应用之汉字小字库和全字库制作 

43.3.3 第3步,复制生成的数组到工程中

在输出窗口鼠标右击,选择“全选”,然后再次鼠标右击选择复制。

【STM32F429开发板用户手册】第43章       STM32F429的LTDC应用之汉字小字库和全字库制作 

这样就可以粘贴到工程的hz.c文件里面:

【STM32F429开发板用户手册】第43章       STM32F429的LTDC应用之汉字小字库和全字库制作 

将点阵数据放在相应的文件里面时要注意加上两个0XFF。hz.c文件的内容如下:

/*
    FLASH中内嵌小字库,只包括本程序用到的汉字点阵
    每行点阵数据,头2字节是汉子的内码,后面是16点阵汉子的字模数据。
*/

#ifdef USE_SMALL_FONT

unsigned char const g_Hz16[] = {



0xA1,0xA1, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//   //
           0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,

           
0xA1,0xA2, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,////
           0x00,0x00,0x00,0x00,0x20,0x00,0x18,0x00,0x0C,0x00,0x04,0x00,0x00,0x00,0x00,0x00,

           
0xA1,0xA3, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,////
           0x00,0x00,0x00,0x00,0x18,0x00,0x24,0x00,0x24,0x00,0x18,0x00,0x00,0x00,0x00,0x00,

 /* 中间部分省略未写 */
           
0xF7,0xFB, 0x20,0x0E,0xCE,0xF0,0x82,0x22,0xEE,0x92,0x82,0x44,0x82,0x20,0xFE,0x44,0x00,0xF8,////
           0x92,0x10,0x92,0x24,0xDA,0xFE,0x92,0x10,0xDA,0xFE,0x92,0x28,0x93,0x44,0xD9,0x82,

           
0xF7,0xFC, 0x10,0x20,0x3E,0x20,0x22,0x20,0x3E,0x20,0x22,0xF8,0x3E,0x28,0x00,0x28,0x7F,0x28,////
           0x49,0x28,0x7F,0x28,0x49,0x28,0x7F,0x2A,0x00,0x2A,0xFF,0xCA,0x22,0x46,0x42,0x80,

           
0xF7,0xFD, 0x10,0x00,0x3E,0x00,0x22,0x7C,0x3E,0x10,0x22,0x10,0x3E,0x10,0x00,0x10,0x7F,0x10,////
           0x49,0xFE,0x7F,0x10,0x49,0x10,0x7F,0x10,0x00,0x10,0xFF,0x90,0x22,0x10,0x42,0x10,

           
0xF7,0xFE, 0x10,0x10,0x3E,0x10,0x22,0xFE,0x3E,0x38,0x22,0x54,0x3E,0x92,0x00,0x00,0x7F,0x7C,////
           0x49,0x44,0x7F,0x7C,0x49,0x44,0x7F,0x7C,0x00,0x44,0xFF,0x80,0x22,0xFE,0x42,0x00,

          
/* 最后一行必须用0xFF,0xFF结束,这是字库数组结束标志 */
0xFF,0xFF

};

#else
    unsigned char const g_Hz16[] = {0xFF, 0xFF};
#endif

添加完毕点阵数据后,在font.h文件里面使能宏定义:

#define USE_SMALL_FONT     /*这个宏只在bsp_tft+lcd.c中使用 */

至此就完成了全字库的汉字添加,用户就可以使用16点阵的汉字了。

43.4 C文件格式汉字使用方法

汉字的显示方法比较简单。

  •   定义一个FONT_T类型变量:
FONT_T tFont12;        /* 定义一个12点阵字体结构体变量,用于设置字体参数 */
FONT_T tFont16;        /* 定义一个16点阵字体结构体变量,用于设置字体参数 */
FONT_T tFont24;        /* 定义一个24点阵字体结构体变量,用于设置字体参数 */

FONT_T的原始定义如下:

typedef struct
{
    FONT_CODE_E FontCode;    /* 字体代码 FONT_CODE_E  */
    uint16_t FrontColor;   /* 字体颜色 */
    uint16_t BackColor;    /* 文字背景颜色,透明 */
    uint16_t Space;        /* 文字间距,单位 = 像素 */
}FONT_T;
  •   初始化变量tFont:

设置12,16和24点阵。

/* 设置字体属性 */
tFont.FontCode = FC_ST_12;        /* 字体选择宋体12点阵,高12 x宽11) */
tFont.FrontColor = CL_WHITE;    /* 字体颜色设置为白色 */
tFont.BackColor = CL_MASK;         /* 文字背景颜色,透明 */
tFont.Space = 0;                /* 字符水平间距, 单位 = 像素 */

tFont.FontCode = FC_ST_16;        /* 字体选择宋体16点阵,高16 x宽15) */
tFont.FrontColor = CL_WHITE;    /* 字体颜色设置为白色 */
tFont.BackColor = CL_MASK;         /* 文字背景颜色,透明 */
tFont.Space = 0;                /* 字符水平间距, 单位 = 像素 */

tFont.FontCode = FC_ST_24;        /* 字体选择宋体24点阵,高24 x宽23) */
tFont.FrontColor = CL_WHITE;    /* 字体颜色设置为白色 */
tFont.BackColor = CL_MASK;         /* 文字背景颜色,透明 */
tFont.Space = 0;                /* 字符水平间距, 单位 = 像素 */
  •  调用函数LCD_DispStr显示字符:

下面显示了12,16和24点阵字符。

LCD_DispStr(5, 3,  "故人西辞黄鹤楼,烟花三月下扬州。www.armfly.com", &tFont12); 
LCD_DispStr(5, 20, "孤帆远影碧空尽,唯见长江天际流。www.armfly.com", &tFont12); 
LCD_DispStr(5, 38, "故人西辞黄鹤楼,烟花三月下扬州。", &tFont16); 
LCD_DispStr(5, 68, "孤帆远影碧空尽,唯见长江天际流。", &tFont16); 
LCD_DispStr(5, 98, "故人西辞黄鹤楼烟花三月下扬州", &tFont24); 
LCD_DispStr(5, 128, "孤帆远影碧空尽唯见长江天际流", &tFont24);

43.5 汉字显示方法解析

下面将汉字的显示流程做个说明,几个函数的调用关系如下:

LCD_DispStr ----> LCD_DispStrEx ----->_LCD_ReadAsciiDot

_LCD_ReadHZDot

43.5.1 函数LCD_DispStr

中英文显示都是调用的如下函数实现:

/*
*********************************************************************************************************
*    函 数 名: LCD_DispStr
*    功能说明: 在LCD指定坐标(左上角)显示一个字符串
*    形    参:
*        _usX : X坐标
*        _usY : Y坐标
*        _ptr  : 字符串指针
*        _tFont : 字体结构体,包含颜色、背景色(支持透明)、字体代码、文字间距等参数
*    返 回 值: 无
*********************************************************************************************************
*/
void LCD_DispStr(uint16_t _usX, uint16_t _usY, char *_ptr, FONT_T *_tFont)
{
    LCD_DispStrEx(_usX, _usY, _ptr, _tFont, 0, 0);
}

这个函数的注释已经比较详细,这里就不再赘述了。而这个函数是通过调用LCD_DispStrEx实现。

43.5.2 函数LCD_DispStrEx

此函数的源码如下:

1.    /*
2.    ******************************************************************************************************
3.    *    函 数 名: LCD_DispStrEx
4.    *    功能说明: 在LCD指定坐标(左上角)显示一个字符串。 增强型函数。支持左\中\右对齐,支持定长清屏。
5.    *    形    参:
6.    *        _usX : X坐标
7.    *        _usY : Y坐标
8.    *        _ptr  : 字符串指针
9.    *        _tFont : 字体结构体,包含颜色、背景色(支持透明)、字体代码、文字间距等参数。可以指定RA8875字库
10.    *                 显示汉字。
11.    *        _Width : 字符串显示区域的宽度. 0 表示不处理留白区域,此时_Align无效
12.    *        _Align :字符串在显示区域的对齐方式,
13.    *                ALIGN_LEFT = 0,
14.    *                ALIGN_CENTER = 1,
15.    *                ALIGN_RIGHT = 2
16.    *    返 回 值: 无
17.    ******************************************************************************************************
18.    */
19.    void LCD_DispStrEx(uint16_t _usX, uint16_t _usY, char *_ptr, FONT_T *_tFont, uint16_t _Width,
20.        uint8_t _Align)
21.    {
22.        uint32_t i;
23.        uint8_t code1;
24.        uint8_t code2;
25.        uint8_t buf[32 * 32 / 8];    /* 最大支持32点阵汉字 */
26.        uint8_t width;
27.        uint16_t m;
28.        uint8_t font_width = 0;
29.        uint8_t font_height = 0;
30.        uint16_t x, y;
31.        uint16_t offset;
32.        uint16_t str_width;    /* 字符串实际宽度  */
33.    
34.        switch (_tFont->FontCode)
35.        {
36.            case FC_ST_12:        /* 12点阵 */
37.                font_height = 12;
38.                font_width = 12;
39.                break;
40.            
41.            case FC_ST_16:
42.                font_height = 16;
43.                font_width = 16;
44.                break;
45.    
46.            case FC_ST_24:
47.                font_height = 24;
48.                font_width = 24;
49.                break;
50.                            
51.            case FC_ST_32:    
52.                font_height = 32;
53.                font_width = 32;
54.                break;                    
55.        }
56.        
57.        str_width = LCD_GetStrWidth(_ptr, _tFont);/* 计算字符串实际宽度(RA8875内部ASCII点阵宽度为变长 */
58.        offset = 0;
59.        if (_Width > str_width)
60.        {
61.            if (_Align == ALIGN_RIGHT)    /* 右对齐 */
62.            {
63.                offset = _Width - str_width;
64.            }
65.            else if (_Align == ALIGN_CENTER)    /* 居中 */
66.            {
67.                offset = (_Width - str_width) / 2;
68.            }
69.            else    /* 左对齐 ALIGN_LEFT */
70.            {
71.                ;
72.            }
73.        }
74.    
75.        /* 左侧填背景色, 中间对齐和右边对齐  */
76.        if (offset > 0)
77.        {
78.            LCD_Fill_Rect(_usX, _usY, LCD_GetFontHeight(_tFont), offset,  _tFont->BackColor);
79.            _usX += offset;
80.        }
81.        
82.        /* 右侧填背景色 */
83.        if (_Width > str_width)
84.        {
85.            LCD_Fill_Rect(_usX + str_width, _usY, LCD_GetFontHeight(_tFont), _Width - str_width - offset,
86.                            _tFont->BackColor);
87.        }
88.        
89.        /* 使用CPU内部字库. 点阵信息由CPU读取 */
90.        {
91.            /* 开始循环处理字符 */
92.            while (*_ptr != 0)
93.            {
94.                code1 = *_ptr;    /* 读取字符串数据, 该数据可能是ascii代码,也可能汉字代码的高字节 */
95.                if (code1 < 0x80)
96.                {
97.                    /* 将ascii字符点阵复制到buf */
98.                    //memcpy(buf, &pAscDot[code1 * (font_bytes / 2)], (font_bytes / 2));
99.                    _LCD_ReadAsciiDot(code1, _tFont->FontCode, buf);    /* 读取ASCII字符点阵 */
100.                    width = font_width / 2;
101.                }
102.                else
103.                {
104.                    code2 = *++_ptr;
105.                    if (code2 == 0)
106.                    {
107.                        break;
108.                    }
109.                    /* 读1个汉字的点阵 */
110.                    _LCD_ReadHZDot(code1, code2, _tFont->FontCode, buf);
111.                    width = font_width;
112.                }
113.        
114.                y = _usY;
115.                /* 开始刷LCD */
116.                for (m = 0; m < font_height; m++)    /* 字符高度 */
117.                {
118.                    x = _usX;
119.                    for (i = 0; i < width; i++)    /* 字符宽度 */
120.                    {
121.                        if ((buf[m * ((2 * width) / font_width) + i / 8] & (0x80 >> (i % 8 ))) != 0x00)
122.                        {
123.                            LCD_PutPixel(x, y, _tFont->FrontColor);    /* 设置像素颜色为文字色 */
124.                        }
125.                        else
126.                        {
127.                            if (_tFont->BackColor != CL_MASK)    /* 透明色 */
128.                            {
129.                                LCD_PutPixel(x, y, _tFont->BackColor);/* 设置像素颜色为文字背景色 */
130.                            }
131.                        }
132.        
133.                        x++;
134.                    }
135.                    y++;
136.                }
137.        
138.                if (_tFont->Space > 0)
139.                {
140.                    /* 如果文字底色按_tFont->usBackColor,并且字间距大于点阵的宽度,那么需要在文字之间填
141.                          充(暂时未实现) */
142.                }
143.                _usX += width + _tFont->Space;    /* 列地址递增 */
144.                _ptr++;            /* 指向下一个字符 */
145.            }
146.        }
147.    }

下面将代码中几个关键地方做个阐释:

  •   第34-55行,根据使用的的12,16,24和32点阵字体,设置字体的高度变量font_height和宽度变量font_width。
  •   第57-73行,通过函数LCD_GetStrWidth计算字符串的长度,然后根据设置的字符总宽度和实际宽度做比较,来实现左对齐,右对齐和居中显示。由于函数LCD_DispStr调用LCD_DispStrEx时,将形参_Width设置为0,所以这部分代码功能未用到。
  •   第76-87行,用于填充显示字符以外区域的背景色,只有设置的字符总宽度大于实际宽度时才会用到,填充的就是实际宽度以外的区域。
  •   第90-146行,显示所有字符。
    •   第95行,如果编码值小于0x80,表示ASCII字符。
    •   第99行,根据编码值读取ASCII值对应的点阵数据到数组buf里面。
    •   第100行,显示ASCII字符仅需要一半宽度即可,比如显示12*12点阵字符,显示成ASCII仅需6*12即可。
    •   第102行,如果编码值大于等于0x80,汉字编码在这个范围。
    •   第104行,因为GB编码需要两个字节表示,所以这里再读取一个字节。
    •   第110行,根据汉字编码值对应的点阵数据到数组buf里面。
    •   第116-136行,采用从左到右,从上到下的方式刷新字符。这里特别注意点阵数据位置的获取:buf[m * ((2 * width) / font_width) + i / 8] & (0x80 >> (i % 8 )

对于这个公式,大家通过代数法,代入两次数值就好理解了。

43.5.3 函数_LCD_ReadAsciiDot

此函数的作用是根据ASCII编码值,读取对应的点阵数据出来。

1.    /*
2.    ******************************************************************************************************
3.    *    函 数 名: _LCD_ReadAsciiDot
4.    *    功能说明: 读取1个ASCII字符的点阵数据
5.    *    形    参:
6.    *        _code : ASCII字符的编码,1字节。1-128
7.    *        _fontcode :字体代码
8.    *        _pBuf : 存放读出的字符点阵数据
9.    *    返 回 值: 文字宽度
10.    ******************************************************************************************************
11.    */
12.    static void _LCD_ReadAsciiDot(uint8_t _code, uint8_t _fontcode, uint8_t *_pBuf)
13.    {
14.        const uint8_t *pAscDot;
15.        uint8_t font_bytes = 0;
16.    
17.        pAscDot = 0;
18.        switch (_fontcode)
19.        {
20.            case FC_ST_12:        /* 12点阵 */
21.                font_bytes = 24;
22.                pAscDot = g_Ascii12;    
23.                break;
24.            
25.            case FC_ST_24:
26.            case FC_ST_32:
27.            case FC_ST_16:
28.                /* 缺省是16点阵 */
29.                font_bytes = 32;
30.                pAscDot = g_Ascii16;
31.                break;
32.            
33.            case FC_RA8875_16:
34.            case FC_RA8875_24:
35.            case FC_RA8875_32:
36.                return;
37.        }    
38.    
39.        /* 将CPU内部Flash中的ascii字符点阵复制到buf */
40.        memcpy(_pBuf, &pAscDot[_code * (font_bytes / 2)], (font_bytes / 2));    
41.    }

下面将此函数涉及到的知识点为大家做个阐释:

  •   第20-23行,显示12点阵ASCII,每个字符需要24个字节,存储在数组g_Ascii12里面。
  •   第25-31行,显示16,24和32点阵ASCII,这里采用同一大小字符进行显示。每个字符需要32个字节,存储在数组g_Ascii16里面。
  •   第33-35行,这个是RA8875的字库处理,V6开发板用不到。
  •   第40行,将ASCII点阵数据复制到缓冲_pBuf里面。

43.5.4 函数_LCD_ReadHZDot

此函数的作用是根据ASCII编码值,读取对应的点阵数据出来。

1.    /*
2.    ******************************************************************************************************
3.    *    函 数 名: _LCD_ReadHZDot
4.    *    功能说明: 读取1个汉字的点阵数据
5.    *    形    参:
6.    *        _code1, _cod2 : 汉字内码. GB2312编码
7.    *        _fontcode :字体代码
8.    *        _pBuf : 存放读出的字符点阵数据
9.    *    返 回 值: 无
10.    ******************************************************************************************************
11.    */
12.    static void _LCD_ReadHZDot(uint8_t _code1, uint8_t _code2,  uint8_t _fontcode, uint8_t *_pBuf)
13.    {
14.        #ifdef USE_SMALL_FONT    /* 使用CPU 内部Flash 小字库 */
15.            uint8_t *pDot;
16.            uint8_t font_bytes = 0;
17.            uint32_t address;
18.            uint16_t m;
19.    
20.            pDot = 0;    /* 仅仅用于避免告警 */
21.            switch (_fontcode)
22.            {
23.                case FC_ST_12:        /* 12点阵 */
24.                    font_bytes = 24;
25.                    pDot = (uint8_t *)g_Hz12;    
26.                    break;
27.                
28.                case FC_ST_16:
29.                    font_bytes = 32;
30.                    pDot = (uint8_t *)g_Hz16;
31.                    break;
32.        
33.                case FC_ST_24:
34.                    font_bytes = 72;
35.                    pDot = (uint8_t *)g_Hz24;
36.                    break;            
37.                    
38.                case FC_ST_32:    
39.                    font_bytes = 128;
40.                    pDot = (uint8_t *)g_Hz32;
41.                    break;                        
42.                
43.                case FC_RA8875_16:
44.                case FC_RA8875_24:
45.                case FC_RA8875_32:
46.                    return;
47.            }    
48.    
49.            m = 0;
50.            while(1)
51.            {
52.                address = m * (font_bytes + 2);
53.                m++;
54.                if ((_code1 == pDot[address + 0]) && (_code2 == pDot[address + 1]))
55.                {
56.                    address += 2;
57.                    memcpy(_pBuf, &pDot[address], font_bytes);
58.                    break;
59.                }
60.                else if ((pDot[address + 0] == 0xFF) && (pDot[address + 1] == 0xFF))
61.                {
62.                    /* 字库搜索完毕,未找到,则填充全FF */
63.                    memset(_pBuf, 0xFF, font_bytes);
64.                    break;
65.                }
66.            }
67.        #else    /* 用全字库 */
68.            uint8_t *pDot = 0;
69.            uint8_t font_bytes = 0;
70.                
71.            switch (_fontcode)
72.            {
73.                case FC_ST_12:        /* 12点阵 */
74.                    font_bytes = 24;
75.                    pDot = (uint8_t *)HZK12_ADDR;    
76.                    break;
77.                
78.                case FC_ST_16:
79.                    font_bytes = 32;
80.                    pDot = (uint8_t *)HZK16_ADDR;
81.                    break;
82.        
83.                case FC_ST_24:
84.                    font_bytes = 72;
85.                    pDot = (uint8_t *)HZK24_ADDR;
86.                    break;            
87.                    
88.                case FC_ST_32:    
89.                    font_bytes = 128;
90.                    pDot = (uint8_t *)HZK32_ADDR;
91.                    break;                        
92.                
93.                case FC_RA8875_16:
94.                case FC_RA8875_24:
95.                case FC_RA8875_32:
96.                    return;
97.            }            
98.        
99.            /* 此处需要根据字库文件存放位置进行修改 */
100.            if (_code1 >=0xA1 && _code1 <= 0xA9 && _code2 >=0xA1)
101.            {
102.                pDot += ((_code1 - 0xA1) * 94 + (_code2 - 0xA1)) * font_bytes;
103.            }
104.            else if (_code1 >=0xB0 && _code1 <= 0xF7 && _code2 >=0xA1)
105.            {
106.                pDot += ((_code1 - 0xB0) * 94 + (_code2 - 0xA1) + 846) * font_bytes;
107.            }
108.            memcpy(_pBuf, pDot, font_bytes);
109.        #endif
110.    }

下面将此函数涉及到的知识点为大家做个阐释:

  •   第15-66行,小字库显示,这个方案既可以显示小字库,也可以显示全字库。
    •   第23-41行,获取12点阵,16点阵,24点阵和32点阵汉字显示需要的字节数以及存储点阵数据的缓冲地址。
    •   第49-66行,这里是通过比较汉字的编码值找到点阵数据位置,如果遇到两个0xFF,表示检索到数组末尾了也没有找到汉字点阵数组。找到数据后,将其复制到缓冲_pBuf里面。
  •   第68-108行,本章暂时用不到这种方案,后面章节用到这种方案了再为大家做说明。

43.6 LCD驱动移植和使用

与第41章41.7小节相同,这里就不再赘述了。

43.7 实验例程设计框架

通过程序设计框架,让大家先对配套例程有一个全面的认识,然后再理解细节,本次实验例程的设计框架如下:

【STM32F429开发板用户手册】第43章       STM32F429的LTDC应用之汉字小字库和全字库制作

  第1阶段,上电启动阶段:

  • 这部分在第14章进行了详细说明。

  第2阶段,进入main函数:

  •  第1步,硬件初始化,主要是HAL库,系统时钟,滴答定时器,LED,串口,LCD,SDRAM等。
  •  第2步,LCD应用程序设计部分,显示汉字。通过按键实现三种界面的处理,其中GB2312有几十个界面。

43.8 实验例程说明(MDK)

配套例子:

V6-021_LCD的汉字小字库和全字库制作

实验目的:

  1. 学习LCD的汉字小字库和全字库制作实验。

实验内容:

  1. 小字库和全字库通过此软件生成:
  2. LCD界面上展示ASCII字符和GB2312编码汉字。
  3. 启动1个200ms的自动重装定时器,让LED2每200ms翻转一次。

实验操作:

  1. 摇杆上键,增加LCD背景光亮度。
  2. 摇杆下键,降低LCD背景光亮度。
  3. 摇杆左键,显示上一页汉字。
  4. 摇杆右键,显示下一页汉字。
  5. 摇杆OK键,返回首页。

LCD的界面显示效果如下:

部分截图:

【STM32F429开发板用户手册】第43章       STM32F429的LTDC应用之汉字小字库和全字库制作 

 【STM32F429开发板用户手册】第43章       STM32F429的LTDC应用之汉字小字库和全字库制作

 【STM32F429开发板用户手册】第43章       STM32F429的LTDC应用之汉字小字库和全字库制作

上电后串口打印的信息:

波特率 115200,数据位 8,奇偶校验位无,停止位 1

【STM32F429开发板用户手册】第43章       STM32F429的LTDC应用之汉字小字库和全字库制作 

程序设计:

  系统栈大小分配:

【STM32F429开发板用户手册】第43章       STM32F429的LTDC应用之汉字小字库和全字库制作 

  硬件外设初始化

硬件外设的初始化是在 bsp.c 文件实现:

/*
*********************************************************************************************************
*    函 数 名: bsp_Init
*    功能说明: 初始化所有的硬件设备。该函数配置CPU寄存器和外设的寄存器并初始化一些全局变量。只需要调用一次
*    形    参:无
*    返 回 值: 无
*********************************************************************************************************
*/
void bsp_Init(void)
{
    /* 
       STM32F429 HAL 库初始化,此时系统用的还是F429自带的16MHz,HSI时钟:
       - 调用函数HAL_InitTick,初始化滴答时钟中断1ms。
       - 设置NVIV优先级分组为4。
     */
    HAL_Init();

    /* 
       配置系统时钟到168MHz
       - 切换使用HSE。
       - 此函数会更新全局变量SystemCoreClock,并重新配置HAL_InitTick。
    */
    SystemClock_Config();


    /* 
       Event Recorder:
       - 可用于代码执行时间测量,MDK5.25及其以上版本才支持,IAR不支持。
       - 默认不开启,如果要使能此选项,务必看V7开发板用户手册第8章
    */    
#if Enable_EventRecorder == 1  
    /* 初始化EventRecorder并开启 */
    EventRecorderInitialize(EventRecordAll, 1U);
    EventRecorderStart();
#endif
    
    bsp_InitKey();        /* 按键初始化,要放在滴答定时器之前,因为按钮检测是通过滴答定时器扫描 */
    bsp_InitTimer();      /* 初始化滴答定时器 */
    bsp_InitUart();    /* 初始化串口 */
    bsp_InitExtIO();    /* 初始化FMC总线74HC574扩展IO. 必须在 bsp_InitLed()前执行 */    
    bsp_InitLed();        /* 初始化LED */    

    bsp_InitI2C();     /* 初始化I2C总线 */
    TOUCH_InitHard();   /* 初始化触摸芯片,LCD面板型号的检查也在此函数,所以要在函数LCD_InitHard前调用 */ 
    LCD_InitHard();     /* 初始化LCD */
}

  主功能:

主程序实现如下操作:

  •   LCD界面上展示ASCII字符和GB2312编码汉字
  •   启动1个200ms的自动重装定时器,让LED2每200ms翻转一次。
  •   通过按键来实现翻页功能,方便查看所有GB2312编码汉字。
/*
*********************************************************************************************************
*    函 数 名: main
*    功能说明: c程序入口
*    形    参: 无
*    返 回 值: 错误代码(无需处理)
*********************************************************************************************************
*/
int main(void)
{
    uint16_t ucBright;           /* 背光亮度(0-255) */
    uint8_t ucKeyCode;        /* 按键代码 */
    uint8_t ucStatus;        /* 主程序状态字 */
    uint8_t fRefresh;        /* 刷屏请求标志,1表示需要刷新 */
    
    
    bsp_Init();    /* 硬件初始化 */
    PrintfLogo();    /* 打印例程名称和版本等信息 */
    PrintfHelp();    /* 打印操作提示 */

    /* 延迟200ms再点亮背光,避免瞬间高亮 */
    bsp_DelayMS(200); 
    
    DispFirstPage();    /* 显示第1页 */
    
    /* 界面整体显示完毕后,再打开背光,设置为缺省亮度 */
    bsp_DelayMS(100); 
    ucBright = BRIGHT_DEFAULT;
    LCD_SetBackLight(ucBright);
    
    bsp_StartAutoTimer(0, 200); /* 启动1个200ms的自动重装的定时器,软件定时器0 */
    
    /* 进入主程序循环体 */
    ucStatus = 0;
    fRefresh = 0;    
    while (1)
    {
        /* 判断软件定时器0是否超时 */
        if(bsp_CheckTimer(0))
        {
            /* 每隔200ms 进来一次 */  
            bsp_LedToggle(2);
        }
        
        if (fRefresh == 1)
        {
            fRefresh = 0;

            switch (ucStatus)
            {
                case 0:
                    DispFirstPage();    /* 显示第1页 */
                    break;

                case 1:
                    DispAsciiDot();        /* 显示ASCII点阵 */
                    break;

                default:
                    /* 区码范围 :1 - 87 */
                    if (ucStatus <= 89)
                    {
                        DispHZK16(ucStatus);    /* 显示一个区的94个汉字 */
                    }
                    break;
            }
        }

        ucKeyCode = bsp_GetKey();    /* 读取键值, 无键按下时返回 KEY_NONE = 0 */
        if (ucKeyCode != KEY_NONE)
        {
            /* 有键按下 */
            switch (ucKeyCode)
            {
                case JOY_DOWN_L:        /* 摇杆LEFT键按下 */
                    if (ucStatus > 0)
                    {
                        ucStatus--;
                    }
                    fRefresh = 1;        /* 请求刷新LCD */
                    break;

                case JOY_DOWN_R:        /* 摇杆RIGHT键按下 */
                    if (ucStatus < DEMO_PAGE_COUNT - 1)
                    {
                        ucStatus++;
                    }
                    fRefresh = 1;        /* 请求刷新LCD */
                    break;

                case  JOY_DOWN_OK:        /* 摇杆OK键 */
                    ucStatus = 0;        /* 返回首页 */                    
                    fRefresh = 1;        /* 请求刷新LCD */
                    break;

                case JOY_DOWN_U:        /* 摇杆UP键按下 */
                    ucBright += BRIGHT_STEP;
                    if (ucBright > BRIGHT_MAX)
                    {
                        ucBright = BRIGHT_MAX;
                    }
                    LCD_SetBackLight(ucBright);
                    printf("当前背景光亮度 : %d\r\n", ucBright);
                    break;

                case JOY_DOWN_D:        /* 摇杆DOWN键按下 */
                    if (ucBright < BRIGHT_STEP)
                    {
                        ucBright = 0;
                    }
                    else
                    {
                        ucBright -= BRIGHT_STEP;
                    }
                    LCD_SetBackLight(ucBright);
                    printf("当前背景光亮度 : %d\r\n", ucBright);
                    break;

                default:
                    break;
            }
        }
    }
}

下面的代码用于LCD首页显示:

/*
*********************************************************************************************************
*    函 数 名: DispFirstPage
*    功能说明: 显示操作提示
*    形    参:无
*    返 回 值: 无
*********************************************************************************************************
*/
static void DispFirstPage(void)
{
    FONT_T tFont;            /* 定义一个字体结构体变量,用于设置字体参数 */
    uint16_t y;            /* Y坐标 */
    uint16_t usLineCap;    /* 行高 */
    uint8_t buf[50];

    LCD_ClrScr(CL_BLUE);          /* 清屏,背景蓝色 */
    
    
    /* 设置字体属性 */
    tFont.FontCode = FC_ST_16;        /* 字体选择宋体16点阵,高16x宽15) */
    tFont.FrontColor = CL_WHITE;    /* 字体颜色设置为白色 */
    tFont.BackColor = CL_MASK;         /* 文字背景颜色,透明 */
    tFont.Space = 0;                /* 字符水平间距, 单位 = 像素 */

    y = 0;
    usLineCap = 18; /* 行间距 */
    LCD_DispStr(5, y, "安富莱STM32-V6开发板  www.armfly.com", &tFont);
    y += usLineCap;
    LCD_DispStr(5, y, "汉字小字库和全字库测试实验", &tFont);
    
    y += 2 * usLineCap;
    LCD_DispStr(30, y, "操作提示:", &tFont);
    
    y += usLineCap;
    LCD_DispStr(50, y, "摇杆上键 = 增加背光亮度", &tFont);
    
    y += usLineCap;
    LCD_DispStr(50, y, "摇杆下键 = 降低背光亮度", &tFont);
    
    y += usLineCap;
    LCD_DispStr(50, y, "摇杆左键 = 向前翻页", &tFont);
    
    y += usLineCap;
    LCD_DispStr(50, y, "摇杆右键 = 向后翻页", &tFont);
    
    y += usLineCap;
    LCD_DispStr(50, y, "摇杆OK键 = 返回首页", &tFont);

    y += 2 * usLineCap;    
    
    sprintf((char *)buf, "显示器分辨率 :%dx%d", g_LcdWidth, g_LcdHeight);
    LCD_DispStr(5, y, (char *)buf, &tFont);
    
    y += usLineCap;
    LCD_DispStr(5, y, "每行可以显示25个汉字,或50个字符", &tFont);
}

下面是ASCII字符显示:

/*
*********************************************************************************************************
*    函 数 名: DispAsciiDot
*    功能说明: 显示ASCII点阵
*    形    参:无
*    返 回 值: 无
*********************************************************************************************************
*/
static void DispAsciiDot(void)
{
    uint8_t i,k;
    FONT_T tFont;        /* 定义一个字体结构体变量,用于设置字体参数 */
    uint16_t x;        /* X坐标 */
    uint16_t y;        /* Y坐标 */    
    char buf[32 + 1];
    uint8_t ascii;

    LCD_ClrScr(CL_BLUE);          /* 清屏,背景蓝色 */
    
    /* 设置字体属性 */
    tFont.FontCode = FC_ST_16;        /* 字体选择宋体16点阵,高16x宽15) */
    tFont.FrontColor = CL_WHITE;    /* 字体颜色设置为白色 */
    tFont.BackColor = CL_MASK;         /* 文字背景颜色,透明 */
    tFont.Space = 2;                /* 字符水平间距, 单位 = 像素 */

    LCD_DispStr(50, 0, "16点阵ASCII码字库,代码1-127", &tFont);

    x = 50;
    y = 40;
    ascii = 0;
    for (i = 0; i < 4; i++)
    {
        for (k = 0; k < 32; k++)
        {
            buf[k] = ascii++;
        }
        buf[32] = 0;
        if (buf[0] == 0)
        {
            buf[0] = ' ';
        }
        LCD_DispStr(x, y, buf, &tFont);
        y += 20;
    }
}

下面是GB2312编码字符显示:

/*
*********************************************************************************************************
*    函 数 名: DispHZK16
*    功能说明: 显示16点阵汉字阵
*    形    参:无
*    返 回 值: 无
*********************************************************************************************************
*/
static void DispHZK16(uint8_t _ucIndex)
{
    uint8_t i,k;
    uint16_t x,y;
    char buf[50 + 1];
    uint8_t code1,code2;    /* 汉字内码 */
    uint8_t usLineCap = 18;
    FONT_T tFont;            /* 定义一个字体结构体变量,用于设置字体参数 */

    printf(" Display HZK Area Code = %d\r\n", _ucIndex - 1);

    if (_ucIndex == 2)
    {
        /* 第1次清屏,以后显示位置不变,可以不清屏,避免闪烁 */
        LCD_ClrScr(CL_BLUE);          /* 清屏,背景蓝色 */
    }
    
    /* 设置字体属性 */
    tFont.FontCode = FC_ST_16;        /* 字体选择宋体16点阵,高16x宽15) */
    tFont.FrontColor = CL_WHITE;    /* 字体颜色设置为白色 */
    tFont.BackColor = CL_BLUE;         /* 文字背景颜色,蓝色 */
    tFont.Space = 0;                /* 字符水平间距, 单位 = 像素 */

    y = 0;
    LCD_DispStr(20, y, "国标GB2312 16点阵汉字库(区码1-87,位码1-94)", &tFont);

    code1 = _ucIndex - 1; /* 得到区码 */
    code2 = 1;            /* 位码从1开始 */

    y += usLineCap;
    sprintf((char *)buf, (char *)"当前区码: %2d, 本页位码:1-94, 第10-15区无字符", code1);
    LCD_DispStr(20, y, buf, &tFont);
    y += (2 * usLineCap);

    /*
        机内码高位 = 区码 + 0xA0
        机内码低位 = 位码 + 0xA0

        区码范围 :1 - 87
        位码范围 : 1 - 94

        每行显示20个汉字,一个区是94个汉字,需要5行显示,第5行显示14个汉字
    */
    
    x = 40;
    code1 += 0xA0; /* 换算到内码高位 */
    code2 = 0xA1;  /* 内码低位起始 */
    for (i = 0; i < 5; i++)
    {
        for (k = 0; k < 20; k++)
        {
            buf[2 * k] = code1;
            buf[2 * k + 1] = code2;
            code2++;
            if ((i == 4) && (k == 13))
            {
                k++;
                break;
            }
        }
        buf[2 * k] = 0;
        LCD_DispStr(x, y, buf, &tFont);
        y += usLineCap;
    }
}

43.9 实验例程说明(IAR)

配套例子:

V6-021_LCD的汉字小字库和全字库制作

实验目的:

  1. 学习LCD的汉字小字库和全字库制作实验。

实验内容:

  1. 小字库和全字库通过此软件生成:
  2. LCD界面上展示ASCII字符和GB2312编码汉字。
  3. 启动1个200ms的自动重装定时器,让LED2每200ms翻转一次。

实验操作:

  1. 摇杆上键,增加LCD背景光亮度。
  2. 摇杆下键,降低LCD背景光亮度。
  3. 摇杆左键,显示上一页汉字。
  4. 摇杆右键,显示下一页汉字。
  5. 摇杆OK键,返回首页。

LCD的界面显示效果如下:

部分截图:

【STM32F429开发板用户手册】第43章       STM32F429的LTDC应用之汉字小字库和全字库制作 

 【STM32F429开发板用户手册】第43章       STM32F429的LTDC应用之汉字小字库和全字库制作

 【STM32F429开发板用户手册】第43章       STM32F429的LTDC应用之汉字小字库和全字库制作

上电后串口打印的信息:

波特率 115200,数据位 8,奇偶校验位无,停止位 1

【STM32F429开发板用户手册】第43章       STM32F429的LTDC应用之汉字小字库和全字库制作 

程序设计:

  系统栈大小分配:

【STM32F429开发板用户手册】第43章       STM32F429的LTDC应用之汉字小字库和全字库制作 

  硬件外设初始化

硬件外设的初始化是在 bsp.c 文件实现:

/*
*********************************************************************************************************
*    函 数 名: bsp_Init
*    功能说明: 初始化所有的硬件设备。该函数配置CPU寄存器和外设的寄存器并初始化一些全局变量。只需要调用一次
*    形    参:无
*    返 回 值: 无
*********************************************************************************************************
*/
void bsp_Init(void)
{
    /* 配置MPU */
    MPU_Config();
    
    /* 使能L1 Cache */
    CPU_CACHE_Enable();

    /* 
       STM32H7xx HAL 库初始化,此时系统用的还是H7自带的64MHz,HSI时钟:
       - 调用函数HAL_InitTick,初始化滴答时钟中断1ms。
       - 设置NVIV优先级分组为4。
     */
    HAL_Init();

    /* 
       配置系统时钟到400MHz
       - 切换使用HSE。
       - 此函数会更新全局变量SystemCoreClock,并重新配置HAL_InitTick。
    */
    SystemClock_Config();

    /* 
       Event Recorder:
       - 可用于代码执行时间测量,MDK5.25及其以上版本才支持,IAR不支持。
       - 默认不开启,如果要使能此选项,务必看V7开发板用户手册第8章
    */    
#if Enable_EventRecorder == 1  
    /* 初始化EventRecorder并开启 */
    EventRecorderInitialize(EventRecordAll, 1U);
    EventRecorderStart();
#endif
    
    bsp_InitKey();        /* 按键初始化,要放在滴答定时器之前,因为按钮检测是通过滴答定时器扫描 */
    bsp_InitTimer();      /* 初始化滴答定时器 */
    bsp_InitUart();    /* 初始化串口 */
    bsp_InitExtIO();    /* 初始化FMC总线74HC574扩展IO. 必须在 bsp_InitLed()前执行 */    
    bsp_InitLed();        /* 初始化LED */    

    bsp_InitI2C();     /* 初始化I2C总线 */
    TOUCH_InitHard();   /* 初始化触摸芯片,LCD面板型号的检查也在此函数,所以要在函数LCD_InitHard前调用 */ 
    LCD_InitHard();     /* 初始化LCD */
}

  主功能:

主程序实现如下操作:

  •   LCD界面上展示ASCII字符和GB2312编码汉字
  •   启动1个200ms的自动重装定时器,让LED2每200ms翻转一次。
  •   通过按键来实现翻页功能,方便查看所有GB2312编码汉字。
/*
*********************************************************************************************************
*    函 数 名: main
*    功能说明: c程序入口
*    形    参: 无
*    返 回 值: 错误代码(无需处理)
*********************************************************************************************************
*/
int main(void)
{
    uint16_t ucBright;           /* 背光亮度(0-255) */
    uint8_t ucKeyCode;        /* 按键代码 */
    uint8_t ucStatus;        /* 主程序状态字 */
    uint8_t fRefresh;        /* 刷屏请求标志,1表示需要刷新 */
    
    
    bsp_Init();    /* 硬件初始化 */
    PrintfLogo();    /* 打印例程名称和版本等信息 */
    PrintfHelp();    /* 打印操作提示 */

    /* 延迟200ms再点亮背光,避免瞬间高亮 */
    bsp_DelayMS(200); 
    
    DispFirstPage();    /* 显示第1页 */
    
    /* 界面整体显示完毕后,再打开背光,设置为缺省亮度 */
    bsp_DelayMS(100); 
    ucBright = BRIGHT_DEFAULT;
    LCD_SetBackLight(ucBright);
    
    bsp_StartAutoTimer(0, 200); /* 启动1个200ms的自动重装的定时器,软件定时器0 */
    
    /* 进入主程序循环体 */
    ucStatus = 0;
    fRefresh = 0;    
    while (1)
    {
        /* 判断软件定时器0是否超时 */
        if(bsp_CheckTimer(0))
        {
            /* 每隔200ms 进来一次 */  
            bsp_LedToggle(2);
        }
        
        if (fRefresh == 1)
        {
            fRefresh = 0;

            switch (ucStatus)
            {
                case 0:
                    DispFirstPage();    /* 显示第1页 */
                    break;

                case 1:
                    DispAsciiDot();        /* 显示ASCII点阵 */
                    break;

                default:
                    /* 区码范围 :1 - 87 */
                    if (ucStatus <= 89)
                    {
                        DispHZK16(ucStatus);    /* 显示一个区的94个汉字 */
                    }
                    break;
            }
        }

        ucKeyCode = bsp_GetKey();    /* 读取键值, 无键按下时返回 KEY_NONE = 0 */
        if (ucKeyCode != KEY_NONE)
        {
            /* 有键按下 */
            switch (ucKeyCode)
            {
                case JOY_DOWN_L:        /* 摇杆LEFT键按下 */
                    if (ucStatus > 0)
                    {
                        ucStatus--;
                    }
                    fRefresh = 1;        /* 请求刷新LCD */
                    break;

                case JOY_DOWN_R:        /* 摇杆RIGHT键按下 */
                    if (ucStatus < DEMO_PAGE_COUNT - 1)
                    {
                        ucStatus++;
                    }
                    fRefresh = 1;        /* 请求刷新LCD */
                    break;

                case  JOY_DOWN_OK:        /* 摇杆OK键 */
                    ucStatus = 0;        /* 返回首页 */                    
                    fRefresh = 1;        /* 请求刷新LCD */
                    break;

                case JOY_DOWN_U:        /* 摇杆UP键按下 */
                    ucBright += BRIGHT_STEP;
                    if (ucBright > BRIGHT_MAX)
                    {
                        ucBright = BRIGHT_MAX;
                    }
                    LCD_SetBackLight(ucBright);
                    printf("当前背景光亮度 : %d\r\n", ucBright);
                    break;

                case JOY_DOWN_D:        /* 摇杆DOWN键按下 */
                    if (ucBright < BRIGHT_STEP)
                    {
                        ucBright = 0;
                    }
                    else
                    {
                        ucBright -= BRIGHT_STEP;
                    }
                    LCD_SetBackLight(ucBright);
                    printf("当前背景光亮度 : %d\r\n", ucBright);
                    break;

                default:
                    break;
            }
        }
    }
}

下面的代码用于LCD首页显示:

/*
*********************************************************************************************************
*    函 数 名: DispFirstPage
*    功能说明: 显示操作提示
*    形    参:无
*    返 回 值: 无
*********************************************************************************************************
*/
static void DispFirstPage(void)
{
    FONT_T tFont;            /* 定义一个字体结构体变量,用于设置字体参数 */
    uint16_t y;            /* Y坐标 */
    uint16_t usLineCap;    /* 行高 */
    uint8_t buf[50];

    LCD_ClrScr(CL_BLUE);          /* 清屏,背景蓝色 */
    
    
    /* 设置字体属性 */
    tFont.FontCode = FC_ST_16;        /* 字体选择宋体16点阵,高16x宽15) */
    tFont.FrontColor = CL_WHITE;    /* 字体颜色设置为白色 */
    tFont.BackColor = CL_MASK;         /* 文字背景颜色,透明 */
    tFont.Space = 0;                /* 字符水平间距, 单位 = 像素 */

    y = 0;
    usLineCap = 18; /* 行间距 */
    LCD_DispStr(5, y, "安富莱STM32-V6开发板  www.armfly.com", &tFont);
    y += usLineCap;
    LCD_DispStr(5, y, "汉字小字库和全字库测试实验", &tFont);
    
    y += 2 * usLineCap;
    LCD_DispStr(30, y, "操作提示:", &tFont);
    
    y += usLineCap;
    LCD_DispStr(50, y, "摇杆上键 = 增加背光亮度", &tFont);
    
    y += usLineCap;
    LCD_DispStr(50, y, "摇杆下键 = 降低背光亮度", &tFont);
    
    y += usLineCap;
    LCD_DispStr(50, y, "摇杆左键 = 向前翻页", &tFont);
    
    y += usLineCap;
    LCD_DispStr(50, y, "摇杆右键 = 向后翻页", &tFont);
    
    y += usLineCap;
    LCD_DispStr(50, y, "摇杆OK键 = 返回首页", &tFont);

    y += 2 * usLineCap;    
    
    sprintf((char *)buf, "显示器分辨率 :%dx%d", g_LcdWidth, g_LcdHeight);
    LCD_DispStr(5, y, (char *)buf, &tFont);
    
    y += usLineCap;
    LCD_DispStr(5, y, "每行可以显示25个汉字,或50个字符", &tFont);
}

下面是ASCII字符显示:

/*
*********************************************************************************************************
*    函 数 名: DispAsciiDot
*    功能说明: 显示ASCII点阵
*    形    参:无
*    返 回 值: 无
*********************************************************************************************************
*/
static void DispAsciiDot(void)
{
    uint8_t i,k;
    FONT_T tFont;        /* 定义一个字体结构体变量,用于设置字体参数 */
    uint16_t x;        /* X坐标 */
    uint16_t y;        /* Y坐标 */    
    char buf[32 + 1];
    uint8_t ascii;

    LCD_ClrScr(CL_BLUE);          /* 清屏,背景蓝色 */
    
    /* 设置字体属性 */
    tFont.FontCode = FC_ST_16;        /* 字体选择宋体16点阵,高16x宽15) */
    tFont.FrontColor = CL_WHITE;    /* 字体颜色设置为白色 */
    tFont.BackColor = CL_MASK;         /* 文字背景颜色,透明 */
    tFont.Space = 2;                /* 字符水平间距, 单位 = 像素 */

    LCD_DispStr(50, 0, "16点阵ASCII码字库,代码1-127", &tFont);

    x = 50;
    y = 40;
    ascii = 0;
    for (i = 0; i < 4; i++)
    {
        for (k = 0; k < 32; k++)
        {
            buf[k] = ascii++;
        }
        buf[32] = 0;
        if (buf[0] == 0)
        {
            buf[0] = ' ';
        }
        LCD_DispStr(x, y, buf, &tFont);
        y += 20;
    }
}

下面是GB2312编码字符显示:

/*
*********************************************************************************************************
*    函 数 名: DispHZK16
*    功能说明: 显示16点阵汉字阵
*    形    参:无
*    返 回 值: 无
*********************************************************************************************************
*/
static void DispHZK16(uint8_t _ucIndex)
{
    uint8_t i,k;
    uint16_t x,y;
    char buf[50 + 1];
    uint8_t code1,code2;    /* 汉字内码 */
    uint8_t usLineCap = 18;
    FONT_T tFont;            /* 定义一个字体结构体变量,用于设置字体参数 */

    printf(" Display HZK Area Code = %d\r\n", _ucIndex - 1);

    if (_ucIndex == 2)
    {
        /* 第1次清屏,以后显示位置不变,可以不清屏,避免闪烁 */
        LCD_ClrScr(CL_BLUE);          /* 清屏,背景蓝色 */
    }
    
    /* 设置字体属性 */
    tFont.FontCode = FC_ST_16;        /* 字体选择宋体16点阵,高16x宽15) */
    tFont.FrontColor = CL_WHITE;    /* 字体颜色设置为白色 */
    tFont.BackColor = CL_BLUE;         /* 文字背景颜色,蓝色 */
    tFont.Space = 0;                /* 字符水平间距, 单位 = 像素 */

    y = 0;
    LCD_DispStr(20, y, "国标GB2312 16点阵汉字库(区码1-87,位码1-94)", &tFont);

    code1 = _ucIndex - 1; /* 得到区码 */
    code2 = 1;            /* 位码从1开始 */

    y += usLineCap;
    sprintf((char *)buf, (char *)"当前区码: %2d, 本页位码:1-94, 第10-15区无字符", code1);
    LCD_DispStr(20, y, buf, &tFont);
    y += (2 * usLineCap);

    /*
        机内码高位 = 区码 + 0xA0
        机内码低位 = 位码 + 0xA0

        区码范围 :1 - 87
        位码范围 : 1 - 94

        每行显示20个汉字,一个区是94个汉字,需要5行显示,第5行显示14个汉字
    */
    
    x = 40;
    code1 += 0xA0; /* 换算到内码高位 */
    code2 = 0xA1;  /* 内码低位起始 */
    for (i = 0; i < 5; i++)
    {
        for (k = 0; k < 20; k++)
        {
            buf[2 * k] = code1;
            buf[2 * k + 1] = code2;
            code2++;
            if ((i == 4) && (k == 13))
            {
                k++;
                break;
            }
        }
        buf[2 * k] = 0;
        LCD_DispStr(x, y, buf, &tFont);
        y += usLineCap;
    }
}

43.10   总结

本章节涉及到的知识点比较多,需要大家花点时间去掌握,直至可以独立驱动一个显示屏。

 

相关文章: