完整教程下载地址:http://www.armbbs.cn/forum.php?mod=viewthread&tid=86980
本章教程为大家讲解汉字小字库和全字库的制作方式,实际项目中用到的地方比较多。
53.1 初学者重要提示
53.2 使用MakeDot小软件生成C文件格式小字库方法
53.3 使用MakeDot小软件生成C文件格式全字库方法
53.4 C文件格式汉字使用方法
53.5 汉字显示方法解析
53.6 LCD驱动移植和使用
53.7 实验例程设计框架
53.8 实验例程说明(MDK)
53.9 实验例程说明(IAR)
5.10 总结
生成方法比较简单,这里做个介绍:
比如要显示如下字符,采用16点阵格式:
安富莱电子,www.armfly.com
故人西辞黄鹤楼,烟花三月下扬州。
孤帆远影碧空尽,唯见长江天际流。
选择16点阵,并将要显示的字符复制到输入窗口:
点击生成数组按钮后的效果如下:
在输出窗口鼠标右击,选择“全选”,然后再次鼠标右击选择复制。
这样就可以粘贴到工程的hz.c文件里面:
将点阵数据放在相应的文件里面时要注意加上两个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步中转换的字符了。
生成方法比较简单,这里做个介绍:
GB2312字符集已经在MakeDot小软件里面存好,点击汉字编码按钮可以看到:
复制MakeDot小软件中GB2312所有字符到“输入窗口区”(在GB2312字符显示区,鼠标右击选择全选,之后就可以复制了),
点击生成数组按钮后的效果如下:
在输出窗口鼠标右击,选择“全选”,然后再次鼠标右击选择复制。
这样就可以粘贴到工程的hz.c文件里面:
将点阵数据放在相应的文件里面时要注意加上两个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点阵的汉字了。
汉字的显示方法比较简单。
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;
设置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; /* 字符水平间距, 单位 = 像素 */
下面显示了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);
下面将汉字的显示流程做个说明,几个函数的调用关系如下:
LCD_DispStr ----> LCD_DispStrEx ----->_LCD_ReadAsciiDot
_LCD_ReadHZDot
中英文显示都是调用的如下函数实现:
/*
*********************************************************************************************************
* 函 数 名: 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实现。
此函数的源码如下:
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. }
下面将代码中几个关键地方做个阐释:
对于这个公式,大家通过代数法,代入两次数值就好理解了。
此函数的作用是根据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. }
下面将此函数涉及到的知识点为大家做个阐释:
此函数的作用是根据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. }
下面将此函数涉及到的知识点为大家做个阐释:
与第51章51.7小节相同,这里就不再赘述了。
通过程序设计框架,让大家先对配套例程有一个全面的认识,然后再理解细节,本次实验例程的设计框架如下:
第1阶段,上电启动阶段:
第2阶段,进入main函数:
配套例子:
V7-033_LCD的汉字小字库和全字库制作实验
实验目的:
实验内容:
实验操作:
LCD的界面显示效果如下:
部分截图:
上电后串口打印的信息:
波特率 115200,数据位 8,奇偶校验位无,停止位 1
程序设计:
系统栈大小分配:
RAM空间用的DTCM:
硬件外设初始化
硬件外设的初始化是在 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 */
}
MPU配置和Cache配置:
数据Cache和指令Cache都开启。配置了AXI SRAM区(本例子未用到AXI SRAM),FMC的扩展IO区和SDRAM。由于SDRAM要用于LCD的显存,方便起见,直接将其配置为WT模式。
/*
*********************************************************************************************************
* 函 数 名: MPU_Config
* 功能说明: 配置MPU
* 形 参: 无
* 返 回 值: 无
*********************************************************************************************************
*/
static void MPU_Config( void )
{
MPU_Region_InitTypeDef MPU_InitStruct;
/* 禁止 MPU */
HAL_MPU_Disable();
/* 配置AXI SRAM的MPU属性为Write back, Read allocate,Write allocate */
MPU_InitStruct.Enable = MPU_REGION_ENABLE;
MPU_InitStruct.BaseAddress = 0x24000000;
MPU_InitStruct.Size = MPU_REGION_SIZE_512KB;
MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
MPU_InitStruct.IsBufferable = MPU_ACCESS_BUFFERABLE;
MPU_InitStruct.IsCacheable = MPU_ACCESS_CACHEABLE;
MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE;
MPU_InitStruct.Number = MPU_REGION_NUMBER0;
MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL1;
MPU_InitStruct.SubRegionDisable = 0x00;
MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;
HAL_MPU_ConfigRegion(&MPU_InitStruct);
/* 配置FMC扩展IO的MPU属性为Device或者Strongly Ordered */
MPU_InitStruct.Enable = MPU_REGION_ENABLE;
MPU_InitStruct.BaseAddress = 0x60000000;
MPU_InitStruct.Size = ARM_MPU_REGION_SIZE_64KB;
MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
MPU_InitStruct.IsBufferable = MPU_ACCESS_BUFFERABLE;
MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE;
MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE;
MPU_InitStruct.Number = MPU_REGION_NUMBER1;
MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;
MPU_InitStruct.SubRegionDisable = 0x00;
MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;
HAL_MPU_ConfigRegion(&MPU_InitStruct);
/* 配置SDRAM的MPU属性为Write through, read allocate,no write allocate */
MPU_InitStruct.Enable = MPU_REGION_ENABLE;
MPU_InitStruct.BaseAddress = 0xC0000000;
MPU_InitStruct.Size = MPU_REGION_SIZE_32MB;
MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;
MPU_InitStruct.IsCacheable = MPU_ACCESS_CACHEABLE;
MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE;
MPU_InitStruct.Number = MPU_REGION_NUMBER2;
MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;
MPU_InitStruct.SubRegionDisable = 0x00;
MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;
HAL_MPU_ConfigRegion(&MPU_InitStruct);
/*使能 MPU */
HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);
}
/*
*********************************************************************************************************
* 函 数 名: CPU_CACHE_Enable
* 功能说明: 使能L1 Cache
* 形 参: 无
* 返 回 值: 无
*********************************************************************************************************
*/
static void CPU_CACHE_Enable(void)
{
/* 使能 I-Cache */
SCB_EnableICache();
/* 使能 D-Cache */
SCB_EnableDCache();
}
主功能:
主程序实现如下操作:
/*
*********************************************************************************************************
* 函 数 名: 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-V7开发板 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;
}
}
配套例子:
V7-033_LCD的汉字小字库和全字库制作实验
实验目的:
实验内容:
实验操作:
LCD的界面显示效果如下:
部分截图:
上电后串口打印的信息:
波特率 115200,数据位 8,奇偶校验位无,停止位 1
程序设计:
系统栈大小分配:
RAM空间用的DTCM:
硬件外设初始化
硬件外设的初始化是在 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 */
}
MPU配置和Cache配置:
数据Cache和指令Cache都开启。配置了AXI SRAM区(本例子未用到AXI SRAM),FMC的扩展IO区和SDRAM。由于SDRAM要用于LCD的显存,方便起见,直接将其配置为WT模式。
/*
*********************************************************************************************************
* 函 数 名: MPU_Config
* 功能说明: 配置MPU
* 形 参: 无
* 返 回 值: 无
*********************************************************************************************************
*/
static void MPU_Config( void )
{
MPU_Region_InitTypeDef MPU_InitStruct;
/* 禁止 MPU */
HAL_MPU_Disable();
/* 配置AXI SRAM的MPU属性为Write back, Read allocate,Write allocate */
MPU_InitStruct.Enable = MPU_REGION_ENABLE;
MPU_InitStruct.BaseAddress = 0x24000000;
MPU_InitStruct.Size = MPU_REGION_SIZE_512KB;
MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
MPU_InitStruct.IsBufferable = MPU_ACCESS_BUFFERABLE;
MPU_InitStruct.IsCacheable = MPU_ACCESS_CACHEABLE;
MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE;
MPU_InitStruct.Number = MPU_REGION_NUMBER0;
MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL1;
MPU_InitStruct.SubRegionDisable = 0x00;
MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;
HAL_MPU_ConfigRegion(&MPU_InitStruct);
/* 配置FMC扩展IO的MPU属性为Device或者Strongly Ordered */
MPU_InitStruct.Enable = MPU_REGION_ENABLE;
MPU_InitStruct.BaseAddress = 0x60000000;
MPU_InitStruct.Size = ARM_MPU_REGION_SIZE_64KB;
MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
MPU_InitStruct.IsBufferable = MPU_ACCESS_BUFFERABLE;
MPU_InitStruct.IsCacheable = MPU_ACCESS_NOT_CACHEABLE;
MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE;
MPU_InitStruct.Number = MPU_REGION_NUMBER1;
MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;
MPU_InitStruct.SubRegionDisable = 0x00;
MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;
HAL_MPU_ConfigRegion(&MPU_InitStruct);
/* 配置SDRAM的MPU属性为Write through, read allocate,no write allocate */
MPU_InitStruct.Enable = MPU_REGION_ENABLE;
MPU_InitStruct.BaseAddress = 0xC0000000;
MPU_InitStruct.Size = MPU_REGION_SIZE_32MB;
MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE;
MPU_InitStruct.IsCacheable = MPU_ACCESS_CACHEABLE;
MPU_InitStruct.IsShareable = MPU_ACCESS_NOT_SHAREABLE;
MPU_InitStruct.Number = MPU_REGION_NUMBER2;
MPU_InitStruct.TypeExtField = MPU_TEX_LEVEL0;
MPU_InitStruct.SubRegionDisable = 0x00;
MPU_InitStruct.DisableExec = MPU_INSTRUCTION_ACCESS_ENABLE;
HAL_MPU_ConfigRegion(&MPU_InitStruct);
/*使能 MPU */
HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);
}
/*
*********************************************************************************************************
* 函 数 名: CPU_CACHE_Enable
* 功能说明: 使能L1 Cache
* 形 参: 无
* 返 回 值: 无
*********************************************************************************************************
*/
static void CPU_CACHE_Enable(void)
{
/* 使能 I-Cache */
SCB_EnableICache();
/* 使能 D-Cache */
SCB_EnableDCache();
}
主功能:
主程序实现如下操作:
/*
*********************************************************************************************************
* 函 数 名: 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-V7开发板 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;
}
}
本章节涉及到的知识点比较多,需要大家花点时间去掌握,直至可以独立驱动一个显示屏。