xotr.com.cn-久久99青青精品免费观看,国产精品99久久久精品无码,特级aaaaaaaaa毛片免费视频,最好看的免费观看视频西瓜

歡迎來到廣東TFT屏幕廠家官方網(wǎng)站!
contact us

聯(lián)系我們

廣東TFT屏幕廠家 > 新聞資訊 > ALIENTEK 阿波羅 STM32F767 開發(fā)板資料連載第十八章 TFTLCD實(shí)驗(yàn)

ALIENTEK 阿波羅 STM32F767 開發(fā)板資料連載第十八章 TFTLCD實(shí)驗(yàn)

編輯 :

廣東TFT屏幕

時(shí)間 : 2021-12-22 15:27 瀏覽量 : 48

1)試驗(yàn)服務(wù)平臺:alientek 阿波羅 STM32F767 單片機(jī)開發(fā)板2)節(jié)選自《STM32F7 開發(fā)設(shè)計(jì)指引(HAL 庫版)》關(guān)心官微號微信公眾號,獲得大量材料:正點(diǎn)原子



第十八章 TFTLCD(MCU 屏)試驗(yàn)

在第 16 章大家詳細(xì)介紹了 OLED 模塊以及顯示,可是該模塊只有顯示純色/兩色,不可以顯示彩

色,并且規(guī)格也較小。此章大家將詳細(xì)介紹 ALIENTEK 的 TFT LCD 模塊(MCU 屏),該模塊選用

TFTLCD 控制面板,可以顯示 16 位色的真彩照片。在這章中,大家將應(yīng)用阿波羅 STM32F767 開發(fā)設(shè)計(jì)

板底版上的 TFTLCD 插口(僅適用 MCU 屏,此章僅詳細(xì)介紹 MCU 屏的應(yīng)用),來照亮 TFTLCD,

并完成 ASCII 標(biāo)識符和彩色的顯示等作用,并在串口通信打印出 LCD 控制板 ID,與此同時(shí)在 LCD 上邊顯示。

此章分成如下所示一些一部分:

18.1 TFTLCD&FMC 介紹

18.2 硬件開發(fā)

18.3 軟件開發(fā)

18.4 在線下載認(rèn)證

18.5 STM32CubeMX 配備 FMC(SRAM)

18.1 TFTLCD&FMC 介紹

此章大家將根據(jù) STM32F767的 FMC 插口來操縱TFTLCD 的顯示,因此這節(jié)分成2個一部分,

各自詳細(xì)介紹 TFTLCD 和 FMC。

18.1.1 TFTLCD 介紹

TFT-LCD 即塑料薄膜晶體三極管液晶顯示器。其英語全稱之為:Thin Film Transistor-Liquid Crystal

Display。TFT-LCD 與微波感應(yīng)器 TN-LCD、STN-LCD 的簡易引流矩陣不一樣,它在液晶顯示屏的每一個象

素上面設(shè)定有一個塑料薄膜晶體三極管(TFT),可合理地?cái)[脫非選通時(shí)的串?dāng)_,使顯示液晶顯示屏的靜態(tài)數(shù)據(jù)特

性與掃描線數(shù)不相干,因而進(jìn)一步提高了圖象品質(zhì)。TFT-LCD 也被稱為真彩液晶顯示器。

上一章詳細(xì)介紹了 OLED 模塊,此章,大家給各位詳細(xì)介紹 ALIENTEK TFTLCD 模塊(MCU 插口),

該模塊有以下特性:

1,2.8’/3.5’/4.3’/7’等 4 種尺寸的顯示屏可選。

2,320×240 的屏幕分辨率(3.5’屏幕分辨率為:320*480,4.3’和 7’屏幕分辨率為:800*480)。

3,16 位真彩顯示。

4,內(nèi)置觸摸顯示屏,可以拿來做為操縱鍵入。

此章,大家以 2.8 寸(別的 3.5 寸/4.3 寸等 LCD 方式相近,請參照 2.8 的就可以)的 ALIENTEK

TFTLCD 模塊為例子詳細(xì)介紹,該模塊適用 65K 色顯示,顯示屏幕分辨率為 320×240,插口為 16 位的 80

并口,內(nèi)置觸摸顯示屏。

該模塊的外型圖如下圖 18.1.1.1 所顯示

圖 18.1.1.1 ALIENTEK 2.8 寸 TFTLCD 外型圖


模塊電路原理圖如下圖 18.1.1.2 所顯示:

圖 18.1.1.2 ALIENTEK 2.8 寸 TFTLCD 模塊電路原理圖


TFTLCD 模塊選用 2*17 的 2.54 公排針與外界聯(lián)接,接口定義如下圖 18.1.1.3 所顯示:

圖 18.1.1.3 ALIENTEK 2.8 寸 TFTLCD 模塊插口圖


從圖 18.1.1.3 可以看得出,ALIENTEK TFTLCD 模塊選用 16 位的并方法與外界聯(lián)接,往往

不選用 8 位的方法,是由于顯示屏的信息量較為大,特別是在在顯示照片的情況下,假如用 8 位手機(jī)充電線,

便會比 16 位方法慢一倍以上,大家自然期待速率越是快就越好,因此大家挑選 16 位的插口。圖

18.1.1.3 還列舉了觸摸顯示屏集成ic的插口,有關(guān)觸摸顯示屏此章大家很少詳細(xì)介紹,后邊的章節(jié)目錄會出現(xiàn)詳盡的介

紹。該模塊的 80 并口有以下一些電源線:

CS:TFTLCD 片選數(shù)據(jù)信號。

WR:向 TFTLCD 載入數(shù)據(jù)信息。

RD:從 TFTLCD 接收數(shù)據(jù)。

D[15:0]:16 位雙重手機(jī)充電線。

RST:硬校準(zhǔn) TFTLCD。

RS:指令/數(shù)據(jù)信息標(biāo)示(0,讀寫能力指令;1,讀寫能力數(shù)據(jù)信息)。

80 并口在上一節(jié)大家早已有完整的講解了,這兒大家就不會再詳細(xì)介紹,必須表明的是,TFTLCD

模塊的 RST 電源線是立即收到 STM32F767 的校準(zhǔn)腳底,并不由自主APP操縱,那樣可以省出來一

個 IO 口。此外大家還要一個led背光控線來操縱 TFTLCD 的led背光。因此,大家一共必須的 IO

口數(shù)額為 21 個。這兒還要留意,大家標(biāo)明的 DB1~DB8,DB10~DB17,是相比于 LCD 操縱

IC 標(biāo)明的,事實(shí)上大伙兒可以把她們就相當(dāng)于 D0~D15,那樣解釋起來就相對簡單一點(diǎn)。

ALIENTEK給予 2.8/3.5/4.3/7 寸等 4種不一樣規(guī)格和分辯率的TFTLCD 模塊,其推動集成ic為:

ILI9341/NT35310/NT35510/SSD1963 等(實(shí)際的型號規(guī)格,大伙兒可以根據(jù)在線下載此章試驗(yàn)編碼,根據(jù)串

口或是 LCD 顯示查詢),這兒大家僅以 ILI9341 控制板為例子開展詳細(xì)介紹,別的的操縱基本上都相近,

大家也不詳盡論述了。

ILI9341 液晶控制板內(nèi)置獨(dú)顯存儲,其獨(dú)顯存儲總尺寸為 172800(240*320*18/8),即 18 位方式(26

萬色)下的顯總量。在 16 位方式下,ILI9341 選用 RGB565 文件格式儲存色調(diào)數(shù)據(jù)信息,這時(shí) ILI9341

的 18 位手機(jī)充電線與 MCU 的 16 位手機(jī)充電線及其 LCD GRAM 的對應(yīng)關(guān)系如下圖 18.1.1.4 所顯示:

圖 18.1.1.4 16 位數(shù)據(jù)信息與獨(dú)顯存儲對應(yīng)關(guān)系圖

從圖內(nèi)可以看得出,ILI9341 在 16 位方式下邊,手機(jī)充電線有效的是:D17~D13 和 D11~D1,D0

和 D12 沒有使用,事實(shí)上在大家 LCD 模塊里邊,ILI9341 的 D0 和 D12 根本就沒有引過來,這

樣,ILI9341 的 D17~D13 和 D11~D1 相匹配 MCU 的 D15~D0。

那樣 MCU 的 16 位數(shù)據(jù)信息,最少 5 位意味著深藍(lán)色,正中間 6 位為翠綠色,最大 5 位為鮮紅色。標(biāo)值越

大,表明該色調(diào)越重。此外,需注意 ILI9341 全部的命令全是 8 位的(高 8 位失效),且主要參數(shù)

除開讀寫能力 GRAM 的那時(shí)候是 16 位,別的實(shí)際操作主要參數(shù),全是 8 位的。

下面,大家介紹一下 ILI9341 的一些關(guān)鍵指令,由于 ILI9341 的指令許多,大家這兒就

不所有詳細(xì)介紹了,有感興趣的各位可以尋找 ILI9341 的 datasheet 看一下。里邊對這種指令有完整的介

紹。大家將詳細(xì)介紹:0XD3,0X36,0X2A,0X2B,0X2C,0X2E 等 6 條命令。

最先看來命令:0XD3,這個是讀 ID4 命令,用以載入 LCD 控制板的 ID,該命令如表 18.1.1.1

所顯示:

表 18.1.1.1 0XD3 命令敘述


從以上可以看得出,0XD3 命令后邊跟了 4 個主要參數(shù),最終 2 個主要參數(shù),讀出是 0X93 和 0X41,

恰好是大家控制板 ILI9341 的小數(shù)一部分,進(jìn)而,根據(jù)該命令,就可以辨別常用的 LCD 控制器是什

么型號規(guī)格,那樣,大家的編碼,就可以依據(jù)控制板的型號規(guī)格去實(shí)行相匹配推動 IC 的復(fù)位編碼,進(jìn)而

兼容不一樣推動 IC 的屏,促使一個編碼適用幾款 LCD。

下面看命令:0X36,這也是儲存瀏覽程序控制,可以操縱 ILI9341 儲存器的讀寫能力方位,簡

單的說,便是在持續(xù)寫 GRAM 的情況下,可以操縱 GRAM 表針的提高方位,進(jìn)而操縱顯示方法

(讀 GRAM 也是一樣)。該命令如表 18.1.1.2 所顯示:

表 18.1.1.2 0X36 命令敘述


從以上可以看得出,0X36 命令后邊,緊隨一個主要參數(shù),這兒大家關(guān)鍵關(guān)心:MY、MX、MV

這三個位,根據(jù)這三個位的設(shè)定,我們可以操縱全部 ILI9341 的所有掃描儀方位,如表 18.1.1.3

所顯示:



表 18.1.1.3 MY、MX、MV 設(shè)定與 LCD 掃描儀方位關(guān)系表


那樣,我們在運(yùn)用 ILI9341 顯示內(nèi)容的情況下,就會有非常大靈敏性了,例如顯示 BMP 照片,

BMP 編解碼數(shù)據(jù)信息,就是以照片的左下方逐漸,漸漸地顯示到右上方,假如設(shè)定 LCD 掃描儀方位為從

左到右,從下向上,那麼大家只必須設(shè)定一次座標(biāo),隨后就不斷的往 LCD 填充顏色數(shù)據(jù)信息就可以,

那樣可以進(jìn)一步提高顯示速率。

下面看命令:0X2A,這也是列詳細(xì)地址設(shè)定命令,在從左往右,自上而下的掃描儀方法(默認(rèn)設(shè)置)

下邊,該命令用以設(shè)定橫坐標(biāo)軸(x 座標(biāo)),該命令如表 18.1.1.4 所顯示:

表 18.1.1.4 0X2A 命令敘述

在默認(rèn)設(shè)置掃描儀方法時(shí),該命令用以設(shè)定 x 座標(biāo),該命令含有 4 個主要參數(shù),事實(shí)上是 2 個平面坐標(biāo):

SC 和 EC,即列詳細(xì)地址的起始值和完畢值,SC 務(wù)必不大于 EC,且 0≤SC/EC≤239。一般在設(shè)

置 x 座標(biāo)的情況下,大家只必須帶 2 個主要參數(shù)就可以,也就是設(shè)定 SC 就可以,由于假如 EC 沒有轉(zhuǎn)變,

大家只必須設(shè)定一次就可以(在復(fù)位 ILI9341 的過程中設(shè)定),進(jìn)而提高速度。

與 0X2A 命令相近,命令:0X2B,是頁詳細(xì)地址設(shè)定命令,在從左往右,自上而下的掃描儀方法

(默認(rèn)設(shè)置)下邊,該命令用以設(shè)定縱軸(y 座標(biāo))。該命令如表 18.1.1.5 所顯示:

表 18.1.1.5 0X2B 命令敘述


在默認(rèn)設(shè)置掃描儀方法時(shí),該命令用以設(shè)定 y 座標(biāo),該命令含有 4 個主要參數(shù),事實(shí)上是 2 個平面坐標(biāo):

SP 和 EP,即頁詳細(xì)地址的起始值和完畢值,SP 務(wù)必不大于 EP,且 0≤SP/EP≤319。一般在設(shè)定

y 座標(biāo)的情況下,大家只必須帶 2 個主要參數(shù)就可以,也就是設(shè)定 SP 就可以,由于假如 EP 沒有轉(zhuǎn)變,我

們只必須設(shè)定一次就可以(在復(fù)位 ILI9341 的過程中設(shè)定),進(jìn)而提高速度。

下面看命令:0X2C,該命令是寫 GRAM 命令,在推送該命令以后,大家便可以往 LCD

的 GRAM 里邊載入色調(diào)數(shù)據(jù)信息了,該命令適用持續(xù)寫,命令敘述如表 18.1.1.6 所顯示:


表 18.1.1.6 0X2C 命令敘述



從以上得知,在接到命令 0X2C 以后,數(shù)據(jù)信息合理位寬變成 16 位,我們可以持續(xù)載入 LCD

GRAM 值,而 GRAM 的詳細(xì)地址將依據(jù) MY/MX/MV 設(shè)定的掃描儀方位開展自增。比如:假定設(shè)定

的是從左往右,自上而下的掃描儀方法,那麼設(shè)定好起止座標(biāo)(根據(jù) SC,SP 設(shè)定)后,每載入

一個顏色值,GRAM 詳細(xì)地址可能全自動自增 1(SC  ),假如遇到 EC,則返回 SC,與此同時(shí) SP  ,一

直到座標(biāo):EC,EP 完畢,期間不用再度設(shè)定的座標(biāo),進(jìn)而進(jìn)一步提高載入速率。

最終,一起來看看命令:0X2E,該命令是讀 GRAM 命令,用以載入 ILI9341 的獨(dú)顯存儲(GRAM),

該命令在 ILI9341 的數(shù)據(jù)信息指南上邊的敘述是不正確的,真正的導(dǎo)出狀況如表 18.1.1.7 所顯示:


表 18.1.1.7 0X2E 命令敘述


該命令用以載入 GRAM,如表 18.1.1.7 所顯示,ILI9341 在得到該命令后,第一次導(dǎo)出的是

dummy 數(shù)據(jù)信息,也就是失效的數(shù)據(jù)信息,第二次逐漸,載入到的才算是合理的 GRAM 數(shù)據(jù)信息(從座標(biāo):

SC,SP 逐漸),導(dǎo)出規(guī)律性為:每一個色調(diào)份量占 8 個位數(shù),一次導(dǎo)出 2 個色調(diào)份量。例如:第一次

導(dǎo)出是 R1G1,接著的規(guī)律性為:B1R2?G2B2?R3G3?B3R4?G4B4?R5G5... 依此類推。假如

大家只必須載入一個點(diǎn)的顏色值,那麼只必須接受到主要參數(shù) 3 就可以,假如要持續(xù)載入(運(yùn)用 GRAM

詳細(xì)地址自增,方式跟上面一樣),那麼就依照以上規(guī)律性去接受色調(diào)數(shù)據(jù)信息。

以上,便是實(shí)際操作 ILI9341 常見的好多個命令,根據(jù)這好多個命令,大家便可以不錯的操縱 ILI9341

顯示大家所要顯示的內(nèi)容了。

一般 TFTLCD 模塊的應(yīng)用步驟如下圖 18.1.1.5:

圖 18.1.1.5 TFTLCD 應(yīng)用步驟


一切 LCD,應(yīng)用步驟都能夠簡易的用以上流程表表明。在其中硬校準(zhǔn)和復(fù)位編碼序列,只必須

實(shí)行一次就可以。而畫點(diǎn)步驟便是:設(shè)定座標(biāo)?寫 GRAM 命令?載入色調(diào)數(shù)據(jù)信息,隨后在 LCD 上

面,大家就可以見到相應(yīng)的點(diǎn)顯示大家載入的色調(diào)了。讀點(diǎn)步驟為:設(shè)定座標(biāo)?讀 GRAM 命令

?載入色調(diào)數(shù)據(jù)信息,那樣就可以獲得到對應(yīng)的點(diǎn)的色調(diào)數(shù)據(jù)信息了。

以上僅僅非常簡單的實(shí)際操作,也是最常見的實(shí)際操作,擁有這種實(shí)際操作,一般就可以正常的應(yīng)用 TFTLCD

了。下面人們將該模塊用于來顯示標(biāo)識符和數(shù)據(jù),根據(jù)以上詳細(xì)介紹,我們可以得到 TFTLCD 顯示

必須的有關(guān)設(shè)定流程如下所示:

1)設(shè)定 STM32F767 與 TFTLCD 模塊相連接的 IO。

這一步,先將我們與 TFTLCD 模塊相連的 IO 口進(jìn)行初始化,以便驅(qū)動 LCD。這里我們用

到的是 FMC,F(xiàn)MC 將在 18.1.2 節(jié)向大家詳細(xì)介紹。

2)初始化 TFTLCD 模塊。

即圖 18.1.1.5 的初始化序列,這里我們沒有硬復(fù)位 LCD,因?yàn)榘⒉_ STM32F767 開發(fā)板

的 LCD 接口,將 TFTLCD 的 RST 同 STM32F767 的 RESET 連接在一起了,只要按下開發(fā)板的

RESET 鍵,就會對 LCD 進(jìn)行硬復(fù)位。初始化序列,就是向 LCD 控制器寫入一系列的設(shè)置值(比

如伽馬校準(zhǔn)),這些初始化序列一般 LCD 供應(yīng)商會提供給客戶,我們直接使用這些序列即可,

不需要深入研究。在初始化之后,LCD 才可以正常使用。

3)通過函數(shù)將字符和數(shù)字顯示到 TFTLCD 模塊上。

這一步則通過圖 18.1.1.5 左側(cè)的流程,即:設(shè)置坐標(biāo)?寫 GRAM 指令?寫 GRAM 來實(shí)現(xiàn),

但是這個步驟,只是一個點(diǎn)的處理,我們要顯示字符/數(shù)字,就必須要多次使用這個步驟,從而

達(dá)到顯示字符/數(shù)字的目的,所以需要設(shè)計(jì)一個函數(shù)來實(shí)現(xiàn)數(shù)字/字符的顯示,之后調(diào)用該函數(shù),

就可以實(shí)現(xiàn)數(shù)字/字符的顯示了。

STM32F767xx 系列芯片都帶有 FMC 接口,即可變存儲存儲控制器,能夠與同步或異步存

儲器、SDRAM 存儲器和 NAND FLASH 等連接,STM32F767 的 FMC 接口支持包括 SRAM、

SDRAM、NAND FLASH、NOR FLASH 和 PSRAM 等存儲器。FMC 的框圖如圖 18.1.2.1 所示:

圖 18.1.2.1 FMC 框圖


從上圖我們可以看出,STM32F767 的 FMC 將外部設(shè)備分為 3 類:NOR/PSRAM 設(shè)備、NAND

設(shè)備和 SDRAM 設(shè)備。他們共用地址數(shù)據(jù)總線等信號,他們具有不同的 CS 以區(qū)分不同的設(shè)備,

比如本章我們用到的 TFTLCD 就是用的 FMC_NE1 做片選,其實(shí)就是將 TFTLCD 當(dāng)成 SRAM

來控制。

這里我們介紹下為什么可以把 TFTLCD 當(dāng)成 SRAM 設(shè)備用:首先我們了解下外部 SRAM

的連接,外部 SRAM 的控制一般有:地址線(如 A0~A18)、數(shù)據(jù)線(如 D0~D15)、寫信號(WE)、

讀信號(OE)、片選信號(CS),如果 SRAM 支持字節(jié)控制,那么還有 UB/LB 信號。而 TFTLCD

的信號我們在 18.1.1 節(jié)有介紹,包括:RS、D0~D15、WR、RD、CS、RST 和 BL 等,其中真

正在操作 LCD 的時(shí)候需要用到的就只有:RS、D0~D15、WR、RD 和 CS。其操作時(shí)序和 SRAM

的控制完全類似,唯一不同就是 TFTLCD 有 RS 信號,但是沒有地址信號。

TFTLCD 通過 RS 信號來決定傳送的數(shù)據(jù)是數(shù)據(jù)還是命令,本質(zhì)上可以理解為一個地址信

號,比如我們把 RS 接在 A0 上面,那么當(dāng) FMC 控制器寫地址 0 的時(shí)候,會使得 A0 變?yōu)?0,

對 TFTLCD 來說,就是寫命令。而 FMC 寫地址 1 的時(shí)候,A0 將會變?yōu)?1,對 TFTLCD 來說,

就是寫數(shù)據(jù)了。這樣,就把數(shù)據(jù)和命令區(qū)分開了,他們其實(shí)就是對應(yīng) SRAM 操作的兩個連續(xù)地

址。當(dāng)然 RS 也可以接在其他地址線上,阿波羅 STM32F767 開發(fā)板是把 RS 連接在 A18 上面的。

STM32F767 的 FMC 支持 8/16/32 位數(shù)據(jù)寬度,我們這里用到的 LCD 是 16 位寬度的,所

以在設(shè)置的時(shí)候,選擇 16 位寬就 OK 了。我們再來看看 FMC 的外部設(shè)備地址映像,STM32F767

的 FMC 將外部存儲器劃分為 6 個固定大小為 256M 字節(jié)的存儲區(qū)域,如圖 18.1.2.2 所示:

圖 18.1.2.2 FMC 存儲塊地址映像


從上圖可以看出,F(xiàn)MC 總共管理 1.5GB 空間,擁有 6 個存儲塊(Bank),本章,我們用到

的是塊 1,所以在本章我們僅討論塊 1 的相關(guān)配置,其他塊的配置,請參考《STM32F7 中文參

考手冊》第 13 章(286 頁)的相關(guān)介紹。

STM32F767 的 FMC 存儲塊 1(Bank1)被分為 4 個區(qū),每個區(qū)管理  ** M 字節(jié)空間,每個

區(qū)都有獨(dú)立的寄存器對所連接的存儲器進(jìn)行配置。Bank1 的 256M 字節(jié)空間由 28 根地址線

(HADDR[27:0])尋址。

這里 HADDR 是內(nèi)部AHB地址總線,其中HADDR[25:0]來自外部存儲器地址 FMC_A[25:0],

而 HADDR[26:27]對 4 個區(qū)進(jìn)行尋址。如表 18.1.2.1 所示:

表 18.1.2.1 Bank1 存儲區(qū)選擇表

HADDR[25:0]位包含外部存儲器的地址,由于 HADDR 為字節(jié)地址,而存儲器按字尋址,

所以,根據(jù)存儲器數(shù)據(jù)寬度的不同,實(shí)際上向存儲器發(fā)送的地址也有所不同,如表 18.1.2.2 所

示:

表 18.1.2.2 NOR/PSRAM 外部存儲器地址


因此,F(xiàn)MC 內(nèi)部 HADDR 與存儲器尋址地址的實(shí)際對應(yīng)關(guān)系就是:

當(dāng)接的是 32 位寬度存儲器的時(shí)候:HADDR[25:2]? FMC_A [23:0]。

當(dāng)接的是 16 位寬度存儲器的時(shí)候:HADDR[25:1]? FMC_A [24:0]。

當(dāng)接的是 8 位寬度存儲器的時(shí)候:HADDR[25:0]? FMC_A [25:0]。

不論外部接 8 位/16 位/32 位寬設(shè)備,F(xiàn)MC_A[0]永遠(yuǎn)接在外部設(shè)備地址 A[0]。 這里,

TFTLCD 使用的是 16 位數(shù)據(jù)寬度,所以 HADDR[0]并沒有用到,只有 HADDR[25:1]是有效的,

對應(yīng)關(guān)系變?yōu)椋篐ADDR[25:1]? FMC_A[24:0],相當(dāng)于右移了一位,這里請大家特別留意。另

外,HADDR[27:26]的設(shè)置,是不需要我們干預(yù)的,比如:當(dāng)你選擇使用 Bank1 的第一個區(qū),

即使用 FMC_NE1 來連接外部設(shè)備的時(shí)候,即對應(yīng)了 HADDR[27:26]=00,我們要做的就是配置

對應(yīng)第 1 區(qū)的寄存器組,來適應(yīng)外部設(shè)備即可。STM32F767 的 FMC 各 Bank 配置寄存器如表

18.1.2.3 所示:

表 18.1.2.3 FMC 各 Bank 配置寄存器表


對于 NOR FLASH 控制器,主要是通過 FMC_BCRx、FMC_BTRx 和 FMC_BWTRx 寄存器

設(shè)置(其中 x=1~4,對應(yīng) 4 個區(qū))。通過這 3 個寄存器,可以設(shè)置 FMC 訪問外部存儲器的時(shí)序

參數(shù),拓寬了可選用的外部存儲器的速度范圍。FMC 的 NOR FLASH 控制器支持同步和異步突

發(fā)兩種訪問方式。選用同步突發(fā)訪問方式時(shí),F(xiàn)MC 將 HCLK(系統(tǒng)時(shí)鐘)分頻后,發(fā)送給外部存

儲器作為同步時(shí)鐘信號 FMC_CLK。此時(shí)需要的設(shè)置的時(shí)間參數(shù)有 2 個:

1,HCLK 與 FMC_CLK 的分頻系數(shù)(CLKDIV),可以為 2~16 分頻;

2,同步突發(fā)訪問中獲得第 1 個數(shù)據(jù)所需要的等待延遲(DATLAT)。

對于異步突發(fā)訪問方式,F(xiàn)MC 主要設(shè)置 3 個時(shí)間參數(shù):地址建立時(shí)間(ADDSET)、數(shù)據(jù)建

立時(shí)間(DATAST)和地址保持時(shí)間(ADDHLD)。FMC 綜合了 SRAM、PSRAM 和 NOR Flash 產(chǎn)品

的信號特點(diǎn),定義了 4 種不同的異步時(shí)序模型。選用不同的時(shí)序模型時(shí),需要設(shè)置不同的時(shí)序

參數(shù),如表 18.1.2.4 所列:

表 18.1.2.4 NOR FLASH/PSRAM 控制器支持的時(shí)序模型


在實(shí)際擴(kuò)展時(shí),根據(jù)選用存儲器的特征確定時(shí)序模型,從而確定各時(shí)間參數(shù)與存儲器讀/

寫周期參數(shù)指標(biāo)之間的計(jì)算關(guān)系;利用該計(jì)算關(guān)系和存儲芯片數(shù)據(jù)手冊中給定的參數(shù)指標(biāo),可

計(jì)算出 FMC 所需要的各時(shí)間參數(shù),從而對時(shí)間參數(shù)寄存器進(jìn)行合理的配置。

本章,我們使用異步模式 A(ModeA)方式來控制 TFTLCD,模式 A 的讀操作時(shí)序如圖

18.1.2.3 所示:

圖 18.1.2.3 模式 A 讀操作時(shí)序圖


模式 A 支持獨(dú)立的讀寫時(shí)序控制,這個對我們驅(qū)動 TFTLCD 來說非常有用,因?yàn)?TFTLCD

在讀的時(shí)候,一般比較慢,而在寫的時(shí)候可以比較快,如果讀寫用一樣的時(shí)序,那么只能以讀

的時(shí)序?yàn)榛鶞?zhǔn),從而導(dǎo)致寫的速度變慢,或者在讀數(shù)據(jù)的時(shí)候,重新配置 FMC 的延時(shí),在讀

操作完成的時(shí)候,再配置回寫的時(shí)序,這樣雖然也不會降低寫的速度,但是頻繁配置,比較麻

煩。而如果有獨(dú)立的讀寫時(shí)序控制,那么我們只要初始化的時(shí)候配置好,之后就不用再配置,

既可以滿足速度要求,又不需要頻繁改配置。

模式 A 的寫操作時(shí)序如圖 18.1.2.4 所示:


圖 18.1.2.4 模式 A 寫操作時(shí)序

圖 18.1.2.3 和圖 18.1.2.4 中的 ADDSET 與 DATAST,是通過不同的寄存器設(shè)置的,接下來

我們講解一下 Bank1 的幾個控制寄存器

首先,我們介紹 SRAM/NOR 閃存片選控制寄存器:FMC_BCRx(x=1~4),該寄存器各位

描述如圖 18.1.2.5 所示:

圖 18.1.2.5 FMC_BCRx 寄存器各位描述


該寄存器我們在本章用到的設(shè)置有:EXTMOD、WREN、MWID、MTYP 和 MBKEN 這幾

個設(shè)置,我們將逐個介紹。

EXTMOD:擴(kuò)展模式使能位,也就是是否允許讀寫不同的時(shí)序,很明顯,我們本章需要讀

寫不同的時(shí)序,故該位需要設(shè)置為 1。

WREN:寫使能位。我們需要向 TFTLCD 寫數(shù)據(jù),故該位必須設(shè)置為 1。

MWID[1:0]:存儲器數(shù)據(jù)總線寬度。00,表示 8 位數(shù)據(jù)模式;01 表示 16 位數(shù)據(jù)模式;10

表示 32 位數(shù)據(jù)模式;11 保留。我們的 TFTLCD 是 16 位數(shù)據(jù)線,所以設(shè)置 WMID[1:0]=01。

MTYP[1:0]:存儲器類型。00 表示 SRAM;01 表示 PSRAM;10 表示 NOR FLASH/OneNAND

FLASH;11 保留。前面提到,我們把 TFTLCD 當(dāng)成 SRAM 用,所以需要設(shè)置 MTYP[1:0]=00。

MBKEN:存儲塊使能位。這個容易理解,我們需要用到該存儲塊控制 TFTLCD,當(dāng)然要

使能這個存儲塊了。

接下來,我們看看 SRAM/NOR 閃存片選時(shí)序寄存器:FMC_BTRx(x=1~4),該寄存器各

位描述如圖 18.1.2.6 所示:

圖 18.1.2.6 FMC_BTRx 寄存器各位描述


這個寄存器包含了每個存儲器塊的控制信息,可以用于 SRAM 和 NOR 閃存存儲器等。如

果 FMC_BCRx 寄存器中設(shè)置了 EXTMOD 位,則有兩個時(shí)序寄存器分別對應(yīng)讀(本寄存器)和寫

操作(FMC_BWTRx 寄存器)。因?yàn)槲覀円笞x寫分開時(shí)序控制,所以 EXTMOD 是使能了的,

也就是本寄存器是讀操作時(shí)序寄存器,控制讀操作的相關(guān)時(shí)序。本章我們要用到的設(shè)置有:

ACCMOD、DATAST 和 ADDSET 這三個設(shè)置。

ACCMOD[1:0]:訪問模式。00 表示訪問模式 A;01 表示訪問模式 B;10 表示訪問模式 C;

11 表示訪問模式 D,本章我們用到模式 A,故設(shè)置為 00。

DATAST[7:0]:數(shù)據(jù)保持時(shí)間。0 為保留設(shè)置,其他設(shè)置則代表保持時(shí)間為: DATAST 個

HCLK 時(shí)鐘周期,最大為 255 個 HCLK 周期。對 ILI9341 來說,其實(shí)就是 RD 低電平持續(xù)時(shí)間,

一般為 355ns。而一個 HCLK 時(shí)鐘周期為 4.6ns 左右(1/216Mhz),為了兼容其他屏,我們這里

設(shè)置 DATAST 為 80,也就是 80 個 HCLK 周期,時(shí)間大約是 368ns。

ADDSET[3:0]:地址建立時(shí)間。其建立時(shí)間為:ADDSET 個 HCLK 周期,最大為 15 個 HCLK

周期。對 ILI9341 來說,這里相當(dāng)于 RD 高電平持續(xù)時(shí)間,為 90ns,我們設(shè)置 ADDSET 為最大

15,即 15*4.6=69ns(略超)。

最后,我們再來看看 SRAM/NOR 閃寫時(shí)序寄存器:FMC_BWTRx(x=1~4),該寄存器各

位描述如圖 18.1.2.7 所示:

圖 18.1.2.7 FMC_BWTRx 寄存器各位描述


該寄存器在本章用作寫操作時(shí)序控制寄存器,需要用到的設(shè)置同樣是:ACCMOD、DATAST

和 ADDSET 這三個設(shè)置。這三個設(shè)置的方法同 FMC_BTRx 一模一樣,只是這里對應(yīng)的是寫操

作的時(shí)序,ACCMOD 設(shè)置同 FMC_BTRx 一模一樣,同樣是選擇模式 A,另外 DATAST 和

ADDSET 則對應(yīng)低電平和高電平持續(xù)時(shí)間,對 ILI9341 來說,這兩個時(shí)間只需要 15ns 就夠了,

比讀操作快得多。所以我們這里設(shè)置 DATAST 為 4,即 4 個 HCLK 周期,時(shí)間約為 18.4ns。然

后 ADDSET 設(shè)置為 4,即 4 個 HCLK 周期,時(shí)間為 18.4ns。

至此,我們對 STM32F767 的 FMC 介紹就差不多了,關(guān)于 FMC 的詳細(xì)介紹,請大家參考

《STM32F7 中文參考手冊》第 13 章。通過以上兩個小節(jié)的了解,我們可以開始寫 LCD 的驅(qū)動

代碼了。不過,這里還要給大家做下科普,在 MDK 的寄存器定義里面,并沒有定義 FMC_BCRx、

FMC_BTRx、FMC_BWTRx 等這個單獨(dú)的寄存器,而是將他們進(jìn)行了一些組合。

FMC_BCRx 和 FMC_BTRx,組合成 BTCR[8]寄存器組,他們的對應(yīng)關(guān)系如下:

BTCR[0]對應(yīng) FMC_BCR1,BTCR[1]對應(yīng) FMC_BTR1

BTCR[2]對應(yīng) FMC_BCR2,BTCR[3]對應(yīng) FMC_BTR2

BTCR[4]對應(yīng) FMC_BCR3,BTCR[5]對應(yīng) FMC_BTR3

BTCR[6]對應(yīng) FMC_BCR4,BTCR[7]對應(yīng) FMC_BTR4

FMC_BWTRx 則組合成 BWTR[7],他們的對應(yīng)關(guān)系如下:

BWTR[0]對應(yīng) FMC_BWTR1,BWTR[2]對應(yīng) FMC_BWTR2,

BWTR[4]對應(yīng) FMC_BWTR3,BWTR[6]對應(yīng) FMC_BWTR4,

BWTR[1]、BWTR[3]和 BWTR[5]保留,沒有用到。

通過上面的講解,通過對 FSC 相關(guān)的寄存器的描述,大家對 FMC 的原理有了一個初步的

認(rèn)識,如果還不熟悉的朋友,請一定要搜索網(wǎng)絡(luò)資料理解 FMC 的原理。只有理解了原理,使

用庫函數(shù)才可以得心應(yīng)手。那么在庫函數(shù)中是怎么實(shí)現(xiàn) FMC 的配置的呢?FMC_BCRx,

FMC_BTRx 寄存器在庫函數(shù)是通過什么函數(shù)來配置的呢?下面我們來講解一下使用 FMC 接口

驅(qū)動 LCD(SRAM)相關(guān)的庫函數(shù)操作過程。與 SRAM 和 FMC 相關(guān)的庫函數(shù)定義和聲明在源

文件 stm32f7xx_hal_fmc.c/stm32f7xx_hal_sram.c 以及頭文件

stm32f7xx_hal_fmc.h/stm32f7xx_hal_sram.h 中。

1) 使能 FMC 和 GPIO 時(shí)鐘,初始化 IO 口配置,設(shè)置映射關(guān)系

這個步驟在前面實(shí)驗(yàn)已多次講解。這里我們主要列出 FMC 時(shí)鐘使能方法:

__HAL_RCC_FMC_CLK_ENABLE ();

//使能 FMC 時(shí)鐘

對于 IO 配置,調(diào)用函數(shù) HAL_GPIO_Init 配置即可,具體 請參考實(shí)驗(yàn)源碼。

2) 初始化 FMC 接口讀寫時(shí)序參數(shù),初始化 LCD(SRAM)控制接口

根據(jù)前面的講解,我們把 LCD 當(dāng) SRAM 使用,連接在 FMC 接口之上,所以我們要初始化

FMC 讀寫時(shí)序參數(shù)以及 LCD 數(shù)據(jù)接口,也就是初始化三個寄存器 FMC_BCRx,F(xiàn)MC_BTRx

和 FMC_BWTRx。HAL 庫提供了 SRAM 初始化函數(shù) HAL_SRAM_Init,該函數(shù)聲明如下:

HAL_StatusTypeDef HAL_SRAM_Init(SRAM_HandleTypeDef *hsram,

FMC_NORSRAM_TimingTypeDef *Timing,

FMC_NORSRAM_TimingTypeDef *ExtTiming);

該函數(shù)有三個入口參數(shù),首先我們來看看第一個入口參數(shù) hsram,它是

SRAM_HandleTypeDef 結(jié)構(gòu)體指針類型,該參數(shù)用來初始化當(dāng) FMC 接口當(dāng) SRAM 使用時(shí)的控

制接口參數(shù)。結(jié)構(gòu)體 SRAM_HandleTypeDef 定義如下:

typedef struct

{

FMC_NORSRAM_TypeDef

*Instance;

FMC_NORSRAM_EXTENDED_TypeDef

*Extended;

FMC_NORSRAM_InitTypeDef

Init;

HAL_LockTypeDef

Lock;

__IO HAL_SRAM_StateTypeDef

State;

DMA_HandleTypeDef

*hd ** ;

}SRAM_HandleTypeDef;

成員變量 Instance 和成員變量 Extended 實(shí)際上是用來在指定的時(shí)序模型下,寄存器基地址

和擴(kuò)展模式寄存器基地址。這個怎么理解呢,本實(shí)驗(yàn)我們使用異步模式 A(ModeA)方式來控

制 TFTLCD,使用的存儲塊是 Bank1,所以寄存器基地址 Instance 我們直接寫 FMC_Bank1 即可,

當(dāng)然,HAL 庫定義好了宏定義 FMC_NORSRAM_DEVICE,也就是如果是 SRAM 設(shè)備,直接

填寫這個宏定義標(biāo)識符即可。因?yàn)槲覀円渲玫淖x寫時(shí)序是不一樣的,也就是我們前面講解的

FMC_BCRx 寄存器的 EXTMOD 位我們會配置為 1 允許讀寫不同的時(shí)序,所以我們這里還要指

定寫操作時(shí)序寄存器地址,也就是通過參數(shù) Extended 來指定的,這里我們設(shè)置為 FMC_Bank1E

即可,同樣 MDK 定義好了宏定義標(biāo)識符 FMC_NORSRAM_EXTENDED_DEVICE,所以這里

我們填寫這個宏定義標(biāo)識符也是一樣的。對于寫時(shí)序參數(shù)配置,是在函數(shù) HAL_SRAM_Init 的

第三個參數(shù) ExtTiming 來配置的,這個我們后面會講解。

成員變量 Init 是 FMC_NORSRAM_InitTypeDef 結(jié)構(gòu)體指針類型,改變量才是真正用來設(shè)置

SRAM 控制接口參數(shù)的。我們接下來看看這個結(jié)構(gòu)體定義:

typedef struct

{

uint32_t NSBank;

//存儲區(qū)塊號

uint32_t DataAddressMux;

//地址/數(shù)據(jù)復(fù)用使能

uint32_t MemoryType;

//存儲器類型

uint32_t MemoryDataWidth; //存儲器數(shù)據(jù)寬度

uint32_t BurstAccessMode;

uint32_t WaitSignalPolarity;

uint32_t WaitSignalActive;

uint32_t WriteOperation;

//存儲器寫使能

uint32_t WaitSignal;

uint32_t ExtendedMode;

//是否使能擴(kuò)展模式

uint32_t AsynchronousWait;

uint32_t WriteBurst;

uint32_t ContinuousClock;

//啟用/禁止 FMC 時(shí)鐘輸出到外部存儲設(shè)備

uint32_t WriteFifo;

uint32_t PageSize;

}FMC_NORSRAM_InitTypeDef;

NSBank 用來指定使用到的存儲塊區(qū)號,前面講過,我們是使用的存儲塊區(qū)號 1,所以選擇

值為 FMC_NORSRAM_BANK1。DataAddressMux 用來設(shè)置是否使能地址/數(shù)據(jù)復(fù)用,該變量僅對

NOR/PSRAM 有 效 , 所 以 這 里 我 們 選 擇 不 使 能 地 址 / 數(shù)據(jù)復(fù)用值

FMC_DATA_ADDRESS_MUX_DISABLE 即可。MemoryType 用來設(shè)置存儲器類型,這里我們

把 LCD 當(dāng) SRAM 使用,所以設(shè)置為 FMC_MEMORY_TYPE_SRAM 即可。MemoryDataWidth

用來設(shè)置存儲器數(shù)據(jù)總線寬度,可選 8 位還是 16 位,這里我們選擇 16 位數(shù)據(jù)寬度

FMC_NORSRAM_MEM_BUS_WIDTH_16。WriteOperation 用來設(shè)置存儲器寫使能,也就是是

否允許寫入。毫無疑問我們會進(jìn)行存儲器寫操作,所以這里設(shè)置為

FMC_WRITE_OPERATION_ENABLE。ExtendedMode 用來設(shè)置是否使能擴(kuò)展模式,也就是是

否允許讀寫使用不同時(shí)序,前面講解過本實(shí)驗(yàn)讀寫采用不同時(shí)序,所以設(shè)置值為使能值

FMC_EXTENDED_MODE_ENABLE。ContinuousClock 用來設(shè)置啟用/禁止 FMC 時(shí)鐘輸出到外

部存儲設(shè)備 ,這里 僅 當(dāng) 使 用 FMC_BCR1 寄 存 器 的 時(shí) 候 需 要 啟 用 , 啟 用 值 為

FMC_CONTINUOUS_CLOCK_SYNC_ASYNC 。 其 他 參 數(shù) WriteBurst , BurstAccessMode ,

WaitSignalPolarity,WaitSignalActive,WaitSignal,AsynchronousWait 等是用在突發(fā)訪問和異步

時(shí)序情況下,這里我們不做過多講解。

成員變量 Lock 和 State 是 HAL 庫處理狀態(tài)標(biāo)識變量。這里就不做過多講解。

成員變量 hd **  在使用 DMA 時(shí)候才使用,這里就先不講解了。

函數(shù) HAL_SRAM_Init 的第一個入口參數(shù)就給大家講解到這里。

接下來看看后面 2 個參數(shù) Timing 和 ExtTiming,它們都是 FMC_NORSRAM_TimingTypeDef

結(jié)構(gòu)體指針類型,分別用來設(shè)置 FMC 接口讀和寫時(shí)序,主要涉及地址建立保持時(shí)間,數(shù)據(jù)建

立時(shí)間等等配置,對于我們的實(shí)驗(yàn)中,讀寫時(shí)序不一樣,讀寫速度要求不一樣,所以對于參數(shù)

Timing 和 ExtTiming 設(shè)置了不同的值。

FMC_NORSRAM_TimingTypeDef 結(jié)構(gòu)體定義如下:

typedef struct

{

uint32_t AddressSetupTime;

//地址建立時(shí)間

uint32_t AddressHoldTime;

//地址保持時(shí)間

uint32_t DataSetupTime;

//數(shù)據(jù)簡歷時(shí)間

uint32_t BusTurnAroundDuration; //總線周轉(zhuǎn)階段的持續(xù)時(shí)間

uint32_t CLKDivision;

//CLK 時(shí)鐘輸出信號的周期

uint32_t DataLatency;

//同步突發(fā) NOR FLASH 的數(shù)據(jù)延遲

uint32_t AccessMode;

//異步模式配置

}FMC_NORSRAM_TimingTypeDef;

成員變量 AddressSetupTime 用來設(shè)置地址建立時(shí)間。AddressHoldTime 用來設(shè)置地址保持

時(shí)間。DataSetupTime 用來設(shè)置數(shù)據(jù)建立時(shí)間。BusTurnAroundDuration 用來配置總線周轉(zhuǎn)階段

的持續(xù)時(shí)間。CLKDivision 用來配置 CLK 時(shí)鐘輸出信號的周期,以 HCLK 周期數(shù)表示。

DataLatency 用來設(shè)置同步突發(fā) NOR FLASH 的數(shù)據(jù)延遲。AccessMode 用來設(shè)置異步模式,取

值范圍為 FMC_ACCESS_MODE_A,F(xiàn)MC_ACCESS_MODE_B, FMC_ACCESS_MODE_C 和

FMC_ACCESS_MODE_D,這里我們用是異步模式 A,所以取值為 FMC_ACCESS_MODE_A。

HAL_SRAM_Init 函數(shù)各個入口參數(shù)含義和配置就給大家講解到這里。

和其他外設(shè)一樣,HAL 庫也提供了 SRAM 的初始化 MSP 回調(diào)函數(shù),函數(shù)聲明如下:

void HAL_SRAM_MspInit(SRAM_HandleTypeDef *hsram) ;

關(guān)于 MSP 函數(shù)的使用方法相信大家已經(jīng)非常熟悉。該函數(shù)內(nèi)部一般用來使能時(shí)鐘以及初

始化 IO 口這些與 MCU 相關(guān)的步驟。

前面我們講解過,F(xiàn)MC 接口支持多種存儲器,包括 SDRAM,NOR,NAND 和 PC CARD

等。HAL 庫為每種支持的存儲器類型都定義了一個獨(dú)立的 HAL 庫文件,并且在文件中定義了

獨(dú)立的初始化函數(shù)。這里以 SDRAM 為例,HAL 提供庫支持文件 stm32f7xx_hal_sdram.c 和頭文

件 stm32f7xx_hal_sdram.h,同時(shí)還提供了獨(dú)立的初始化函數(shù) HAL_SDRAM_Init,這里我們就列

出幾種存儲器的初始化函數(shù):

HAL_SDRAM_Init();//SDRAM 初始化函數(shù),省略入口參數(shù)

HAL_NOR_Init();//NOR 初始化函數(shù),省略入口參數(shù)

HAL_NAND_Init();//NAND 初始化函數(shù),省略入口參數(shù)

3)存儲區(qū)使能

實(shí)際上,當(dāng)我們調(diào)用了存儲器初始化函數(shù)之后,相應(yīng)的使用到的存儲區(qū)就已經(jīng)被使能。

SRAM 存儲區(qū)使能方法為:

__FMC_NORSRAM_ENABLE(FMC_Bank1,F(xiàn)MC_NORSRAM_BANK1);

18.2 硬件設(shè)計(jì)

本實(shí)驗(yàn)用到的硬件資源有:

1) 指示燈 DS0

2) TFTLCD 模塊

TFTLCD 模塊的電路見圖 18.1.1.2,這里我們介紹 TFTLCD 模塊與 ALIETEK 阿波羅

STM32F767 開發(fā)板的連接,阿波羅 STM32F767 開發(fā)板底板的 LCD 接口和 ALIENTEK TFTLCD

模塊直接可以對插,連接關(guān)系如圖 18.2.1 所示:

圖 18.2.1 TFTLCD 與開發(fā)板連接示意圖


圖 18.2.1 中圈出來的部分就是連接 TFTLCD 模塊的接口,液晶模塊直接插上去即可。

在硬件上,TFTLCD 模塊與阿波羅 STM32F767 開發(fā)板的 IO 口對應(yīng)關(guān)系如下:

LCD_BL(背光控制)對應(yīng) PB5;

LCD_CS 對應(yīng) PD7 即 FMC_NE1;

LCD _RS 對應(yīng) PD13 即 FMC_A18;

LCD _WR 對應(yīng) PD5 即 FMC_NWE;

LCD _RD 對應(yīng) PD4 即 FMC_NOE;

LCD _D[15:0]則直接連接在 FMC_D15~FMC_D0;

這些線的連接,阿波羅 STM32F767 開發(fā)板的內(nèi)部已經(jīng)連接好了,我們只需要將 TFTLCD

模塊插上去就好了。實(shí)物連接(4.3 寸 TFTLCD 模塊)如圖 18.2.2 所示:

圖 18.2.2 TFTLCD 與開發(fā)板連接實(shí)物圖


18.3 軟件設(shè)計(jì)

打開我們光盤的實(shí)驗(yàn) 13 TFTLCD(MCU 屏)工程可以看到我們添加了兩個文件 lcd.c 和頭

文 件 lcd.h 。 同 時(shí) , FMC 和 SRAM 相 關(guān) 的 庫 函 數(shù) 和 聲 明 定 義 在 源 文 件

stm32f7xx_hal_fmc.c/stm32f7xx_hal_sdram.c 和頭文件 stm32f7xx_hal_fmc.h

/stm32f7xx_hal_sram.h 中。

在 lcd.c 里面要輸入的代碼比較多,我們這里就不貼出來了,只針對幾個重要的函數(shù)進(jìn)行講

解。完整版的代碼見光盤?4,程序源碼?標(biāo)準(zhǔn)例程-寄存器版本?實(shí)驗(yàn) 13 TFTLCD(MCU 屏)

實(shí)驗(yàn) 的 lcd.c 文件。

本實(shí)驗(yàn),我們用到 FMC 驅(qū)動 LCD,通過前面的介紹,我們知道 TFTLCD 的 RS 接在 FMC

的 A18 上面,CS 接在 FMC_NE1 上,并且是 16 位數(shù)據(jù)總線。即我們使用的是 FMC 存儲器 1

的第 1 區(qū),我們定義如下 LCD 操作結(jié)構(gòu)體(在 lcd.h 里面定義):

//LCD 地址結(jié)構(gòu)體

typedef struct

{

vu16 LCD_REG;

vu16 LCD_RAM;

} LCD_TypeDef;

//使用 NOR/SRAM 的 Bank1.sector1,地址位 HADDR[27,26]=00 A18 作為數(shù)據(jù)命令區(qū)分線

//注意設(shè)置時(shí) STM32 內(nèi)部會右移一位對其!

#define LCD_BASE ((u32)(0x | 0x0007FFFE))

#define LCD ((LCD_TypeDef *) LCD_BASE)

其中 LCD_BASE,必須根據(jù)我們外部電路的連接來確定,我們使用 Bank1.sector1 就是從

地址 0X 開始,而 0x0007FFFE,則是 A18 的偏移量,這里很多朋友不理解這個偏移量

的概念,簡單說明下:以 A18 為例,0x0007FFFE 轉(zhuǎn)換成二進(jìn)制就是:0111 1111 1111 1111 1110,

而 16 位數(shù)據(jù)時(shí),地址右移一位對齊,那么實(shí)際對應(yīng)到地址引腳的時(shí)候,就是:A18:A0=011 1111

1111 1111 1111,此時(shí) A18 是 0,但是如果 16 位地址再加 1(注意:對應(yīng)到 8 位地址是加 2,即

0x0007FFFE +0X02),那么:A18:A0=100 0000 0000 0000 0000,時(shí) A18 就是 1 了,即實(shí)現(xiàn)了對

RS 的 0 和 1 的控制。

我們將這個地址強(qiáng)制轉(zhuǎn)換為 LCD_TypeDef 結(jié)構(gòu)體地址,那么可以得到 LCD->LCD_REG 的

地址就是 0X6007,FFFE,對應(yīng) A18 的狀態(tài)為 0(即 RS=0),而 LCD->LCD_RAM 的地址就是

0X6008,0000(結(jié)構(gòu)體地址自增),對應(yīng) A18 的狀態(tài)為 1(即 RS=1)。

所以,有了這個定義,當(dāng)我們要往 LCD 寫命令/數(shù)據(jù)的時(shí)候,可以這樣寫:

LCD->LCD_REG=CMD; //寫命令

LCD->LCD_RAM=DATA; //寫數(shù)據(jù)

而讀的時(shí)候反過來操作就可以了,如下所示:

CMD= LCD->LCD_REG; //讀 LCD 寄存器

DATA = LCD->LCD_RAM; //讀 LCD 數(shù)據(jù)

這其中,CS、WR、RD 和 IO 口方向都是由 FMC 硬件自動控制,不需要我們手動設(shè)置了。

接下來,我們先介紹一下 lcd.h 里面的另一個重要結(jié)構(gòu)體:

//LCD 重要參數(shù)集

typedef struct

{

u16 width;

//LCD 寬度

u16 height;

//LCD 高度

u16 id;

//LCD ID

u8 dir;

//橫屏還是豎屏控制:0,豎屏;1,橫屏。

u16 wramcmd;

//開始寫 gram 指令

u16 setxcmd;

//設(shè)置 x 坐標(biāo)指令

u16 setycmd;

//設(shè)置 y 坐標(biāo)指令

}_lcd_dev;

//LCD 參數(shù)

extern _lcd_dev lcddev; //管理 LCD 重要參數(shù)

該結(jié)構(gòu)體用于保存一些 LCD 重要參數(shù)信息,比如 LCD 的長寬、LCD ID(驅(qū)動 IC 型號)、

LCD 橫豎屏狀態(tài)等,這個結(jié)構(gòu)體雖然占用了十幾個字節(jié)的內(nèi)存,但是卻可以讓我們的驅(qū)動函數(shù)

支持不同尺寸的 LCD,同時(shí)可以實(shí)現(xiàn) LCD 橫豎屏切換等重要功能,所以還是利大于弊的。有

了以上了解,下面我們開始介紹 lcd.c 里面的一些重要函數(shù)。

先看 7 個簡單,但是很重要的函數(shù):

//寫寄存器函數(shù)

//regval:寄存器值

void LCD_WR_REG(vu16 regval)

{

regval=regval;

//使用-O2 優(yōu)化的時(shí)候,必須插入的延時(shí)

LCD->LCD_REG=regval;//寫入要寫的寄存器序號

}

//寫 LCD 數(shù)據(jù)

//data:要寫入的值

void LCD_WR_DATA(vu16 data)

{

data=data;

//使用-O2 優(yōu)化的時(shí)候,必須插入的延時(shí)

LCD->LCD_RAM=data;

}

//讀 LCD 數(shù)據(jù)

//返回值:讀到的值

u16 LCD_RD_DATA(void)

{

vu16 ram;

//防止被優(yōu)化

ram=LCD->LCD_RAM;

return ram;

}

//寫寄存器

//LCD_Reg:寄存器地址

//LCD_RegValue:要寫入的數(shù)據(jù)

void LCD_WriteReg(u16 LCD_Reg, u16 LCD_RegValue)

{

LCD->LCD_REG = LCD_Reg;

//寫入要寫的寄存器序號

LCD->LCD_RAM = LCD_RegValue; //寫入數(shù)據(jù)

}

//讀寄存器

//LCD_Reg:寄存器地址

//返回值:讀到的數(shù)據(jù)

u16 LCD_ReadReg(u16 LCD_Reg)

{

LCD_WR_REG(LCD_Reg);

//寫入要讀的寄存器序號

delay_us(5);

return LCD_RD_DATA();

//返回讀到的值

}

//開始寫 GRAM

void LCD_WriteRAM_Prepare(void)

{

LCD->LCD_REG=lcddev.wramcmd;

}

//LCD 寫 GRAM

//RGB_Code:顏色值

void LCD_WriteRAM(u16 RGB_Code)

{

LCD->LCD_RAM = RGB_Code;//寫十六位 GRAM

}

因?yàn)?FMC 自動控制了 WR/RD/CS 等這些信號,所以這 7 個函數(shù)實(shí)現(xiàn)起來都非常簡單,我

們就不多說,注意,上面有幾個函數(shù),我們添加了一些對 MDK –O2 優(yōu)化的支持,去掉的話,

在-O2 優(yōu)化的時(shí)候會出問題。這些函數(shù)實(shí)現(xiàn)功能見函數(shù)前面的備注,通過這幾個簡單函數(shù)的組

合,我們就可以對 LCD 進(jìn)行各種操作了。

第七個要介紹的函數(shù)是坐標(biāo)設(shè)置函數(shù),該函數(shù)代碼如下:

//設(shè)置光標(biāo)位置

//Xpos:橫坐標(biāo)

//Ypos:縱坐標(biāo)

void LCD_SetCursor(u16 Xpos, u16 Ypos)

{

if(lcddev.id==0X9341||lcddev.id==0X5310)

{

LCD_WR_REG(lcddev.setxcmd);

LCD_WR_DATA(Xpos>>8);LCD_WR_DATA(Xpos&0XFF);

LCD_WR_REG(lcddev.setycmd);

LCD_WR_DATA(Ypos>>8);LCD_WR_DATA(Ypos&0XFF);

}else if(lcddev.id==0X1963)

{

if(lcddev.dir==0)//x 坐標(biāo)需要變換

{

Xpos=lcddev.width-1-Xpos;

LCD_WR_REG(lcddev.setxcmd);

LCD_WR_DATA(0);LCD_WR_DATA(0);

LCD_WR_DATA(Xpos>>8);LCD_WR_DATA(Xpos&0XFF);

}else

{

LCD_WR_REG(lcddev.setxcmd);

LCD_WR_DATA(Xpos>>8);LCD_WR_DATA(Xpos&0XFF);

LCD_WR_DATA((lcddev.width-1)>>8);

LCD_WR_DATA((lcddev.width-1)&0XFF);

}

LCD_WR_REG(lcddev.setycmd);

LCD_WR_DATA(Ypos>>8);LCD_WR_DATA(Ypos&0XFF);

LCD_WR_DATA((lcddev.height-1)>>8);LCD_WR_DATA((lcddev.height-1)&0XFF);

}else if(lcddev.id==0X5510)

{

LCD_WR_REG(lcddev.setxcmd);LCD_WR_DATA(Xpos>>8);

LCD_WR_REG(lcddev.setxcmd+1);LCD_WR_DATA(Xpos&0XFF);

LCD_WR_REG(lcddev.setycmd);LCD_WR_DATA(Ypos>>8);

LCD_WR_REG(lcddev.setycmd+1);LCD_WR_DATA(Ypos&0XFF);

}

}

該函數(shù)實(shí)現(xiàn)將 LCD 的當(dāng)前操作點(diǎn)設(shè)置到指定坐標(biāo)(x,y)。因?yàn)?9341/5310/1963/5510 等的設(shè)

置有些不太一樣,所以進(jìn)行了區(qū)別對待。

接下來我們介紹第八個函數(shù):畫點(diǎn)函數(shù)。該函數(shù)實(shí)現(xiàn)代碼如下:

//畫點(diǎn)

//x,y:坐標(biāo)

//POINT_COLOR:此點(diǎn)的顏色

void LCD_DrawPoint(u16 x,u16 y)

{

LCD_SetCursor(x,y);

//設(shè)置光標(biāo)位置

LCD_WriteRAM_Prepare(); //開始寫入 GRAM

LCD->LCD_RAM=POINT_COLOR;

}

該函數(shù)實(shí)現(xiàn)比較簡單,就是先設(shè)置坐標(biāo),然后往坐標(biāo)寫顏色。其中 POINT_COLOR 是我們

定義的一個全局變量,用于存放畫筆顏色,順帶介紹一下另外一個全局變量:BACK_COLOR,

該變量代表 LCD 的背景色。LCD_DrawPoint 函數(shù)雖然簡單,但是至關(guān)重要,其他幾乎所有上

層函數(shù),都是通過調(diào)用這個函數(shù)實(shí)現(xiàn)的。

有了畫點(diǎn),當(dāng)然還需要有讀點(diǎn)的函數(shù),第九個介紹的函數(shù)就是讀點(diǎn)函數(shù),用于讀取 LCD

的 GRAM,這里說明一下,為什么 OLED 模塊沒做讀 GRAM 的函數(shù),而這里做了。因?yàn)?OLED

模塊是單色的,所需要全部 GRAM 也就 1K 個字節(jié),而 TFTLCD 模塊為彩色的,點(diǎn)數(shù)也比 OLED

模塊多很多,以 16 位色計(jì)算,一款 320×240 的液晶,需要 320×240×2 個字節(jié)來存儲顏色值,

也就是也需要 150K 字節(jié),這對任何一款單片機(jī)來說,都不是一個小數(shù)目了。而且我們在圖形

疊加的時(shí)候,可以先讀回原來的值,然后寫入新的值,在完成疊加后,我們又恢復(fù)原來的值。

這樣在做一些簡單菜單的時(shí)候,是很有用的。這里我們讀取 TFTLCD 模塊數(shù)據(jù)的函數(shù)為

LCD_ReadPoint,該函數(shù)直接返回讀到的 GRAM 值。該函數(shù)使用之前要先設(shè)置讀取的 GRAM

地址,通過 LCD_SetCursor 函數(shù)來實(shí)現(xiàn)。LCD_ReadPoint 的代碼如下:

//讀取個某點(diǎn)的顏色值

//x,y:坐標(biāo)

//返回值:此點(diǎn)的顏色

u16 LCD_ReadPoint(u16 x,u16 y)

{

u16 r=0,g=0,b=0;

if(x>=lcddev.width||y>=lcddev.height)return 0; //超過了范圍,直接返回

LCD_SetCursor(x,y);

if(lcddev.id==0X9341||lcddev.id==0X5310||lcddev.id==0X1963)

LCD_WR_REG(0X2E);//9341/3510/1963 發(fā)送讀 GRAM 指令

else if(lcddev.id==0X5510)LCD_WR_REG(0X2E00);//5510 發(fā)送讀 GRAM 指令

r=LCD_RD_DATA();

//dummy Read

if(lcddev.id==0X1963)return r;

//1963 直接讀就可以

opt_delay(2);

r=LCD_RD_DATA();

//實(shí)際坐標(biāo)顏色

//9341/NT35310/NT35510 要分 2 次讀出

opt_delay(2);

b=LCD_RD_DATA();

g=r&0XFF; //對于 9341/5310/5510,第一次讀取的是 RG 的值,R 在前,G 在后,各占 8 位

g<<=8;

return (((r>>11)<<11)|((g>>10)<<5)|(b>>11));

//需要公式轉(zhuǎn)換一下

}

在 LCD_ReadPoint 函數(shù)中,因?yàn)槲覀兊拇a不止支持一種 LCD 驅(qū)動器,所以,我們根據(jù)

不同的 LCD 驅(qū)動器((lcddev.id)型號,執(zhí)行不同的操作,以實(shí)現(xiàn)對各個驅(qū)動器兼容,提高函數(shù)

的通用性。

第十個要介紹的是字符顯示函數(shù) LCD_ShowChar,該函數(shù)同前面 OLED 模塊的字符顯示函

數(shù)差不多,但是這里的字符顯示函數(shù)多了 1 個功能,就是可以以疊加方式顯示,或者以非疊加

方式顯示。疊加方式顯示多用于在顯示的圖片上再顯示字符。非疊加方式一般用于普通的顯示。

該函數(shù)實(shí)現(xiàn)代碼如下:

//在指定位置顯示一個字符

//x,y:起始坐標(biāo)

//num:要顯示的字符:" "--->"~"

//size:字體大小 12/16/24/32

//mode:疊加方式(1)還是非疊加方式(0)

void LCD_ShowChar(u16 x,u16 y,u8 num,u8 size,u8 mode)

{

u8 temp,t1,t;

u16 y0=y;

u8 csize=(size/8+((size%8)?1:0))*(size/2);//得到字體一個字符對應(yīng)點(diǎn)陣集所占的字節(jié)數(shù)

num=num-' ';//ASCII 字庫是從空格開始取模,所以-' '就是對應(yīng)字符的字庫

for(t=0;t<csize;t++)

{

if(size==12)temp=asc2_1206[num][t];

//調(diào)用 1206 字體

else if(size==16)temp=asc2_1608[num][t]; //調(diào)用 1608 字體

else if(size==24)temp=asc2_2412[num][t]; //調(diào)用 2412 字體

else if(size==32)temp=asc2_3216[num][t]; //調(diào)用 3216 字體

else return;

//沒有的字庫

for(t1=0;t1<8;t1++)

{

if(temp&0x80)LCD_Fast_DrawPoint(x,y,POINT_COLOR);

else if(mode==0)LCD_Fast_DrawPoint(x,y,BACK_COLOR);

temp<<=1;

y++;

if(y>=lcddev.height)return;

//超區(qū)域了

if((y-y0)==size)

{

y=y0;

x++;

if(x>=lcddev.width)return; //超區(qū)域了

break;

}

}

}

}

在 LCD_ShowChar 函數(shù)里面,我們采用快速畫點(diǎn)函數(shù) LCD_Fast_DrawPoint 來畫點(diǎn)顯示字

符,該函數(shù)同 LCD_DrawPoint 一樣,只是帶了顏色參數(shù),且減少了函數(shù)調(diào)用的時(shí)間,詳見本例

程源碼。該代碼中我們用到了四個字符集點(diǎn)陣數(shù)據(jù)數(shù)組 asc2_3216、asc2_2412、asc2_1206 和

asc2_1608,這幾個字符集的點(diǎn)陣數(shù)據(jù)的提取方式,同十六章介紹的提取方法是一模一樣的。詳

細(xì)請參考第十六章。

最后,我們再介紹一下 TFTLCD 模塊的初始化函數(shù) LCD_Init,該函數(shù)先配置 FMC 控制器,

然后讀取 LCD 控制器的型號,根據(jù)控制 IC 的型號執(zhí)行不同的初始化代碼,其簡化代碼如下:

//初始化 lcd

//該初始化函數(shù)可以初始化各種型號的 LCD(詳見本.c 文件最前面的描述)

void LCD_Init(void)

{

GPIO_InitTypeDef GPIO_Initure;

FMC_NORSRAM_TimingTypeDef FMC_ReadWriteTim;

FMC_NORSRAM_TimingTypeDef FMC_WriteTim;

__HAL_RCC_GPIOB_CLK_ENABLE();

//開啟 GPIOB 時(shí)鐘

GPIO_Initure.Pin=GPIO_PIN_5;

//PB5,背光控制

GPIO_Initure.Mode=GPIO_MODE_OUTPUT_PP; //推挽輸出

GPIO_Initure.Pull=GPIO_PULLUP;

//上拉

GPIO_Initure.Speed=GPIO_SPEED_HIGH;

//高速

HAL_GPIO_Init(GPIOB,&GPIO_Initure);

LCD_MPU_Config(); //使能 MPU 保護(hù) LCD 區(qū)域

SRAM_Handler.Instance= FMC_NORSRAM_DEVICE;

//SRAM BANK1

SRAM_Handler.Extended= FMC_NORSRAM_EXTENDED_DEVICE;

SRAM_Handler.Init.NSBank=FMC_NORSRAM_BANK1;

//使用 NE1

SRAM_Handler.Init.DataAddressMux=FMC_DATA_ADDRESS_MUX_DISABLE;

//地址/數(shù)據(jù)線不復(fù)用

SRAM_Handler.Init.MemoryType=FMC_MEMORY_TYPE_SRAM; //SRAM

SRAM_Handler.Init.MemoryDataWidth=FMC_NORSRAM_MEM_BUS_WIDTH_16;

//16 位數(shù)據(jù)寬度

SRAM_Handler.Init.BurstAccessMode=FMC_BURST_ACCESS_MODE_DISABLE;

//是否使能突發(fā)訪問,僅對同步突發(fā)存儲器有效,此處未用到

SRAM_Handler.Init.WaitSignalPolarity=FMC_WAIT_SIGNAL_POLARITY_LOW;

//等待信號的極性,僅在突發(fā)模式訪問下有用

SRAM_Handler.Init.WaitSignalActive=FMC_WAIT_TIMING_BEFORE_WS;

//存儲器是在等待周期之前的一個時(shí)鐘周期還是等待周期期間使能 NWAIT

SRAM_Handler.Init.WriteOperation=FMC_WRITE_OPERATION_ENABLE;

//存儲器寫使能

SRAM_Handler.Init.WaitSignal=FMC_WAIT_SIGNAL_DISABLE;

//等待使能位,此處未用到

SRAM_Handler.Init.ExtendedMode=FMC_EXTENDED_MODE_ENABLE;

//讀寫使用不同的時(shí)序

SRAM_Handler.Init.AsynchronousWait=FMC_ASYNCHRONOUS_WAIT_DISABLE;

//是否使能同步傳輸模式下的等待信號,此處未用到

SRAM_Handler.Init.WriteBurst=FMC_WRITE_BURST_DISABLE;

//禁止突發(fā)寫

SRAM_Handler.Init.ContinuousClock=FMC_CONTINUOUS_CLOCK_SYNC_ASYNC;

//FMC 讀時(shí)序控制寄存器

FMC_ReadWriteTim.AddressSetupTime=0x011; //地址建立時(shí)間為 17 個 HCLK

FMC_ReadWriteTim.AddressHoldTime=0x00;

FMC_ReadWriteTim.DataSetupTime=0x55; //數(shù)據(jù)保存時(shí)間(DATAST)為 85 個 HCLK

FMC_ReadWriteTim.AccessMode=FMC_ACCESS_MODE_A; //模式 A

//FMC 寫時(shí)序控制寄存器

FMC_WriteTim.AddressSetupTime=0x15; //地址建立時(shí)間(ADDSET)為 21 個 HCLK

FMC_WriteTim.AddressHoldTime=0x00;

FMC_WriteTim.DataSetupTime=0x015; //數(shù)據(jù)保存時(shí)間(DATAST)為 21 個 HCLK

FMC_WriteTim.AccessMode=FMC_ACCESS_MODE_A; //模式 A

HAL_SRAM_Init(&SRAM_Handler,&FMC_ReadWriteTim,&FMC_WriteTim);

delay_ms(50); // delay 50 ms

//嘗試 9341 ID 的讀取

LCD_WR_REG(0XD3);

lcddev.id=LCD_RD_DATA(); //dummy read

lcddev.id=LCD_RD_DATA(); //讀到 0X00

lcddev.id=LCD_RD_DATA();

//讀取 93

lcddev.id<<=8;

lcddev.id|=LCD_RD_DATA();

//讀取 41

if(lcddev.id!=0X9341)

//非 9341,嘗試看看是不是 NT35310

{

LCD_WR_REG(0XD4);

lcddev.id=LCD_RD_DATA();//dummy read

lcddev.id=LCD_RD_DATA();//讀回 0X01

lcddev.id=LCD_RD_DATA();//讀回 0X53

lcddev.id<<=8;

lcddev.id|=LCD_RD_DATA();

//這里讀回 0X10

if(lcddev.id!=0X5310)

//也不是 NT35310,嘗試看看是不是 NT35510

{

LCD_WR_REG(0XDA00);

lcddev.id=LCD_RD_DATA();

//讀回 0X00

LCD_WR_REG(0XDB00);

lcddev.id=LCD_RD_DATA();

//讀回 0X80

lcddev.id<<=8;

LCD_WR_REG(0XDC00);

lcddev.id|=LCD_RD_DATA();

//讀回 0X00

if(lcddev.id==0x8000)lcddev.id=0x5510;

//NT35510 讀回的 ID 是 8000H,為方便區(qū)分,我們強(qiáng)制設(shè)置為 5510

if(lcddev.id!=0X5510)

//也不是 NT5510,嘗試看看是不是 SSD1963

{

LCD_WR_REG(0XA1);

lcddev.id=LCD_RD_DATA();

lcddev.id=LCD_RD_DATA();

//讀回 0X57

lcddev.id<<=8;

lcddev.id|=LCD_RD_DATA();

//讀回 0X61

if(lcddev.id==0X5761)lcddev.id=0X1963;

//SSD1963 讀回的 ID 是 5761H,為方便區(qū)分,我們強(qiáng)制設(shè)置為 1963

}

}

}

printf(" LCD ID:%x",lcddev.id); //打印 LCD ID

if(lcddev.id==0X9341)

//9341 初始化

{

……//9341 初始化代碼

}else if(lcddev.id==0xXXXX) //其他 LCD 初始化代碼

{

……//其他 LCD 驅(qū)動 IC,初始化代碼

}

//初始化完成以后,提速

if(lcddev.id==0X9341||lcddev.id==0X5310||lcddev.id==0X5510||lcddev.id==0X1963)

{

//重新配置寫時(shí)序控制寄存器的時(shí)序

FMC_Bank1E->BWTR[0]&=~(0XF<<0);

//地址建立時(shí)間(ADDSET)清零

FMC_Bank1E->BWTR[0]&=~(0XF<<8);

//數(shù)據(jù)保存時(shí)間清零

FMC_Bank1E->BWTR[0]|=5<<0; //地址建立時(shí)間(ADDSET)為 5 個 HCLK =21ns

FMC_Bank1E->BWTR[0]|=5<<8;//數(shù)據(jù)保存時(shí)間(DATAST) 為 21ns

}

LCD_Display_Dir(0);

//默認(rèn)為豎屏顯示

LCD_LED(1);

//點(diǎn)亮背光

LCD_Clear(WHITE);

}

該函數(shù)先對 FMC 相關(guān) IO 進(jìn)行初始化,然后是 FMC 的初始化,這個我們在前面都有介紹,

最后根據(jù)讀到的 LCD ID,對不同的驅(qū)動器執(zhí)行不同的初始化代碼,從上面的代碼可以看出,

這個初始化函數(shù)針對多款不同的驅(qū)動 IC 執(zhí)行初始化操作,這樣提高了整個程序的通用性。大家

在以后的學(xué)習(xí)中應(yīng)該多使用這樣的方式,以提高程序的通用性、兼容性。

這里還要提醒大家,在 LCD_Init 函數(shù)中有如下一行代碼:

LCD_MPU_Config(); //使能 MPU 保護(hù) LCD 區(qū)域

這行代碼的作用是調(diào)用函數(shù) LCD_MPU_Config 使能 MPU 保護(hù) LCD 區(qū)域,而函數(shù)

LCD_MPU_Config 定義的內(nèi)容實(shí)際上是我們上一章給大家講解的使能 MPU 保護(hù) LCD 區(qū)域。這

里我們之所以直接在 LCD 程序中加入 MPU 保護(hù),是因?yàn)榉奖愦蠹以谝浦?LCD 相關(guān)代碼到自

己的工程中的時(shí)候不會因?yàn)闆]有引入 MPU 相關(guān)配置而導(dǎo)致 LCD 無 ** 常工作。

特別注意:本函數(shù)使用了 printf 來打印 LCD ID,所以,如果你在主函數(shù)里面沒有初始化串

口,那么將導(dǎo)致程序死在 printf 里面!!如果不想用 printf,那么請注釋掉它。

SRAM 初始化 MSP 回調(diào)函數(shù) HAL_SRAM_MspInit 內(nèi)容比較簡單,主要是進(jìn)行時(shí)鐘使能以

及 IO 口映射配置,這里就不做過多講解。

LCD 驅(qū)動相關(guān)的函數(shù)就給大家講解到這里。接下來,我們看看主函數(shù)代碼如下:

int  ** in(void)

{

u8 x=0;

u8 lcd_id[12];

Cache_Enable(); //打開 L1-Cache

HAL_Init();

//初始化 HAL 庫

Stm32_Clock_Init(432,25,2,9); //設(shè)置時(shí)鐘,216Mhz

delay_init(216); //延時(shí)初始化

uart_init(115200);

//串口初始化

LED_Init(); //初始化 LED

LCD_Init(); //初始化 LCD

POINT_COLOR=RED;

sprintf((char*)lcd_id,"LCD ID:%04X",lcddev.id);//將 LCD ID 打印到 lcd_id 數(shù)組。

while(1)

{

switch(x)

{

case 0:LCD_Clear(WHITE);break;

……//此處省略部分代碼

case 11:LCD_Clear(BROWN);break;

}

POINT_COLOR=RED;

LCD_ShowString(10,40,260,32,32,"Apollo STM32F4/F7");

LCD_ShowString(10,80,240,24,24,"TFTLCD TEST");

LCD_ShowString(10,110,240,16,16,"ATOM@ALIENTEK");

LCD_ShowString(10,130,240,16,16,lcd_id);

//顯示 LCD ID

LCD_ShowString(10,150,240,12,12,"2016/7/11");

x++;

if(x==12)x=0;

LED0_Toggle;

delay_ms(1000);

}

}

該部分代碼將顯示一些固定的字符,字體大小包括 32*16、24*12、16*8 和 12*6 等四種,

同時(shí)顯示 LCD 驅(qū)動 IC 的型號,然后不停的切換背景顏色,每 1s 切換一次。而 LED0 也會不停

的閃爍,指示程序已經(jīng)在運(yùn)行了。其中我們用到一個 sprintf 的函數(shù),該函數(shù)用法同 printf,只

是 sprintf 把打印內(nèi)容輸出到指定的內(nèi)存區(qū)間上,sprintf 的詳細(xì)用法,請百度學(xué)習(xí)。

另外特別注意:uart_init 函數(shù),不能去掉,因?yàn)樵?LCD_Init 函數(shù)里面調(diào)用了 printf,所以

一旦你去掉這個初始化,就會死機(jī)了!實(shí)際上,只要你的代碼有用到 printf,就必須初始化串口,

否則都會死機(jī),即停在 usart.c 里面的 fputc 函數(shù),出不來。

在編譯通過之后,我們開始下載驗(yàn)證代碼。

18.4 下載驗(yàn)證

將程序下載到阿波羅 STM32 后,可以看到 DS0 不停的閃爍,提示程序已經(jīng)在運(yùn)行了。同

時(shí)可以看到 TFTLCD 模塊的顯示如圖 18.4.1 所示:

圖 18.4.1 TFTLCD 顯示效果圖


我們可以看到屏幕的背景是不停切換的,同時(shí) DS0 不停的閃爍,證明我們的代碼被正確的

執(zhí)行了,達(dá)到了我們預(yù)期的目的。

18.5 STM32CubeMX 配置 FMC(SRAM)

當(dāng)大家了解了 FMC 的基本工作原理,那么使用 STM32CubeMX 配置 FMC 相關(guān)參數(shù)就會非

常簡單。如果大家對 FMC 沒有理解,請仔細(xì)看教程學(xué)習(xí)。這里我們們不再詳細(xì)講解每個配置

項(xiàng)的含義。使用 STM32CubeMX 配置 FMC 的一般步驟為:

① 進(jìn)入 Pinout->FMC 配置欄,配置 FMC 基本參數(shù)。根據(jù)前面的講解,這里我們使用的是

BANK1 的第一個分區(qū) NE1,同時(shí)吧 LCD 作為 SRAM 使用,19 位地址線,16 位數(shù)據(jù)線。

配置參數(shù)如下圖 18.5.1 所示:

圖 18.5.1 FMC 配置參數(shù)


② 點(diǎn)擊 Configuration->FMC 進(jìn)入 FMC 配置界面,在 NOR/SRAM 1 選項(xiàng)卡之下配置相關(guān)參

數(shù)。這些參數(shù)的含義這里我們不累贅,在 18.1 小節(jié)講解 HAL_SRAM_Init 函數(shù)的時(shí)候都

有講解。配置方法如下圖 18.5.2 所示:

圖 18.5.2 FMC Configuration 配置界面 NOR/PSRAM1 選項(xiàng)卡


在該配置界面,點(diǎn)擊右邊的 GPIO Settigns 選項(xiàng)卡,還可以配置相關(guān) IO 口的信息。

經(jīng)過上面配置步驟,我們就可以生成相應(yīng)的初始化代碼,大家生成后和本章實(shí)驗(yàn)工

程對比學(xué)習(xí)。

熱門推薦:

cache
Processed in 0.010453 Second.