一、常見(jiàn)顯示器類(lèi)型介紹
顯示器屬于輸出設(shè)備,它是一種將特定電子信息輸出到屏幕上再反射到人眼的顯示工具。常見(jiàn)顯示器有三類(lèi):CRT顯示器、LCD液晶顯示器和LED點(diǎn)陣顯示器。
CRT顯示器:CRT顯示器是靠電子束激發(fā)屏幕內(nèi)表面的熒光粉來(lái)顯示圖像的,由于熒光粉被點(diǎn)亮后很快會(huì)熄滅,所以電子槍必須循環(huán)地不斷激發(fā)這些點(diǎn)。
LCD顯示器:液晶顯示器,簡(jiǎn)稱 LCD(Liquid Crystal Display),相對(duì)于上一代 CRT顯示器,LCD 顯示器具有功耗低、體積小、承載的信息量大及不傷眼的優(yōu)點(diǎn),因而它成為了現(xiàn)在的主流電子顯示設(shè)備,其中包括電視、電腦顯示器、手機(jī)屏幕及各種嵌入式設(shè)備的顯示器。
液晶是一種介于固體和液體之間的特殊物質(zhì),它是一種有機(jī)化合物,常態(tài)下呈液態(tài),但是它的分子排列卻和固體晶體一樣非常規(guī)則,因此取名液晶。如果給液晶施加電場(chǎng),會(huì)改變它的分子排列,從而改變光線的傳播方向,配合偏振光片,它就具有控制光線透過(guò)率的作用,再配合彩色濾光片,改變加給液晶電壓大小,就能改變某一顏色透光量的多少。利用這種原理,做出可控紅、綠、藍(lán)光輸出強(qiáng)度的顯示結(jié)構(gòu),把三種顯示結(jié)構(gòu)組成一個(gè)顯示單位,通過(guò)控制紅綠藍(lán)的強(qiáng)度,可以使該單位混合輸出不同的色彩,這樣的一個(gè)顯示單位被稱為像素。注意: 液晶本身是不發(fā)光的,所以需要有一個(gè)背光燈提供光源。
LED顯示器:LED點(diǎn)陣彩色顯示器的單個(gè)像素點(diǎn)內(nèi)包含紅綠藍(lán)三色LED燈,通過(guò)控制紅綠藍(lán)顏色的強(qiáng)度進(jìn)行混色,實(shí)現(xiàn)全彩顏色輸出,多個(gè)像素點(diǎn)構(gòu)成一個(gè)屏幕。由于每個(gè)像素點(diǎn)都是LED燈自發(fā)光的,所以在戶外白天也顯示得非常清晰,但由于LED燈體積較大,導(dǎo)致屏幕的像素密度低,所以它一般只適合用于廣場(chǎng)上的巨型顯示器。相對(duì)來(lái)說(shuō),單色的LED點(diǎn)陣顯示器應(yīng)用得更廣泛,如公交車(chē)上的信息展示牌、店廣告牌等。
OLED顯示器:新一代的OLED顯示器與LED點(diǎn)陣彩色顯示器的原理類(lèi)似,但由于它采用的像素單元是“有機(jī)發(fā)光二極管”(Organic Light Emitting Diode),所以像素密度比普通LED點(diǎn)陣顯示器高得多。OLED顯示器具有不需要背光源、對(duì)比度高、輕薄、視角廣及響應(yīng)速度快等優(yōu)點(diǎn)。待到生產(chǎn)工藝更加成熟時(shí),必將取代現(xiàn)在液晶顯示器的地位。
二、顯示器的基本參數(shù)
像素:是組成圖像的最基本單元要素,顯示器的像素指它成像最小的點(diǎn),即前面講解液晶原理中提到的一個(gè)顯示單元。
分辨率: 一些嵌入式設(shè)備的顯示器常常以“行像素值x列像素值”表示屏幕的分辨率。如分辨率800x480表示該顯示器的每一行有800個(gè)像素點(diǎn),每一列有480個(gè)像素點(diǎn),也可理解為有800列,480行。
色彩深度:指顯示器的每個(gè)像素點(diǎn)能表示多少種顏色,一般用“位”(bit)來(lái)表示。如單色屏的每個(gè)像素點(diǎn)能表示亮或滅兩種狀態(tài)(即實(shí)際上能顯示2種顏色),用1個(gè)數(shù)據(jù)位就可以表示像素點(diǎn)的所有狀態(tài),所以它的色彩深度為1bit,其它常見(jiàn)的顯示屏色深為16bit、24bit。
顯示器尺寸:顯示器的大小一般以英寸表示,如5英寸、21英寸、24英寸等,這個(gè)長(zhǎng)度是指屏幕對(duì)角線的長(zhǎng)度,通過(guò)顯示器的對(duì)角線長(zhǎng)度及長(zhǎng)寬比可確定顯示器的實(shí)際長(zhǎng)寬尺寸
顯存:液晶屏中的每個(gè)像素點(diǎn)都是數(shù)據(jù),在實(shí)際應(yīng)用中需要把每個(gè)像素點(diǎn)的數(shù)據(jù)緩存起來(lái),再傳輸給液晶屏,一般會(huì)使用 SRAM 或 SDRAM 性質(zhì)的存儲(chǔ)器,而這些專(zhuān)門(mén)用于存儲(chǔ)顯示數(shù)據(jù)的存儲(chǔ)器,則被稱為顯存。顯存一般至少要能存儲(chǔ)液晶屏的一幀顯示數(shù)據(jù)。
如分辨率為 800x480 的 液 晶 屏 使 用 RGB888 格 式 顯 示 , 它 的 一 幀 顯 示 數(shù) 據(jù) 大 小 為 :3(字節(jié))x800x480=1152000 字 節(jié) ;若 使 用 RGB565 格 式 顯 示 , 一 幀 顯 示 數(shù) 據(jù) 大 小 為 :2(字節(jié))x800x480=768000 字節(jié)。
一般來(lái)說(shuō),外置的液晶控制器會(huì)自帶顯存,而像 STM32F429等集成液晶控制器的芯片可使用內(nèi)部 SRAM或外擴(kuò) SDRAM用于顯存空間
三、TFT-LCD控制框圖
STM32F429 系列的芯片不需要額外的液晶控制器(可以理解為常規(guī)意義上的顯卡),也就是說(shuō)它把專(zhuān)用液晶控制器的功能集成到STM32F429芯片內(nèi)部了,可以理解為電腦的CPU集成顯卡。而 STM32F407 系列的芯片由于沒(méi)有集成液晶控制器到芯片內(nèi)部,所以它只能驅(qū)動(dòng)自帶控制器的屏幕,可以理解為電腦的外置顯卡。
帶有液晶控制器的顯示面板工作時(shí),STM32將數(shù)據(jù)寫(xiě)到LCD控制器的顯存里,LCD控制器將顯存中的數(shù)據(jù)渲染到顯示面板上進(jìn)行顯示。而不帶液晶控制器的面板,也就是MCU自集成了液晶控制器,MCU會(huì)在自己的內(nèi)存中開(kāi)辟一部分用作為液晶控制器的顯存。
四、TFT-LCD控制原理
TFT-LCD結(jié)構(gòu):完整的顯示屏由液晶顯示面板、電容觸摸面板以及 PCB底板構(gòu)成
1.液晶顯示面板:用于顯示圖像,文字的彩色顯示設(shè)備
2.觸摸面板:觸摸面板帶有觸摸控制芯片,該芯片處理觸摸信號(hào)并通過(guò)引出的信號(hào)線與外部器件通訊,觸摸面板中間是透明的,它貼在液晶面板上面,一起構(gòu)成屏幕的主體
3.PCB 底板:PCB 底板上可能會(huì)帶有“液晶控制器芯片”因?yàn)榭刂埔壕姘逍枰容^多的資源,所以大部分低級(jí)微控制器都不能直接控制液晶面板,需要額外配套一個(gè)專(zhuān)用液晶控制器來(lái)處理顯示過(guò)程,外部微控制器只要把它希望顯示的數(shù)據(jù)直接交給液晶控制器即可。而不帶液晶控制器的PCB底板,只有小部分的電源管理電路,液晶面板的信號(hào)線與外部微控制器相連,直接控制。
五、RGB-LCD控制原理
RGB信號(hào)線:RGB信號(hào)線各有8根,分別用于表示液晶屏一個(gè)像素點(diǎn)的紅、綠、藍(lán)顏色分量。使用紅綠藍(lán)顏色分量來(lái)表示顏色是一種通用的做法,打開(kāi)Windows系統(tǒng)自帶的畫(huà)板調(diào)色工具,可看到顏色的紅綠藍(lán)分量值,常見(jiàn)的顏色表示會(huì)在“RGB”后面附帶各個(gè)顏色分量值的數(shù)據(jù)位數(shù),如RGB565格式表示紅綠藍(lán)的數(shù)據(jù)線數(shù)分別為5、6、5根,一共為16個(gè)數(shù)據(jù)位,可表示216種顏色;如果液晶屏的種顏色分量的數(shù)據(jù)線有8根,那它表示RGB888格式,一共24位數(shù)據(jù)線,可表示的顏色為224種。
同步時(shí)鐘信號(hào)CLK:液晶屏與外部使用同步通訊方式,以CLK信號(hào)作為同步時(shí)鐘,在同步時(shí)鐘的驅(qū)動(dòng)下,每個(gè)時(shí)鐘傳輸一個(gè)像素點(diǎn)數(shù)據(jù)。
水平同步信號(hào)HSYNC:水平同步信號(hào)HSYNC(Horizontal Sync)用于表示液晶屏一行像素?cái)?shù)據(jù)的傳輸結(jié)束,每傳輸完成液晶屏的一行像素?cái)?shù)據(jù)時(shí),HSYNC會(huì)發(fā)生電平跳變,如分辨率為800x480的顯示屏(800列,480行),傳輸一幀的圖像HSYNC的電平會(huì)跳變480次。
垂直同步信號(hào)VSYNC:垂直同步信號(hào)VSYNC(Vertical Sync)用于表示液晶屏一幀像素?cái)?shù)據(jù)的傳輸結(jié)束,每傳輸完成一幀像素?cái)?shù)據(jù)時(shí),VSYNC會(huì)發(fā)生電平跳變。其中“幀”是圖像的單位,一幅圖像稱為一幀,在液晶屏中,一幀指一個(gè)完整屏液晶像素點(diǎn)。人們常常用“幀/秒”來(lái)表示液晶屏的刷新特性,即液晶屏每秒可以顯示多少幀圖像,如液晶屏以60幀/秒的速率運(yùn)行時(shí),VSYNC每秒鐘電平會(huì)跳變60次。
數(shù)據(jù)使能信號(hào)DE:數(shù)據(jù)使能信號(hào)DE(Data Enable)用于表示數(shù)據(jù)的有效性,當(dāng)DE信號(hào)線為高電平時(shí),RGB信號(hào)線表示的數(shù)據(jù)有效。
LCD數(shù)據(jù)傳輸時(shí)序
一個(gè)VSYNC(即一幀)包含若干個(gè)HSYNC(即若干行),而一個(gè)HSYNC包含若干個(gè)像素點(diǎn)(一個(gè)24位數(shù)據(jù))
液晶屏顯示的圖像可看作一個(gè)矩形,液晶屏有一個(gè)顯示指針,它指向?qū)⒁@示的像素。顯示指針的掃描方向方向從左到右、從上到下,一個(gè)像素點(diǎn)一個(gè)像素點(diǎn)地描繪圖形。這些像素點(diǎn)的數(shù)據(jù)通過(guò)RGB數(shù)據(jù)線傳輸至液晶屏,它們?cè)谕綍r(shí)鐘CLK的驅(qū)動(dòng)下一個(gè)一個(gè)地傳輸?shù)揭壕林?,交給顯示指針,傳輸完成一行時(shí),水平同步信號(hào)HSYNC電平跳變一次,而傳輸完一幀時(shí)VSYNC電平跳變一次。
液晶顯示指針在行與行之間,幀與幀之間切換時(shí)需要延時(shí),而且HSYNC及VSYNC信號(hào)本身也有寬度,這些時(shí)間參數(shù)說(shuō)明見(jiàn)下表:
六、SSD1963液晶控制器
液晶驅(qū)動(dòng)芯片或LCD驅(qū)動(dòng)器,其內(nèi)部有著較大的緩存空間可以存儲(chǔ)文字、圖像等數(shù)據(jù),并能夠?qū)⑦@些信息送入液晶模塊進(jìn)行顯示,由于專(zhuān)用的芯片,因此速度往往比較快。
LCD驅(qū)動(dòng)芯片的主要功能就是對(duì)主機(jī)發(fā)送過(guò)來(lái)的數(shù)據(jù)/命令,進(jìn)行變換,變成每個(gè)像素的RGB數(shù)據(jù),使之在屏幕上顯示出來(lái)。常見(jiàn)的液晶驅(qū)動(dòng)芯片有ILI932、ILI9328、SSD1963、HX8347、ILI9341、NT5510等。
SSD1963特性:內(nèi)部包含1215KB frame buffer(顯存)、支持分辨率為864*480的顯示屏、支持像素位深為24bpp的顯示模式(RGB888)。后面我們使用4.3寸TFT LCD真彩屏(分辨率480x272 )RGB565的方式進(jìn)行實(shí)驗(yàn)。
8080傳輸效率比SPI傳輸效率更高,因此管腳足夠的情況下采用8080時(shí)序
STM32與LCD電器連線圖如下:
8080時(shí)序-寫(xiě)數(shù)據(jù)/命令
//用GPIO管腳模擬8080時(shí)序
void LCD_WR_Byte(uint8_t dat, uint8_t cmd)
{
LCD_Data_Out(dat); //放入數(shù)據(jù)
if(cmd)
LCD_DC_Set(); //傳命令
else
LCD_DC_Clr(); //傳數(shù)據(jù)
LCD_CS_Clr(); //拉低片選
LCD_WR_Clr(); //寫(xiě)使能
LCD_WR_Set(); //WR產(chǎn)生上升沿,數(shù)據(jù)鎖存
LCD_CS_Set(); //取消片選
LCD_DC_Set(); //復(fù)位DC信號(hào)線
}
注:STM32通過(guò)8080接口與SSD1963 芯片進(jìn)行通訊,實(shí)現(xiàn)對(duì)液晶屏的控制。通訊的內(nèi)容主要包括命令和顯存數(shù)據(jù),顯存數(shù)據(jù)即各個(gè)像素點(diǎn)的RGB565內(nèi)容;命令是指對(duì)SSD1963的控制指令,MCU 可通過(guò)8080接口發(fā)送命令編碼控制 SSD1963的工作方式,例如復(fù)位指令、設(shè)置光標(biāo)指令、睡眠。
FSMC模擬8080時(shí)序
重要的時(shí)序參數(shù)如下:時(shí)間相對(duì)長(zhǎng)一點(diǎn),也不能過(guò)大,否則屏幕刷新時(shí)間就會(huì)變成長(zhǎng),視覺(jué)上表現(xiàn)卡頓。
對(duì)于FSMC和8080接口,前四種信號(hào)線都是完全一樣的,僅僅是FSMC的地址信號(hào)線A[25:0]與8080的數(shù)據(jù)/命令選擇線D/C#有區(qū)別。為了模擬出8080時(shí)序,我們可以把FSMC的A0地址線(選擇地址線的一條)與SSD1963芯片8080接口的D/C#信號(hào)線連接,那么當(dāng)A0為高電平時(shí)(即D/C#為高電平),數(shù)據(jù)線D[15:0]的信號(hào)會(huì)被SSD1963理解為數(shù)據(jù),若A0為低電平時(shí)(即D/C#為低電平),傳輸?shù)男盘?hào)則會(huì)被理解為命令。
關(guān)于如何讓控制A0電平的高低,首先要清楚,LCD控制器的片選連入到FSMC的NE4管腳。所以當(dāng)發(fā)出0x6C000000-0x6FFF FFFF之間的地址時(shí)NE4輸出低電平,選中LCD控制器,那么A0作為原來(lái)地址線的最低位,要調(diào)整地址使得A0為0。
可以看到顯示器在傳輸過(guò)程中并沒(méi)有高低字節(jié)控制的選項(xiàng)(在讀寫(xiě)SRAM的過(guò)程中,使用掩碼信號(hào)LB#與UB#指示要訪問(wèn)目標(biāo)地址的高、低字節(jié)部分),也就是說(shuō)液晶控制器(顯存)與MCU之間一次就要傳輸16位數(shù)據(jù)。
在實(shí)際控制時(shí),以上地址計(jì)算方式還不完整,根據(jù)《STM32 參考手冊(cè)》對(duì) FSMC 訪問(wèn)NOR FLASH (LCD讀寫(xiě)數(shù)據(jù)的方式與NOR FLASN幾乎是一樣的,都是16位,但是FSMC 訪問(wèn)NOR FLASH具有高低字節(jié)控制選項(xiàng))的說(shuō)明STM32 內(nèi)部訪問(wèn)地址時(shí)使用的是內(nèi)部 HADDR 總線, HADDR[25:0] 包含外部存儲(chǔ)器地址。由于 HADDR 為字節(jié)地址(一次傳輸8位),而存儲(chǔ)器按字尋址,所以根據(jù)存儲(chǔ)器數(shù)據(jù)寬度不同,實(shí)際向存儲(chǔ)器發(fā)送的地址也將有所不同,如下表所示。
因此發(fā)出一個(gè)地址后,只看第二低位。最低位表示一個(gè)字節(jié)的單位,而第二低位表示兩個(gè)字節(jié)的單位。讀者可類(lèi)比10進(jìn)制數(shù)取余,十進(jìn)制數(shù)的讀到最后一位表示幾個(gè)1,而讀到倒數(shù)第二位表示幾個(gè)10,這樣回到二進(jìn)制,讀到最后一位表示有幾個(gè)字節(jié),讀到第二低位表示有多少個(gè)字(2字節(jié),而又剛剛好對(duì)應(yīng)二進(jìn)制,沒(méi)有余數(shù))。
若讀者當(dāng)下理解困難可記住結(jié)論:發(fā)出一個(gè)地址后會(huì)自動(dòng)對(duì)該地址左移1位,就是真正的地址,如果還想保持原來(lái)的地址,在發(fā)地址之前先把地址右移。
0x6C000000 低電平表示命令
0x6C000002 高電平表示數(shù)據(jù)
LCD 測(cè)試
步驟:
1.配置RCC
2.配置FSMC
根據(jù)上圖進(jìn)行時(shí)序大小的設(shè)定,圖中單位是ns,(讀者需根據(jù)不同發(fā)開(kāi)發(fā)設(shè)備進(jìn)行調(diào)試,沒(méi)有固定值)
3.編程
//lcd.c
#include "lcd.h"
#include "font.h"
#include "stdlib.h"
#define MAX_HZ_POSX 480
#define MAX_HZ_POSY 227
#define LCD_RAM *(__IO uint16_t *) (0x6C000002) //數(shù)據(jù)寄存器
#define LCD_REG *(__IO uint16_t *) (0x6C000000)//指令寄存器
#define rw_data_prepare() write_cmd(34)
void write_cmd(unsigned short cmd);
unsigned short read_data(void);
unsigned short DeviceCode;
/*
*
*/
void write_cmd(unsigned short cmd)
{
LCD_REG = cmd;
}
unsigned short read_data(void)
{
unsigned short temp;
temp = LCD_RAM;
temp = LCD_RAM;
return temp;
}
void write_data(unsigned short data_code )
{
LCD_RAM = data_code;
}
void write_reg(unsigned char reg_addr,unsigned short reg_val)
{
write_cmd(reg_addr);
write_data(reg_val);
}
unsigned short read_reg(unsigned char reg_addr)
{
unsigned short val=0;
write_cmd(reg_addr);
val = read_data();
return (val);
}
void lcd_SetCursor(unsigned int x,unsigned int y)
{
write_reg(0x004e,x); /* 0-239 */
write_reg(0x004f,y); /* 0-319 */
}
/*讀取指定地址的GRAM */
static unsigned short lcd_read_gram(unsigned int x,unsigned int y)
{
unsigned short temp;
lcd_SetCursor(x,y);
rw_data_prepare();
/* dummy read */
temp = read_data();
temp = read_data();
return temp;
}
static void lcd_data_bus_test(void)
{
unsigned short temp1;
unsigned short temp2;
/* wirte */
lcd_SetCursor(0,0);
rw_data_prepare();
write_data(0x5555);
lcd_SetCursor(1,0);
rw_data_prepare();
write_data(0xAAAA);
/* read */
lcd_SetCursor(0,0);
temp1 = lcd_read_gram(0,0);
temp2 = lcd_read_gram(1,0);
if( (temp1 == 0x5555) && (temp2 == 0xAAAA) )
{
//printf(" data bus test pass!rn");
}
else
{
//printf(" data bus test error: %04X %04Xrn",temp1,temp2);
}
}
void lcd_clear(unsigned short Color)
{
unsigned int count;
write_cmd(0x002a); //發(fā)送列地址:起始-結(jié)束
write_data(0);
write_data(0);
write_data(HDP >?>8);
write_data(HDP&0x00ff);
write_cmd(0x002b); //發(fā)送行地址:起始-結(jié)束
write_data(0);
write_data(0);
write_data(VDP >?>8);
write_data(VDP&0x00ff);
write_cmd(0x002c);//寫(xiě)frame buffer命令
for(count=0;count< 130560;count++){
write_data(Color);
}
}
void lcd_init(void)
{
//GPIO_SetBits(GPIOF,GPIO_Pin_9);
HAL_Delay(50);
DeviceCode = read_reg(0x0000);
write_cmd(0x002b);
write_data(0);
HAL_Delay(50); // delay 50 ms
write_cmd(0x00E2);//PLL multiplier, set PLL clock to 120M
write_data(0x001D);//N=0x36 for 6.5M, 0x23 for 10M crystal
write_data(0x0002);
write_data(0x0004);
write_cmd(0x00E0);//PLL enable
write_data(0x0001);
HAL_Delay(10);
write_cmd(0x00E0);
write_data(0x0003);
HAL_Delay(12);
write_cmd(0x0001); //software reset
HAL_Delay(10);
write_cmd(0x00E6);//PLL setting for PCLK, depends on resolution
//LCD_WriteRAM(0x0001);
//LCD_WriteRAM(0x0033);
//LCD_WriteRAM(0x0032);
write_data(0x0000);
write_data(0x00D9);
write_data(0x0016);
write_cmd(0x00B0);//LCD SPECIFICATION
write_data(0x0020);
write_data(0x0000);
write_data((HDP >?>8)&0X00FF);//Set HDP
write_data(HDP&0X00FF);
write_data((VDP >?>8)&0X00FF);//Set VDP
write_data(VDP&0X00FF);
write_data(0x0000);
write_cmd(0x00B4);//HSYNC
write_data((HT >?>8)&0X00FF); //Set HT
write_data(HT&0X00FF);
write_data((HPS >?>8)&0X00FF);//Set HPS
write_data(HPS&0X00FF);
write_data(HPW);//Set HPW
write_data((LPS >?>8)&0X00FF); //Set HPS
write_data(LPS&0X00FF);
write_data(0x0000);
write_cmd(0x00B6);//VSYNC
write_data((VT >?>8)&0X00FF); //Set VT
write_data(VT&0X00FF);
write_data((VPS >?>8)&0X00FF); //Set VPS
write_data(VPS&0X00FF);
write_data(VPW);//Set VPW
write_data((FPS >?>8)&0X00FF);//Set FPS
write_data(FPS&0X00FF);
//=============================================
//=============================================
write_cmd(0x00BA);
write_data(0x0005); //0x000F); //GPIO[3:0] out 1
write_cmd(0x00B8);
write_data(0x0007); //GPIO3=input, GPIO[2:0]=output
write_data(0x0001); //GPIO0 normal
write_cmd(0x0036); //rotation
write_data(0x0000);
HAL_Delay(50);
write_cmd(0x00BE); //set PWM for B/L
write_data(0x0006);
write_data(0x0080);
write_data(0x0001);
write_data(0x00f0);
write_data(0x0000);
write_data(0x0000);
write_cmd(0x00d0);//設(shè)置動(dòng)態(tài)背光控制設(shè)置
write_data(0x000d);
write_cmd(0x00F0); //pixel data interface
write_data(0x0003);//03:16位 02:位?
write_cmd(0x0029); //display on
//lcd_data_bus_test();
lcd_clear(Yellow);//初始化全屏填充顏色
}
/*********************************************************************************************************
** Functoin name: LCD_SetCursor
** Descriptions: 設(shè)置做標(biāo)
** input paraments: Xpos、Ypos坐標(biāo)
** output paraments: 無(wú)
** Returned values: 無(wú)
*********************************************************************************************************/
void LCD_SetCursor(uint16_t Xpos, uint16_t Ypos)
{
write_cmd(0x002A);
write_data(Xpos >?>8);
write_data(Xpos&0x00ff);
write_data(479 >?>8);
write_data(479&0x00ff);
write_cmd(0x002b);
write_data(Ypos >?>8);
write_data(Ypos&0x00ff);
write_data(271 >?>8);
write_data(271&0x00ff);
}
/*********************************************************************************************************
** Functoin name: LCD_DrawPoint
** Descriptions: 畫(huà)點(diǎn)
** input paraments: x.y:畫(huà)點(diǎn)的坐標(biāo)
color:顏色
** output paraments: 無(wú)
** Returned values: 無(wú)
*********************************************************************************************************/
void LCD_DrawPoint(uint16_t xsta, uint16_t ysta, uint16_t color)
{
LCD_SetCursor(xsta, ysta); /*設(shè)置光標(biāo)位置 */
write_data_Prepare(); /*開(kāi)始寫(xiě)入GRAM */
write_data(color);
}
/**
*名稱:void WriteOneHz(uint16_t x0, uint16_t y0, uint8_t *pucMsk, uint16_t PenColor, uint16_t BackColor)
*參數(shù):x0,y0起始坐標(biāo)
*pucMsk 指向
PenColor 字符顏色
BackColor 背景顏色
*功能:
*備注:此函數(shù)不能單獨(dú)作為漢字字符顯示
**/
void WriteOneHz(uint16_t x0, uint16_t y0, uint8_t *pucMsk, uint16_t PenColor, uint16_t BackColor)
{
uint16_t i,j;
uint16_t mod[16]; /* 當(dāng)前字模 16*16 */
uint8_t *pusMsk; /* 當(dāng)前字庫(kù)地址 */
uint16_t y;
pusMsk = pucMsk;
for(i=0; i< 16; i++) /*保存當(dāng)前漢字點(diǎn)陣字模式 */
{
mod[i] = (*pusMsk < < 8) | (*(pusMsk + 1)); /*取得當(dāng)前字模,合并為半字對(duì)齊訪問(wèn) */
pusMsk = pusMsk+2;
}
y = y0;
for(i=0; i< 16; i++) /* 16行 */
{
for(j=0; j< 16; j++) /* 16列 */
{
if((mod[i] < < j) & 0x8000) /* 顯示第1行,共16個(gè)點(diǎn)*/
{
LCD_DrawPoint(x0+j, y0+i, PenColor);
}
else
{
LCD_DrawPoint(x0+j, y0+i, BackColor);
}
}
y++;
}
}
/**
*名稱: uint16_t findHzIndex(uint8_t *hz)
*參數(shù):hz
*功能:索引漢字存儲(chǔ)的內(nèi)存地址
*備注
**/
uint16_t findHzIndex(uint8_t *hz) /* 在自定義漢字庫(kù)查找要顯示的漢字的位置 */
{
uint16_t i=0;
FNT_GB16 *ptGb16 = (FNT_GB16 *)GBHZ_16;/*ptGb16指向BHZ_16*/
while(ptGb16[i].Index[0] > 0x80)
{
if ((*hz == ptGb16[i].Index[0]) && (*(hz+1) == ptGb16[i].Index[1]))
/*漢字用兩位來(lái)表示地址碼*/
{
return i;
}
i++;
if(i > (sizeof((FNT_GB16 *)GBHZ_16) / sizeof(FNT_GB16) - 1)) /*搜索下標(biāo)約束*/
{
break;
}
}
return 0;
}
/**
*名稱:void LCD_ShowHzString(uint16_t x0, uint16_t y0, uint8_t *pcStr, uint16_t PenColor, uint16_t BackColor)
*參數(shù):x0,y0 起始坐標(biāo)
pcStr 指向
PenColor 字體顏色
BackColor 字體背景
*功能:顯示漢字字符串
*備注:這個(gè)函數(shù)不能單獨(dú)調(diào)用
**/
void LCD_ShowHzString(uint16_t x0, uint16_t y0, uint8_t *pcStr, uint16_t PenColor, uint16_t BackColor)
{
uint16_t usIndex;
uint8_t size = 16;
FNT_GB16 *ptGb16 = 0;
ptGb16 = (FNT_GB16 *)GBHZ_16;
if(x0 >MAX_HZ_POSX){x0=0;y0+=size;}/*超出x軸字體最小單位,換行*/
if(y0 >MAX_HZ_POSY){y0=x0=0;lcd_clear(White);} /*超出r軸字體最小單位,回到原點(diǎn),并且清屏*/
usIndex = findHzIndex(pcStr);
WriteOneHz(x0, y0, (uint8_t *)&(ptGb16[usIndex].Msk[0]), PenColor, BackColor); /* 顯示字符*/
}
/**
*名稱:void LCD_ShowChar(uint8_t x, uint16_t y, uint8_t num, uint8_t size, uint16_t PenColor, uint16_t BackColor)
*參數(shù):x,y 起始坐標(biāo)x:0~234 y:0~308£?
num 字符AsCII碼值
size 字符大小,使用默認(rèn)8*16
PenColor 字體顏色
BackColor 字體背景顏色
*功能:
*備注:注意屏幕大小
**/
void LCD_ShowChar(uint16_t x, uint16_t y, uint8_t num, uint8_t size, uint16_t PenColor, uint16_t BackColor)
{
#define MAX_CHAR_POSX (272-8)
#define MAX_CHAR_POSY (480-16)
uint8_t temp;
uint8_t pos,t;
if(x >MAX_CHAR_POSX||y >MAX_CHAR_POSY)return;
num=num-' '; /*得到偏移后的值*/
for(pos=0;pos< size;pos++)
{
if(size==12)
temp=asc2_1206[num][pos];/*調(diào)用1206字體*/
else
temp=asc2_1608[num][pos];/*調(diào)用1608字體*/
for(t=0;t< size/2;t++)
{
if(temp&0x01) /*從低位開(kāi)始*/
{
LCD_DrawPoint(x+t, y+pos, PenColor); /*畫(huà)字體顏色,一個(gè)點(diǎn)*/
}
else
LCD_DrawPoint(x+t, y+pos, BackColor);/*畫(huà)背景顏色,一個(gè)點(diǎn)*/
temp > >=1;
}
}
}
/**
名稱:void LCD_ShowCharString(uint16_t x, uint16_t y, const uint8_t *p, uint16_t PenColor, uint16_t BackColor)
參數(shù):x,y 起始坐標(biāo)
p 指向字符串起始地址·
PenColor 字符顏色
BackColor 背景顏色
功能:
備注:用16字體,可以調(diào)節(jié) 此函數(shù)不能單獨(dú)調(diào)用
**/
void LCD_ShowCharString(uint16_t x, uint16_t y, const uint8_t *p, uint16_t PenColor, uint16_t BackColor)
{
uint8_t size = 16; /*---字符大小默認(rèn)16*8---*/
if(x >MAX_HZ_POSX){x=0;y+=size;}/*超出x軸字體最小單位,換行*/
if(y >MAX_HZ_POSY){y=x=0;lcd_clear(White);} /*超出y軸字體最小單位,回到原點(diǎn),并且清屏*/
LCD_ShowChar(x, y, *p, size, PenColor, BackColor);/*0表示非疊加方式*/
}
/**
*名稱:ovoid LCD_ShowString(uint16_t x0, uint16_t y0, uint8_t *pcstr, uint16_t PenColor, uint16_t BackColor)
*參數(shù):x,y 起始坐標(biāo)
pcstr 字符串指針
PenColor 字符顏色
BackColor 背景顏色
*功能:調(diào)用字符串和漢字顯示函數(shù),實(shí)現(xiàn)字符串顯示
*備注
**/
void LCD_ShowString(uint16_t x0, uint16_t y0, uint8_t *pcStr, uint16_t PenColor, uint16_t BackColor)
{
while(*pcStr!='?')
{
if(*pcStr >0x80) /*顯示漢字*/
{
LCD_ShowHzString(x0, y0, pcStr, PenColor, BackColor);
pcStr += 2;
x0 += 16;
}
else /*顯示字符*/
{
LCD_ShowCharString(x0, y0, pcStr, PenColor, BackColor);
pcStr +=1;
x0+= 8;
}
}
}
//
///*********************************************************************************************************
//** Functoin name: write_data_Prepare
//** Descriptions: 寫(xiě)數(shù)據(jù)開(kāi)始
//** input paraments: 無(wú)
//** output paraments: 無(wú)
//** Returned values: 無(wú)
//*********************************************************************************************************/
void write_data_Prepare(void)
{
write_cmd(0x002C);
}
/*********************************************************************************************************
** Functoin name: LCD_WindowMax
** Descriptions: 設(shè)置窗口
** input paraments: 窗口的位置
** output paraments: 無(wú)
** Returned values: 無(wú)
*********************************************************************************************************/
void LCD_WindowMax (unsigned int xsta,unsigned int xend, unsigned int ysta,unsigned int yend)
{
write_cmd(0X002A);
write_data(xsta >?>8);
write_data(xsta&0X00FF);
write_data(xend >?>8);
write_data(xend&0X00FF);
write_cmd(0X002B);
write_data(ysta >?>8);
write_data(ysta&0X00FF);
write_data(yend >?>8);
write_data(yend&0X00FF);
}
/*********************************************************************************************************
** Functoin name: LCD_Fill
** Descriptions: 填充窗口
** input paraments: 窗口的位置
colour£: 顏色
** output paraments: 無(wú)
** Returned values: 無(wú)
*********************************************************************************************************/
void LCD_Fill(uint16_t xsta, uint16_t xend, uint16_t ysta, uint16_t yend, uint16_t colour)
{
uint32_t n;
/*設(shè)置窗口*/
LCD_WindowMax (xsta, xend, ysta, yend);
write_data_Prepare(); /*開(kāi)始寫(xiě)入GRAM*/
n=(uint32_t)(yend-ysta+1)*(xend-xsta+1);
while(n--){write_data(colour);} /*顯示所填充的顏色*/
}
/*********************************************************************************************************
** Functoin name: LCD_DrawLine
** Descriptions: 指定坐標(biāo)(兩點(diǎn))畫(huà)線
** input paraments: xsta X起始坐標(biāo)
ysta Y起始坐標(biāo)
xend X終點(diǎn)坐標(biāo)
yend Y終點(diǎn)坐標(biāo)
colour顏色
** output paraments: 無(wú)
** Returned values: 無(wú)
*********************************************************************************************************/
void LCD_DrawLine(uint16_t xsta, uint16_t xend, uint16_t ysta,uint16_t yend, uint16_t color)
{
uint16_t x, y, t;
if((xsta==xend)&&(ysta==yend))
LCD_DrawPoint(xsta, ysta, color);
else
if(abs(yend-ysta) >abs(xend-xsta))//斜率大于1
{
if(ysta >yend)
{
t=ysta;
ysta=yend;
yend=t;
t=xsta;
xsta=xend;
xend=t;
}
for(y=ysta;y< yend;y++) /*以y軸為基準(zhǔn)*/
{
x=(uint32_t)(y-ysta)*(xend-xsta)/(yend-ysta)+xsta;
LCD_DrawPoint(x, y, color);
}
}
else /*斜率小于等于1*/
{
if(xsta >xend)
{
t=ysta;
ysta=yend;
yend=t;
t=xsta;
xsta=xend;
xend=t;
}
for(x=xsta;x<=xend;x++) /*以x軸為基準(zhǔn)/
{
y =(uint32_t)(x-xsta)*(yend-ysta)/(xend-xsta)+ysta;
LCD_DrawPoint(x, y, color);
}
}
}
/**
*名稱:void Draw_Circle(uint16_t x0, uint16_t y0, uint8_t r)
*參數(shù):x0 中心點(diǎn)橫坐標(biāo)
y0 中心點(diǎn)縱坐標(biāo)
r 半徑
*返回:無(wú)
*功能:在指定位置畫(huà)一個(gè)指定大小的圓
*備注:加入顏色參數(shù),是否填充等
**/
void Draw_Circle(uint16_t x0, uint16_t y0, uint8_t r, uint16_t color)
{
int a,b;
int di;
a=0;b=r;
di=3-(r< 1); /*判斷下個(gè)點(diǎn)位置標(biāo)志*/
while(a<=b)
{
LCD_DrawPoint(x0-b, y0-a, color); //3
LCD_DrawPoint(x0+b, y0-a, color); //0
LCD_DrawPoint(x0-a, y0+b, color); //1
LCD_DrawPoint(x0-b, y0-a, color); //7
LCD_DrawPoint(x0-a, y0-b, color); //2
LCD_DrawPoint(x0+b, y0+a, color); //4
LCD_DrawPoint(x0+a, y0-b, color); //5
LCD_DrawPoint(x0+a, y0+b, color); //6
LCD_DrawPoint(x0-b, y0+a, color);
a++;
/*使用Bresenham算法畫(huà)圓*/
if(di< 0)di +=4*a+6;
else
{
di+=10+4*(a-b);
b--;
}
LCD_DrawPoint(x0+a, y0+b, color);
}
}
/**
*名稱:void LCD_DrawRectangle(uint16_t xsta, uint16_t ysta, uint16_t xend, uint16_t yend)
*參數(shù):xsta x起始坐標(biāo)
ysta Y起始坐標(biāo)
xend x結(jié)束坐標(biāo)
yend Y結(jié)束坐標(biāo)
*返回:無(wú)
*功能:在指定區(qū)域畫(huà)矩形
*備注:
**/
void LCD_DrawRectangle(uint16_t xsta, uint16_t xend, uint16_t ysta,uint16_t yend, uint16_t color)
{
LCD_DrawLine(xsta, xend, ysta, ysta, color);
LCD_DrawLine(xsta, xsta, ysta, yend, color);
LCD_DrawLine(xsta, xend, yend, yend, color);
LCD_DrawLine(xend, xend, ysta, yend, color);
}
/****************************************************************************
*名稱:void LCD_DrawPicture(uint16_t StartX,uint16_t StartY,uint16_t EndX,uint16_t EndY,uint16_t *pic)
*功能:在指定座標(biāo)范圍顯示一副圖片
*入口參數(shù):StartX 行起始坐標(biāo)
* EndX 行結(jié)束坐標(biāo)
* StartY 列起始坐標(biāo)
* EndY 列結(jié)束坐標(biāo)
pic 圖片頭指針
* 出口參數(shù):無(wú)
* 說(shuō) 明:圖片取模格式為水平掃描,16位顏色模式
* 調(diào)用方法:oLCD_DrawPicture(0,0,100,100,(uint16_t*)demo);
****************************************************************************/
void LCD_DrawPicture(uint16_t StartX,uint16_t Xend,uint16_t StartY,uint16_t Yend,uint8_t *pic)
{
staticuint16_t i=0,j=0;
uint16_t *bitmap = (uint16_t *)pic;
for(j=0; j< Yend-StartY; j++)
{
for(i=0; i< Xend-StartX; i++)
LCD_DrawPoint(StartX+i, StartY+j, *bitmap++);
}
}
評(píng)論