(本文以HD44780主控芯片的LCD1602為藍本進行描述,其中的截圖也來自HD44780數據手冊,用戶可自行搜索其datasheet,有部分整理網上的,但絕對要比你看到的要深入得多)
一.接口
LCD1602是很多單片機愛好者較早接觸的字符型液晶顯示器,它的主控芯片是HD44780或者其它兼容芯片。剛開始接觸它的大多是單片機的初學者。由於對它的不了解,不能隨心所欲地對它進行驅動。經過一段時間的學習,我對它的驅動有了一點點心得,今天把它記錄在這里,以備以后查閱。與此相仿的是LCD12864液晶顯示器,它是一種圖形點陣顯示器,能顯示的內容比LCD1602要豐富得多,除了普通字符外,還可以顯示點陣圖案,帶有漢字庫的還可以顯示漢字,它的並行驅動方式與LCD1602相差無幾,所以,在這里花點時間是值得的。
一般來說,LCD1602有16條引腳,據說還有14條引腳的,與16腳的相比缺少了背光電源A(15腳)和地線K(16腳)。我手里這塊LCD1602的型號是不知道是哪家的(知道也不告訴你,博客園不允許打廣告的),如圖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。
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所示。
二.基本操作
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):
寫操作時序圖(如圖6):
(總結一下:實際編程驅動時,共有11根信號需要驅動:並行數據為8位(D0-D7),程序通過這8位數據線控制或讀取LCD1602模塊的顯示或狀態,這樣就需要另一根信號線標識當前是寫操作還是讀操作的信號線,即RW【Read/Write】,至於寫進LCD1602模塊的是數據還是指令,就靠信號線RS【Register Select】來控制,字面意思就是“寄存器選擇”,實際就是通過RS信號控制當前的8位數據是寫進“數據寄存器Data Register/DR”,還是“指令寄存器Instruction Register/IR”,如果是指令,就需要經過“指令解碼Instruction Decoder”,如果是數據,就直接寫進DDRAM或CGRAM,另有一根使能信號線E(Enable),在下降沿寫入信號。這樣恰好就11根信號線:D0-D7、RW、RS、E。
你問我怎么會知道需要解碼什么的?HD44780數據手冊是這么寫的,其實我都不需要寫什么博文了,把英文數據手冊一頁頁貼上就行了,犯得着嗎我。看下面這張HD44780功能框圖就知道了,后續會參考到,很重要的)
時序時間參數(如圖7):
(總結一下:時序時間參數的意義,在編程上面的具體表現就是“延時”,Delay函數,因為LCD1602內部也是芯片,是芯片就會有反應時間,如果速度過快,內部芯片就采集不到數據,其實最主要的還是E信號,從時序上看好像是高低電平鎖存信號的,實質上E信號是下降沿觸發時鍾,而不是鎖存器Latch的使能EN信號)
三.DDRAM、CGROM和CGRAM
DDRAM(Display Data RAM)就是顯示數據RAM,用來寄存待顯示的字符代碼。共80個字節,其地址和屏幕的對應關系如下(如圖8):
DDRAM相當於計算機的顯存,我們為了在屏幕上顯示字符,就把字符代碼送入顯存,這樣該字符就可以顯示在屏幕上了。同樣LCD1602共有80個字節的顯存,即DDRAM。但LCD1602的顯示屏幕只有16×2大小,因此,並不是所有寫入DDRAM的字符代碼都能在屏幕上顯示出來,只有寫在上圖所示范圍內的字符才可以顯示出來,寫在范圍外的字符不能顯示出來。這樣,我們在程序中可以利用下面的“光標或顯示移動指令”使字符慢慢移動到可見的顯示范圍內,看到字符的移動效果。
前面說了,為了在液晶屏幕上顯示字符,就把字符代碼送入DDRAM。例如,如果想在屏幕左上角顯示字符‘A’,那么就把字符‘A’的字符代碼41H寫入DDRAM的00H地址處即可。至於怎么寫入,后面會有說明。那么為什么把字符代碼寫入DDRAM,就可以在相應位置顯示這個代碼的字符呢?我們知道,LCD1602是一種字符點陣顯示器,為了顯示一種字符的字形,必須要有這個字符的字模數據,什么叫字符的字模數據,看看下面的這個圖就明白了(如圖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)說明的是5×8點陣和5×10點陣字符的字形和光標的位置。先來說5×8點陣,它有8行5列。那么定義這樣一個字符需要8個字節,每個字節的前3個位沒有被使用。例如,定義攝氏溫標的符號{0x10,0x06,0x09,0x08,0x08,0x09,0x06,0x00}。
上面這個圖(如圖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地址,依次寫入這個字模數據即可。我們在后面的例子中再進行說明。
(總結一下:CGRAM與DDRAM的數據寫入采用不同的指令,但是如果在CGRAM定義好了字模,使用上與CGROM是完全一樣的,只不過只允許定義8個字符,這些地址恰好是CGROM本身沒有用到的地址,所以實際使用起來與CGROM沒有區別,無論你是CGROM還是CGRAM,都是寫8位的地址,芯片將地址對應的字模進行顯示)
四.LCD1602指令
1.工作方式設置指令(如圖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)
D=1:顯示開,D=0:顯示關。
C=1:光標顯示,C=0:光標不顯示。
B=1:光標閃爍,B=0:光標不閃爍。
說明:這里的設置是顯示開,不顯示光標,光標不閃爍,設置字為0x0c。
(總結一下:顯示開關與否不影響DDRAM已經寫入的內容,光標閃爍速度與內部時鍾Fosc有關)
3.進入模式設置指令(如圖15、16)
I/D=1:寫入新數據后光標右移。
I/D=0:寫入新數據后光標左移。
S=1:顯示移動。
S=0:顯示不移動。
說明:這里的設置是0x06。
(總結一下:光標的位置實際就是“地址計數器Address Counter/AC”的位置,I/D用來控制AC增加或減小。Shift就是屏幕移動,實際使用注意方向即可,如果只是屏移操作,是不會影響AC值的,是不是光標的位置也不變呢?當然要變,因為屏幕平移了,AC沒有變即光標位置沒有變,但相對位置變了。要注意這個指令與下一指令的區別:這個指令必須要有數據寫入到DDRAM后才會相應有變化,而下一個指令是不需要有數據寫入,直接控制光標或屏幕移動)
4.光標或顯示移動指令(如圖17、18)
說明:在需要進行整屏移動時,這個指令非常有用,可以實現屏幕的滾動顯示效果。初始化時不使用這個指令。
(總結一下:如果光標持續移動到某一行的結尾,比如光標在第一行向右移到第40(0x27)個字符,再移動的話,就會跳到第二行的第一個字符(0x40),注意看內存地址,兩行的內存地址不是連續的)
5.清屏指令(如圖19)
說明:清除屏幕顯示內容。光標返回屏幕左上角。執行這個指令時需要一定時間。
(總結一下:清屏指令就是將所有80個字符地址寫“Space”的字模地址,即20H,CGROM表中第一行從左到右第三個,也是空字符的ASCII碼)
6.光標歸位指令(如圖20)
圖20
說明:光標返回屏幕左上角,它不改變屏幕顯示內容。
7.設置CGRAM地址指令(如圖21)
說明:這個指令在上面已經介紹過。用法在后面例子中說明。
(總結一下:設置CGRAM地址或寫CGRAM數據時,應將光標光閉,因為此時的光標是沒有意義的)
8.設置DDRAM地址指令(如圖22)
說明:這個指令用於設置DDRAM地址。在對DDRAM進行讀寫之前,首先要設置DDRAM地址,然后才能進行讀寫。前面我們說過,DDRAM就是LCD1602的顯示存儲器。我們要在它上面進行顯示,就要把要顯示的字符寫入DDRAM。同樣,我們想知道DDRAM某個地址上有什么字符,也要先設置DDRAM地址,然后將它讀出到單片機。
9.讀忙信號和地址計數器AC(如圖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)
說明:RS=1,數據;RW=0,寫。指令執行時,要在DB7—DB0上先設置好要寫入的數據,然后執行寫命令。
11.從CGRAM或DDRAM讀數據指令(如圖25)
說明:RS=1,數據;RW=1,讀。先設置好CGRAM或DDRAM的地址,然后執行讀取命令。數據就被讀入后DB7—DB0。