TFT-LCD
一、簡介:
TFT-LCD即薄膜半導體液晶顯示器,依據其尺寸、分辨率和驅動晶片的不同有很多分類,下邊會依據2.8寸320X240分辨率以ILI9341晶片驅動的TFT-LCD做相關介紹。
二、接口:
子產品采用16位并方式與外部連接配接,其相關接口圖及信号線功能如下:
CS:TFTLCD片選信号。WR:向TFTLCD寫資料。RD:從TFTLCD讀取資料。D[15:0]:16位資料線。RS:指令/資料标示(0,讀寫指令;1,讀寫資料)。
三、驅動時序:
對于寫時序:CS拉低做片選,RS表示是要寫資料還是要寫指令,在WR信号線的上升沿擷取資料線D[0:15]上的資料,在寫時序上RD信号線總是處于高電平。對于讀時序同理。
四、驅動流程:
對于LCD的驅動流程可由下圖表示:
首先通過LCD_RST引腳做複位,再進行初始化序列,由于本人現階段水準有限,先不去研究相關初始化序列,是以就直接運用LCD商家給出的初始化序列代碼。無論是讀寫指令,都需要設定好坐标,再做出讀寫GRAM的相關指令。在随後涉及到顔色資料的相關處理,下邊就針對顔色資料做一下相關說明。
對于顔色的設定也有多種格式,在這裡隻是針對RGB565顔色格式做說明。RGB565這樣看(Red)[5位](Green)[6位](Blue)[5位],組成16位顔色深度。
五、指令:
對于ILI9341的指令有很多,下邊對ILI9341驅動晶片的個别指令做相關說明:1、0XD3:該指令用于讀取晶片ID。由此可以依據不同的LCD做相關初始化,做到更好的相容。2、OX36:存儲器通路控制指令,可以在讀寫資料過程中控制GRAM指針的增長方向,簡單說明就是控制像素的掃描方式。3、0X2A:用于設定列位址,也就是在從左到右從上到下的掃描方式下,設定x坐标。即用于設定x坐标的範圍。4、0X2B:與OX2A類似,該指令用于設定y坐标。需要說明的是在OX2A和OX2B的控制下就可以在螢幕上開窗顯示了。5、0X2C:該指令用于向GRAM中寫入顔色資料。6、0X2E:讀取GRAM中的顔色資料。
FSMC
一、簡介:
FSMC即靈活靜态存儲控制器,用于靜态存儲器的擴充。對于TFT-LCD顯示中将LCD當做一個SRAM來進行操作,下邊會有所介紹。
二、框圖結構:
對于FSMC的引腳已經在框圖中有所标注,對于下邊的存儲塊的圖是FSMC對其存儲器的管理方式,每個存儲塊大小為256M,由于LCD是要當做SRAM來處理的,那麼就要有存儲塊1的擴充來使得LCD工作。存儲塊1由28根位址線(HADDR[27:0])尋址,由于每個存儲塊分為四個區,HADDR[27:26]用于做相關區域選擇。注意:由于在這裡LCD作為一個16位寬的存儲器,而内部的存儲是以位元組為機關的,則需要HADDR[25:1]對應到FSMC[24:0],即相當于内部的存儲位址除以2(右移1位),進而與外部位址對應上。
三、相關寄存器:
1、FSMC_BCRx:SRAM/NOR閃存片選控制寄存器。
相關位:EXTMOD:控制是否允許讀寫使用不同的時序。WREN:寫使能。MWID[1:0]:設定資料總線寬。MTYP[1:0]:配置存儲器類型。MBKEN:存儲塊使能。
2、FSMC_BTRx:SRAM/NOR閃存片選時序寄存器。
相關位:ACCMOD[1:0]:設定通路模式。DATAST[7:0]:資料保持時間。ADDSET[3:0]:位址建立時間設定。
3、FSMC_BWTRx:SRAM/NOR閃存寫時序控制器。
相位位同FSMC_BTRx對應位相同。
TFT-LCD顯示部分代碼參考
一、LCD位址結構體分析
//LCD位址結構體
typedef struct
{
u16 LCD_REG;
u16 LCD_RAM;
} LCD_TypeDef;
//使用NOR/SRAM的 Bank1.sector4,位址位HADDR[27,26]=11 A6作為資料指令區分線
//注意設定時STM32内部會右移一位對其! 111 1110=0X7E
#define LCD_BASE ((u32)(0x6C000000 | 0x0000007E))
#define LCD ((LCD_TypeDef *) LCD_BASE)
由于存儲塊1的第4區的起始位址為0X6C000000,又由于A6作為資料和指令的區分線,根據代碼可得:LCD是将LCD_BASE位址經過強制類型轉換,裝換為結構體類型,由此知:LCD_REG表示的為寫指令位址,LCD_RAM表示為寫資料位址。
二、LCD重要參數結構體
//LCD重要參數集
typedef struct
{
u16 width; //LCD 寬度
u16 height; //LCD 高度
u16 id; //LCD ID
u8 dir; //橫屏還是豎屏控制:0,豎屏;1,橫屏。
u16 wramcmd; //開始寫gram指令
u16 setxcmd; //設定x坐标指令
u16 setycmd; //設定y坐标指令
}_lcd_dev;
三、讀寫寄存器或資料函數(底層接口函數)
//寫寄存器函數
//regval:寄存器值
void LCD_WR_REG(vu16 regval)
{
regval=regval; //使用-O2優化的時候,必須插入的延時
LCD->LCD_REG=regval; //寫入要寫的寄存器序号
}
//寫LCD資料
//data:要寫入的值
void LCD_WR_DATA(vu16 data)
{
data=data; //使用-O2優化的時候,必須插入的延時
LCD->LCD_RAM=data;
}
//讀LCD資料
//傳回值:讀到的值
u16 LCD_RD_DATA(void)
{
vu16 ram; //防止被優化
ram=LCD->LCD_RAM;
return ram;
}
//寫寄存器
//LCD_Reg:寄存器位址
//LCD_RegValue:要寫入的資料
void LCD_WriteReg(u16 LCD_Reg,u16 LCD_RegValue)
{
LCD->LCD_REG = LCD_Reg; //寫入要寫的寄存器序号
LCD->LCD_RAM = LCD_RegValue;//寫入資料
}
//讀寄存器
//LCD_Reg:寄存器位址
//傳回值:讀到的資料
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
}
四、設定坐标(根據不同的晶片選擇不同的設定方式)
//設定光标位置
//Xpos:橫坐标
//Ypos:縱坐标
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==0X6804)
{
if(lcddev.dir==1)Xpos=lcddev.width-1-Xpos;//橫屏時處理
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坐标需要變換
{
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);
}else
{
if(lcddev.dir==1)Xpos=lcddev.width-1-Xpos;//橫屏其實就是調轉x,y坐标
LCD_WriteReg(lcddev.setxcmd, Xpos);
LCD_WriteReg(lcddev.setycmd, Ypos);
}
}
五、畫點函數
//畫點
//x,y:坐标
//POINT_COLOR:此點的顔色
void LCD_DrawPoint(u16 x,u16 y)
{
LCD_SetCursor(x,y); //設定光标位置
LCD_WriteRAM_Prepare(); //開始寫入GRAM
LCD->LCD_RAM=POINT_COLOR;
}
//快速畫點
//x,y:坐标
//color:顔色
void LCD_Fast_DrawPoint(u16 x,u16 y,u16 color)
{
if(lcddev.id==0X9341||lcddev.id==0X5310)
{
LCD_WR_REG(lcddev.setxcmd);
LCD_WR_DATA(x>>8);LCD_WR_DATA(x&0XFF);
LCD_WR_REG(lcddev.setycmd);
LCD_WR_DATA(y>>8);LCD_WR_DATA(y&0XFF);
}else if(lcddev.id==0X5510)
{
LCD_WR_REG(lcddev.setxcmd);LCD_WR_DATA(x>>8);
LCD_WR_REG(lcddev.setxcmd+1);LCD_WR_DATA(x&0XFF);
LCD_WR_REG(lcddev.setycmd);LCD_WR_DATA(y>>8);
LCD_WR_REG(lcddev.setycmd+1);LCD_WR_DATA(y&0XFF);
}else if(lcddev.id==0X1963)
{
if(lcddev.dir==0)x=lcddev.width-1-x;
LCD_WR_REG(lcddev.setxcmd);
LCD_WR_DATA(x>>8);LCD_WR_DATA(x&0XFF);
LCD_WR_DATA(x>>8);LCD_WR_DATA(x&0XFF);
LCD_WR_REG(lcddev.setycmd);
LCD_WR_DATA(y>>8);LCD_WR_DATA(y&0XFF);
LCD_WR_DATA(y>>8);LCD_WR_DATA(y&0XFF);
}else if(lcddev.id==0X6804)
{
if(lcddev.dir==1)x=lcddev.width-1-x;//橫屏時處理
LCD_WR_REG(lcddev.setxcmd);
LCD_WR_DATA(x>>8);LCD_WR_DATA(x&0XFF);
LCD_WR_REG(lcddev.setycmd);
LCD_WR_DATA(y>>8);LCD_WR_DATA(y&0XFF);
}else
{
if(lcddev.dir==1)x=lcddev.width-1-x;//橫屏其實就是調轉x,y坐标
LCD_WriteReg(lcddev.setxcmd,x);
LCD_WriteReg(lcddev.setycmd,y);
}
LCD->LCD_REG=lcddev.wramcmd;
LCD->LCD_RAM=color;
}
兩個函數一個是調用函數,一個是直接快速設定。功能相同。
六、讀點函數
//讀取個某點的顔色值
//x,y:坐标
//傳回值:此點的顔色
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==0X6804||lcddev.id==0X5310||lcddev.id==0X1963)LCD_WR_REG(0X2E);//9341/6804/3510/1963 發送讀GRAM指令
else if(lcddev.id==0X5510)LCD_WR_REG(0X2E00); //5510 發送讀GRAM指令
else LCD_WR_REG(0X22); //其他IC發送讀GRAM指令
if(lcddev.id==0X9320)opt_delay(2); //FOR 9320,延時2us
r=LCD_RD_DATA(); //dummy Read
if(lcddev.id==0X1963)return r; //1963直接讀就可以
opt_delay(2);
r=LCD_RD_DATA(); //實際坐标顔色
if(lcddev.id==0X9341||lcddev.id==0X5310||lcddev.id==0X5510) //9341/NT35310/NT35510要分2次讀出
{
opt_delay(2);
b=LCD_RD_DATA();
g=r&0XFF; //對于9341/5310/5510,第一次讀取的是RG的值,R在前,G在後,各占8位
g<<=8;
}
if(lcddev.id==0X9325||lcddev.id==0X4535||lcddev.id==0X4531||lcddev.id==0XB505||lcddev.id==0XC505)return r; //這幾種IC直接傳回顔色值
else if(lcddev.id==0X9341||lcddev.id==0X5310||lcddev.id==0X5510)return (((r>>11)<<11)|((g>>10)<<5)|(b>>11));//ILI9341/NT35310/NT35510需要公式轉換一下
else return LCD_BGR2RGB(r); //其他IC
}
這是TFT-LCD顯示基本的一些函數,這是有關TFT-LCD的初步認識,後邊還會繼續學習和認識有關其操作和應用。