【STM32H7教程】第53章 STM32H7的LTDC應用之漢字小字庫和全字庫製做

完整教程下載地址:http://www.armbbs.cn/forum.php?mod=viewthread&tid=86980php

第53章       STM32H7的LTDC應用之漢字小字庫和全字庫製做

本章教程爲你們講解漢字小字庫和全字庫的製做方式,實際項目中用到的地方比較多。數組

53.1 初學者重要提示框架

53.2 使用MakeDot小軟件生成C文件格式小字庫方法函數

53.3 使用MakeDot小軟件生成C文件格式全字庫方法學習

53.4 C文件格式漢字使用方法測試

53.5 漢字顯示方法解析字體

53.6 LCD驅動移植和使用ui

53.7 實驗例程設計框架編碼

53.8 實驗例程說明(MDK)spa

53.9 實驗例程說明(IAR)

5.10 總結

 

 

53.1 初學者重要提示

  1.   學習本章節前,務必優先學習第52章,須要對點陣字體字符編碼有個認識。
  2.   LTDC驅動設計和相關問題在第51章有詳細說明。
  3.   本章節爲你們講解的小字庫和全字庫方法,簡單易用,是直接以C文件格式存儲到內部Flash的。支持12點陣,16點陣,24點陣和32點陣的ASCII以及GB2312編碼漢字顯示。

53.2 使用MakeDot小軟件生成C文件格式小字庫方法

生成方法比較簡單,這裏作個介紹:

53.2.1 第1步,準備好顯示的字符

好比要顯示以下字符,採用16點陣格式:

安富萊電子,www.armfly.com
故人西辭黃鶴樓,煙花三月下揚州。
孤帆遠影碧空盡,惟見長江天際流。

 

53.2.2 第2步,複製要顯示的字符到MakeDot小軟件

選擇16點陣,並將要顯示的字符複製到輸入窗口:

 

點擊生成數組按鈕後的效果以下:

 

53.2.3 第3步,複製生成的數組到工程中

在輸出窗口鼠標右擊,選擇「全選」,而後再次鼠標右擊選擇複製。

 

這樣就能夠粘貼到工程的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步中轉換的字符了。

53.3 使用MakeDot小軟件生成C文件格式全字庫方法

生成方法比較簡單,這裏作個介紹:

53.3.1 第1步,準備好GB2312字符集

GB2312字符集已經在MakeDot小軟件裏面存好,點擊漢字編碼按鈕能夠看到:

 

53.3.2 第2步,複製GB2312所有字符到MakeDot小軟件

複製MakeDot小軟件中GB2312全部字符到「輸入窗口區」(在GB2312字符顯示區,鼠標右擊選擇全選,以後就能夠複製了),

 

點擊生成數組按鈕後的效果以下:

 

53.3.3 第3步,複製生成的數組到工程中

在輸出窗口鼠標右擊,選擇「全選」,而後再次鼠標右擊選擇複製。

 

這樣就能夠粘貼到工程的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點陣的漢字了。

53.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);

 

53.5 漢字顯示方法解析

下面將漢字的顯示流程作個說明,幾個函數的調用關係以下:

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

_LCD_ReadHZDot

53.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實現。

53.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.    }

 

下面將代碼中幾個關鍵地方作個闡釋:

  1.   第34-55行,根據使用的的12,16,24和32點陣字體,設置字體的高度變量font_height和寬度變量font_width。
  2.   第57-73行,經過函數LCD_GetStrWidth計算字符串的長度,而後根據設置的字符總寬度和實際寬度作比較,來實現左對齊,右對齊和居中顯示。因爲函數LCD_DispStr調用LCD_DispStrEx時,將形參_Width設置爲0,因此這部分代碼功能未用到。
  3.   第76-87行,用於填充顯示字符之外區域的背景色,只有設置的字符總寬度大於實際寬度時纔會用到,填充的就是實際寬度之外的區域。
  4.   第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.    /*
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的字庫處理,V7開發板用不到。
  •   第40行,將ASCII點陣數據複製到緩衝_pBuf裏面。

53.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行,本章暫時用不到這種方案,後面章節用到這種方案了再爲你們作說明。

53.6 LCD驅動移植和使用

與第51章51.7小節相同,這裏就再也不贅述了。

53.7 實驗例程設計框架

經過程序設計框架,讓你們先對配套例程有一個全面的認識,而後再理解細節,本次實驗例程的設計框架以下:

 

  第1階段,上電啓動階段:

  • 這部分在第14章進行了詳細說明。

  第2階段,進入main函數:

  •   第1步,硬件初始化,主要是MPU,Cache,HAL庫,系統時鐘,滴答定時器,LED,串口,LCD,SDRAM等。
  •   第2步,LCD應用程序設計部分,顯示漢字。經過按鍵實現三種界面的處理,其中GB2312有幾十個界面。

53.8 實驗例程說明(MDK)

配套例子:

V7-033_LCD的漢字小字庫和全字庫製做實驗

實驗目的:

  1. 學習LCD的漢字小字庫和全字庫製做實驗。

實驗內容:

  1. 小字庫和全字庫經過此軟件生成:http://www.armbbs.cn/forum.php?mod=viewthread&tid=202
  2. LCD界面上展現ASCII字符和GB2312編碼漢字。
  3. 啓動1個200ms的自動重裝定時器,讓LED2每200ms翻轉一次。

實驗操做:

  1. 搖桿上鍵,增長LCD背景光亮度。
  2. 搖桿下鍵,下降LCD背景光亮度。
  3. 搖桿左鍵,顯示上一頁漢字。
  4. 搖桿右鍵,顯示下一頁漢字。
  5. 搖桿OK鍵,返回首頁。

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();
}

 

  主功能:

主程序實現以下操做:

  •   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-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;
    }
}

 

53.9 實驗例程說明(IAR)

配套例子:

V7-033_LCD的漢字小字庫和全字庫製做實驗

實驗目的:

  1. 學習LCD的漢字小字庫和全字庫製做實驗。

實驗內容:

  1. 小字庫和全字庫經過此軟件生成:http://www.armbbs.cn/forum.php?mod=viewthread&tid=202
  2. LCD界面上展現ASCII字符和GB2312編碼漢字。
  3. 啓動1個200ms的自動重裝定時器,讓LED2每200ms翻轉一次。

實驗操做:

  1. 搖桿上鍵,增長LCD背景光亮度。
  2. 搖桿下鍵,下降LCD背景光亮度。
  3. 搖桿左鍵,顯示上一頁漢字。
  4. 搖桿右鍵,顯示下一頁漢字。
  5. 搖桿OK鍵,返回首頁。

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();
}

 

  主功能:

主程序實現以下操做:

  •   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-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;
    }
}

 

53.10   總結

本章節涉及到的知識點比較多,須要你們花點時間去掌握,直至能夠獨立驅動一個顯示屏。

相關文章
相關標籤/搜索