最新教程下載:http://www.armbbs.cn/forum.php?mod=viewthread&tid=93255
第41章 STM32F429的LTDC應用之LCD漢字顯示和2D圖形顯示
本章教程為大家講解LTDC應用中最基本的漢字顯示和2D圖形顯示功能實現。
41.1 初學者重要提示
41.2 LCD相關的基礎支持
41.3 LCD硬件設計
41.4 LCD驅動設計
41.5 LCD板級支持包(bsp_ltdc_429.c和bsp_tft_lcd.c)
41.6 LCD的驅動移植和使用
41.7 實驗例程設計框架
41.8 實驗例程說明(MDK)
41.9 實驗例程說明(IAR)
41.10 總結
41.1 初學者重要提示
- 學習本章節前,務必優先學習第40章,需要對LTDC的基礎知識和HAL庫的幾個常用API有個認識。
- 本章的第4小節LCD驅動設計非常重要。
- 如果自己觀察的話,LCD上電會有一個瞬間高亮的問題,在此貼進行了描述:http://www.armbbs.cn/forum.php?mod=viewthread&tid=82619 。這個解決方案已經應用到本章配套的例子上。
- 本章節用到的漢字方案會在下章專門為大家講解,下面是小字庫的制作方法:http://www.armbbs.cn/forum.php?mod=viewthread&tid=202 。
- 調試狀態或者剛下載LCD的程序到里面,屏幕會抖動,這個是正常現象,之前F429就有這個問題,詳情看此貼:http://www.armbbs.cn/forum.php?mod=viewthread&tid=16892 。
41.2 LCD相關的基礎知識
41.2.1 顯示屏相關知識
顯示屏的結構有必要給大家普及下,這里我們通過如下三種類型的顯示屏進行說明,基本已經涵蓋我們常用的方式了。
- RA8875 + RGB接口裸屏
首先RA8875是一個顯示屏控制器,自帶顯存,它的作用就是讓不支持RGB接口的MCU也可以使用RGB接口的大屏。這起到了一個橋接的作用,可以將RGB接口屏轉換成8080總線接口、SPI接口或者I2C接口方式。這種情況下,甚至低速的51單片機都可以外接大屏了。另外像SSD1963也是同樣的作用。
- ili9488類顯示屏
這種類型是把顯示控制器和顯示屏都集成好了,支持8080總線接口,有些還支持SPI或者I2C接口,而且顯存也都集成了,不過主要是驅動一些小屏。像ili9341,ili9326,SPFD5420等也是一樣的。此外還要注意,部分這種類型顯示屏也是支持RGB接口的,像ST官方的STM32F429探索板外接的ili9431就是用的RGB接口。
- STM32F429 + SDRAM + RGB接口裸屏
這個是我們本章節要講解的,STM32F429是自帶LCD控制器的,再配合SDRAM作為顯示屏的顯存,整體作用跟RA8875是一樣的,可以直接外接RGB接口的屏了。
有了這些認識后,對於裸屏還有些知識點需要了解。首先,裸屏本身不是什么控制芯片都沒有,其構成也是比較復雜的,有興趣了解的話,可以搜索關鍵字“TFT結構”進行學習。其次,TFT裸屏中主要的兩個IC是Gate Driver IC和Source Driver IC,這兩個IC的引腳都超級多,基本都是幾百個引腳。最后,不管使用的哪種裸屏,一般都有規格書,會給出時序參數,這個在配置STM32H7的LTDC時要用到,如果規格書沒有直接給出時序參數,則會給出使用的Driver IC型號,用戶可以搜索此Driver IC的手冊,在手冊中會給出。
為了讓大家有個感性認識,我們來看一看TFT裸屏的實際效果,下面是SPDF5420顯示屏,400*240分辨率:
下面是TFT裸屏,480*272分辨率:
下面是TFT裸屏,800*480分辨率:
41.2.2 電阻觸摸和電容觸摸相關知識
有了TFT裸屏后還要配套電阻觸摸板或者電容觸摸板才可以獲取觸摸信息。觸摸板是貼到TFT屏上面的,然后再通過電阻觸摸芯片就可以獲取電阻觸摸板的信息,通過電容觸摸芯片采集電容觸摸板的信息。教程配套開發板的顯示屏使用了三種觸摸IC,電阻觸摸IC是STMPE811,電容觸摸IC是GT811和FT5X06。其中,電阻觸摸和電容觸摸兩者的區別是初學者務必要知道的:
- 電阻觸摸芯片STMPE811其實就是ADC,返回的是ADC數值,而電容觸摸芯片GT811,GT911和FT5X06返回的是顯示屏實際的坐標值。
- 使用電阻觸摸芯片STMPE811需要做觸摸校准,而使用電容觸摸芯片GT811,GT911和FT5X06是自動校准的,無需手動校准。
下面是四線電阻觸摸板的效果:
下面是電容觸摸板的效果:
了解了這些知識,基本已經夠我們本章節使用了,更多電阻觸摸和電容觸摸的相關知識可以看這個文檔,講解比較全面:http://www.armbbs.cn/forum.php?mod=viewthread&tid=14898 。
41.3 LCD硬件設計
下面是RGB888硬件接口的原理圖,STM32-V6開發板制作了三個硬件接口。
- 加高2層的雙排母接口
- 2.54mm的排針接口
- FPC軟排線接口方式
了解了原理圖后,再來看下實際的接口效果:
通過上面的原理圖,我們要了解以下幾個問題:
- V6開發板采用的是RGB888硬件接口,也許大家會問ARGB8888這種顏色格式怎么用於這種接口?Alpha通道是軟件編程的時候用的,用於設置透明度,透明度會反應到RGB顏色值上。
- STM32F429支持的8種顏色格式都可以在RGB888硬件接口上實現。
- 如果大家用的是16位色的RGB565顏色格式,那么僅需用到LCD_R[7:3]、LCD_G[7:2] 和 LCD_B[7:3]引腳即可,沒有用到的引腳可以繼續用作其它功能。
41.4 LCD驅動設計
下面將程序設計中的相關問題逐一為大家做個說明。
41.4.1 第1步,LTDC顯存使用SDRAM
設計LTDC驅動前,要先保證顯存可以正常使用,V6開發板用的外部SDRAM作為顯存。所以一定要保證SDRAM大批量讀寫數據時是正常的,SDRAM的測試可以自己專門做一個工程測試下。對於SDRAM的驅動實現,可以學習本教程第39章。不管你使用的是鎂光的,海力士的,三星的,ISSI的或者華邦的,實現方法基本都是一樣的。
V6開發板使用鎂光的32位帶寬、16MB的SDRAM,如果想最大限度的發揮STM32F429驅動SDRAM的性能,強烈建議使用32位帶寬的SDRAM,或者兩個16位SDRAM組成32位帶寬的SDRAM也是可以的。那SDRAM主要起到什么作用呢?作用有二:
- 用作顯示屏的顯存
STM32F429的LTDC外接RGB接口屏是沒有顯存的,所以需要SDRAM用作顯存。如果用戶選擇STM32F429 LTDC的顏色格式是32位色ARGB8888,那么所需要顯存大小(單位字節)是:顯示屏寬 * 顯示屏高 * (32/8), 其中32/8是表示這種顏色格式的一個像素點需要4個字節來表示。又比如配置顏色格式是16位色的RGB565,那么需要的顯存大小是:顯示屏寬 * 顯示屏高 * (16/8),其中16/8是表示這種顏色格式的一個像素點需要2個字節來表示。其它的顏色格式,依此類推。
- 用作GUI動態內存
如果想要實現炫酷效果,GUI是極其消耗動態內存的,所以用戶可以將SDRAM除了用於顯存以外的所有內存全部用作GUI動態內存。
如果SDRAM的驅動測試已經沒有問題了,就可以將其添加到工程里面了,V6使用的SDRAM驅動文件是bsp_fmc_sdram.c。圖層1占用2MB,圖層2占用2MB,最后12MB可做其它使用。也許會有初學者會問,每個圖層分配2MB是不是有些多了?實際上不多的,因為我們要讓不同的顏色格式都通用,這里分配2MB的話,教程實例使用很方便。大家實際項目中的使用可以配置成實際大小。具體的配置如下,詳情見bsp_fmc_sdram.h文件:
#define EXT_SDRAM_ADDR ((uint32_t)0xC0000000) #define EXT_SDRAM_SIZE (16 * 1024 * 1024) /* LCD顯存,第1頁, 分配2M字節 */ #define SDRAM_LCD_BUF1 EXT_SDRAM_ADDR /* LCD顯存,第2頁, 分配2M字節 */ #define SDRAM_LCD_BUF2 (EXT_SDRAM_ADDR + SDRAM_LCD_SIZE) #define SDRAM_LCD_SIZE (2 * 1024 * 1024) /* 每層2M */ #define SDRAM_LCD_LAYER 2 /* 2層 */ /* 剩下的12M字節,提供給應用程序使用 */ #define SDRAM_APP_BUF (EXT_SDRAM_ADDR + SDRAM_LCD_SIZE * SDRAM_LCD_LAYER) #define SDRAM_APP_SIZE (EXT_SDRAM_SIZE - SDRAM_LCD_SIZE * SDRAM_LCD_LAYER)
41.4.2 第2步,LTDC涉及到的引腳配置
本章第3小節用到了哪些引腳,這些引腳全部要做初始化,初始化時別忘了初始化引腳對應的時鍾:
static void LCDF4_ConfigLTDC(void) { /* 配置LCD相關的GPIO */ { /* GPIOs Configuration */ /* +------------------------+-----------------------+----------------------------+ + LCD pins assignment + +------------------------+-----------------------+----------------------------+ | LCD429_TFT R0 <-> PI.15 | LCD429_TFT G0 <-> PJ.07 | LCD429_TFT B0 <-> PJ.12 | | LCD429_TFT R1 <-> PJ.00 | LCD429_TFT G1 <-> PJ.08 | LCD429_TFT B1 <-> PJ.13 | | LCD429_TFT R2 <-> PJ.01 | LCD429_TFT G2 <-> PJ.09 | LCD429_TFT B2 <-> PJ.14 | | LCD429_TFT R3 <-> PJ.02 | LCD429_TFT G3 <-> PJ.10 | LCD429_TFT B3 <-> PJ.15 | | LCD429_TFT R4 <-> PJ.03 | LCD429_TFT G4 <-> PJ.11 | LCD429_TFT B4 <-> PK.03 | | LCD429_TFT R5 <-> PJ.04 | LCD429_TFT G5 <-> PK.00 | LCD429_TFT B5 <-> PK.04 | | LCD429_TFT R6 <-> PJ.05 | LCD429_TFT G6 <-> PK.01 | LCD429_TFT B6 <-> PK.05 | | LCD429_TFT R7 <-> PJ.06 | LCD429_TFT G7 <-> PK.02 | LCD429_TFT B7 <-> PK.06 | ------------------------------------------------------------------------------- | LCD429_TFT HSYNC <-> PI.12 | LCDTFT VSYNC <-> PI.13 | | LCD429_TFT CLK <-> PI.14 | LCD429_TFT DE <-> PK.07 | ----------------------------------------------------- */ GPIO_InitTypeDef GPIO_Init_Structure; /*##-1- Enable peripherals and GPIO Clocks #################################*/ /* 使能LTDC時鍾 */ __HAL_RCC_LTDC_CLK_ENABLE(); /* 使能GPIO時鍾 */ __HAL_RCC_GPIOI_CLK_ENABLE(); __HAL_RCC_GPIOJ_CLK_ENABLE(); __HAL_RCC_GPIOK_CLK_ENABLE(); /* GPIOI 配置 */ GPIO_Init_Structure.Pin = GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15; GPIO_Init_Structure.Mode = GPIO_MODE_AF_PP; GPIO_Init_Structure.Pull = GPIO_NOPULL; GPIO_Init_Structure.Speed = GPIO_SPEED_FREQ_HIGH; GPIO_Init_Structure.Alternate = GPIO_AF14_LTDC; HAL_GPIO_Init(GPIOI, &GPIO_Init_Structure); /* GPIOJ 配置 */ GPIO_Init_Structure.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 | \ GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7 | \ GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_11 | \ GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15; GPIO_Init_Structure.Mode = GPIO_MODE_AF_PP; GPIO_Init_Structure.Pull = GPIO_NOPULL; GPIO_Init_Structure.Speed = GPIO_SPEED_FREQ_HIGH; GPIO_Init_Structure.Alternate = GPIO_AF14_LTDC; HAL_GPIO_Init(GPIOJ, &GPIO_Init_Structure); /* GPIOK 配置 */ GPIO_Init_Structure.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 | \ GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_6 | GPIO_PIN_7; GPIO_Init_Structure.Mode = GPIO_MODE_AF_PP; GPIO_Init_Structure.Pull = GPIO_NOPULL; GPIO_Init_Structure.Speed = GPIO_SPEED_FREQ_HIGH; GPIO_Init_Structure.Alternate = GPIO_AF14_LTDC; HAL_GPIO_Init(GPIOK, &GPIO_Init_Structure); } /* 其它省略未寫 */ }
41.4.3 第3步,LTDC時鍾和時序配置
LTDC時序配置主要分三步就可以完成:
- 行同步,場同步和DE的極性配置。
- CLK時鍾配置。
- 時序參數配置。
下面將這三點分別做個說明:
- 行同步,場同步和DE的極性配置
這里以V6開發板7寸RGB屏使用的source driver ic OTA7001為例進行說明(手冊下載地址:
http://www.armbbs.cn/forum.php?mod=viewthread&tid=18528)。
這幾項配置要看OTA7001手冊上面的時序圖,對於DE模式,行同步和場同步的極性配置為高或者為低均可。因為我們這里使用的就是DE模式,所以主要配置DE的極性。這里要特別注意一個小問題,看時序圖是DE高電平時數據有效,但是配置的時候要設置為低電平才可以。
下面的是V6開發板配套的7寸裸屏使用的source driver ic OTA7001的時序圖:
實際配置STM32F429的工程時,將DE配置為低有效才是上面截圖的效果,這個問題的確是有些奇葩了。
大家使用的時候也特別注意。
/* 配置信號極性 */ hltdc_F.Init.HSPolarity = LTDC_HSPOLARITY_AL; /* HSYNC 低電平有效 */ hltdc_F.Init.VSPolarity = LTDC_VSPOLARITY_AL; /* VSYNC 低電平有效 */ hltdc_F.Init.DEPolarity = LTDC_DEPOLARITY_AL; /* DE 低電平有效 */ hltdc_F.Init.PCPolarity = LTDC_PCPOLARITY_IPC; /* Pixel Clock 或者Dot Clock極性 */
ps:注意LTDC_PCPOLARITY_IPC和LTDC_PCPOLARITY_IIPC兩種極性,選擇不當會有一些問題。比如下面這個現象,底邊會有黑的。
下面是用示波器實際測量的波形效果,黃色的波形是DE信號,另一個是行同步信號Hsync:
將波形放縮后:
- LTDC的像素時鍾輸出配置
在OTA7001手冊上面給出了支持的時鍾范圍:
下面配置LTDC輸出30MHz
PLLSAI_VCO Input = HSE_VALUE / PLL_M = 8M / 8 = 1MHz PLLSAI_VCO Output = PLLSAI_VCO Input * PLLSAI_N = 1 * 420 = 420MHz PLLLCDCLK = PLLSAI_VCO Output / PLLSAI_R = 420 / 7 = 60MHz LTDC 時鍾 = PLLLCDCLK / RCC_PLLSAIDivR = 60 / 2 = 30MHz
這里再額外補充點知識,LCD_CLK=30MHz時
刷新率 = 30MHz /((Width + HSYNC_W + HBP + HFP)*(Height + VSYNC_W + VBP + VFP))
= 30000000/((800 + 96 + 10 + 10)*(480 + 2 + 10 + 10))
= 30000000/(916*502)
= 65Hz
- 時序參數配置
時序參數的配置也比較容易,其實就是先看STM3F429參考手冊上面的公式說明,說是公式,其實就是簡單的加減法。然后將OTA7001的參數代到這個公式就可以了。又因為手冊一般都是給出了參數的最小值,典型值和最大值,大家可以根據實際情況做簡單的調整即可。需要用到的參數:
uint16_t Width, Height, HSYNC_W, VSYNC_W, HBP, HFP, VBP, VFP;
Horizontal Synchronization (Hsync) 對應變量HSYNC_W
Horizontal Back Porch (HBP) 對應變量HBP
Active Width 對應變量Width
Horizontal Front Porch (HFP) 對應變量HFP
Vertical Synchronization (Vsync) 對應變量VSYNC_W
Vertical Back Porch (VBP) 對應變量VBP
Active Heigh 對應變量Heigh
Vertical Front Porch (VFP) 對應變量VFP
STM32F429參考手冊上面的公式如下:
********************************************************************************************************* * LCD_TFT 同步時序配置(整理自官方做的一個截圖,言簡意賅): * ---------------------------------------------------------------------------- * * Total Width * <---------------------------------------------------> * Hsync width HBP Active Width HFP * <---><--><--------------------------------------><--> * ____ ____|_______________________________________|____ * |___| | | | * | | | * __| | | | * /|\ /|\ | | | | * | VSYNC| | | | | * |Width\|/ |__ | | | * | /|\ | | | | * | VBP | | | | | * | \|/_____|_________|_______________________________________| | * | /|\ | | / / / / / / / / / / / / / / / / / / / | | * | | | |/ / / / / / / / / / / / / / / / / / / /| | * Total | | | |/ / / / / / / / / / / / / / / / / / / /| | * Heigh | | | |/ / / / / / / / / / / / / / / / / / / /| | * |Active| | |/ / / / / / / / / / / / / / / / / / / /| | * |Heigh | | |/ / / / / / Active Display Area / / / /| | * | | | |/ / / / / / / / / / / / / / / / / / / /| | * | | | |/ / / / / / / / / / / / / / / / / / / /| | * | | | |/ / / / / / / / / / / / / / / / / / / /| | * | | | |/ / / / / / / / / / / / / / / / / / / /| | * | | | |/ / / / / / / / / / / / / / / / / / / /| | * | \|/_____|_________|_______________________________________| | * | /|\ | | * | VFP | | | * \|/ \|/_____|______________________________________________________| * * * 每個LCD設備都有自己的同步時序值: * Horizontal Synchronization (Hsync) * Horizontal Back Porch (HBP) * Active Width * Horizontal Front Porch (HFP) * * Vertical Synchronization (Vsync) * Vertical Back Porch (VBP) * Active Heigh * Vertical Front Porch (VFP) * * LCD_TFT 窗口水平和垂直的起始以及結束位置 : * ---------------------------------------------------------------- * * HorizontalStart = (Offset_X + Hsync + HBP); * HorizontalStop = (Offset_X + Hsync + HBP + Window_Width - 1); * VarticalStart = (Offset_Y + Vsync + VBP); * VerticalStop = (Offset_Y + Vsync + VBP + Window_Heigh - 1); * *********************************************************************************************************
OTA7001手冊中已經給出了我們需要的數值:
uint16_t Width, Height, HSYNC_W, HBP, HFP, VSYNC_W, VBP, VFP。
參數設置好了,直接代入公式並與行同步,場同步和DE一起初始化:
/* 時序配置 */ hltdc_F.Init.HorizontalSync = (HSYNC_W - 1); hltdc_F.Init.VerticalSync = (VSYNC_W - 1); hltdc_F.Init.AccumulatedHBP = (HSYNC_W + HBP - 1); hltdc_F.Init.AccumulatedVBP = (VSYNC_W + VBP - 1); hltdc_F.Init.AccumulatedActiveH = (Height + VSYNC_W + VBP - 1); hltdc_F.Init.AccumulatedActiveW = (Width + HSYNC_W + HBP - 1); hltdc_F.Init.TotalHeigh = (Height + VSYNC_W + VBP + VFP - 1); hltdc_F.Init.TotalWidth = (Width + HSYNC_W + HBP + HFP - 1);
至此,時序配置工作就完成了。
這里特別注意,當前程序中實際使用的參數與本小節的參數略有區別。由於這些參數都有較大的容錯范圍,所以很多參數都可以正常使用。
41.4.4 第4步,如何驗證LTDC的時序配置是否正確
下面說一個最重要的問題,配置好時序了,怎么檢查自己的配置是否成功了?用戶僅需在函數LCDF4_ConfigLTDC里面的如下代碼后面加上兩個函數:
/* 配置LTDC */ if (HAL_LTDC_Init(&hltdc_F) != HAL_OK) { /* 初始化錯誤 */ Error_Handler(__FILE__, __LINE__); } /* 下面是添加的 */ LCD_SetBackLight(BRIGHT_DEFAULT); while(1);
加上這兩行代碼后,再將背景層設置為一個合適的顏色,建議設置成紅色,方便觀察:
/* 配置背景層顏色 */ hltdc_F.Init.Backcolor.Blue = 0; hltdc_F.Init.Backcolor.Green = 0; hltdc_F.Init.Backcolor.Red = 255;
如果背景層可以正常顯示紅色,說明引腳和時序配置都是沒有問題的。如果不成功要從以下幾個方面着手檢查:
- 首先要清楚一點,當前的配置是否成功與SDRAM沒有任何關系,因為背景層還用不到SDRAM,圖層1和圖層2才需要SDRAM做顯存使用。
- 從硬件着手檢查,保證STM32F429芯片焊接沒問題,TFT接口一定要牢固,防止接觸不良,特別是使用FPC軟排線的時候,測試階段,軟排線越短越好。有時候也可能是顯示屏有問題,最好可以備兩個顯示屏測試。
- 從軟件配置着手檢查,查看LTDC涉及到的所有引腳是否配置,引腳時鍾是否使能。有時候無法顯示也有可能是板子硬件設計不規范導致干擾較大造成的,此時,可以降低LTDC所涉及到GPIO的速度等級。
- 如果顯示了,但是顯示的位置不正確,可以重新調整時序參數即可。
41.4.5 第5步,LTDC圖層配置
LTDC的圖層配置就比較好理解了,下面是完整的驅動代碼:
1. /* 2. ****************************************************************************************************** 3. * 函 數 名: LCDF4_ConfigLTDC 4. * 功能說明: 配置LTDC 5. * 形 參: 無 6. * 返 回 值: 無 7. ****************************************************************************************************** 8. */ 9. static void LCDF4_ConfigLTDC(void) 10. { 11. /* GPIO初始化部分省略未寫 */ 12. 13. /*##-2- LTDC初始化 #############################################################*/ 14. { 15. LTDC_LayerCfgTypeDef pLayerCfg; 16. uint16_t Width, Height, HSYNC_W, HBP, HFP, VSYNC_W, VBP, VFP; 17. RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0}; 18. 19. /* 支持6種面板 */ 20. switch (g_LcdType) 21. { 22. case LCD_35_480X320: /* 3.5寸 480 * 320 未使用 */ 23. Width = 480; 24. Height = 272; 25. HSYNC_W = 10; 26. HBP = 20; 27. HFP = 20; 28. VSYNC_W = 20; 29. VBP = 20; 30. VFP = 20; 31. break; 32. 33. case LCD_43_480X272: /* 4.3寸 480 * 272 */ 34. case LCD_50_480X272: /* 5.0寸 480 * 272 */ 35. Width = 480; 36. Height = 272; 37. 38. HSYNC_W = 40; 39. HBP = 2; 40. HFP = 2; 41. VSYNC_W = 9; 42. VBP = 2; 43. VFP = 2; 44. 45. /* LCD 時鍾配置 */ 46. /* 47. PLLSAI_VCO Input = HSE_VALUE / PLL_M = 8M / 8 = 1MHz 48. PLLSAI_VCO Output = PLLSAI_VCO Input * PLLSAI_N = 1 * 420 = 420MHz 49. PLLLCDCLK = PLLSAI_VCO Output / PLLSAI_R = 420 / 7 = 60MHz 50. LTDC 時鍾 = PLLLCDCLK / RCC_PLLSAIDivR = 60 / 4 = 15MHz 51. */ 52. /* 53. 刷新率 = 15MHz /((Width + HSYNC_W + HBP + HFP)*(Height + VSYNC_W + VBP + VFP)) 54. = 15000000/((480 + 40 + 2 + 2)*(272 + 9 + 2 + 2)) 55. = 15000000/(524*285) 56. = 100Hz 57. 58. */ 59. PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_LTDC; 60. PeriphClkInitStruct.PLLSAI.PLLSAIN = 420; 61. PeriphClkInitStruct.PLLSAI.PLLSAIR = 7; 62. PeriphClkInitStruct.PLLSAIDivR = RCC_PLLSAIDIVR_4; 63. if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK) 64. { 65. Error_Handler(__FILE__, __LINE__); 66. } 67. break; 68. 69. case LCD_50_800X480: /* 5.0寸 800 * 480 */ 70. case LCD_70_800X480: /* 7.0寸 800 * 480 */ 71. Width = 800; 72. Height = 480; 73. 74. HSYNC_W = 96; 75. HBP = 10; 76. HFP = 10; 77. VSYNC_W = 2; 78. VBP = 10; 79. VFP = 10; 80. 81. /* LCD 時鍾配置 */ 82. /* 83. PLLSAI_VCO Input = HSE_VALUE / PLL_M = 8M / 8 = 1MHz 84. PLLSAI_VCO Output = PLLSAI_VCO Input * PLLSAI_N = 1 * 420 = 420MHz 85. PLLLCDCLK = PLLSAI_VCO Output / PLLSAI_R = 420 / 7 = 60MHz 86. LTDC 時鍾 = PLLLCDCLK / RCC_PLLSAIDivR = 60 / 2 = 30MHz 87. */ 88. /* 89. 刷新率 = 30MHz /((Width + HSYNC_W + HBP + HFP)*(Height + VSYNC_W + VBP + VFP)) 90. = 30000000/((800 + 96 + 10 + 10)*(480 + 2 + 10 + 10)) 91. = 30000000/(916*502) 92. = 65Hz 93. 94. 24位或者32位色選擇LTDC輸出15MHz,16位或者8位30MHz 95. */ 96. PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_LTDC; 97. PeriphClkInitStruct.PLLSAI.PLLSAIN = 420; 98. PeriphClkInitStruct.PLLSAI.PLLSAIR = 7; 99. PeriphClkInitStruct.PLLSAIDivR = RCC_PLLSAIDIVR_2; 100. if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK) 101. { 102. Error_Handler(__FILE__, __LINE__); 103. } 104. break; 105. 106. case LCD_70_1024X600: /* 7.0寸 1024 * 600,未使用 */ 107. Width = 1024; 108. Height = 600; 109. 110. HSYNC_W = 2; 111. HBP = 157; 112. HFP = 160; 113. VSYNC_W = 2; 114. VBP = 20; 115. VFP = 12; 116. 117. break; 118. 119. default: /* 未使用 */ 120. Width = 800; 121. Height = 480; 122. 123. HSYNC_W = 80; 124. HBP = 10; 125. HFP = 10; 126. VSYNC_W = 10; 127. VBP = 10; 128. VFP = 10; 129. 130. break; 131. } 132. 133. g_LcdHeight = Height; 134. g_LcdWidth = Width; 135. 136. /* 配置信號極性 */ 137. hltdc_F.Init.HSPolarity = LTDC_HSPOLARITY_AL; /* HSYNC 低電平有效 */ 138. hltdc_F.Init.VSPolarity = LTDC_VSPOLARITY_AL; /* VSYNC 低電平有效 */ 139. hltdc_F.Init.DEPolarity = LTDC_DEPOLARITY_AL; /* DE 低電平有效 */ 140. hltdc_F.Init.PCPolarity = LTDC_PCPOLARITY_IPC; 141. 142. /* 時序配置 */ 143. hltdc_F.Init.HorizontalSync = (HSYNC_W - 1); 144. hltdc_F.Init.VerticalSync = (VSYNC_W - 1); 145. hltdc_F.Init.AccumulatedHBP = (HSYNC_W + HBP - 1); 146. hltdc_F.Init.AccumulatedVBP = (VSYNC_W + VBP - 1); 147. hltdc_F.Init.AccumulatedActiveH = (Height + VSYNC_W + VBP - 1); 148. hltdc_F.Init.AccumulatedActiveW = (Width + HSYNC_W + HBP - 1); 149. hltdc_F.Init.TotalHeigh = (Height + VSYNC_W + VBP + VFP - 1); 150. hltdc_F.Init.TotalWidth = (Width + HSYNC_W + HBP + HFP - 1); 151. 152. /* 配置背景層顏色 */ 153. hltdc_F.Init.Backcolor.Blue = 0; 154. hltdc_F.Init.Backcolor.Green = 0; 155. hltdc_F.Init.Backcolor.Red = 0; 156. 157. hltdc_F.Instance = LTDC; 158. 159. /* 開始配置圖層 ------------------------------------------------------*/ 160. /* 窗口顯示區設置 */ 161. pLayerCfg.WindowX0 = 0; 162. pLayerCfg.WindowX1 = Width; 163. pLayerCfg.WindowY0 = 0; 164. pLayerCfg.WindowY1 = Height; 165. 166. /* 配置顏色格式 */ 167. pLayerCfg.PixelFormat = LTDC_PIXEL_FORMAT_RGB565; 168. 169. /* 顯存地址 */ 170. pLayerCfg.FBStartAdress = LCDF4_FRAME_BUFFER; 171. 172. /* Alpha常數 (255 表示完全不透明) */ 173. pLayerCfg.Alpha = 255; 174. 175. /* 無背景色 */ 176. pLayerCfg.Alpha0 = 0; /* 完全透明 */ 177. pLayerCfg.Backcolor.Blue = 0; 178. pLayerCfg.Backcolor.Green = 0; 179. pLayerCfg.Backcolor.Red = 0; 180. 181. /* 配置圖層混合因數 */ 182. pLayerCfg.BlendingFactor1 = LTDC_BLENDING_FACTOR1_CA; 183. pLayerCfg.BlendingFactor2 = LTDC_BLENDING_FACTOR2_CA; 184. 185. /* 配置行列大小 */ 186. pLayerCfg.ImageWidth = Width; 187. pLayerCfg.ImageHeight = Height; 188. 189. /* 配置LTDC */ 190. if (HAL_LTDC_Init(&hltdc_F) != HAL_OK) 191. { 192. /* 初始化錯誤 */ 193. Error_Handler(__FILE__, __LINE__); 194. } 195. 196. /* 配置圖層1 */ 197. if (HAL_LTDC_ConfigLayer(&hltdc_F, &pLayerCfg, LTDC_LAYER_1) != HAL_OK) 198. { 199. /* 初始化錯誤 */ 200. Error_Handler(__FILE__, __LINE__); 201. } 202. 203. #if 0 204. /* 配置圖層2 */ 205. if (HAL_LTDC_ConfigLayer(&hltdc_F, &pLayerCfg, LTDC_LAYER_2) != HAL_OK) 206. { 207. /* 初始化錯誤 */ 208. Error_Handler(__FILE__, __LINE__); 209. } 210. #endif 211. } 212. 213. #if 1 214. HAL_NVIC_SetPriority(LTDC_IRQn, 0xE, 0); 215. HAL_NVIC_EnableIRQ(LTDC_IRQn); 216. #endif 217. }
下面將幾個關鍵的地方做個闡釋:
- 第20行,六種顯示面板的LTDC輸出時鍾和時序參數配置,六種面板的識別是在bsp_ts_touch.c文件中實現的。大家自己配置時用不到這個,僅需提供一組時序參數和輸出時鍾即可,除非項目中需要切換不同顯示屏。
- 第69-104行,這里是7寸面板的LTDC時鍾輸出配置和時序參數配置,配置方法在前面幾步已經介紹,這里不再贅述,其它面板的設置方法是一樣的。
- 第133-134行,全局變量g_LcdWidth和g_LcdHeight在文件bsp_tft_lcd.c文件定義,用來記錄顯示屏的分辨率。
- 第137-140行,用來配置行同步,場同步,DE數據使能和LTDC像素時鍾的極性。
- 第143-150行,配置時序。
- 第153-155行,配置背景層顏色。
- 第161-164行,用來設置圖層在LCD顯示區的起始位置和結束位置。
- 第167行,用來設置圖層的顏色格式,STM32F429支持8種顏色格式,這里是設置為RGB565。
- 第170行,用來設置圖層的顯示首地址。
- 第173-183行,在第40章的2.5小節詳細講解了這行代碼的作用。
- 第232-233行,用於設置從顯存中要讀取的行長和行數。
- 第186-187行,配置LTDC的基本參數。
- 第197-201行,配置圖層1。
- 第205-209行,配置圖層2,暫時未用到圖層2(通過條件編譯取消執行)。
- 第214-215行,配置LTDC中斷的優先級並使能。
41.4.6 第6步,LCD背光實現
LCD的背光是PWM驅動方式,涉及到的代碼如下:
/* ********************************************************************************************************* * 函 數 名: LCD_SetBackLight * 功能說明: 初始化控制LCD背景光的GPIO,配置為PWM模式。 * 當關閉背光時,將CPU IO設置為浮動輸入模式(推薦設置為推挽輸出,並驅動到低電平);將TIM3關閉 省電 * 形 參: _bright 亮度,0是滅,255是最亮 * 返 回 值: 無 ********************************************************************************************************* */ void LCD_SetBackLight(uint8_t _bright) { s_ucBright = _bright; /* 保存背光值 */ LCD_SetPwmBackLight(s_ucBright); } /* ********************************************************************************************************* * 函 數 名: LCD_SetPwmBackLight * 功能說明: 初始化控制LCD背景光的GPIO,配置為PWM模式。 * 當關閉背光時,將CPU IO設置為浮動輸入模式(推薦設置為推挽輸出,並驅動到低電平);將TIM3關閉 省電 * 形 參: _bright 亮度,0是滅,255是最亮 * 返 回 值: 無 ********************************************************************************************************* */ static void LCD_SetPwmBackLight(uint8_t _bright) { /* 背光有CPU輸出PWM控制,PA0/TIM5_CH1/TIM2_CH1 */ //bsp_SetTIMOutPWM(GPIOA, GPIO_PIN_0, TIM5, 1, 100, (_bright * 10000) /255); bsp_SetTIMOutPWM(GPIOA, GPIO_PIN_0, TIM5, 1, 20000, (_bright * 10000) /255); //bsp_SetTIMOutPWM(GPIOA, GPIO_PIN_8, TIM1, 1, 20000, (_bright * 10000) /255); }
函數的注釋已經比較詳細。另外,背光是基於第24章的API:bsp_SetTIMOutPWM實現,關於這個函數可以看第24章節。
41.5 LCD板級支持包(bsp_ltdc_429.c和 bsp_tft_lcd.c)
bsp_ltdc_429.c是429的LTDC驅動文件,涉及到的函數比較多。而bsp_tft_lcd.c文件是在LTDC的API基礎上面封裝出更通用的函數,不僅僅LTDC,像RA8875,ili9488等也可通過此文件進行封裝。
本章節主要給幾個常用的基本API做個介紹:
- LCD_InitHard
- LCD_ClrScr
- LCD_SetBackLight
- LCD_DispStr
- LCD_PutPixel
- LCD_DrawLine
- LCD_DrawRect
- LCD_DrawCircle
- LCD_Fill_Rect
41.5.1 函數LCD_InitHard
函數原型:
/* ********************************************************************************************************* * 函 數 名: LCD_InitHard * 功能說明: 初始化LCD * 形 參: 無 * 返 回 值: 無 ********************************************************************************************************* */ void LCD_InitHard(void) { LCD_HardReset(); LCDH7_InitHard(); LCD_SetDirection(0); LCD_ClrScr(CL_BLACK); /* 清屏,顯示全黑 */ // LCD_SetBackLight(BRIGHT_DEFAULT); }
函數描述:
此函數用於初始化LCD,配置了STM32F429的LTDC控制器,設置橫向顯示,默認清屏為黑色。
注意事項:
- 調用此函數前,務必優先調用函數TOUCH_InitHard識別不同分辨率面板。
- 通過函數LCD_SetDirection可以設置橫向,豎向,橫向180度,豎向180度顯示。在后面章節再為大家介紹具體的實現方法。
使用舉例:
作為初始化函數,直接在bsp.c文件的bsp_Init函數里面調用即可。
41.5.2 函數LCD_ClrScr
函數原型:
void LCD_ClrScr(uint16_t _usColor)
函數描述:
此函數用於清屏操作。
函數參數:
- 第1個參數是清屏的顏色值設置,在bsp_tft_lcd.h文件中定義了幾個常用的顏色:
/* LCD 顏色代碼,CL_是Color的簡寫 16Bit由高位至低位, RRRR RGGG GGGB BBBB 下面的RGB 宏將24位的RGB值轉換為16位格式。 啟動windows的畫筆程序,點擊編輯顏色,選擇自定義顏色,可以獲得的RGB值。 推薦使用迷你取色器軟件獲得你看到的界面顏色。 */ #define RGB(R,G,B) (((R >> 3) << 11) | ((G >> 2) << 5) | (B >> 3))/* 將8位R,G,B轉化為 16位RGB565格式 */ /* 解碼出 R=8bit G=8bit B=8bit */ #define RGB565_R(x) ((x >> 8) & 0xF8) #define RGB565_G(x) ((x >> 3) & 0xFC) #define RGB565_B(x) ((x << 3) & 0xF8) /* 解碼出 R=5bit G=6bit B=5bit */ #define RGB565_R2(x) ((x >> 11) & 0x1F) #define RGB565_G2(x) ((x >> 5) & 0x3F) #define RGB565_B2(x) ((x >> 0) & 0x1F) enum { CL_WHITE = RGB(255,255,255), /* 白色 */ CL_BLACK = RGB( 0, 0, 0), /* 黑色 */ CL_RED = RGB(255, 0, 0), /* 紅色 */ CL_GREEN = RGB( 0,255, 0), /* 綠色 */ CL_BLUE = RGB( 0, 0,255), /* 藍色 */ CL_YELLOW = RGB(255,255, 0), /* 黃色 */ CL_GREY = RGB( 98, 98, 98), /* 深灰色 */ CL_GREY1 = RGB( 150, 150, 150), /* 淺灰色 */ CL_GREY2 = RGB( 180, 180, 180), /* 淺灰色 */ CL_GREY3 = RGB( 200, 200, 200), /* 最淺灰色 */ CL_GREY4 = RGB( 230, 230, 230), /* 最淺灰色 */ CL_BUTTON_GREY = RGB( 220, 220, 220), /* WINDOWS 按鈕表面灰色 */ CL_MAGENTA = 0xF81F, /* 紅紫色,洋紅色 */ CL_CYAN = 0x7FFF, /* 藍綠色,青色 */ CL_BLUE1 = RGB( 0, 0, 240), /* 深藍色 */ CL_BLUE2 = RGB( 0, 0, 128), /* 深藍色 */ CL_BLUE3 = RGB( 68, 68, 255), /* 淺藍色1 */ CL_BLUE4 = RGB( 0, 64, 128), /* 淺藍色1 */ /* UI 界面 Windows控件常用色 */ CL_BTN_FACE = RGB(236, 233, 216), /* 按鈕表面顏色(灰) */ CL_BTN_FONT = CL_BLACK, /* 按鈕字體顏色(黑) */ CL_BOX_BORDER1 = RGB(172, 168,153), /* 分組框主線顏色 */ CL_BOX_BORDER2 = RGB(255, 255,255), /* 分組框陰影線顏色 */ CL_MASK = 0x9999 /* 顏色掩碼,用於文字背景透明 */ };
使用舉例:
比如將LCD清為紅色,即LCD_ClrSrc(CL_RED)。
41.5.3 函數LCD_SetBackLight
函數原型:
/* ********************************************************************************************************* * 函 數 名: LCD_SetBackLight * 功能說明: 初始化控制LCD背景光的GPIO,配置為PWM模式。 * 當關閉背光時,將CPU IO設置為浮動輸入模式(推薦設置為推挽輸出,並驅動到低電平);將TIM3關閉 省電 * 形 參: _bright 亮度,0是滅,255是最亮 * 返 回 值: 無 ********************************************************************************************************* */ void LCD_SetBackLight(uint8_t _bright) { s_ucBright = _bright; /* 保存背光值 */ LCD_SetPwmBackLight(s_ucBright); }
函數描述:
此函數主要用於LCD背光設置。
函數參數:
- 第1個參數是背光參數,0表示滅,255表示最亮。
使用舉例:
比如設置LCD最亮LCD_SetBackLight(255)。
41.5.4 函數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指定位置顯示字符串,中英文均支持。由於這個函數涉及到的知識點比較多,下章節會專門為大家講解。
函數參數:
- 第1個參數是x軸坐標位置。
- 第2個參數是y軸坐標位置。
- 第3個參數是要顯示的字符串。
- 第4個參數是FONT_T類型結構體,定義如下:
/* 字體屬性結構, 用於LCD_DispStr() */ typedef struct { FONT_CODE_E FontCode; /* 字體代碼 FONT_CODE_E */ uint16_t FrontColor; /* 字體顏色 */ uint16_t BackColor; /* 文字背景顏色,透明 */ uint16_t Space; /* 文字間距,單位 = 像素 */ }FONT_T;
使用舉例:
比如顯示12點陣和16點陣字符。
FONT_T tFont12; /* 定義一個字體結構體變量,用於設置字體參數 */ FONT_T tFont16; /* 定義一個字體結構體變量,用於設置字體參數 */ /* 設置字體參數 */ { tFont12.FontCode = FC_ST_12; /* 字體代碼 12點陣 */ tFont12.FrontColor = CL_WHITE; /* 字體顏色 */ tFont12.BackColor = CL_BLUE; /* 文字背景顏色 */ tFont12.Space = 0; /* 文字間距,單位 = 像素 */ } /* 設置字體參數 */ { tFont16.FontCode = FC_ST_16; /* 字體代碼 16點陣 */ tFont16.FrontColor = CL_WHITE; /* 字體顏色 */ tFont16.BackColor = CL_BLUE; /* 文字背景顏色 */ tFont16.Space = 0; /* 文字間距,單位 = 像素 */ } LCD_ClrScr(CL_BLUE); LCD_DispStr(5, 3, "故人西辭黃鶴樓,煙花三月下揚州。", &tFont12); LCD_DispStr(5, 18, "孤帆遠影碧空盡,唯見長江天際流。", &tFont12); LCD_DispStr(5, 38, "故人西辭黃鶴樓,煙花三月下揚州。", &tFont16); LCD_DispStr(5, 58, "孤帆遠影碧空盡,唯見長江天際流。", &tFont16);
41.5.5 函數LCD_PutPixel
函數原型:
/* ********************************************************************************************************* * 函 數 名: LCD_PutPixel * 功能說明: 畫1個像素 * 形 參: * _usX,_usY : 像素坐標 * _usColor : 像素顏色 * 返 回 值: 無 ********************************************************************************************************* */ void LCD_PutPixel(uint16_t _usX, uint16_t _usY, uint16_t _usColor) { LCDH7_PutPixel(_usX, _usY, _usColor); }
函數描述:
此函數用於在指定位置顯示一個像素點。
函數參數:
- 第1個參數是x軸坐標位置。
- 第2個參數是y軸坐標位置。
- 第3個參數是像素點顏色。
使用舉例:
比如在坐標(0, 0)顯示紅色,那就是LCD_PutPixel(0, 0, CL_RED)。
41.5.6 函數LCD_DrawLine
函數原型:
/* ********************************************************************************************************* * 函 數 名: LCD_DrawLine * 功能說明: 采用 Bresenham 算法,在2點間畫一條直線。 * 形 參: * _usX1, _usY1 : 起始點坐標 * _usX2, _usY2 : 終止點Y坐標 * _usColor : 顏色 * 返 回 值: 無 ********************************************************************************************************* */ void LCD_DrawLine(uint16_t _usX1 , uint16_t _usY1 , uint16_t _usX2 , uint16_t _usY2 , uint16_t _usColor) { LCDH7_DrawLine(_usX1 , _usY1 , _usX2, _usY2 , _usColor); }
函數描述:
此函數用於任意兩點間的直線繪制,采用的Bresenham算法,關於這個算法的介紹在帖子:
http://www.armbbs.cn/forum.php?mod=viewthread&tid=4048 。
函數參數:
- 第1個參數是起始坐標x軸位置。
- 第2個參數是起始坐標y軸位置。
- 第3個參數是結束坐標x軸位置。
- 第4個參數是結束坐標y軸位置。
- 第5個參數是直線顏色。
使用舉例:
比如在坐標(0, 0)到坐標(100, 100)顯示一條紅色直線,那就是LCD_DrawLine(0, 0, 100, 100, CL_RED)。
41.5.7 函數LCD_DrawRect
函數原型:
/* ********************************************************************************************************* * 函 數 名: LCD_DrawRect * 功能說明: 繪制水平放置的矩形。 * 形 參: * _usX,_usY: 矩形左上角的坐標 * _usHeight : 矩形的高度 * _usWidth : 矩形的寬度 * 返 回 值: 無 ********************************************************************************************************* */ void LCD_DrawRect(uint16_t _usX, uint16_t _usY, uint16_t _usHeight, uint16_t _usWidth, uint16_t _usColor) { LCDH7_DrawRect(_usX, _usY, _usHeight, _usWidth, _usColor); }
函數描述:
此函數用於繪制矩形框。
函數參數:
- 第1個參數是左上角X軸位置。
- 第2個參數是左上角Y軸位置。
- 第3個參數是矩形框的長度。
- 第4個參數是矩形框的高度。
- 第5個參數是矩形框的顏色。
使用舉例:
比如在坐標(0, 0)繪制一個長度為100,高度為50的紅色矩形框,那么就是LCD_DrawRect(0, 0, 100, 50, CL_RED)。
41.5.8 函數LCD_DrawCircle
函數原型:
/* ********************************************************************************************************* * 函 數 名: LCD_DrawCircle * 功能說明: 繪制一個圓,筆寬為1個像素 * 形 參: * _usX,_usY : 圓心的坐標 * _usRadius : 圓的半徑 * 返 回 值: 無 ********************************************************************************************************* */ void LCD_DrawCircle(uint16_t _usX, uint16_t _usY, uint16_t _usRadius, uint16_t _usColor) { LCDH7_DrawCircle(_usX, _usY, _usRadius, _usColor); }
函數描述:
此函數顯示一個圓圈。
函數參數:
- 第1個參數是圓心坐標x軸。
- 第2個參數是圓心坐標y軸。
- 第3個參數是圓半徑。
- 第4個參數是圓顏色。
使用舉例:
比如在坐標(200, 200)繪制一個半徑為50的紅色圓圈,那么就是LCD_DrawCircle (200, 200, 50, CL_RED)。
41.5.9 函數LCD_Fill_Rect
函數原型:
/* ********************************************************************************************************* * 函 數 名: LCD_Fill_Rect * 功能說明: 用一個顏色值填充一個矩形。【emWin 中有同名函數 LCD_FillRect,因此加了下划線區分】 * 形 參: * _usX,_usY: 矩形左上角的坐標 * _usHeight : 矩形的高度 * _usWidth : 矩形的寬度 * 返 回 值: 無 ********************************************************************************************************* */ void LCD_Fill_Rect(uint16_t _usX, uint16_t _usY, uint16_t _usHeight, uint16_t _usWidth, uint16_t _usColor) { LCDH7_FillRect(_usX, _usY, _usHeight, _usWidth, _usColor); }
函數描述:
此函數用繪制一個填充的矩形。
函數參數:
- 第1個參數是左上角X軸位置。
- 第2個參數是左上角Y軸位置。
- 第3個參數是填充矩形的長度。
- 第4個參數是填充矩形的高度。
- 第5個參數是填充矩形的顏色。
使用舉例:
比如在坐標(0, 0)繪制一個長度為100,高度為50的紅色填充矩形,那么就是LCD_Fill_Rect (0, 0, 100, 50, CL_RED)。
41.6 LCD驅動移植和使用
由於我們開發板要做不同顯示屏的自適應,所以關聯了好多個文件,所有關於TFT,觸摸,觸摸校准參數保存和字體的文件都要添加進來。這里有必要先為大家做個介紹才好移植。
- Fonts分組中的文件
asc12.c ---12點陣ASCII字符字庫。
asc16.c---16點陣ASCII字符字庫。
hz12.c --- 12點陣宋體小字庫。
hz16.c --- 16點陣宋體小字庫。
hz24.c --- 24點陣宋體小字庫。
hz32.c --- 32點陣宋體小字庫。
ra8875_asc_width.c -- RA8875 ASCII字體的寬度表。
- bsp分組中的文件
bsp_fmc_sdram.c---用於TFT的顯存。
bsp_tft_429.c --- STM32F429的LTDC的驅動文件。
bsp_tft_lcd.c --- TFT驅動和相關API函數匯總文件,比如RA8875顯示屏,ili9488顯示屏,
STM32f429所帶TFT控制器驅動顯示屏都可以有一個單獨的文件,然后將這些顯示屏相同功能的函數匯總成一個函數。這個文件就起到這個作用。
bsp_ts_touch.c --- 觸摸芯片自適應驅動,根據用戶使用的觸摸IC選擇不同的驅動。另外,電阻屏的觸摸掃描,觸摸校准和觸摸濾波也是在這個文件里面實現。
bsp_gt811.c --- 電容觸摸芯片GT811的驅動以及觸摸掃描。
bsp_gt911.c --- 電容觸摸芯片GT911的驅動以及觸摸掃描。
bsp_ft5x06.c --- 電容觸摸芯片FT5X06的驅動以及觸摸掃描。
bsp_tim_pwm.c --- 定時器驅動,顯示屏的背光要用到PWM。
bsp_ts_stmpe811.c --- 電阻觸摸芯片 STMPE811 的驅動。
bsp_i2c_gpio.c --- I2C接口驅動,EEPROM,GT811,GT911,STMPE811和FT5X06都要用到,因為他們的接口都是I2C方式。
bsp_eeprom_24xx.c --- EEPROM驅動,用於存儲電阻屏觸摸校准參數。
- HAL_Driver分組中的文件
stm32f4xx_ll_fmc.c 和stm32f4xx_hal_sdram.c ---SDRAM的驅動文件。
stm32f4xx_hal_tim.c --- 顯示屏的背光是用PWM驅動的,需要用到這個定時器庫文件。
stm32f4xx_hal_ltdc.c --- LTDC相關的API函數需要用到這個庫文件。
stm32f4xx_hal_dma2d.c --- DMA2D相關的API函數需要用到這個庫文件。
對於本章節的驅動,不推薦單獨移植了,建議直接使用本章節配套例子的基礎上做修改。
41.7 實驗例程設計框架
通過程序設計框架,讓大家先對配套例程有一個全面的認識,然后再理解細節,本次實驗例程的設計框架如下:
第1階段,上電啟動階段:
- 這部分在第14章進行了詳細說明。
第2階段,進入main函數:
- 第1步,硬件初始化,主要是HAL庫,系統時鍾,滴答定時器,LED和串口。
- 第2步,LCD應用程序設計部分,顯示漢字和2D圖形。
41.8 實驗例程說明(MDK)
配套例子:
V6-020_LCD的漢字顯示和2D圖形顯示(小字庫)
實驗目的:
- 學習LCD的小字庫實現和2D圖形顯示。
實驗內容:
- 小字庫通過此軟件生成:
- LCD界面上顯示了漢字和2D圖形。
- 啟動1個200ms的自動重裝定時器,讓LED2每200ms翻轉一次。
- 同時在LCD界面上實現一個簡單計數,每200ms加1,計數到255后繼續從0開始。
上電后串口打印的信息:
波特率 115200,數據位 8,奇偶校驗位無,停止位 1
程序設計:
系統棧大小分配:
硬件外設初始化
硬件外設的初始化是在 bsp.c 文件實現:
/* ********************************************************************************************************* * 函 數 名: bsp_Init * 功能說明: 初始化所有的硬件設備。該函數配置CPU寄存器和外設的寄存器並初始化一些全局變量。只需要調用一次 * 形 參:無 * 返 回 值: 無 ********************************************************************************************************* */ void bsp_Init(void) { /* STM32F429 HAL 庫初始化,此時系統用的還是F429自帶的16MHz,HSI時鍾: - 調用函數HAL_InitTick,初始化滴答時鍾中斷1ms。 - 設置NVIV優先級分組為4。 */ HAL_Init(); /* 配置系統時鍾到168MHz - 切換使用HSE。 - 此函數會更新全局變量SystemCoreClock,並重新配置HAL_InitTick。 */ SystemClock_Config(); /* Event Recorder: - 可用於代碼執行時間測量,MDK5.25及其以上版本才支持,IAR不支持。 - 默認不開啟,如果要使能此選項,務必看V7開發板用戶手冊第8章 */ #if Enable_EventRecorder == 1 /* 初始化EventRecorder並開啟 */ EventRecorderInitialize(EventRecordAll, 1U); EventRecorderStart(); #endif bsp_InitKey(); /* 按鍵初始化,要放在滴答定時器之前,因為按鈕檢測是通過滴答定時器掃描 */ bsp_InitTimer(); /* 初始化滴答定時器 */ bsp_InitUart(); /* 初始化串口 */ bsp_InitExtIO(); /* 初始化FMC總線74HC574擴展IO. 必須在 bsp_InitLed()前執行 */ bsp_InitLed(); /* 初始化LED */ bsp_InitI2C(); /* 初始化I2C總線 */ TOUCH_InitHard(); /* 初始化觸摸芯片,LCD面板型號的檢查也在此函數,所以要在函數LCD_InitHard前調用 */ LCD_InitHard(); /* 初始化LCD */ }
主功能:
主程序實現如下操作:
- LCD界面上顯示了漢字和2D圖形。
- 啟動1個200ms的自動重裝定時器,讓LED2每200ms翻轉一次。
- 同時在LCD界面上實現一個簡單計數,每200ms加1,計數到255后繼續從0開始。
/* ********************************************************************************************************* * 函 數 名: main * 功能說明: c程序入口 * 形 參: 無 * 返 回 值: 錯誤代碼(無需處理) ********************************************************************************************************* */ int main(void) { FONT_T tFont12; /* 定義一個字體結構體變量,用於設置字體參數 */ FONT_T tFont16; /* 定義一個字體結構體變量,用於設置字體參數 */ uint8_t buf[100], count = 0; /* 設置字體參數 */ { tFont12.FontCode = FC_ST_12; /* 字體代碼 12點陣 */ tFont12.FrontColor = CL_WHITE; /* 字體顏色 */ tFont12.BackColor = CL_BLUE; /* 文字背景顏色 */ tFont12.Space = 0; /* 文字間距,單位 = 像素 */ } /* 設置字體參數 */ { tFont16.FontCode = FC_ST_16; /* 字體代碼 16點陣 */ tFont16.FrontColor = CL_WHITE; /* 字體顏色 */ tFont16.BackColor = CL_BLUE; /* 文字背景顏色 */ tFont16.Space = 0; /* 文字間距,單位 = 像素 */ } bsp_Init(); /* 硬件初始化 */ PrintfLogo(); /* 打印例程名稱和版本等信息 */ /* 延遲200ms再點亮背光,避免瞬間高亮 */ bsp_DelayMS(200); /* 清屏 */ LCD_ClrScr(CL_BLUE); /* 顯示漢字 */ LCD_DispStr(5, 3, "故人西辭黃鶴樓,煙花三月下揚州。", &tFont12); LCD_DispStr(5, 18, "孤帆遠影碧空盡,唯見長江天際流。", &tFont12); LCD_DispStr(5, 38, "故人西辭黃鶴樓,煙花三月下揚州。", &tFont16); LCD_DispStr(5, 58, "孤帆遠影碧空盡,唯見長江天際流。", &tFont16); /* 繪制2D圖形 */ LCD_DrawLine(5, 120, 100, 220, CL_RED); LCD_DrawRect(120, 120, 100, 100, CL_RED); LCD_DrawCircle(280, 170, 50, CL_RED); LCD_Fill_Rect (340, 120, 100, 100, CL_BUTTON_GREY); /* 界面整體顯示完畢后,再打開背光,設置為缺省亮度 */ bsp_DelayMS(100); LCD_SetBackLight(BRIGHT_DEFAULT); bsp_StartAutoTimer(0, 200); /* 啟動1個200ms的自動重裝的定時器,軟件定時器0 */ while (1) { /* 判斷軟件定時器0是否超時 */ if(bsp_CheckTimer(0)) { /* 每隔200ms 進來一次 */ bsp_LedToggle(2); sprintf((char *)buf, "count = %03d", count++); LCD_DispStr(5, 90, (char *)buf, &tFont16); } } }
41.9 實驗例程說明(IAR)
配套例子:
V7-024_LCD的漢字顯示和2D圖形顯示(小字庫)
實驗目的:
- 學習LCD的小字庫實現和2D圖形顯示。
實驗內容:
- 小字庫通過此軟件生成:
- LCD界面上顯示了漢字和2D圖形。
- 啟動1個200ms的自動重裝定時器,讓LED2每200ms翻轉一次。
- 同時在LCD界面上實現一個簡單計數,每200ms加1,計數到255后繼續從0開始。
上電后串口打印的信息:
波特率 115200,數據位 8,奇偶校驗位無,停止位 1
程序設計:
系統棧大小分配:
硬件外設初始化
硬件外設的初始化是在 bsp.c 文件實現:
/* ********************************************************************************************************* * 函 數 名: bsp_Init * 功能說明: 初始化所有的硬件設備。該函數配置CPU寄存器和外設的寄存器並初始化一些全局變量。只需要調用一次 * 形 參:無 * 返 回 值: 無 ********************************************************************************************************* */ void bsp_Init(void) { /* STM32F429 HAL 庫初始化,此時系統用的還是F429自帶的16MHz,HSI時鍾: - 調用函數HAL_InitTick,初始化滴答時鍾中斷1ms。 - 設置NVIV優先級分組為4。 */ HAL_Init(); /* 配置系統時鍾到168MHz - 切換使用HSE。 - 此函數會更新全局變量SystemCoreClock,並重新配置HAL_InitTick。 */ SystemClock_Config(); /* Event Recorder: - 可用於代碼執行時間測量,MDK5.25及其以上版本才支持,IAR不支持。 - 默認不開啟,如果要使能此選項,務必看V7開發板用戶手冊第8章 */ #if Enable_EventRecorder == 1 /* 初始化EventRecorder並開啟 */ EventRecorderInitialize(EventRecordAll, 1U); EventRecorderStart(); #endif bsp_InitKey(); /* 按鍵初始化,要放在滴答定時器之前,因為按鈕檢測是通過滴答定時器掃描 */ bsp_InitTimer(); /* 初始化滴答定時器 */ bsp_InitUart(); /* 初始化串口 */ bsp_InitExtIO(); /* 初始化FMC總線74HC574擴展IO. 必須在 bsp_InitLed()前執行 */ bsp_InitLed(); /* 初始化LED */ bsp_InitI2C(); /* 初始化I2C總線 */ TOUCH_InitHard(); /* 初始化觸摸芯片,LCD面板型號的檢查也在此函數,所以要在函數LCD_InitHard前調用 */ LCD_InitHard(); /* 初始化LCD */ }
主功能:
主程序實現如下操作:
- LCD界面上顯示了漢字和2D圖形。
- 啟動1個200ms的自動重裝定時器,讓LED2每200ms翻轉一次。
- 同時在LCD界面上實現一個簡單計數,每200ms加1,計數到255后繼續從0開始。
/* ********************************************************************************************************* * 函 數 名: main * 功能說明: c程序入口 * 形 參: 無 * 返 回 值: 錯誤代碼(無需處理) ********************************************************************************************************* */ int main(void) { FONT_T tFont12; /* 定義一個字體結構體變量,用於設置字體參數 */ FONT_T tFont16; /* 定義一個字體結構體變量,用於設置字體參數 */ uint8_t buf[100], count = 0; /* 設置字體參數 */ { tFont12.FontCode = FC_ST_12; /* 字體代碼 12點陣 */ tFont12.FrontColor = CL_WHITE; /* 字體顏色 */ tFont12.BackColor = CL_BLUE; /* 文字背景顏色 */ tFont12.Space = 0; /* 文字間距,單位 = 像素 */ } /* 設置字體參數 */ { tFont16.FontCode = FC_ST_16; /* 字體代碼 16點陣 */ tFont16.FrontColor = CL_WHITE; /* 字體顏色 */ tFont16.BackColor = CL_BLUE; /* 文字背景顏色 */ tFont16.Space = 0; /* 文字間距,單位 = 像素 */ } bsp_Init(); /* 硬件初始化 */ PrintfLogo(); /* 打印例程名稱和版本等信息 */ /* 延遲200ms再點亮背光,避免瞬間高亮 */ bsp_DelayMS(200); /* 清屏 */ LCD_ClrScr(CL_BLUE); /* 顯示漢字 */ LCD_DispStr(5, 3, "故人西辭黃鶴樓,煙花三月下揚州。", &tFont12); LCD_DispStr(5, 18, "孤帆遠影碧空盡,唯見長江天際流。", &tFont12); LCD_DispStr(5, 38, "故人西辭黃鶴樓,煙花三月下揚州。", &tFont16); LCD_DispStr(5, 58, "孤帆遠影碧空盡,唯見長江天際流。", &tFont16); /* 繪制2D圖形 */ LCD_DrawLine(5, 120, 100, 220, CL_RED); LCD_DrawRect(120, 120, 100, 100, CL_RED); LCD_DrawCircle(280, 170, 50, CL_RED); LCD_Fill_Rect (340, 120, 100, 100, CL_BUTTON_GREY); /* 界面整體顯示完畢后,再打開背光,設置為缺省亮度 */ bsp_DelayMS(100); LCD_SetBackLight(BRIGHT_DEFAULT); bsp_StartAutoTimer(0, 200); /* 啟動1個200ms的自動重裝的定時器,軟件定時器0 */ while (1) { /* 判斷軟件定時器0是否超時 */ if(bsp_CheckTimer(0)) { /* 每隔200ms 進來一次 */ bsp_LedToggle(2); sprintf((char *)buf, "count = %03d", count++); LCD_DispStr(5, 90, (char *)buf, &tFont16); } } }
41.10 總結
本章節涉及到的知識點比較多,需要大家花點時間去掌握,直至可以獨立驅動一個顯示屏。