1. 程式人生 > >LCD1602顯示屏的驅動設定及例程

LCD1602顯示屏的驅動設定及例程

一般來說,LCD1602有16條引腳,據說還有14條引腳的,與16腳的相比缺少了背光電源A(15腳)和地線K(16腳)。我手裡這塊LCD1602的型號是HJ1602A,是繪晶科技公司的產品,它有16條引腳。如圖1所示:



圖1

再來一張它的背面的,如圖2所示:



圖2

它的16條引腳定義如下:

引腳號

符號

引腳說明

引腳號

符號

引腳說明

1

VSS

電源地

9

D2

資料埠

2

VDD

電源正極

10

D3

資料埠

3

VO

偏壓訊號

11

D4

資料埠

4

RS

命令/資料

12

D5

資料埠

5

RW

讀/寫

13

D6

資料埠

6

E

使能

14

D7

資料埠

7

D0

資料埠

15

A

背光正極

8

D1

資料埠

16

K

背光負極

對這個表的說明:

1.    VSS接電源地。

2.    VDD接+5V。

3.    VO是液晶顯示的偏壓訊號,可接10K的3296精密電位器。或同樣阻值的RM065/RM063藍白可調電阻。見圖3。


圖3

4.    RS是命令/資料選擇引腳,接微控制器的一個I/O,當RS為低電平時,選擇命令;當RS為高電平時,選擇資料。

5.    RW是讀/寫選擇引腳,接微控制器的一個I/O,當RW為低電平時,向LCD1602寫入命令或資料;當RW為高電平時,從LCD1602讀取狀態或資料。如果不需要進行讀取操作,可以直接將其接VSS。

6.    E,執行命令的使能引腳,接微控制器的一個I/O。

7.    D0—D7,並行資料輸入/輸出引腳,可接微控制器的P0—P3任意的8個I/O口。如果接P0口,P0口應該接4.7K—10K的上拉電阻。如果是4線並行驅動,只須接4個I/O口。

8.    A背光正極,可接一個10—47歐的限流電阻到VDD。

9.    K背光負極,接VSS。見圖4所示。


圖4

二.基本操作

LCD1602的基本操作分為四種:

1.    讀狀態:輸入RS=0,RW=1,E=高脈衝。輸出:D0—D7為狀態字。

2.    讀資料:輸入RS=1,RW=1,E=高脈衝。輸出:D0—D7為資料。

3.    寫命令:輸入RS=0,RW=0,E=高脈衝。輸出:無。

4.    寫資料:輸入RS=1,RW=0,E=高脈衝。輸出:無。

讀操作時序圖(如圖5):


 圖5

寫操作時序圖(如圖6):


圖6

時序時間引數(如圖7):


圖7

三.DDRAM、CGROM和CGRAM

DDRAM(Display Data RAM)就是顯示資料RAM,用來寄存待顯示的字元程式碼。共80個位元組,其地址和螢幕的對應關係如下(如圖8):


 圖8

DDRAM相當於計算機的視訊記憶體,我們為了在螢幕上顯示字元,就把字元程式碼送入視訊記憶體,這樣該字元就可以顯示在螢幕上了。同樣LCD1602共有80個位元組的視訊記憶體,即DDRAM。但LCD1602的顯示螢幕只有16×2大小,因此,並不是所有寫入DDRAM的字元程式碼都能在螢幕上顯示出來,只有寫在上圖所示範圍內的字元才可以顯示出來,寫在範圍外的字元不能顯示出來。這樣,我們在程式中可以利用下面的“游標或顯示移動指令”使字元慢慢移動到可見的顯示範圍內,看到字元的移動效果。

前面說了,為了在液晶螢幕上顯示字元,就把字元程式碼送入DDRAM。例如,如果想在螢幕左上角顯示字元‘A’,那麼就把字元‘A’的字元程式碼41H寫入DDRAM的00H地址處即可。至於怎麼寫入,後面會有說明。那麼為什麼把字元程式碼寫入DDRAM,就可以在相應位置顯示這個程式碼的字元呢?我們知道,LCD1602是一種字元點陣顯示器,為了顯示一種字元的字形,必須要有這個字元的字模資料,什麼叫字元的字模資料,看看下面的這個圖就明白了(如圖9)。


圖9

上圖的左邊就是字元‘A’的字模資料,右邊就是將左邊資料用“○”代表0,用“■”代表1。從而顯示出‘A’這個字形。從下面的圖可以看出,字元‘A’的高4位是0100,低4位是0001,合在一起就是01000001b,即41H。它恰好與該字元的ASCII碼一致,這樣就給了我們很大的方便,我們可以在PC上使用P2=‘A’這樣的語法。編譯後,正好是這個字元的字元程式碼。

在LCD1602模組上固化了字模儲存器,就是CGROM和CGRAM,HD44780內建了192個常用字元的字模,存於字元產生器CGROM(Character Generator ROM)中,另外還有8個允許使用者自定義的字元產生RAM,稱為CGRAM(Character Generator RAM)。下圖(如圖12)說明了CGROM和CGRAM與字元的對應關係。從ROM和RAM的名字我們也可以知道,ROM是早已固化在LCD1602模組中的,只能讀取;而RAM是可讀寫的。也就是說,如果只需要在螢幕上顯示已存在於CGROM中的字元,那麼只須在DDRAM中寫入它的字元程式碼就可以了;但如果要顯示CGROM中沒有的字元,比如攝氏溫標的符號,那麼就只有先在CGRAM中定義,然後再在DDRAM中寫入這個自定義字元的字元程式碼即可。和CGROM中固化的字元不同,CGRAM中本身沒有字元,所以要在DDRAM中寫入某個CGROM不存在的字元,必須在CGRAM中先定義後使用。程式退出後CGRAM中定義的字元也不復存在,下次使用時,必須重新定義。


圖10

上面這個圖(如圖10)說明的是5×8點陣和5×10點陣字元的字形和游標的位置。先來說5×8點陣,它有8行5列。那麼定義這樣一個字元需要8個位元組,每個位元組的前3個位沒有被使用。例如,定義攝氏溫標的符號{0x10,0x06,0x09,0x08,0x08,0x09,0x06,0x00}。


 圖11

上面這個圖(如圖11)說明的是設定CGRAM地址指令。從這個指令的格式中我們可以看出,它共有aaaaaa這6位,一共可以表示64個地址,即64個位元組。一個5×8點陣字元共佔用8個位元組,那麼這64個位元組一共可以自定義8個字元。也就是說,上面這個圖的6位地址中的DB5DB4DB3用來表示8個自定義的字元,DB2DB1DB0用來表示每個字元的8個位元組。這DB5DB4DB3所表示的8個自定義字元(0--7)就是要寫入DDRAM中的字元程式碼。我們知道,在CGRAM中只能定義8個自定義字元,也就是隻有0—7這8個字元程式碼,但在下面的這個表(如圖12)中一共有16個字元程式碼(××××0000b--××××1111b)。實際上,如圖所示,它只能表示8個自定義字元 (××××0000b=××××1000b, ××××0001b=××××1001b……依次類推)。也就是說,寫入DDRAM中的字元程式碼0和字元程式碼8是同一個自定義字元。 5×10點陣每個字元共佔用16個位元組的空間,所以CGRAM中只能定義4個這樣的自定義字元。

那麼如何在CGRAM中自定義字元呢?在上面的介紹中,我們知道有一個設定CGRAM地址指令,同寫DDRAM指令相似,只須設定好某個自定義字元的字模資料,然後按照上面介紹的方法,設定好CGRAM地址,依次寫入這個字模資料即可。我們在後面的例子中再進行說明。


 圖12

四.LCD1602指令

1.工作方式設定指令(如圖13)


 圖13

×:不關心,也就是說這個位是0或1都可以,一般取0。

DL:設定資料介面位數。

DL=1:8位資料介面(D7—D0)。

DL=0:4位資料介面(D7—D4)。

N=0:一行顯示。

N=1:兩行顯示。

F=0:5×8點陣字元。

F=1:5×10點陣字元。

說明:因為是寫指令字,所以RS和RW都是0。LCD1602只能用並行方式驅動,不能用序列方式驅動。而並行方式又可以選擇8位資料介面或4位資料介面。這裡我們選擇8位資料介面(D7—D0)。我們的設定是8位資料介面,兩行顯示,5×8點陣,即0b00111000也就是0x38。(注意:NF是10或11的效果是一樣的,都是兩行5×8點陣。因為它不能以兩行5×10點陣方式進行顯示,換句話說,這裡用0x38或0x3c是一樣的)。

2.顯示開關控制指令(如圖14)


圖14

D=1:顯示開,D=0:顯示關。

C=1:游標顯示,C=0:游標不顯示。

B=1:游標閃爍,B=0:游標不閃爍。

說明:這裡的設定是顯示開,不顯示游標,游標不閃爍,設定字為0x0c。

3.進入模式設定指令(如圖15、16)


圖15

I/D=1:寫入新資料後游標右移。

I/D=0:寫入新資料後游標左移。

S=1:顯示移動。

S=0:顯示不移動。


 圖16

說明:這裡的設定是0x06。

4.游標或顯示移動指令(如圖17、18)


圖17


 圖18

說明:在需要進行整屏移動時,這個指令非常有用,可以實現螢幕的滾動顯示效果。初始化時不使用這個指令。

5.清屏指令(如圖19)


圖19

說明:清除螢幕顯示內容。游標返回螢幕左上角。執行這個指令時需要一定時間。

6.游標歸位指令(如圖20)

 圖20

說明:游標返回螢幕左上角,它不改變螢幕顯示內容。

7.設定CGRAM地址指令(如圖21)


圖21

說明:這個指令在上面已經介紹過。用法在後面例子中說明。

8.設定DDRAM地址指令(如圖22)


圖22

說明:這個指令用於設定DDRAM地址。在對DDRAM進行讀寫之前,首先要設定DDRAM地址,然後才能進行讀寫。前面我們說過,DDRAM就是LCD1602的顯示儲存器。我們要在它上面進行顯示,就要把要顯示的字元寫入DDRAM。同樣,我們想知道DDRAM某個地址上有什麼字元,也要先設定DDRAM地址,然後將它讀出到微控制器。

9.讀忙訊號和地址計數器AC(如圖23)


圖23

說明:這個指令用來讀取LCD1602狀態。對於微控制器來說,LCD1602屬於慢速裝置。當微控制器向其傳送一個指令後,它將去執行這個指令。這時如果微控制器再次傳送下一條指令,由於LCD1602速度較慢,前一條指令還未執行完畢,它將不接受這新的指令,導致新的指令丟失。因此這條讀忙指令可以用來判斷LCD1602是否忙,能否接收單片機發來的指令。當BF=1,表示LCD1602正忙,不能接受微控制器的指令;當BF=0,表示LCD1602空閒,可以接收微控制器的指令。RS=0,表示是指令;RW=1,表示是讀取。這條指令還有一個副產品:即可以得到地址記數器AC的值(address counter)。LCD1602維護了一個地址計數器AC,用來記錄下一次讀寫CGRAM或DDRAM的位置。需要強調的是:這條指令我一次也沒有執行成功。很多網友似乎也是這樣。好在我們有另外的辦法,也就是延時。通過檢視每條指令的執行時間,再經過一些試驗,可以確定指令的延時。這樣就可以在上一條指令執行完畢後再執行下一條指令了。

10.寫資料到CGRAM或DDRAM指令(如圖24)


圖24

說明:RS=1,資料;RW=0,寫。指令執行時,要在DB7—DB0上先設定好要寫入的資料,然後執行寫命令。

11.從CGRAM或DDRAM讀資料指令(如圖25)


圖25

說明:RS=1,資料;RW=1,讀。先設定好CGRAM或DDRAM的地址,然後執行讀取命令。資料就被讀入後DB7—DB0。

五.例項

下面我們就以一個例項來結束這篇文章。先介紹一下背景:微控制器最小系統(擴充了外部RAM 62256)。採用STC89C52RC,晶振22.1184MHZ。以5×8點陣,16×2行,8位資料埠。首先在第一行顯示“I love MCU!”,第二行顯示“LCD1602 Test!”。延時一段時間,清屏。然後在第一行顯示自定義字元:攝氏溫標標誌。第二行顯示圓周率(pai)標誌。再延時一段時間,清屏。最後在第一行顯示“Welcome to my blog!”,顯示方式是從螢幕右面移入,左面移出。周而復始(如圖26)。


圖26

例程:

#include<reg52.h>
#include"./delay/delay.h"

sbit RS = P2^4;
sbit RW = P2^5;
sbit E = P2^6;

#define LCDPORT P0
#define LCD_WRITE_DATA 1
#define LCD_WRITE_COM 0
void lcd_write(unsigned char byte,unsigned char flag)
{
    if(flag)
		{
				RS = 1;//資料
		}
		else
		{
				RS = 0;//命令
		}
		RW = 0;//寫
		E = 1;//使能
		LCDPORT = byte;
		delay_us(10);
		E = 0;
}
void lcd_init()
{
    delay_ms(15);
		lcd_write(0x38,LCD_WRITE_COM);//設定工作方式,8位資料介面,兩行顯示,5*8點陣字元
		delay_ms(5);
		lcd_write(0x38,LCD_WRITE_COM);
		delay_ms(5);
		lcd_write(0x38,LCD_WRITE_COM);
		delay_ms(5);
		lcd_write(0x38,LCD_WRITE_COM);
		delay_ms(5);
		lcd_write(0x38,LCD_WRITE_COM);
		delay_ms(5);
		lcd_write(0x08,LCD_WRITE_COM);//關閉顯示
		delay_ms(5);
		lcd_write(0x01,LCD_WRITE_COM);//清屏
		delay_ms(5);
		lcd_write(0x06,LCD_WRITE_COM);//寫入新資料之後游標後移,顯示移動
		delay_ms(5);
		lcd_write(0x0c,LCD_WRITE_COM);//顯示開,游標不顯示,游標不閃爍
		delay_ms(5);
}
void dis_lcd_write(unsigned char x,unsigned char y,unsigned char byte)
{	
			unsigned char i = 0;
			/*byte*/
			if(y == 0)
			{
				lcd_write(0x80+x,LCD_WRITE_COM);
				lcd_write(byte,LCD_WRITE_DATA);
			}
			if(y == 1)
			{
				lcd_write(0x80+0x40+x,LCD_WRITE_COM);
				lcd_write(byte,LCD_WRITE_DATA);
			}		
}
void dis_lcd_src(unsigned char x,unsigned char y,unsigned char *src) 
{
	if(y == 0)
	{		
		lcd_write(0x80+x,LCD_WRITE_COM);			
	}
	if(y == 1)
	{
		lcd_write(0x80+0x40+x,LCD_WRITE_COM);
	}
	
	while(*src != '\0')
	{
		lcd_write(*src,LCD_WRITE_DATA);
		src++;
	}
}


自定義字元緩衝區:

CGRAM 1602能儲存8個自定義字元,這8個自定義字元儲存空間的首地址分別是:

0X40,0X48,0X50,0X58,0X60,0X68,0X70,0X78。在

以0x40來說,它的儲存空間如圖所示


不過字元的畫素通常是5X7。如果需要更大畫素的字元,就只能用多個5X7的字元拼合。每個自定義字元的位元組有8個,最後一個是0x00;每個位元組的高3位為0,即000? ????。

比如說:uchar  code table1[]={0x10,0x06,0x09,0x08,0x08,0x09,0x06,0x00};//字元℃ 

void lcd_dis_self()
{
	unsigned char i = 6;
	while((i < 7) && (i > 1))
	{
	        lcd_write(0x40+i,LCD_WRITE_COM);//自定義字元的第幾行
		lcd_write(0x1f,LCD_WRITE_DATA);//設定自定義字元第幾行的內容
		lcd_write(0x40+0x80,LCD_WRITE_COM);//顯示在顯示屏上的第二行的第一個
		lcd_write(0x0,LCD_WRITE_DATA);//顯示的是自定義字元的第1個
			
		delay_ms(500);
		i --;
			
	}
}
void my_self()
{
			lcd_write(0x40,LCD_WRITE_COM);//表示設定的是第一個自定義字元
			lcd_write(0x06,LCD_WRITE_DATA);//顯示的是一個電池的樣子
			lcd_write(0x1f,LCD_WRITE_DATA);
			lcd_write(0x11,LCD_WRITE_DATA);
			lcd_write(0x11,LCD_WRITE_DATA);
			lcd_write(0x11,LCD_WRITE_DATA);
			lcd_write(0x11,LCD_WRITE_DATA);
			lcd_write(0x1f,LCD_WRITE_DATA);
			lcd_write(0x00,LCD_WRITE_DATA);
		
			lcd_write(0x40+0x80,LCD_WRITE_COM);
			lcd_write(0x0,LCD_WRITE_DATA);
			delay_ms(500);	
			lcd_dis_self();
}