第7章 ILI9341液晶顯示與DHT11溫溼度傳感器

第7章 ILI9341液晶顯示與DHT11溫溼度傳感器

7.1液晶顯示原理

TFT-LCD(Thin Film Transistor Liquid Crystal Display)即薄膜晶體管液晶顯示器,是微電子技術與液晶顯示器技術巧妙結合的的一種技術。

CRT顯示器的工作原理是通電後燈絲髮熱,陰極被激發後發射出電子流,電子流受到高電壓的金屬層的加速,經過透鏡聚焦形成極細的電子束打在熒光屏上,使熒光粉發光顯示圖像。LCD顯示器需要來自背後的光源,當光束通過這層液晶時,液晶會呈不規則扭轉形狀(形狀由TFT上的信號與電壓改變實現),所以液晶更像是一個個閘門,選擇光線穿透與否,這樣就可以在屏幕上看到深淺不一,錯落有致的圖像。目前主流的LCD顯示器都是TFT-LCD,是由原有液晶技術發展而來。TFT液晶為每個像素都設有一個半導體開關,以此做到完全的單獨控制一個像素點,液晶材料被夾在TFT陣列和彩色濾光片之間,通過改變刺激液晶的電壓值就可以控制最後出現的光線強度和色彩,如圖7-1所示。

第7章 ILI9341液晶顯示與DHT11溫溼度傳感器

圖7-1 液晶顯示屏結構圖

Kingst-32F1開發板配套的TFT-LCD是3.2寸大小,分辨率為240*320,即一共有240×320=76800個像素點,每個像素都設有一個半導體開關,像素之間是相對獨立的,這麼多像素如何控制呢?聯想一下51單片機驅動LED點陣時,為了減少IO口的使用,採用三八譯碼器驅動點陣模塊。同理,TFT-LCD也可以用專門的驅動器來驅動,教材所用的TFT-LCD採用ILI9341驅動芯片。該控制芯片是封裝在TFT-LCD內部,只留有外部引腳接口。對於用戶來說,只要掌握如何向ILI9341控制器發送指令和讀寫數據,並不需要再設計額外的驅動電路,該液晶的具體參數如表7-1所示。

第7章 ILI9341液晶顯示與DHT11溫溼度傳感器

7.1.1ILI9341硬件接口和像素格式

ILI9341驅動芯片主要由接口電路、顯存(GRAM)、LCD驅動電路、背光控制、電源等部分組成,主要結構如圖7-2所示。

第7章 ILI9341液晶顯示與DHT11溫溼度傳感器

圖7-2 ILI9341控制器內部結構圖

ILI9341控制器的通信接口支持8/9/16/18-bit 8080並行接口、3/4線SPI串行接口、6/16/18-bit RGB通信接口,這些接口通過TFT-LCD的38~40引腳IM0、IM1、IM2設置,具體如表7-2所示。不同的接口主要是為了適應不同的應用場合。由於STM32的I/O口資源豐富,為了提高數據的讀寫效率,採用16位的8080並行接口,可以比8位的8080並行接口的傳輸速率高出一倍(數據線多出一倍),由於是並行接口,比SPI串行接口的傳輸速率更快,並且通訊時序簡單,因此這裡將TFT-LCD的IM2~IM0引腳接地。

第7章 ILI9341液晶顯示與DHT11溫溼度傳感器

採用8080總線接口的ILI9341TFT-LCD一共 40 個引腳,每個引腳的功能,都可以在其數據手冊上獲得。這些基本的信息,在設計電路和編寫代碼之前,必須先搞清楚,如圖7-3 Kingst-32F1開發板TFT-LCD電路圖和表7-3 LCD引腳功能表所示。

第7章 ILI9341液晶顯示與DHT11溫溼度傳感器

圖7-3 ILI9341 TFTLCD 引腳電路原理圖

第7章 ILI9341液晶顯示與DHT11溫溼度傳感器

7.1.2ILI9341 TFT-LCD引腳初始化

首先對TFT-LCD模塊的引腳進行初始化配置,TFT-LCD相關引腳連接如圖7-4和表7-4所示。

第7章 ILI9341液晶顯示與DHT11溫溼度傳感器

第7章 ILI9341液晶顯示與DHT11溫溼度傳感器

然後還需要在Ili9341.h頭文件中對部分引腳進行宏定義,採用直接操作IO口寄存器的方式,避免程序跳轉時浪費時間,從而提高LCD程序的執行效率,具體如下:

第7章 ILI9341液晶顯示與DHT11溫溼度傳感器

7.1.3 8080並行總線協議

8080並行總線協議是由Intel公司提出的一種數據傳輸協議,接口包括:復位(RESET)、片選(CS)、雙向數據線(DB0~DB15)、數據/指令選擇端(DC)、讀使能(RD)、寫使能(WR)。

8080並行總線時序分為兩部分:“寫操作”時序和“讀操作”時序,同時“寫操作”時序又分為“寫命令”操作和“寫數據”操作。通過操作DC端口,當DC為低表示“命令”傳輸,當DC為高表示“數據”傳輸。

(1)寫操作:

寫指令時,單片機發送過程為,CS = H→L,DC = H→ L,WR = H→L,RD = H,D[15:0] = Data,此時信號發生變化;當D[15:0]數據穩定後,WR = L→H,ILI9341在WR的上升沿讀取D[15:0]總線上的信號。

寫數據和寫指令的時序唯一差別是:寫指令時,DC為低電平;寫數據時,DC為高電平。寫操作的時序圖如圖7-5所示。

當命令或數據傳輸完成,且不再進行“寫操作”時,需要將CS置高,失能片選。

第7章 ILI9341液晶顯示與DHT11溫溼度傳感器

圖7-5 8080並行總線“寫”時序

第7章 ILI9341液晶顯示與DHT11溫溼度傳感器

(2)讀操作:

讀數據之前,首先要進行一次寫命令操作,通知LCD主機所要讀取的數據類別。寫命令操作完成後,首先DC= L→H,而後RD = H→L,通知ILI9341輸出數據,最終RD = L→H,開始讀取D[15:0]上的數據。當讀操作完畢後,需要將CS置高,失能片選。讀操作的時序圖如圖7-6所示。

第7章 ILI9341液晶顯示與DHT11溫溼度傳感器

圖7-6 8080CPU總線“讀”時序

第7章 ILI9341液晶顯示與DHT11溫溼度傳感器

(3)時序特徵

編寫時序程序時必須嚴格按照數據手冊中要求的時間和順序,否則容易造成數據通信錯誤。8080時序的寫操作週期為twc=66ns,其中twrl和twrh分別表示主機寫週期和ILI9341讀週期,即當WR置低時,主機開始寫,此時WR至少保持tdst=10ns的低電平,等待總線數據鎖存;當數據線輸出數據後,如果WR低電平週期低於10ns,有可能在WR置高時,總線上的數據還在變化。當WR置高時,至少保持tdht=10ns的高電平,等待ILI9341讀取數據完畢。在執行寫操作時,主機可以先發送數據,然後WR = L→H,當WR置高時,數據一定準備好了。因此編寫時序程序時,注意加適當延時保證時序的準確性,由於STM32執行一條語句超過10ns,在此並不需要使用延時。

讀操作與寫操作類似,當RD置低時,ILI9341開始輸出數據,此時必須等待tratfm ns,等待ILI9341將數據準備好,其中tratfm最大為340ns,沒有規定最小時間。我們取 tratfm大於等於340ns,因為超過340ns,ILI9341一定將數據準備好了,但是少於340ns就不能保證數據完全正確。RD置高時,單片機開始讀取數據,此時需要保持RD高電平時間不少於trod=20ns,保證ILI9341將數據輸出完畢,8080總線時序參數如圖7-7所示。

第7章 ILI9341液晶顯示與DHT11溫溼度傳感器

圖7-7 8080總線時序參數說明圖

7.1.4 ILI9341 GRAM指令和像素格式

GRAM(Graphics RAM)——顯存,也稱作幀存儲器,是ILI9341用來存儲顯示數據的圖像RAM。GRAM中一個像素點的顏色數據用18bit表示,GRAM的大小為240*320*18/8=172800字節,所有像素數據都存儲在GRAM中。當TFT-LCD開顯示時,LCD源極驅動會根據GRAM中存儲的數據對液晶像素進行刷新,從而實現圖像顯示。如果改變GRAM中單個像素點的數據,刷新顯示時,TFT-LCD對應的像素狀態也會改變。如何才能準確的向每個像素對應的數據位寫入顯示數據呢?ILI9341控制器內部設計了一個“控制寄存器”,用戶只需要按照要求發送相應的控制指令,“控制寄存器”收到控制指令後,通過“地址計數器”在對應的像素位置寫入像素數據,最終通過LCD源極驅動LCD刷新顯示,ILI9341控制器內部結構如圖7-8所示。

第7章 ILI9341液晶顯示與DHT11溫溼度傳感器

圖7-8 ILI9341控制器內部結構圖

ILI9341控制器共有76條控制指令,每條指令的控制功能在手冊中都有詳細描述,本書只針對常用指令做重點說明。

1、讀取驅動器ID:用於讀取TFT-LCD的驅動器的的ID,板載液晶的驅動器是ILI9341,ID固定為0x9341。在讀取的過程中,首先通過寫命令函數發送指令0xD3,然後連續讀取4次數據。其中第1次是無效數據,第二次是版本號,也是無效數據,第三次和第四次的高8位也是無效數據,只有第三次和第四次的低8位才是有效的ID數據,讀取ID成功,表明單片機和驅動器通信正常,讀ID指令如圖7-9所示。

第7章 ILI9341液晶顯示與DHT11溫溼度傳感器

圖7-9 讀ID指令

讀ID代碼如下:

第7章 ILI9341液晶顯示與DHT11溫溼度傳感器

2、設置顯示窗口:當用戶將一部分要顯示的內容填充到液晶顯示屏的某一個區域,這個區域的列範圍用0x2A這條指令設置,行範圍用0x2B這條指令設置。首先通過寫命令函數發送指令0x2A,緊跟著列起始地址的高字節、列起始地址的低字節、列結束地址的高字節、列結束地址的低字節;然後通過寫命令函數發送指令0x2B,緊跟著行起始地址的高字節、行起始地址的低字節、行結束地址的高字節、行結束地址的低字節。注意:結束地址只能大於等於起始地址,不能小於起始地址。

通過限定這4個角的座標,就可以從液晶中選取其中一個區域作為顯示窗口。指令和地址都只有低8位數據有效,發送過程如圖7-10和圖7-11所示。

第7章 ILI9341液晶顯示與DHT11溫溼度傳感器

圖7-10 顯示窗口的列地址(X座標)

第7章 ILI9341液晶顯示與DHT11溫溼度傳感器

圖7-11顯示窗口的行地址(Y座標)

設置光標代碼如下:

第7章 ILI9341液晶顯示與DHT11溫溼度傳感器

3、寫存儲器指令:設置好顯示窗口後,在寫入數據之前,需要先寫入0x2C指令。無論當前行寄存器和列寄存器的地址是多少,寫入0x2C後,行寄存器和列寄存器會自動復位,復位值就是通過0x2A和0x2B寫入的列起始地址和行起始地址,此時如果發送數據,數據會寫入幀存儲器對應地址中,數據寫入具體流程如圖7-12所示。

第7章 ILI9341液晶顯示與DHT11溫溼度傳感器

圖7-12 數據寫入流程

4、幀存儲器掃描方向控制指令:設置顯示窗口後,發送0x2C指令開始向內存中寫數據,數據是從設置窗口的起始地址開始寫入,先寫行,行地址自增直至該行的終止地址,然後列地址加1,數據再從下一行的起始地址開始寫入,如此循環直至將整個顯示窗口的數據寫入到幀存儲器中。幀存儲器讀/寫掃描方向如圖7-13所示,圖中B表示起始位置,E表示終止位置。

第7章 ILI9341液晶顯示與DHT11溫溼度傳感器

圖7-13 存儲器讀/寫掃描方向示意圖

數據按照上面介紹的順序寫入,但是液晶屏刷新顯示時,並不一定按照寫入的順序刷新數據,而是可以通過“存儲器訪問控制”指令0x36設置幀存儲器的掃描方向(即行列方向)。設置幀存儲器掃描方向時,先發送指令0x36,緊跟著發送設置參數,參數由18位組成,只有2~7位有效。其中D7:MY-設置行地址方向;D6:MX-設置列地址方向;D5:MV-設置行列地址交換;D4:ML-設置垂直刷新方向;D3:BGR-設置刷新像素格式為BGR或RGB;D2:MH-設置水平刷新方向,存儲器訪問控制指令如圖7-14所示。

第7章 ILI9341液晶顯示與DHT11溫溼度傳感器

圖7-14 存儲器訪問控制指令

其中MY、MX、MV這三位用來設置掃描方向,也是重點介紹的地方,MX和MY分別設置行列掃描方向,MV設置行列交換,它們可以組合成23=8種掃描模式,如圖7-15所示。

注意:無論MY、MX、MV設置的存儲器掃描方向如何,數據總是以相同的順序寫入幀存儲器。設置掃描方向後,還需要通過0x2A、0x2B指令重新設置顯示窗口大小。

第7章 ILI9341液晶顯示與DHT11溫溼度傳感器

圖7-15 ILI9341液晶屏8種掃描模式

Kingst-32F1開發板默認掃描方向為“模式0”,其中模式0和3為豎屏顯示,模式5和6為橫屏顯示,這四種模式的掃描方向和稍後所講的文字取模方向相同,旋轉液晶屏即可達到閱讀效果,其他模式直接顯示時呈現亂碼,需要根據掃描方向重新取模。

ML和MH主要設置幀存儲器到LCD顯示面板的數據刷新方向,就像過年貼春聯,可以選擇從上向下貼,或者從下向上貼,無論哪種方式,最後的顯示效果是不變的,默認ML和MH都為0。

以下是設置液晶掃描方向代碼:

/* 設置LCD掃描方向,dir-掃描模式0~7*/

第7章 ILI9341液晶顯示與DHT11溫溼度傳感器

5、像素格式:

TFT-LCD的每個像素點由紅(R)、綠(G)、藍(B)三原色組成,幀存儲器為每個像素分配了18bit的存儲空間,三原色各用6個數據位表示,也就是常說的RGB666格式,該模式色彩度最大,它們按不同比例的混合可以組成218種顏色,俗稱262K色。同時ILI9341還支持16位、9位數據格式。

Kingst-32F1開發板採用16位的8080並行接口與ILI9341通信,GRAM選擇16位數據格式,16位數據格式下按照R:G:B =5:6:5格式存儲,俗稱RGB565格式,此時8080總線單次傳輸的就是一個像素的數據。由於GRAM為每個像素預留的存儲空間是18bit,為了保證寫入的16bit像素數據能夠正常匹配GRAM中18bit像素存儲空間,控制器會自動將RGB565格式轉換成RGB666格式,轉換後數據存儲形式如圖7-16所示,空白位置表示沒有數據。由於缺少了兩位數據,此時TFT-LCD最大支持216種色彩度,也就是65K色。

第7章 ILI9341液晶顯示與DHT11溫溼度傳感器

圖7-16 幀存儲器中RGB565存儲結構

像素數據在幀存儲器按照圖7-18的格式存儲,即R位於高位,B位於低位。但是像素數據刷新到LCD顯示屏上時,可以通過“存儲器訪問控制(0x36)”指令中的 BGR位選擇像素數據寫入到顯示屏的方向,當BGR位為 0時,數據按照RGB(即R在高位,B在低位)的順序寫入;當BGR位為1時,數據沿BGR(即B在高位,R在低位)的順序寫入到液晶面板中。默認BGR位為1,該模式下寫入的顏色與顯示效果相同,像素刷新示意圖如圖7-17所示。

第7章 ILI9341液晶顯示與DHT11溫溼度傳感器

圖7-17 BGR-RGB控制示意圖

6、讀存儲器指令;讀存儲器指令為0x2E,與上面介紹的寫存儲器指令0x2C類似,首先發送0x2A和0x2B設置行列起始和終止地址,然後發送0x2E,行列地址自動復位。通過讀數據函數可以讀取幀存儲器存儲的像素數據,第一次讀取的數據無效,之後每一次讀取16bit數據,由於幀存儲器中每個像素佔18位,因此一個像素點的數據需要分兩次讀取,第一次讀取RG的值,第二次讀取B值。讀數據時行列地址會自增,直至讀完整個顯示窗口,讀存儲器指令如圖7-18所示。

第7章 ILI9341液晶顯示與DHT11溫溼度傳感器

圖 7-18 讀存儲器指令

7、ILI9341初始化

由於ILI9341液晶屏初始化需要設置的參數比較多,在此就不再一一講解,僅提供初始化代碼。如果想深入研究,可以按照上面介紹指令的方式,到ILI9341參考手冊中查找相關指令和對應參數位的作用。初始化代碼如下:

第7章 ILI9341液晶顯示與DHT11溫溼度傳感器

第7章 ILI9341液晶顯示與DHT11溫溼度傳感器

第7章 ILI9341液晶顯示與DHT11溫溼度傳感器

7.2I LI9341 TFT-LCD 顯示操作

7.2.1 畫點

畫點就是向單個像素點填充顏色,畫點主要分為三部分:

第一步、通過窗口設置函數設置像素點的座標,由於設置的是一個像素點,所以窗口設置函數的起始和終止座標相同;

第二步、發送寫存儲器指令0x2C;

第三步、寫入像素數據。為了提高速率,通過寫指令和數據函數一併將指令和數據寫入。畫點函數如下:

第7章 ILI9341液晶顯示與DHT11溫溼度傳感器

7.2.2 讀點

讀點就是讀取幀存儲器中相應像素點的數據。讀點也分為三部分:

第一步、通過窗口設置函數確定像素點的座標;

第二步、發送讀存儲器指令0x2E;

第三步、讀取像素數據。

由於幀存儲中像素數據為18bit,寫入幀存儲器中的像素數據是RGB565格式,幀存儲器中存儲的數據是RGB666格式。16位並口模式下讀取一個像素點數據需要讀兩次,數據按照高位在前,低位在後順序輸出。第一次讀取的數據無效,之後讀取的才是真正的像素數據;第二次讀取的是RG值,其中高8位為R值,有效位為[15:11]位,低8位為G值,有效位為[7:2]位,第三次讀取的B值位於高8位,有效位為[15:11]位,像素數據讀取完畢後還需要轉換為RGB565格式。需要注意的是讀數據時需要設置數據總線為輸入模式,讀取完畢後再重新設置為輸出模式。讀點函數如下:

第7章 ILI9341液晶顯示與DHT11溫溼度傳感器

7.2.3 畫線,畫矩形,畫圓

(1)畫線分為畫直線和畫斜線,同時直線又分為水平線和豎直線。畫直線是通過“顯示窗口設置函數”設定顯示區域為一行或一列,然後發送0x2C寫存儲器指令,最後通過寫數據函數填充顏色。畫斜線時相對比較麻煩,需要從起始位置開始,計算斜線上每個像素點的座標,然後再調用畫點函數填充每個像素點的顏色。畫線函數如下所示;其中xStart、yStart、xEnd、yEnd分別表示起始和終止座標,Color表示填充的顏色。

void LcdDrawLine(u16 xStart, u16 yStart, u16 xEnd, u16 yEnd, u16 Color);

(2)畫矩形分為填充和非填充兩種情況,非填充矩形是由四條線組成,通過矩形的對角座標,計算每條線的起始座標和終止座標,再調用畫線函數畫出矩形的四條邊。填充矩形可以直接使用“顯示窗口設置函數”,設置一個矩形窗口,然後發送0x2C指令,最後填充顏色。

畫矩形函數如下所示,其中xStart、yStart、xEnd、yEnd表示矩形的對角座標,Color為填充的顏色,Filled 為0表示非填充,為1表示填充。

void LcdDrawRectangle(u16 xStart,u16 yStart,u16 xEnd,u16 yEnd,u16 Color,u8 Filled);

(3)畫圓與畫斜線類似,先確定圓心座標以及半徑後,通過公式計算出圓周的位置,最後調用畫點函數畫出整個圓。畫圓函數如下所示,其中xDot、yDot表示圓心座標,R表示半徑,Color表示圓的顏色,Filled為0表示非填充,為1表示填充。

void LcdDrawCircle(u16 xDot, u16 yDot, u8 R, u16 Color, u8 Filled);

7.2.4 填充和清屏

填充是對某一區域填充特定顏色。首先通過“顯示窗口設置函數”設置被填充區域範圍,然後發送0x2C寫存儲器指令,最後通過寫數據函數寫入像素數據。該函數如下所示:其中xStart、yStart、xEnd、yEnd表示填充區域起始和終止座標,Color表示填充的顏色。

void LcdFill(u16 xStart, u16 yStart, u16 xEnd, u16 yEnd, u16 Color);

清屏函數實際是一個填充函數,只不過清屏函數的顯示窗口大小設置為全屏。該函數如下所示,Color表示全屏填充的顏色。

void LcdClear(u16 Color);

7.3TFT-LCD 顯示字符和漢字

7.3.1 什麼是字模

液晶分為帶字庫和不帶字庫兩種,帶字庫指的是液晶模塊上集成有字庫芯片,比如51單片機上常用的LCD1602(帶ASCII字符集),LCD12864(帶ASCII字符集和中文字庫)都集成有字庫芯片。而多數的TFT-LCD沒有集成字庫芯片,使用無字庫芯片的TFT-LCD顯示字符或漢字時,需要先製作相關字符或漢字的“字模”,然後再控制液晶按照“字模”數據去畫點,最終實現顯示效果。

“字模”是字符和漢字的二進制編碼,將字符或漢字放入m行×n列的正方形內,該正方形共有m*n個小方格,每個小方格用一位二進制數表示,凡是筆劃經過的方格用1表示,未經過用0表示,最終將所有方格用0和1表示即可得到該字符或漢字的“字模”,這種格式的字模稱之為“陰碼”。與之相對的是“陽碼”,即筆畫過的方格用0表示,未經過的用1表示,按照顯示習慣,通常選擇“陰碼”格式取模。比如用16×16點陣來畫一個“中”字,從第一行開始從左向右每取8個點作為一個字節,如果最後不足8個點就補滿8位。取模順序是從低到高,即第一個點作為最低位。如第一行的二進制編碼為“00000001 10000000”用16進製表示為:0x80,0x01; 以此類推對每一行進行取模,16*16格式下一個“中”字的“字模”編碼需要用16*16/8=32Byte存儲,如圖7-19所示。

第7章 ILI9341液晶顯示與DHT11溫溼度傳感器

圖7-19 漢字“中”的16×16點陣圖

7.3.2 自建簡易字模庫

由於計算機系統只能處理二進制,如果要處理文本,就必須先把文本轉換為二進制才能處理。最早的計算機系統在設計時採用8個bit作為一個字節,因此一個字節能表示的最大的整數就是255,0~127被用來表示大小寫英文字母、數字和一些符號,這個編碼表就是ASCII編碼表。

如果要表示中文,顯然一個字節是不夠的,至少需要兩個字節,編碼表中對所有漢字/中文字符采取“分區”處理,每區含有94個漢字/中文字符,第一個字節稱為“高位字節”(也稱“區字節”),用來確定漢字/字符所在分區;第二個字節稱為“低位字節”(也稱“位字節”),用於確定漢字/字符在該區的具體位置。這種表示方式也稱為區位碼,區位碼=區字節+位字節。

由於區位碼採用四位十進制編碼,這和計算機廣泛使用的ASCII編碼衝突。為了兼容00-7f的ASCII編碼,在區位碼的高、低字節上分別加上0xA0,加過兩個A0的編碼也稱為GB2312編碼。GB2312中前15區用來收錄了包括拉丁字母、希臘字母、日文平假名及片假名字母、俄語西裡爾字母在內的682個全角字符。而漢字是從16區開始,共6763個漢字,因此漢字區的“高位字節”的範圍是0xB0-0xF7,“低位字節”的範圍是0xA1-0xFE。例如“啊”為GB2312編碼表中第一個漢字,其編碼為0xB0A1,其中0xB0在第一個字節儲存,0xA1在第二個字節儲存。

數據在內存中是連續排列的,如何區分ASCII碼和GB2312碼呢?已知ASCII碼小於等於127,而GB2312碼大於127,當讀取到的字符編碼小於等於127時,為ASCII碼;大於127時為GB2312碼,由於一個GB2312碼佔2Byte,因此還需要向後再讀取一字節數據,這兩字節數據組合起來才是一個完整的GB2312碼。

大多數TFT-LCD本身不具備存儲字模的能力,當使用TFT-LCD顯示字符和漢字時,就需要添加相應的字模庫。通常採用以下兩種方式存儲字庫,一種是使用外部存儲設備存儲字庫,比如Flash,SD卡;第二種方法是將簡易字模庫隨程序一起燒入單片機內部Flash中。當只需要顯示英文字符時,可以製作ASCII字符集,ASCII字符集僅包含128個字符,生成字模後所佔內存相對較小,可以選擇燒寫到單片機Flash中。在此介紹一下如何使用字符取模軟件對ASCII字符集進行取模,具體步驟如下:

1、對字符取模採用的是PCtoLCD2002取模軟件,該軟件位於“Kingst-32F1開發板配套光盤\相關工具軟件\取模軟件\PCtolcd2002(漢字取模)”路徑下。打開取模軟件,在“模式”一欄選擇“字符模式”,如圖7-20所示。

第7章 ILI9341液晶顯示與DHT11溫溼度傳感器

圖7-20 選擇字符模式

2、接下來點擊“選項”,出現字模選項菜單,具體設置如圖7-21所示,設置完成後點擊“確定”按鈕。

第7章 ILI9341液晶顯示與DHT11溫溼度傳感器

圖7-21 字模選項設置

3、設置字模格式。因為漢字結構比較複雜,需要設置點陣大小為16×16,再小就不足已完整顯示一個漢字。注意ASCII碼採用的是英文長寬比,默認16×16點陣格式下,ASCII碼實際所用到的點陣大小為16×8,其他常用的大小還有12×6,24×12格式。使用時按照需求調整相應字寬和字高。字號和字體設置完畢後,點擊圖7-22紅色方框所示文本圖標。

第7章 ILI9341液晶顯示與DHT11溫溼度傳感器

圖7-22 設置字體、字號

1、生成字模時,有兩種方式:

(1)將要轉換的源字符保存到文本文檔,然後通過“打開文本文件”的方式導入字符;

(2)在“文本編輯區”直接添加字符。

字符添加完畢後切記一定要選中“過濾掉空格和重複字符”、“生成索引文件”以及“自動升序排列”功能,設置方式如圖7-23所示。設置完畢後,點擊“開始生成”。

第7章 ILI9341液晶顯示與DHT11溫溼度傳感器

圖7-23 生成字模

2、點擊開始生成後,軟件會提示設置保存路徑及名稱。填寫文件名,比如font;選擇默

認保存類型,即“文本文件(*.TXT)”;最後選擇合適的保存路徑後,點擊“保存”,操作步驟如圖7-24所示。軟件會生成兩個文本文件:“font.TXT”和“font_index.TXT”。其中“font.TXT”中存儲的便是字符的字模,“font_index.TXT”存儲的是字符索引。

第7章 ILI9341液晶顯示與DHT11溫溼度傳感器

圖7-24 保存字模

3、新建font.c和font.h文件用於存放字模,並將其添加到Keil工程中,並在ili9341.c

文件中#include "font.h" 頭文件調用相應字模數據。本書所提供的例程已經對ASCII字符集的所有字符進行了取模,其中ASCII字符集分為三種字號大小,分別存放在三個數組中,使用時可以直接調用,不需要在額外進行取模,ASCII字模庫如圖7-25所示。具體如下:

ASCII_1206[ASCII_TOTAL*12]數組中存放字號為12×6的ASCII字符集;

ASCII_1608[ASCII_TOTAL*16]數組中存放字號為16×8的ASCII字符集;

ASCII_2412[ASCII_TOTAL*24]數組中存放字號為24×12的ASCII字符集;

第7章 ILI9341液晶顯示與DHT11溫溼度傳感器

圖7-25 font.h中 ASCII字符集字模編碼

7.3.3 顯示字符

1、顯示單個字符

顯示一個字號16(英文長寬比8×16)的字符,首先通過窗口設置函數設定顯示一個8×16大小顯示區域。然後根據該字符的ASCII碼到1608字體對應的ASCII_1608[95][16]數組中找到該字符的字模編碼,按照字模編碼一個個填充像素點,從設定顯示區域起始座標開始,遇到1就對像素點填充顏色,比如紅色,遇到0就填充背景色,比如白色,直到填充完畢整個16×8大小的顯示區域,填充紅的像素點就組成了該字符。單字符顯示函數如下所示:

void LcdShowASCII(u16 x, u16 y, u8 size, u8 chr, u16 Color, u16 BkdColor);

其中x,y為顯示位置的起始座標;size為字號大小,其值可以是12、16、24中的任意一個,設置其他值將不顯示;chr為要顯示字符的ASCII碼;Color為顯示字符的顏色;BkdColor為字體背景色,通常和屏幕背景色設置一致顏色。

比如以屏幕座標(20,30)為起始座標,顯示一個字號為16,填充色為紅色,字體背景色為白色的A:

LcdShowASCII(20, 30, 16, ‘A’, RED, WHITE);

2、顯示ASCII字符串

字符串顯示函數是利用字符顯示函數依次顯示字符串中的每一個字符。字符串顯示函數如下所示:

void LcdShowASCIIString(u16 x, u16 y, u8 size, char *addr, u16 Color, u16 BkdColor);

其中x,y為顯示位置的起始座標;size為字號大小,其值可以是12、16、24中得任意一個,設置其他值將不顯示;*addr為要字符串首地址;Color為顯示數字的顏色;BkdColor為背景色,通常和屏幕背景色設置一致顏色。

比如在屏幕座標(20,40)顯示一個字號為16,填充色為紅色,背景色為白色的字符串hello

LcdShowASCIIString(30, 30, u16, “hello”, RED, WHITE);

3、顯示數字

顯示數字是在顯示ASCII字符串的基礎上實現的。數字顯示函數中傳遞的並不是該數字的ASCII碼,而是一個數值常量或者變量。數字顯示函數如下:

void LcdShowNum(u16 x, u16 y, u8 size, u8 len, s32 num, u16 Color, u16 BkdColor);

其中x,y為顯示位置的起始座標;size為字號大小,其值可以是12、16、24中得任意一個,設置其他值將不顯示;len為顯示內容長度,len的長度一定不能小於實際數值的最大長度;num為要顯示數值常量或變量;Color為顯示數字的顏色;BkdColor為背景色,通常和屏幕背景色設置一致顏色。

7.3.4 顯示漢字

實際開發中除了要用到ASCII碼顯示字符外,還需要顯示漢字,因此還需要製作漢字字模。GB2312編碼表中每個字符編碼佔2Byte,長寬比為16×16格式下每個漢字的字模佔用32Byte內存空間,GB2312編碼表中所有漢字的字模加起來大約211KB左右。由於GB2312字庫所佔內存較大,不能簡單的將字庫燒寫到單片機內存中,此時就需要通過Flash、SD卡等設備來存儲字庫。而如果額外增加Flash、S D卡等存儲設備來存儲字庫勢必會提高產品成本。因此對於漢字取模而言,只針對所用到的漢字進行取模即可。

以顯示李白的“靜夜思”為例,具體步驟如下:

1、顯示漢字與顯示ASCII字符原理相同,即通過查詢漢字的GB2312編碼,去對應字庫中查找漢字的字模。因此需要在font.h文件中新建兩個數組ChsIndex[]和ChsTab[],分別用於保存字模索引和對應的漢字字模,因為漢字的編碼佔2字節,所以數組ChsIndex[]為unsigned short型。

2、對所用到的漢字按照GB2312編碼進行排序。由於Pctolcd2002取模軟件的自動排序功能有問題,需要藉助“GB2312”字符編碼排序軟件對漢字進行排序,操作步驟如圖7-26所示。

第7章 ILI9341液晶顯示與DHT11溫溼度傳感器

圖7-26 中文字符排序

3、對漢字取模。按照7.3.2小結所講的字符取模步驟對漢字進行取模。

4、將PCtoLCD2002生成的索引文件“XX_index.TXT”中漢字的GB2312碼添加到ChsIndex[]數組中,將生成的“XX.TXT”中的字模庫添加到ChsTab[]數組中。注意ChsIndex[]數組中添加的是漢字的GB2312編碼,不是漢字,並且一定要保證漢字索引與漢字字模庫中的順序一一對應,否則會出現顯示內容不匹配。

如何計算漢字的GB2312編碼呢?有兩種方式,一是與取字符的ASCII碼一樣,通過單引號' ' 獲取漢字編碼,具體如圖7-27所示。由於編碼原因,該操作Keil會提示警告,“multicharacter character literal (potential portability problem)”即“多字符的字符文字(潛在的可移植性問題)”。該警告不影響程序運行,使用時可以忽略該警告。

第7章 ILI9341液晶顯示與DHT11溫溼度傳感器

圖7-27 漢字索引及簡易字模庫(一)

如果不想Keil提示警告,可以直接在數組中按照順序添加漢字的GB2312編碼。在此提供一個漢字GB2312碼查詢軟件,該軟件位於配套光盤“\相關工具軟件\取模軟件\漢字區位碼查詢軟件”目錄中。打開GBCode軟件,在軟件中輸入漢字,點擊“查GB碼”即可得到漢字的區位碼和GB2312編碼,比如“床”字的GB2312編碼為“0xB4B2”,如圖7-28所示。

第7章 ILI9341液晶顯示與DHT11溫溼度傳感器

圖7-28 漢字GB2312編碼查詢軟件界面

然後將所有顯示的漢字的GB2312編碼按照從小到大順序一一添加到索引數組中,如圖7-29所示

第7章 ILI9341液晶顯示與DHT11溫溼度傳感器

圖 7-29 漢字索引及簡易字模庫(二)

顯示漢字時通過二分法查找函數在ChsIndex[]數組中查找要顯示的漢字所在位置,然後再到ChsTab數組對應的位置讀取該漢字的字模,最後調用漢字顯示函數顯示該漢字。如果索引數組中未找到要顯示的漢字時,查找函數會返回0,此時如果調用漢字顯示函數,將會顯示ChsTab[]數組中的第0個元素,即第一個漢字,從而引起顯示錯誤,因此將ChsTab[]數組中第0個元素為空白(全為0),當檢測不到漢字時將顯示背景色。與此同時也要將對應的索引數組ChsIndex[]的第0個元素設置為0x00。切記:如果重新添加或刪減漢字,一定要按照漢字的GB2312碼從小到大的順序重新排列漢字索引數組和字模庫數組,並使之一一對應,否則會造成顯示錯誤或顯示內容不匹配。

漢字顯示函數如下所示:

void LcdShowString(u16 x, u8 y, char *str, u16 Color, u16 BkdColor);

其中x,y為顯示位置的起始座標;*str為要漢字的首地址;Color為顯示數字的顏色;BkdColor為背景色,通常設置為屏幕背景色。該函數不僅僅可以顯示漢字,還可以顯示ASCII字符,默認字體大小為16×16。函數通過判斷字符編碼的大小,識別出顯示的內容是漢字還是ASCII字符,如果是ASCII字符就調用ASCII碼顯示函數,如果是漢字就調用漢字顯示函數。比如顯示唐詩“靜夜思”,使用時注意區分半角字符和全角字符,詩中“,”使用的半角字符(ASCII碼),而“。”為全角字符,全角字符屬於GB2312編碼,需要與漢字一樣進行取模。

LcdShowString(80, 160, "靜夜思", RED, WHITE);

LcdShowString(20, 180, "床前明月光,疑似地上霜。", RED, WHITE);

LcdShowString(20, 200, "舉頭望明月,低頭思故鄉。", RED, WHITE);

7.4TFT-LCD顯示圖片

圖片顯示依舊需要對圖片進行取模,由於本文默認TFT-LCD使用豎屏顯示(掃描模式為模式0),以顯示一張240*340大小的十六位真彩色圖片為例介紹圖片顯示功能,首先準備一張尺寸為240*320大小的圖片。

1、打開Image2Lcd取模軟件,該軟件位於光盤資料“相關工具軟件\取模軟件\Image2Lcd 2.9”目錄下,如圖7-30所示。

第7章 ILI9341液晶顯示與DHT11溫溼度傳感器

圖7-30 Image2Lcd取模軟件界面

2、點擊“打開”按鈕,選中準備好的圖片,然後設置如下標註的參數,注意一定根據圖片的實際尺寸設置圖片的最大寬度和高度,如圖7-31所示。

第7章 ILI9341液晶顯示與DHT11溫溼度傳感器

圖7-31 設置圖片取模格式

3、點擊“保存”,選擇合適路徑,保存文件名稱為Startup,保存類型默認為“C file(*.c,*.h)”格式。打開保存的Startup.c文件可以看到一個數組gImage_Startup[153608],該數組中存儲的便是圖像取模數據,其中前八個元素保存的是圖像頭數據。具體內容可以在“幫助->用法與說明->圖像頭數據格式”中查找。

4、新建image.c和image.h文件並將其添加到Keil工程中,將Image2Lcd取模軟件生成的Startup.c文件中的gImage_Startup[153608]全部複製到image.c文件中,如圖7-32所示。由於數組數據較大,注意不要遺漏,使用時直接調用#include "image.h"頭文件即可。

第7章 ILI9341液晶顯示與DHT11溫溼度傳感器

圖7-32 構建簡易圖庫

調用LcdShowImage函數顯示圖片,圖片顯示函數如下:

void LcdShowImage(u16 xStart, u16 yStart, u8 *image);

其中xStart,yStart為顯示位置的起始座標,*image為圖片取模數據首地址。

7.4.1 LCD顯示字符、數字、漢字、圖片實驗

本節通過簡單的顯示實驗,展示圖片、漢字、字符、數字顯示函數的簡單用法,使用時直接調用相應函數。。

第7章 ILI9341液晶顯示與DHT11溫溼度傳感器

第7章 ILI9341液晶顯示與DHT11溫溼度傳感器

第7章 ILI9341液晶顯示與DHT11溫溼度傳感器

7.5 DHT11溫溼度傳感器

DHT11數字溫溼度傳感器是一款含有已校準數字信號輸出的溫溼度複合傳感器,內部由一個8位單片機控制一個電阻式感溼元件和一個NTC測溫元件。DHT11雖然也是採用單總線協議,但是該協議與DS18B20的單總線協議稍微有些不同之處,具體操作時再詳細介紹。相比於DS18B20只能測量溫度,DHT11既能檢測溫度又能檢測溼度,不過 DHT11的精度和測量範圍都要低於DS18B20,其溫度測量範圍為0~50℃,誤差在±2℃;溼度的測量範圍為20%~90%RH(Relative Humidity相對溼度—指空氣中水汽壓與飽和水汽壓的百分比),誤差在±5%RH。DHT11電路很簡單,只需要將 Dout引腳連接單片機的一個I/O即可,不過該引腳需要上拉一個5K的電阻,DHT11的供電電壓為3~5.5V。Kingst-32F1開發板DHT11傳感器連接的是PC13引腳,其電路圖如圖7-33 所示。

第7章 ILI9341液晶顯示與DHT11溫溼度傳感器

圖 7-33 DHT11電路圖

DHT11採用單總線協議與單片機通信,單片機發送一次復位信號後,DHT11從低功耗模式轉換到高速模式,等待主機復位結束後,DHT11發送響應信號,並拉高總線準備傳輸數據。一次完整的數據為40bit,按照高位在前,低位在後的順序傳輸。

數據格式為:8bit溼度整數數據+8bit溼度小數數據+8bit溫度整數數據+8bit溫度小數數據+8bit校驗和,一共5字節(40bit)數據。由於DHT11分辨率只能精確到個位,所以小數部分是數據全為0。校驗和為前4個字節數據相加,校驗的目的是為了保證數據傳輸的準確性。

DHT11只有在接收到開始信號後才觸發一次溫溼度採集,如果沒有接收到主機發送復位信號,DHT11不主動進行溫溼度採集。當數據採集完畢且無開始信號後,DHT11自動切換到低速模式。接下來一起看一下DHT11的配置流程:

由於 DHT11 時序要求非常嚴格,所以在操作時序的時候,為了防止中斷干擾總線時序,先關閉總中斷,操作完畢後再打開總中斷。開關總中斷函數如下:

__set_PRIMASK(1); //關總中斷

__set_PRIMASK(0); //開總中斷

1、主機發送復位信號;

DHT11的初始化過程同樣分為復位信號和響應信號。首先主機拉低總線至少18ms,然後再拉高總線,延時20~40us,取中間值30us,此時復位信號發送完畢。復位時序如圖7- 34主機信號所示。

第7章 ILI9341液晶顯示與DHT11溫溼度傳感器

圖7-34 DHT11初始化時序圖

2、DHT11發送響應信號

DHT11檢測到復位信號後,觸發一次採樣,並拉低總線80us表示響應信號,告訴主機數據已經準備好了;然後DHT11拉高總線80us,之後開始傳輸數據。如果檢測到響應信號為高電平,則DHT11初始化失敗,請檢查線路是否連接正常,響應時序如圖7-33所示。

當復位信號發送完畢後,如果檢測到總線被拉低,就每隔1us計數一次,直至總線拉高,計算低電平時間;當總線被拉高後重新計數檢測80us的高電平。如果檢測到響應信號之後的80us高電平,就準備開始接收數據。實際上DHT11的響應時間並不是標準的80us,往往存在誤差,當響應時間處於20~100us之間時就可以認定響應成功。

復位和檢測響應信號函數如下:

第7章 ILI9341液晶顯示與DHT11溫溼度傳感器

3、數據傳輸;

DHT11在拉高總線80us後開始傳輸數據。每1bit數據都以50us低電平時隙開始,告訴主機開始傳輸一位數據了。DHT11以高電平的長短定義數據位是0還是1,當50us低電平時隙過後拉高總線,高電平持續26~28us表示數據“0”;持續70us表示數據“1”,如圖7-35 所示。當最後1bit數據傳送完畢後,DHT11拉低總線50us,表示數據傳輸完畢,隨後總線由上拉電阻拉高進入空閒狀態。

第7章 ILI9341液晶顯示與DHT11溫溼度傳感器

圖7-35 DHT11數據0和1時序圖

如何區分數據“0”和數據“1”呢?難道還是像檢測響應時間那樣計算高電平持續時間?那樣就太麻煩了,大家想一下,數據“0”的高電平持續26~28us,數據“1”的高電平持續70us,每一位數據前都有50us的起始時隙。如果我們取一箇中間值40us 來區分數據“0”和數據“1”的時隙,怎麼區分呢?很簡單,當數據位之前的50us低電平時隙過後,總線肯定會拉高,此時延時40us後檢測總線狀態,如果為高,說明此時處於70us的時隙,則數據為“1”;如果為低,說明此時處於下一位數據50us的開始時隙,那麼上一位數據肯定是“0”。為什麼延時40us?由於誤差的原因,數據“0”時隙並不是準確26~28us,可能比這短,也可能比這長。當數據“0”時隙大於26~28us時,如果延時太短,無法判斷當前處於數據“0”的時隙還是數據“1”的時隙;如果延時太長,則會錯過下一位數據前的開始時隙,導致檢測不到後面的數據。

/

第7章 ILI9341液晶顯示與DHT11溫溼度傳感器

7.5.1 LCD實時顯示溫溼度

由於DHT11採樣週期間隔要求不得低於1秒鐘。該實驗每隔1S採集一次溫溼度數據,並通過LCD數字顯示函數顯示到液晶屏上,具體程序如下:

第7章 ILI9341液晶顯示與DHT11溫溼度傳感器

第7章 ILI9341液晶顯示與DHT11溫溼度傳感器

第7章 ILI9341液晶顯示與DHT11溫溼度傳感器

第7章 ILI9341液晶顯示與DHT11溫溼度傳感器


分享到:


相關文章: