1)實驗平臺:alientek NANO STM32F411 V1開發板
2)摘自《正點原子STM32F4 開發指南(HAL 庫版》關注官方微信號公眾號,獲取更多資料:正點原子
第二十五章 TFTLCD 顯示實驗
前幾章的實例均沒有涉及到液晶顯示,這一章我們將向大家介紹 1.3 寸 TFTLCD 顯示屏模塊。該顯示屏不像 OLED 模塊只能顯示單色/雙色,不能顯示彩色,而這款 TFTLCD 可以顯示16 位色的真彩圖片,同時在上一章中學習了 SPI,在本章中,我們將通過 SPI 來驅動點亮 TFTLCD顯示屏,並實現 ASCII 字符(12/16/24/32 號字體)、圖片和彩色顯示等功能,本章將分為如下
幾個部分進行講解:
25.1 TFTLCD 介紹
25.2 硬件設計
25.3 實驗準備
25.4 實驗驗證
25.1 TFTLCD 簡介
TFT-LCD 即薄膜晶體液晶顯示器。其英文全稱為:Thin Film Transistor-Liquid Crystal Display。TFT-LCD 與無源 TN-LCD、STN-LCD 的簡單矩陣不同,它在液晶顯示屏的每一個像素上都設置有一個薄膜晶體管(TFT),可有效地克服非選通時的串擾,使顯示液晶屏的靜態特性與掃描線數無關,因此大大提高了圖像質量。TFT-LCD 也被叫做真彩液晶顯示器。
1.3’TFTLCD 模塊主要有以下特點:
1、屏幕尺寸為 1.3 寸
2、分辨率為:240*240
3、支持 16 位真彩色顯示
這裡要提醒大家的是,該模塊不和 5.0V 接口兼容,所以請大家在使用的時候一定要小心,別直接接到 5V 的系統上去,否則可能燒壞模塊。該模塊的外觀圖如圖 25.1.1 所示:
ATK-1.3’TFTLCD 模塊通過 8(2*4)個引腳同外部連接,對外接口原理圖如圖 25.1.2 所示:
對應引腳功能詳細描述如表 25.1.3 所示:
特別注意:模塊出廠是默認選擇四線 SPI,例子是使用四線 SPI 進行通信的。
ATK-1.3’TFTLCD 在四線 SPI 通訊模式下 ,最少需要四線就可以 與 LCD 通訊:
CS/SCL/SDA/WR(DC),該模塊出廠默認使用四線 SPI 通訊,也就是默認焊接 R7 和 R10 電阻。
四線 SPI 接口時序如圖 25.1.4 所示:
圖中各個時間參數見表 25.1.5 所示:
從表中可以看出,模塊的寫週期是非常快的,寫週期為:16ns,而模塊的讀週期相對較慢,
讀週期為:150ns。
LCD 四線 SPI 的詳細讀寫時序,請看 ST7789V2 數據手冊第 56 頁和 60 頁。
模塊採用 ST7789V2 作為 LCD 驅動器,顯示數據可以直接存儲在 240*320*18 位片上的
RAM 中,它可以在沒用外部操作時鐘的情況下執行顯示數據 RAM 讀/寫操作,以最小化功耗。
該驅動芯片採用 SPI 接口與外部連接,需要使用的信號線如下:
CS:LCD 的片選信號線
SCK:SPI 的時鐘信號線
SDA:SPI 的數據信號線
WR(RC):命令/數據標誌(0:寫命令:1:寫數據)
除了以上信號,我們一般還需要用到這 2 個信號:RESET 和 PWR,其中:RST 是 LCD 的
硬復位腳,低電平有效,用於復位 ST7789V2 芯片,實現液晶的復位,在每次初始化之前,我
們強烈建議大家先執行硬復位,再做初始化。而 PWR 則是 LCD 的背光控制引腳,高電平有效,
這個引腳自帶了下拉電阻,所以如果這個引腳懸空,背光是不會亮的。必須接高電平背光才會
亮,另外可以用 PWM 控制 PWR 腳,從而控制背光的亮度。
ST7789V2 自帶 LCD RAM(240*320*3 字節),並且最高支持 18 位顏色深度(262K 色),
不過我們一般使用 16 位顏色深度(65K 色),RGB565 格式,這樣可以在 16 位模式下達到最
快的速度。在 16 位模式下,ST7789V2 採用 RGB565 格式存儲顏色數據,此時 MCU 的 16 位數
據與 LCD RAM 的對應關係如圖 25.1.6 所示:
圖示 MCU 的 16 位數據中,最低 5 位代表藍色,中間 6 位綠色,最高 5 位為紅色,數值越
大,表示該顏色越深。
接下來,就來介紹一下 ST7789V2 的幾條重要指令,因為該芯片的命令有很多,我們這裡
就不全部介紹了,有興趣的可以找數據手冊看看,裡面對命令有詳細介紹。
首先來看一下指令:0x36,這是存儲訪問控制指令,可以控制 ST7789V2 存儲器的讀寫方
向,簡單的來說,就是在連續寫 LCD RAM 數據的時候,可以控制 RAM 指針的增長方向,從
而控制顯示方式(讀操作也是一樣)。該指令如圖 26.1.7 所示:
從上圖可以看出。0x36 指令下可以配置 6 個參數,這裡我們主要關心:MY、MX 和 MV
這 3 位,通過這三個位的設置,我們可以控制整個 ST7789V2 的全部掃描方向。如表 26.1.8 所
示:
這樣,我們在使用 ST7789V2 顯示內容的時候,就有很大靈活性了,比如顯示 BMP 圖片,
BMP 數碼數據,就是叢圖片的左下角開始,慢慢顯示到右上角,如果設置 LCD 掃描方式(默
認)下面,該指令用於設置橫座標(x 座標),該指令如圖 26.1.9 所示:
這裡指令用於 x 座標,x 座標有兩個座標值:XS 和 XE(XS 和 XE 都是 16 位的,由 2 個 8
位組成),即列地址的起始值和結束值,當“MV=0”時,0
0
一般 TFTLCD 模塊的使用流程如圖 26.1.10 所示:
任何 LCD,使用流程都可以簡單的用以上流程圖表示。其中硬復位和初始化序列,只需要
執行一次即可。而畫點流程就是:座標->寫 GRAM 指令->寫入顏色數據,然後在 LCD 上面,
我們就可以看到對應的點顯示我們寫入的顏色了。讀點流程為:設置座標->讀 GRAM 指令->
讀取顏色數據,這樣就可以獲取對應的顏色數據了。
25.2 硬件設計
本實驗功能簡介:開機時先初始化 LCD,然後開始顯示正點原子 LOGO,12/16/24/32 號字
體等信息,同時使用 LED 燈來指示程序正在運行。
本章需要用到的硬件資源如下:
1、指示燈 LED
2、1.3’TFTLCD 模塊
3、NANO STM32F4 開發板
ATK-1.3’TFFLCD 模塊與 NANO STM32F4 開發板對應的關係如下:
25.3 軟件設計
本實驗我們使用四線 SPI 來驅動 ATK-1.3’TFTLCD 模塊,所以我們通過 WR(DC)信號線
來控制是發送命令還是發送數據到 LCD。代碼如下所示:
/**
* @brief
寫命令到 LCD
*
* @param
cmd
需要發送的命令
*
* @return void
*/
static void LCD_Write_Cmd(u8 cmd)
{
LCD_WR = 0;
LCD_SPI_Send(&cmd, 1);
}
/**
* @brief
寫數據到 LCD
*
* @param
cmd
需要發送的數據
*
* @return void
*/
static void LCD_Write_Data(u8 data)
{
LCD_WR = 1;
LCD_SPI_Send(&data, 1);
}
LCD 的 SPI 通訊時序大家可以通過 ST7789V2 數據手冊進行學習,這裡就不多介紹了。
下面我們來重點關注一下上面我們提到的 0x36 指令(存儲訪問控制指令,即 RAM 指針增
長方向),這裡只粘貼了部分代碼。
/* Memory Data Access Control */
LCD_Write_Cmd(0x36);
LCD_Write_Data(0x00);
從以上代碼可以看到,LCD 的 RAM 指令增長方向被設置成了從左到右,從上到下的方式,
這個方式決定了字庫取模方式和圖片顯示等問題。如果方向設置的好,我們只需要將字庫和圖
片數據不停的往 LCD 填充就好了,就可以大大提高顯示速度。
下面我們就來看看畫點函數,該函數的實現代碼如下:
/**
* 設置數據寫入 LCD 緩存區域
*
* @param
x1,y1
起點座標
* @param
x2,y2
終點座標
*
* @return void
*/
void LCD_Address_Set(u16 x1, u16 y1, u16 x2, u16 y2)
{
LCD_Write_Cmd(0x2a);
LCD_Write_Data(x1 >> 8);
LCD_Write_Data(x1);
LCD_Write_Data(x2 >> 8);
LCD_Write_Data(x2);
LCD_Write_Cmd(0x2b);
LCD_Write_Data(y1 >> 8);
LCD_Write_Data(y1);
LCD_Write_Data(y2 >> 8);
LCD_Write_Data(y2);
LCD_Write_Cmd(0x2C);
}
/**
* @brief
寫半個字的數據到 LCD
*
* @param
cmd
需要發送的數據
*
* @return void
*/
void LCD_Write_HalfWord(const u16 da)
{
u8 data[2] = {0};
data[0] = da >> 8;
data[1] = da;
LCD_WR = 1;
LCD_SPI_Send(data, 2);
}
/**
* 畫點函數
*
* @param
x,y
畫點座標
*
* @return void
*/
void LCD_Draw_Point(u16 x, u16 y)
{
LCD_Address_Set(x, y, x, y);
LCD_Write_HalfWord(POINT_COLOR);
}
該函數實現比較簡單,就是先設置了座標,然後往座標寫顏色數據。其中 POINT_COLOR
是我們定義的一個全局變量,用於存放畫筆顏色,順便介紹一下另外一個全局變量
BACK_COLOR,該變量代表 LCD 的背景顏色。LCD_Draw_Point 函數雖然簡單,但是至關重
要,其他函數都可以調用這個函數實現。在例程源碼中,為了提高顯示速度,很少用到畫點函
數來實現上層函數功能,因為畫點函數的效率有點低。但是可以供到大家學習使用。
由於 ATK-1.3’TFTLCD 模塊是 SPI 通訊接口的,在速度上肯定會比不上那些使用 8080 等
並口的 TFTLCD 顯示屏,為了提高顯示速度,增加了一個 LCD 緩存,以提高顯示效果,這個
緩存會影響清屏函數 LCD_Clear、填充函數 LCD_Fill 和畫線函數 LCD_DrawLine,修改緩存大
小時,請注意!!!
//LCD 緩存大小設置,修改此值時請注意!!!!修改這兩個值時可能會影響以下函數
LCD_Clear/LCD_Fill/LCD_DrawLine
#define LCD_TOTAL_BUF_SIZE(240*240*2)
#define LCD_Buf_Size 1152
static u8 lcd_buf[LCD_Buf_Size];
最後就來看一下字符顯示函數 LCD_ShowChar,該函數可以顯示 12/16/24/32 號字體,如果
大家需要其他字體的話可以直接修改這個函數。特別要注意字符取模方向!
/**
* @brief
顯示一個 ASCII 碼字符
*
* @param
x,y
顯示起始座標
* @param
chr
需要顯示的字符
* @param
size 字體大小(支持 16/24/32 號字體)
*
* @return void
*/
void LCD_ShowChar(u16 x, u16 y, char chr, u8 size)
{
u8 temp, t1, t;
u8 csize;
//得到字體一個字符對應點陣集所佔的字節數
u16 colortemp;
u8 sta;
chr = chr - ' '; //得到偏移後的值(ASCII 字庫是從空格開始取模,所以-' '就是對應字符
的字庫)
if((x > (LCD_Width - size / 2)) || (y > (LCD_Height - size)))
return;
LCD_Address_Set(x, y, x + size / 2 - 1, y + size - 1);//(x,y,x+8-1,y+16-1)
if((size == 16) || (size == 32) )
//16 和 32 號字體
{
csize = (size / 8 + ((size % 8) ? 1 : 0)) * (size / 2);
for(t = 0; t < csize; t++)
{
if(size == 16)temp = asc2_1608[chr][t];//調用 1608 字體
else if(size == 32)temp = asc2_3216[chr][t]; //調用 3216 字體
else return;
//沒有的字庫
for(t1 = 0; t1 < 8; t1++)
{
if(temp & 0x80) colortemp = POINT_COLOR;
else colortemp = BACK_COLOR;
LCD_Write_HalfWord(colortemp);
temp <<= 1;
}
}
}
else if (size == 12)
//12 號字體
{
csize = (size / 8 + ((size % 8) ? 1 : 0)) * (size / 2);
for(t = 0; t < csize; t++)
{
temp = asc2_1206[chr][t];
for(t1 = 0; t1 < 6; t1++)
{
if(temp & 0x80) colortemp = POINT_COLOR;
else colortemp = BACK_COLOR;
LCD_Write_HalfWord(colortemp);
temp <<= 1;
}
}
}
else if(size == 24)
//24 號字體
{
csize = (size * 16) / 8;
for(t = 0; t < csize; t++)
{
temp = asc2_2412[chr][t];
if(t % 2 == 0)sta = 8;
else sta = 4;
for(t1 = 0; t1 < sta; t1++)
{
if(temp & 0x80) colortemp = POINT_COLOR;
else colortemp = BACK_COLOR;
LCD_Write_HalfWord(colortemp);
temp <<= 1;
}
}
}
}
關於 LCD 的驅動代碼問題就講到這裡,我們的源碼中還提供了畫矩形、畫圓、顯示數字和
顯示圖片等等函數,大家可以直接對照源碼進行學習。
25.4 下載驗證
代碼編譯成功後,直接下載代碼到我們的 NANO STM32F4 開發板上,然後將 ATK-1.3’
TFTLCD 模塊連接到開發板上的引腳就可以測試模塊的顯示效果了。如圖 25.4.1 所示: