你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【经验分享】STM32H7的LTDC应用之汉字小字库和全字库制作

[复制链接]
STMCU小助手 发布时间:2021-10-31 17:42
53.1 初学者重要提示
  学习本章节前,务必优先学习第52章,需要对点阵字体字符编码有个认识。
  LTDC驱动设计和相关问题在第51章有详细说明。
  本章节为大家讲解的小字库和全字库方法,简单易用,是直接以C文件格式存储到内部Flash的。支持12点阵,16点阵,24点阵和32点阵的ASCII以及GB2312编码汉字显示。
53.2 使用MakeDot小软件生成C文件格式小字库方法
生成方法比较简单,这里做个介绍:

53.2.1 第1步,准备好显示的字符
比如要显示如下字符,采用16点阵格式:

  1. 故人西辞黄鹤楼,烟花三月下扬州。
  2. 孤帆远影碧空尽,唯见长江天际流。
复制代码

53.2.2 第2步,复制要显示的字符到MakeDot小软件
选择16点阵,并将要显示的字符复制到输入窗口:

aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png


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

aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png


53.2.3 第3步,复制生成的数组到工程中
在输出窗口鼠标右击,选择“全选”,然后再次鼠标右击选择复制。

aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png


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

aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png


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

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

  2. #ifdef USE_SMALL_FONT

  3. unsigned char const g_Hz16[] = {

  4. 0xA1,0xA3, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,// 。 //
  5.            0x00,0x00,0x00,0x00,0x18,0x00,0x24,0x00,0x24,0x00,0x18,0x00,0x00,0x00,0x00,0x00,


  6. 0xA3,0xAC, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,// , //
  7.            0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x00,0x30,0x00,0x10,0x00,0x20,0x00,0x00,0x00,


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

  10. /* 中间部分省略未写 */

  11. 0xD7,0xD3, 0x00,0x00,0x7F,0xF8,0x00,0x10,0x00,0x20,0x00,0x40,0x01,0x80,0x01,0x00,0xFF,0xFE,// 子 //
  12.            0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x01,0x00,0x05,0x00,0x02,0x00,


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

  15. };

  16. #else
  17.     unsigned char const g_Hz16[] = {0xFF, 0xFF};
  18. #endif
复制代码

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

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

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

53.3 使用MakeDot小软件生成C文件格式全字库方法
生成方法比较简单,这里做个介绍:

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

aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png


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

aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png


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

aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png


53.3.3 第3步,复制生成的数组到工程中
在输出窗口鼠标右击,选择“全选”,然后再次鼠标右击选择复制。

aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png


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

aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png


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

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

  5. #ifdef USE_SMALL_FONT

  6. unsigned char const g_Hz16[] = {



  7. 0xA1,0xA1, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//   //
  8.            0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,


  9. 0xA1,0xA2, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,// 、 //
  10.            0x00,0x00,0x00,0x00,0x20,0x00,0x18,0x00,0x0C,0x00,0x04,0x00,0x00,0x00,0x00,0x00,


  11. 0xA1,0xA3, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,// 。 //
  12.            0x00,0x00,0x00,0x00,0x18,0x00,0x24,0x00,0x24,0x00,0x18,0x00,0x00,0x00,0x00,0x00,

  13. /* 中间部分省略未写 */

  14. 0xF7,0xFB, 0x20,0x0E,0xCE,0xF0,0x82,0x22,0xEE,0x92,0x82,0x44,0x82,0x20,0xFE,0x44,0x00,0xF8,// 鼷 //
  15.            0x92,0x10,0x92,0x24,0xDA,0xFE,0x92,0x10,0xDA,0xFE,0x92,0x28,0x93,0x44,0xD9,0x82,


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


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


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


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

  24. };

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

复制代码

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

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

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

53.4 C文件格式汉字使用方法
汉字的显示方法比较简单。

  定义一个FONT_T类型变量:
  1. FONT_T tFont12;        /* 定义一个12点阵字体结构体变量,用于设置字体参数 */
  2. FONT_T tFont16;        /* 定义一个16点阵字体结构体变量,用于设置字体参数 */
  3. FONT_T tFont24;        /* 定义一个24点阵字体结构体变量,用于设置字体参数 */
复制代码



FONT_T的原始定义如下:

  1. typedef struct
  2. {
  3.     FONT_CODE_E FontCode;    /* 字体代码 FONT_CODE_E  */
  4.     uint16_t FrontColor;   /* 字体颜色 */
  5.     uint16_t BackColor;    /* 文字背景颜色,透明 */
  6.     uint16_t Space;        /* 文字间距,单位 = 像素 */
  7. }FONT_T;
复制代码



  初始化变量tFont:
设置12,16和24点阵。

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

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

  10. tFont.FontCode = FC_ST_24;        /* 字体选择宋体24点阵,高24 x宽23) */
  11. tFont.FrontColor = CL_WHITE;    /* 字体颜色设置为白色 */
  12. tFont.BackColor = CL_MASK;         /* 文字背景颜色,透明 */
  13. tFont.Space = 0;                /* 字符水平间距, 单位 = 像素 */
复制代码


  调用函数LCD_DispStr显示字符:
下面显示了12,16和24点阵字符。

  1. LCD_DispStr(5, 3,  "故人西辞黄鹤楼,烟花三月下扬州。<a href="http://www.armfly.com" target="_blank">www.armfly.com</a>", &tFont12);
  2. LCD_DispStr(5, 20, "孤帆远影碧空尽,唯见长江天际流。<a href="http://www.armfly.com" target="_blank">www.armfly.com</a>", &tFont12);
  3. LCD_DispStr(5, 38, "故人西辞黄鹤楼,烟花三月下扬州。", &tFont16);
  4. LCD_DispStr(5, 68, "孤帆远影碧空尽,唯见长江天际流。", &tFont16);
  5. LCD_DispStr(5, 98, "故人西辞黄鹤楼烟花三月下扬州", &tFont24);
  6. LCD_DispStr(5, 128, "孤帆远影碧空尽唯见长江天际流", &tFont24);
复制代码



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

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

_LCD_ReadHZDot

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

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

复制代码

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

53.5.2 函数LCD_DispStrEx
此函数的源码如下:

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

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

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


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

  第20-23行,显示12点阵ASCII,每个字符需要24个字节,存储在数组g_Ascii12里面。
  第25-31行,显示16,24和32点阵ASCII,这里采用同一大小字符进行显示。每个字符需要32个字节,存储在数组g_Ascii16里面。
  第33-35行,这个是RA8875的字库处理,V7开发板用不到。
  第40行,将ASCII点阵数据复制到缓冲_pBuf里面。
53.5.4 函数_LCD_ReadHZDot
此函数的作用是根据ASCII编码值,读取对应的点阵数据出来。

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


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

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

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

aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png


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

这部分在第14章进行了详细说明。
  第2阶段,进入main函数:

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

V7-033_LCD的汉字小字库和全字库制作实验

实验目的:

学习LCD的汉字小字库和全字库制作实验。
实验内容:
LCD界面上展示ASCII字符和GB2312编码汉字。
启动1个200ms的自动重装定时器,让LED2每200ms翻转一次。
实验操作:

摇杆上键,增加LCD背景光亮度。
摇杆下键,降低LCD背景光亮度。
摇杆左键,显示上一页汉字。
摇杆右键,显示下一页汉字。
摇杆OK键,返回首页。
LCD的界面显示效果如下:

部分截图:

aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png



aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png


aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png


上电后串口打印的信息:

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

aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png


程序设计:

  系统栈大小分配:

aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png


  RAM空间用的DTCM:

aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png


  硬件外设初始化

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

  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: bsp_Init
  4. *    功能说明: 初始化所有的硬件设备。该函数配置CPU寄存器和外设的寄存器并初始化一些全局变量。只需要调用一次
  5. *    形    参:无
  6. *    返 回 值: 无
  7. *********************************************************************************************************
  8. */
  9. void bsp_Init(void)
  10. {
  11.     /* 配置MPU */
  12.     MPU_Config();

  13.     /* 使能L1 Cache */
  14.     CPU_CACHE_Enable();

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

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

  27.     /*
  28.        Event Recorder:
  29.        - 可用于代码执行时间测量,MDK5.25及其以上版本才支持,IAR不支持。
  30.        - 默认不开启,如果要使能此选项,务必看V7开发板用户手册第8章
  31.     */   
  32. #if Enable_EventRecorder == 1  
  33.     /* 初始化EventRecorder并开启 */
  34.     EventRecorderInitialize(EventRecordAll, 1U);
  35.     EventRecorderStart();
  36. #endif

  37.     bsp_InitKey();        /* 按键初始化,要放在滴答定时器之前,因为按钮检测是通过滴答定时器扫描 */
  38.     bsp_InitTimer();      /* 初始化滴答定时器 */
  39.     bsp_InitUart();    /* 初始化串口 */
  40.     bsp_InitExtIO();    /* 初始化FMC总线74HC574扩展IO. 必须在 bsp_InitLed()前执行 */   
  41.     bsp_InitLed();        /* 初始化LED */   

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

复制代码

  MPU配置和Cache配置:

数据Cache和指令Cache都开启。配置了AXI SRAM区(本例子未用到AXI SRAM),FMC的扩展IO区和SDRAM。由于SDRAM要用于LCD的显存,方便起见,直接将其配置为WT模式。

  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: MPU_Config
  4. *    功能说明: 配置MPU
  5. *    形    参: 无
  6. *    返 回 值: 无
  7. *********************************************************************************************************
  8. */
  9. static void MPU_Config( void )
  10. {
  11.     MPU_Region_InitTypeDef MPU_InitStruct;

  12.     /* 禁止 MPU */
  13.     HAL_MPU_Disable();

  14.     /* 配置AXI SRAM的MPU属性为Write back, Read allocate,Write allocate */
  15.     MPU_InitStruct.Enable           = MPU_REGION_ENABLE;
  16.     MPU_InitStruct.BaseAddress      = 0x24000000;
  17.     MPU_InitStruct.Size             = MPU_REGION_SIZE_512KB;
  18.     MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
  19.     MPU_InitStruct.IsBufferable     = MPU_ACCESS_BUFFERABLE;
  20.     MPU_InitStruct.IsCacheable      = MPU_ACCESS_CACHEABLE;
  21.     MPU_InitStruct.IsShareable      = MPU_ACCESS_NOT_SHAREABLE;
  22.     MPU_InitStruct.Number           = MPU_REGION_NUMBER0;
  23.     MPU_InitStruct.TypeExtField     = MPU_TEX_LEVEL1;
  24.     MPU_InitStruct.SubRegionDisable = 0x00;
  25.     MPU_InitStruct.DisableExec      = MPU_INSTRUCTION_ACCESS_ENABLE;

  26.     HAL_MPU_ConfigRegion(&MPU_InitStruct);


  27.     /* 配置FMC扩展IO的MPU属性为Device或者Strongly Ordered */
  28.     MPU_InitStruct.Enable           = MPU_REGION_ENABLE;
  29.     MPU_InitStruct.BaseAddress      = 0x60000000;
  30.     MPU_InitStruct.Size             = ARM_MPU_REGION_SIZE_64KB;   
  31.     MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
  32.     MPU_InitStruct.IsBufferable     = MPU_ACCESS_BUFFERABLE;
  33.     MPU_InitStruct.IsCacheable      = MPU_ACCESS_NOT_CACHEABLE;   
  34.     MPU_InitStruct.IsShareable      = MPU_ACCESS_NOT_SHAREABLE;
  35.     MPU_InitStruct.Number           = MPU_REGION_NUMBER1;
  36.     MPU_InitStruct.TypeExtField     = MPU_TEX_LEVEL0;
  37.     MPU_InitStruct.SubRegionDisable = 0x00;
  38.     MPU_InitStruct.DisableExec      = MPU_INSTRUCTION_ACCESS_ENABLE;

  39.     HAL_MPU_ConfigRegion(&MPU_InitStruct);

  40.     /* 配置SDRAM的MPU属性为Write through, read allocate,no write allocate */
  41.     MPU_InitStruct.Enable           = MPU_REGION_ENABLE;
  42.     MPU_InitStruct.BaseAddress      = 0xC0000000;
  43.     MPU_InitStruct.Size             = MPU_REGION_SIZE_32MB;
  44.     MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
  45.     MPU_InitStruct.IsBufferable     = MPU_ACCESS_NOT_BUFFERABLE;
  46.     MPU_InitStruct.IsCacheable      = MPU_ACCESS_CACHEABLE;
  47.     MPU_InitStruct.IsShareable      = MPU_ACCESS_NOT_SHAREABLE;
  48.     MPU_InitStruct.Number           = MPU_REGION_NUMBER2;
  49.     MPU_InitStruct.TypeExtField     = MPU_TEX_LEVEL0;
  50.     MPU_InitStruct.SubRegionDisable = 0x00;
  51.     MPU_InitStruct.DisableExec      = MPU_INSTRUCTION_ACCESS_ENABLE;

  52.     HAL_MPU_ConfigRegion(&MPU_InitStruct);

  53.     /*使能 MPU */
  54.     HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);
  55. }

  56. /*
  57. *********************************************************************************************************
  58. *    函 数 名: CPU_CACHE_Enable
  59. *    功能说明: 使能L1 Cache
  60. *    形    参: 无
  61. *    返 回 值: 无
  62. *********************************************************************************************************
  63. */
  64. static void CPU_CACHE_Enable(void)
  65. {
  66.     /* 使能 I-Cache */
  67.     SCB_EnableICache();

  68.     /* 使能 D-Cache */
  69.     SCB_EnableDCache();
  70. }
复制代码


  主功能:

主程序实现如下操作:

  LCD界面上展示ASCII字符和GB2312编码汉字
  启动1个200ms的自动重装定时器,让LED2每200ms翻转一次。
  通过按键来实现翻页功能,方便查看所有GB2312编码汉字。
  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: main
  4. *    功能说明: c程序入口
  5. *    形    参: 无
  6. *    返 回 值: 错误代码(无需处理)
  7. *********************************************************************************************************
  8. */
  9. int main(void)
  10. {
  11.     uint16_t ucBright;           /* 背光亮度(0-255) */
  12.     uint8_t ucKeyCode;        /* 按键代码 */
  13.     uint8_t ucStatus;        /* 主程序状态字 */
  14.     uint8_t fRefresh;        /* 刷屏请求标志,1表示需要刷新 */


  15.     bsp_Init();    /* 硬件初始化 */
  16.     PrintfLogo();    /* 打印例程名称和版本等信息 */
  17.     PrintfHelp();    /* 打印操作提示 */

  18.     /* 延迟200ms再点亮背光,避免瞬间高亮 */
  19.     bsp_DelayMS(200);

  20.     DispFirstPage();    /* 显示第1页 */

  21.     /* 界面整体显示完毕后,再打开背光,设置为缺省亮度 */
  22.     bsp_DelayMS(100);
  23.     ucBright = BRIGHT_DEFAULT;
  24.     LCD_SetBackLight(ucBright);

  25.     bsp_StartAutoTimer(0, 200); /* 启动1个200ms的自动重装的定时器,软件定时器0 */

  26.     /* 进入主程序循环体 */
  27.     ucStatus = 0;
  28.     fRefresh = 0;   
  29.     while (1)
  30.     {
  31.         /* 判断软件定时器0是否超时 */
  32.         if(bsp_CheckTimer(0))
  33.         {
  34.             /* 每隔200ms 进来一次 */  
  35.             bsp_LedToggle(2);
  36.         }

  37.         if (fRefresh == 1)
  38.         {
  39.             fRefresh = 0;

  40.             switch (ucStatus)
  41.             {
  42.                 case 0:
  43.                     DispFirstPage();    /* 显示第1页 */
  44.                     break;

  45.                 case 1:
  46.                     DispAsciiDot();        /* 显示ASCII点阵 */
  47.                     break;

  48.                 default:
  49.                     /* 区码范围 :1 - 87 */
  50.                     if (ucStatus <= 89)
  51.                     {
  52.                         DispHZK16(ucStatus);    /* 显示一个区的94个汉字 */
  53.                     }
  54.                     break;
  55.             }
  56.         }

  57.         ucKeyCode = bsp_GetKey();    /* 读取键值, 无键按下时返回 KEY_NONE = 0 */
  58.         if (ucKeyCode != KEY_NONE)
  59.         {
  60.             /* 有键按下 */
  61.             switch (ucKeyCode)
  62.             {
  63.                 case JOY_DOWN_L:        /* 摇杆LEFT键按下 */
  64.                     if (ucStatus > 0)
  65.                     {
  66.                         ucStatus--;
  67.                     }
  68.                     fRefresh = 1;        /* 请求刷新LCD */
  69.                     break;

  70.                 case JOY_DOWN_R:        /* 摇杆RIGHT键按下 */
  71.                     if (ucStatus < DEMO_PAGE_COUNT - 1)
  72.                     {
  73.                         ucStatus++;
  74.                     }
  75.                     fRefresh = 1;        /* 请求刷新LCD */
  76.                     break;

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

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

  90.                 case JOY_DOWN_D:        /* 摇杆DOWN键按下 */
  91.                     if (ucBright < BRIGHT_STEP)
  92.                     {
  93.                         ucBright = 0;
  94.                     }
  95.                     else
  96.                     {
  97.                         ucBright -= BRIGHT_STEP;
  98.                     }
  99.                     LCD_SetBackLight(ucBright);
  100.                     printf("当前背景光亮度 : %d\r\n", ucBright);
  101.                     break;

  102.                 default:
  103.                     break;
  104.             }
  105.         }
  106.     }
  107. }
复制代码



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

  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: DispFirstPage
  4. *    功能说明: 显示操作提示
  5. *    形    参:无
  6. *    返 回 值: 无
  7. *********************************************************************************************************
  8. */
  9. static void DispFirstPage(void)
  10. {
  11.     FONT_T tFont;            /* 定义一个字体结构体变量,用于设置字体参数 */
  12.     uint16_t y;            /* Y坐标 */
  13.     uint16_t usLineCap;    /* 行高 */
  14.     uint8_t buf[50];

  15.     LCD_ClrScr(CL_BLUE);          /* 清屏,背景蓝色 */


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

  21.     y = 0;
  22.     usLineCap = 18; /* 行间距 */
  23.     LCD_DispStr(5, y, "安富莱STM32-V7开发板  <a href="http://www.armfly.com" target="_blank">www.armfly.com</a>", &tFont);
  24.     y += usLineCap;
  25.     LCD_DispStr(5, y, "汉字小字库和全字库测试实验", &tFont);

  26.     y += 2 * usLineCap;
  27.     LCD_DispStr(30, y, "操作提示:", &tFont);

  28.     y += usLineCap;
  29.     LCD_DispStr(50, y, "摇杆上键 = 增加背光亮度", &tFont);

  30.     y += usLineCap;
  31.     LCD_DispStr(50, y, "摇杆下键 = 降低背光亮度", &tFont);

  32.     y += usLineCap;
  33.     LCD_DispStr(50, y, "摇杆左键 = 向前翻页", &tFont);

  34.     y += usLineCap;
  35.     LCD_DispStr(50, y, "摇杆右键 = 向后翻页", &tFont);

  36.     y += usLineCap;
  37.     LCD_DispStr(50, y, "摇杆OK键 = 返回首页", &tFont);

  38.     y += 2 * usLineCap;   

  39.     sprintf((char *)buf, "显示器分辨率 :%dx%d", g_LcdWidth, g_LcdHeight);
  40.     LCD_DispStr(5, y, (char *)buf, &tFont);

  41.     y += usLineCap;
  42.     LCD_DispStr(5, y, "每行可以显示25个汉字,或50个字符", &tFont);
  43. }
复制代码



下面是ASCII字符显示:

  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: DispAsciiDot
  4. *    功能说明: 显示ASCII点阵
  5. *    形    参:无
  6. *    返 回 值: 无
  7. *********************************************************************************************************
  8. */
  9. static void DispAsciiDot(void)
  10. {
  11.     uint8_t i,k;
  12.     FONT_T tFont;        /* 定义一个字体结构体变量,用于设置字体参数 */
  13.     uint16_t x;        /* X坐标 */
  14.     uint16_t y;        /* Y坐标 */   
  15.     char buf[32 + 1];
  16.     uint8_t ascii;

  17.     LCD_ClrScr(CL_BLUE);          /* 清屏,背景蓝色 */

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

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

  24.     x = 50;
  25.     y = 40;
  26.     ascii = 0;
  27.     for (i = 0; i < 4; i++)
  28.     {
  29.         for (k = 0; k < 32; k++)
  30.         {
  31.             buf[k] = ascii++;
  32.         }
  33.         buf[32] = 0;
  34.         if (buf[0] == 0)
  35.         {
  36.             buf[0] = ' ';
  37.         }
  38.         LCD_DispStr(x, y, buf, &tFont);
  39.         y += 20;
  40.     }
  41. }
复制代码


下面是GB2312编码字符显示:

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

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

  18.     if (_ucIndex == 2)
  19.     {
  20.         /* 第1次清屏,以后显示位置不变,可以不清屏,避免闪烁 */
  21.         LCD_ClrScr(CL_BLUE);          /* 清屏,背景蓝色 */
  22.     }

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

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

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

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

  36.     /*
  37.         机内码高位 = 区码 + 0xA0
  38.         机内码低位 = 位码 + 0xA0

  39.         区码范围 :1 - 87
  40.         位码范围 : 1 - 94

  41.         每行显示20个汉字,一个区是94个汉字,需要5行显示,第5行显示14个汉字
  42.     */

  43.     x = 40;
  44.     code1 += 0xA0; /* 换算到内码高位 */
  45.     code2 = 0xA1;  /* 内码低位起始 */
  46.     for (i = 0; i < 5; i++)
  47.     {
  48.         for (k = 0; k < 20; k++)
  49.         {
  50.             buf[2 * k] = code1;
  51.             buf[2 * k + 1] = code2;
  52.             code2++;
  53.             if ((i == 4) && (k == 13))
  54.             {
  55.                 k++;
  56.                 break;
  57.             }
  58.         }
  59.         buf[2 * k] = 0;
  60.         LCD_DispStr(x, y, buf, &tFont);
  61.         y += usLineCap;
  62.     }
  63. }
复制代码



53.9 实验例程说明(IAR)
配套例子:

V7-033_LCD的汉字小字库和全字库制作实验

实验目的:

学习LCD的汉字小字库和全字库制作实验。
实验内容:
LCD界面上展示ASCII字符和GB2312编码汉字。
启动1个200ms的自动重装定时器,让LED2每200ms翻转一次。
实验操作:

摇杆上键,增加LCD背景光亮度。
摇杆下键,降低LCD背景光亮度。
摇杆左键,显示上一页汉字。
摇杆右键,显示下一页汉字。
摇杆OK键,返回首页。
LCD的界面显示效果如下:

部分截图:




aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png


aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png



上电后串口打印的信息:

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

aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png


程序设计:

  系统栈大小分配:

aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png


  RAM空间用的DTCM:

aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png


  硬件外设初始化

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

  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: bsp_Init
  4. *    功能说明: 初始化所有的硬件设备。该函数配置CPU寄存器和外设的寄存器并初始化一些全局变量。只需要调用一次
  5. *    形    参:无
  6. *    返 回 值: 无
  7. *********************************************************************************************************
  8. */
  9. void bsp_Init(void)
  10. {
  11.     /* 配置MPU */
  12.     MPU_Config();

  13.     /* 使能L1 Cache */
  14.     CPU_CACHE_Enable();

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

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

  27.     /*
  28.        Event Recorder:
  29.        - 可用于代码执行时间测量,MDK5.25及其以上版本才支持,IAR不支持。
  30.        - 默认不开启,如果要使能此选项,务必看V7开发板用户手册第8章
  31.     */   
  32. #if Enable_EventRecorder == 1  
  33.     /* 初始化EventRecorder并开启 */
  34.     EventRecorderInitialize(EventRecordAll, 1U);
  35.     EventRecorderStart();
  36. #endif

  37.     bsp_InitKey();        /* 按键初始化,要放在滴答定时器之前,因为按钮检测是通过滴答定时器扫描 */
  38.     bsp_InitTimer();      /* 初始化滴答定时器 */
  39.     bsp_InitUart();    /* 初始化串口 */
  40.     bsp_InitExtIO();    /* 初始化FMC总线74HC574扩展IO. 必须在 bsp_InitLed()前执行 */   
  41.     bsp_InitLed();        /* 初始化LED */   

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



  MPU配置和Cache配置:

数据Cache和指令Cache都开启。配置了AXI SRAM区(本例子未用到AXI SRAM),FMC的扩展IO区和SDRAM。由于SDRAM要用于LCD的显存,方便起见,直接将其配置为WT模式。

  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: MPU_Config
  4. *    功能说明: 配置MPU
  5. *    形    参: 无
  6. *    返 回 值: 无
  7. *********************************************************************************************************
  8. */
  9. static void MPU_Config( void )
  10. {
  11.     MPU_Region_InitTypeDef MPU_InitStruct;

  12.     /* 禁止 MPU */
  13.     HAL_MPU_Disable();

  14.     /* 配置AXI SRAM的MPU属性为Write back, Read allocate,Write allocate */
  15.     MPU_InitStruct.Enable           = MPU_REGION_ENABLE;
  16.     MPU_InitStruct.BaseAddress      = 0x24000000;
  17.     MPU_InitStruct.Size             = MPU_REGION_SIZE_512KB;
  18.     MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
  19.     MPU_InitStruct.IsBufferable     = MPU_ACCESS_BUFFERABLE;
  20.     MPU_InitStruct.IsCacheable      = MPU_ACCESS_CACHEABLE;
  21.     MPU_InitStruct.IsShareable      = MPU_ACCESS_NOT_SHAREABLE;
  22.     MPU_InitStruct.Number           = MPU_REGION_NUMBER0;
  23.     MPU_InitStruct.TypeExtField     = MPU_TEX_LEVEL1;
  24.     MPU_InitStruct.SubRegionDisable = 0x00;
  25.     MPU_InitStruct.DisableExec      = MPU_INSTRUCTION_ACCESS_ENABLE;

  26.     HAL_MPU_ConfigRegion(&MPU_InitStruct);


  27.     /* 配置FMC扩展IO的MPU属性为Device或者Strongly Ordered */
  28.     MPU_InitStruct.Enable           = MPU_REGION_ENABLE;
  29.     MPU_InitStruct.BaseAddress      = 0x60000000;
  30.     MPU_InitStruct.Size             = ARM_MPU_REGION_SIZE_64KB;   
  31.     MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
  32.     MPU_InitStruct.IsBufferable     = MPU_ACCESS_BUFFERABLE;
  33.     MPU_InitStruct.IsCacheable      = MPU_ACCESS_NOT_CACHEABLE;   
  34.     MPU_InitStruct.IsShareable      = MPU_ACCESS_NOT_SHAREABLE;
  35.     MPU_InitStruct.Number           = MPU_REGION_NUMBER1;
  36.     MPU_InitStruct.TypeExtField     = MPU_TEX_LEVEL0;
  37.     MPU_InitStruct.SubRegionDisable = 0x00;
  38.     MPU_InitStruct.DisableExec      = MPU_INSTRUCTION_ACCESS_ENABLE;

  39.     HAL_MPU_ConfigRegion(&MPU_InitStruct);

  40.     /* 配置SDRAM的MPU属性为Write through, read allocate,no write allocate */
  41.     MPU_InitStruct.Enable           = MPU_REGION_ENABLE;
  42.     MPU_InitStruct.BaseAddress      = 0xC0000000;
  43.     MPU_InitStruct.Size             = MPU_REGION_SIZE_32MB;
  44.     MPU_InitStruct.AccessPermission = MPU_REGION_FULL_ACCESS;
  45.     MPU_InitStruct.IsBufferable     = MPU_ACCESS_NOT_BUFFERABLE;
  46.     MPU_InitStruct.IsCacheable      = MPU_ACCESS_CACHEABLE;
  47.     MPU_InitStruct.IsShareable      = MPU_ACCESS_NOT_SHAREABLE;
  48.     MPU_InitStruct.Number           = MPU_REGION_NUMBER2;
  49.     MPU_InitStruct.TypeExtField     = MPU_TEX_LEVEL0;
  50.     MPU_InitStruct.SubRegionDisable = 0x00;
  51.     MPU_InitStruct.DisableExec      = MPU_INSTRUCTION_ACCESS_ENABLE;

  52.     HAL_MPU_ConfigRegion(&MPU_InitStruct);

  53.     /*使能 MPU */
  54.     HAL_MPU_Enable(MPU_PRIVILEGED_DEFAULT);
  55. }

  56. /*
  57. *********************************************************************************************************
  58. *    函 数 名: CPU_CACHE_Enable
  59. *    功能说明: 使能L1 Cache
  60. *    形    参: 无
  61. *    返 回 值: 无
  62. *********************************************************************************************************
  63. */
  64. static void CPU_CACHE_Enable(void)
  65. {
  66.     /* 使能 I-Cache */
  67.     SCB_EnableICache();

  68.     /* 使能 D-Cache */
  69.     SCB_EnableDCache();
  70. }
复制代码


  主功能:

主程序实现如下操作:

  LCD界面上展示ASCII字符和GB2312编码汉字
  启动1个200ms的自动重装定时器,让LED2每200ms翻转一次。
  通过按键来实现翻页功能,方便查看所有GB2312编码汉字。
  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: main
  4. *    功能说明: c程序入口
  5. *    形    参: 无
  6. *    返 回 值: 错误代码(无需处理)
  7. *********************************************************************************************************
  8. */
  9. int main(void)
  10. {
  11.     uint16_t ucBright;           /* 背光亮度(0-255) */
  12.     uint8_t ucKeyCode;        /* 按键代码 */
  13.     uint8_t ucStatus;        /* 主程序状态字 */
  14.     uint8_t fRefresh;        /* 刷屏请求标志,1表示需要刷新 */


  15.     bsp_Init();    /* 硬件初始化 */
  16.     PrintfLogo();    /* 打印例程名称和版本等信息 */
  17.     PrintfHelp();    /* 打印操作提示 */

  18.     /* 延迟200ms再点亮背光,避免瞬间高亮 */
  19.     bsp_DelayMS(200);

  20.     DispFirstPage();    /* 显示第1页 */

  21.     /* 界面整体显示完毕后,再打开背光,设置为缺省亮度 */
  22.     bsp_DelayMS(100);
  23.     ucBright = BRIGHT_DEFAULT;
  24.     LCD_SetBackLight(ucBright);

  25.     bsp_StartAutoTimer(0, 200); /* 启动1个200ms的自动重装的定时器,软件定时器0 */

  26.     /* 进入主程序循环体 */
  27.     ucStatus = 0;
  28.     fRefresh = 0;   
  29.     while (1)
  30.     {
  31.         /* 判断软件定时器0是否超时 */
  32.         if(bsp_CheckTimer(0))
  33.         {
  34.             /* 每隔200ms 进来一次 */  
  35.             bsp_LedToggle(2);
  36.         }

  37.         if (fRefresh == 1)
  38.         {
  39.             fRefresh = 0;

  40.             switch (ucStatus)
  41.             {
  42.                 case 0:
  43.                     DispFirstPage();    /* 显示第1页 */
  44.                     break;

  45.                 case 1:
  46.                     DispAsciiDot();        /* 显示ASCII点阵 */
  47.                     break;

  48.                 default:
  49.                     /* 区码范围 :1 - 87 */
  50.                     if (ucStatus <= 89)
  51.                     {
  52.                         DispHZK16(ucStatus);    /* 显示一个区的94个汉字 */
  53.                     }
  54.                     break;
  55.             }
  56.         }

  57.         ucKeyCode = bsp_GetKey();    /* 读取键值, 无键按下时返回 KEY_NONE = 0 */
  58.         if (ucKeyCode != KEY_NONE)
  59.         {
  60.             /* 有键按下 */
  61.             switch (ucKeyCode)
  62.             {
  63.                 case JOY_DOWN_L:        /* 摇杆LEFT键按下 */
  64.                     if (ucStatus > 0)
  65.                     {
  66.                         ucStatus--;
  67.                     }
  68.                     fRefresh = 1;        /* 请求刷新LCD */
  69.                     break;

  70.                 case JOY_DOWN_R:        /* 摇杆RIGHT键按下 */
  71.                     if (ucStatus < DEMO_PAGE_COUNT - 1)
  72.                     {
  73.                         ucStatus++;
  74.                     }
  75.                     fRefresh = 1;        /* 请求刷新LCD */
  76.                     break;

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

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

  90.                 case JOY_DOWN_D:        /* 摇杆DOWN键按下 */
  91.                     if (ucBright < BRIGHT_STEP)
  92.                     {
  93.                         ucBright = 0;
  94.                     }
  95.                     else
  96.                     {
  97.                         ucBright -= BRIGHT_STEP;
  98.                     }
  99.                     LCD_SetBackLight(ucBright);
  100.                     printf("当前背景光亮度 : %d\r\n", ucBright);
  101.                     break;

  102.                 default:
  103.                     break;
  104.             }
  105.         }
  106.     }
  107. }
复制代码



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

  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: DispFirstPage
  4. *    功能说明: 显示操作提示
  5. *    形    参:无
  6. *    返 回 值: 无
  7. *********************************************************************************************************
  8. */
  9. static void DispFirstPage(void)
  10. {
  11.     FONT_T tFont;            /* 定义一个字体结构体变量,用于设置字体参数 */
  12.     uint16_t y;            /* Y坐标 */
  13.     uint16_t usLineCap;    /* 行高 */
  14.     uint8_t buf[50];

  15.     LCD_ClrScr(CL_BLUE);          /* 清屏,背景蓝色 */


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

  21.     y = 0;
  22.     usLineCap = 18; /* 行间距 */
  23.     LCD_DispStr(5, y, "安富莱STM32-V7开发板  <a href="http://www.armfly.com" target="_blank">www.armfly.com</a>", &tFont);
  24.     y += usLineCap;
  25.     LCD_DispStr(5, y, "汉字小字库和全字库测试实验", &tFont);

  26.     y += 2 * usLineCap;
  27.     LCD_DispStr(30, y, "操作提示:", &tFont);

  28.     y += usLineCap;
  29.     LCD_DispStr(50, y, "摇杆上键 = 增加背光亮度", &tFont);

  30.     y += usLineCap;
  31.     LCD_DispStr(50, y, "摇杆下键 = 降低背光亮度", &tFont);

  32.     y += usLineCap;
  33.     LCD_DispStr(50, y, "摇杆左键 = 向前翻页", &tFont);

  34.     y += usLineCap;
  35.     LCD_DispStr(50, y, "摇杆右键 = 向后翻页", &tFont);

  36.     y += usLineCap;
  37.     LCD_DispStr(50, y, "摇杆OK键 = 返回首页", &tFont);

  38.     y += 2 * usLineCap;   

  39.     sprintf((char *)buf, "显示器分辨率 :%dx%d", g_LcdWidth, g_LcdHeight);
  40.     LCD_DispStr(5, y, (char *)buf, &tFont);

  41.     y += usLineCap;
  42.     LCD_DispStr(5, y, "每行可以显示25个汉字,或50个字符", &tFont);
  43. }
复制代码



下面是ASCII字符显示:

  1. /*
  2. *********************************************************************************************************
  3. *    函 数 名: DispAsciiDot
  4. *    功能说明: 显示ASCII点阵
  5. *    形    参:无
  6. *    返 回 值: 无
  7. *********************************************************************************************************
  8. */
  9. static void DispAsciiDot(void)
  10. {
  11.     uint8_t i,k;
  12.     FONT_T tFont;        /* 定义一个字体结构体变量,用于设置字体参数 */
  13.     uint16_t x;        /* X坐标 */
  14.     uint16_t y;        /* Y坐标 */   
  15.     char buf[32 + 1];
  16.     uint8_t ascii;

  17.     LCD_ClrScr(CL_BLUE);          /* 清屏,背景蓝色 */

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

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

  24.     x = 50;
  25.     y = 40;
  26.     ascii = 0;
  27.     for (i = 0; i < 4; i++)
  28.     {
  29.         for (k = 0; k < 32; k++)
  30.         {
  31.             buf[k] = ascii++;
  32.         }
  33.         buf[32] = 0;
  34.         if (buf[0] == 0)
  35.         {
  36.             buf[0] = ' ';
  37.         }
  38.         LCD_DispStr(x, y, buf, &tFont);
  39.         y += 20;
  40.     }
  41. }
复制代码



下面是GB2312编码字符显示:

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

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

  18.     if (_ucIndex == 2)
  19.     {
  20.         /* 第1次清屏,以后显示位置不变,可以不清屏,避免闪烁 */
  21.         LCD_ClrScr(CL_BLUE);          /* 清屏,背景蓝色 */
  22.     }

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

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

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

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

  36.     /*
  37.         机内码高位 = 区码 + 0xA0
  38.         机内码低位 = 位码 + 0xA0

  39.         区码范围 :1 - 87
  40.         位码范围 : 1 - 94

  41.         每行显示20个汉字,一个区是94个汉字,需要5行显示,第5行显示14个汉字
  42.     */

  43.     x = 40;
  44.     code1 += 0xA0; /* 换算到内码高位 */
  45.     code2 = 0xA1;  /* 内码低位起始 */
  46.     for (i = 0; i < 5; i++)
  47.     {
  48.         for (k = 0; k < 20; k++)
  49.         {
  50.             buf[2 * k] = code1;
  51.             buf[2 * k + 1] = code2;
  52.             code2++;
  53.             if ((i == 4) && (k == 13))
  54.             {
  55.                 k++;
  56.                 break;
  57.             }
  58.         }
  59.         buf[2 * k] = 0;
  60.         LCD_DispStr(x, y, buf, &tFont);
  61.         y += usLineCap;
  62.     }
  63. }
复制代码



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


aHR0cHM6Ly9pbWcyMDE4LmNuYmxvZ3MuY29tL2NvbW1vbi8xMzc5MTA3LzIwMjAwMi8xMzc5MTA3LTIw.png
收藏 评论0 发布时间:2021-10-31 17:42

举报

0个回答

所属标签

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版