18luck网站

18luck网站電子設計 | 18luck网站Rss 2.0 會員中心 會員注冊
搜索: 您現在的位置: 18luck网站 >> 18luck平台 >> MCU開發實例 >> 正文

LCD1602的單片機驅動詳解

作者:佚名    文章來源:本站原創    點擊數:    更新時間:2018-11-05

一.接口

 

LCD1602是很多單片機愛好者較早接觸的字符型液晶顯示器,它的主控芯片是HD44780或者其它兼容芯片。剛開始接觸它的大多是單片機的初學者。由於(yu) 對它的不了解,不能隨心所欲地對它進行驅動。經過一段時間的學習(xi) ,我對它的驅動有了一點點心得,今天把它記錄在這裏,以備以後查閱。與(yu) 此相仿的是LCD12864液晶顯示器,它是一種圖形點陣顯示器,能顯示的內(nei) 容比LCD1602要豐(feng) 富得多,除了普通字符外,還可以顯示點陣圖案,帶有漢字庫的還可以顯示漢字,它的並行驅動方式與(yu) LCD1602相差無幾,所以,在這裏花點時間是值得的。

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



圖1

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



圖2

它的16條引腳定義(yi) 如下:

引腳號

符號

引腳說明

引腳號

符號

引腳說明

1

VSS

電源地

9

D2

數據端口

2

VDD

電源正極

10

D3

數據端口

3

VO

偏壓信號

11

D4

數據端口

4

RS

命令/數據

12

D5

數據端口

5

RW

讀/寫(xie)

13

D6

數據端口

6

E

使能

14

D7

數據端口

7

D0

數據端口

15

A

背光正極

8

D1

數據端口

16

K

背光負極

對這個(ge) 表的說明:

1.    VSS接電源地。

2.    VDD接+5V。

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


圖3

4.    RS是命令/數據選擇引腳,接單片機的一個(ge) I/O,當RS為(wei) 低電平時,選擇命令;當RS為(wei) 高電平時,選擇數據。

5.    RW是讀/寫(xie) 選擇引腳,接單片機的一個(ge) I/O,當RW為(wei) 低電平時,向LCD1602寫(xie) 入命令或數據;當RW為(wei) 高電平時,從(cong) LCD1602讀取狀態或數據。如果不需要進行讀取操作,可以直接將其接VSS。

6.    E,執行命令的使能引腳,接單片機的一個(ge) I/O。

7.    D0—D7,並行數據輸入/輸出引腳,可接單片機的P0—P3任意的8個(ge) I/O口。如果接P0口,P0口應該接4.7K—10K的上拉電阻。如果是4線並行驅動,隻須接4個(ge) I/O口。

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

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


圖4

二.基本操作

LCD1602的基本操作分為(wei) 四種:

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

2.    讀數據:輸入RS=1,RW=1,E=高脈衝(chong) 。輸出:D0—D7為(wei) 數據。

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

4.    寫(xie) 數據:輸入RS=1,RW=0,E=高脈衝(chong) 。輸出:無。

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


 圖5

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


圖6

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


圖7

三.DDRAM、CGROM和CGRAM

DDRAM(Display Data RAM)就是顯示數據RAM,用來寄存待顯示的字符代碼。共80個(ge) 字節,其地址和屏幕的對應關(guan) 係如下(如圖8):


 圖8

DDRAM相當於(yu) 計算機的顯存,我們(men) 為(wei) 了在屏幕上顯示字符,就把字符代碼送入顯存,這樣該字符就可以顯示在屏幕上了。同樣LCD1602共有80個(ge) 字節的顯存,即DDRAM。但LCD1602的顯示屏幕隻有16×2大小,因此,並不是所有寫(xie) 入DDRAM的字符代碼都能在屏幕上顯示出來,隻有寫(xie) 在上圖所示範圍內(nei) 的字符才可以顯示出來,寫(xie) 在範圍外的字符不能顯示出來。這樣,我們(men) 在程序中可以利用下麵的“光標或顯示移動指令”使字符慢慢移動到可見的顯示範圍內(nei) ,看到字符的移動效果。

前麵說了,為(wei) 了在液晶屏幕上顯示字符,就把字符代碼送入DDRAM。例如,如果想在屏幕左上角顯示字符‘A’,那麽(me) 就把字符‘A’的字符代碼41H寫(xie) 入DDRAM的00H地址處即可。至於(yu) 怎麽(me) 寫(xie) 入,後麵會(hui) 有說明。那麽(me) 為(wei) 什麽(me) 把字符代碼寫(xie) 入DDRAM,就可以在相應位置顯示這個(ge) 代碼的字符呢?我們(men) 知道,LCD1602是一種字符點陣顯示器,為(wei) 了顯示一種字符的字形,必須要有這個(ge) 字符的字模數據,什麽(me) 叫字符的字模數據,看看下麵的這個(ge) 圖就明白了(如圖9)。


圖9

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

在LCD1602模塊上固化了字模存儲(chu) 器,就是CGROM和CGRAM,HD44780內(nei) 置了192個(ge) 常用字符的字模,存於(yu) 字符產(chan) 生器CGROM(Character Generator ROM)中,另外還有8個(ge) 允許用戶自定義(yi) 的字符產(chan) 生RAM,稱為(wei) CGRAM(Character Generator RAM)。下圖(如圖12)說明了CGROM和CGRAM與(yu) 字符的對應關(guan) 係。從(cong) ROM和RAM的名字我們(men) 也可以知道,ROM是早已固化在LCD1602模塊中的,隻能讀取;而RAM是可讀寫(xie) 的。也就是說,如果隻需要在屏幕上顯示已存在於(yu) CGROM中的字符,那麽(me) 隻須在DDRAM中寫(xie) 入它的字符代碼就可以了;但如果要顯示CGROM中沒有的字符,比如攝氏溫標的符號,那麽(me) 就隻有先在CGRAM中定義(yi) ,然後再在DDRAM中寫(xie) 入這個(ge) 自定義(yi) 字符的字符代碼即可。和CGROM中固化的字符不同,CGRAM中本身沒有字符,所以要在DDRAM中寫(xie) 入某個(ge) CGROM不存在的字符,必須在CGRAM中先定義(yi) 後使用。程序退出後CGRAM中定義(yi) 的字符也不複存在,下次使用時,必須重新定義(yi) 。


圖10

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


 圖11

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

那麽(me) 如何在CGRAM中自定義(yi) 字符呢?在上麵的介紹中,我們(men) 知道有一個(ge) 設置CGRAM地址指令,同寫(xie) DDRAM指令相似,隻須設置好某個(ge) 自定義(yi) 字符的字模數據,然後按照上麵介紹的方法,設置好CGRAM地址,依次寫(xie) 入這個(ge) 字模數據即可。我們(men) 在後麵的例子中再進行說明。


 圖12

四.LCD1602指令

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


 圖13

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

DL:設置數據接口位數。

DL=1:8位數據接口(D7—D0)。

DL=0:4位數據接口(D7—D4)。

N=0:一行顯示。

N=1:兩(liang) 行顯示。

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

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

說明:因為(wei) 是寫(xie) 指令字,所以RS和RW都是0。LCD1602隻能用並行方式驅動,不能用串行方式驅動。而並行方式又可以選擇8位數據接口或4位數據接口。這裏我們(men) 選擇8位數據接口(D7—D0)。我們(men) 的設置是8位數據接口,兩(liang) 行顯示,5×8點陣,即0b00111000也就是0x38。(注意:NF是10或11的效果是一樣的,都是兩(liang) 行5×8點陣。因為(wei) 它不能以兩(liang) 行5×10點陣方式進行顯示,換句話說,這裏用0x38或0x3c是一樣的)。

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


圖14

D=1:顯示開,D=0:顯示關(guan) 。

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

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

說明:這裏的設置是顯示開,不顯示光標,光標不閃爍,設置字為(wei) 0x0c。

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


圖15

I/D=1:寫(xie) 入新數據後光標右移。

I/D=0:寫(xie) 入新數據後光標左移。

S=1:顯示移動。

S=0:顯示不移動。


 圖16

說明:這裏的設置是0x06。

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


圖17


 圖18

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

5.清屏指令(如圖19)


圖19

說明:清除屏幕顯示內(nei) 容。光標返回屏幕左上角。執行這個(ge) 指令時需要一定時間。

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

 

 圖20

說明:光標返回屏幕左上角,它不改變屏幕顯示內(nei) 容。

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


圖21

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

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


圖22

說明:這個(ge) 指令用於(yu) 設置DDRAM地址。在對DDRAM進行讀寫(xie) 之前,首先要設置DDRAM地址,然後才能進行讀寫(xie) 。前麵我們(men) 說過,DDRAM就是LCD1602的顯示存儲(chu) 器。我們(men) 要在它上麵進行顯示,就要把要顯示的字符寫(xie) 入DDRAM。同樣,我們(men) 想知道DDRAM某個(ge) 地址上有什麽(me) 字符,也要先設置DDRAM地址,然後將它讀出到單片機。

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


圖23

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

10.寫(xie) 數據到CGRAM或DDRAM指令(如圖24)


圖24

說明:RS=1,數據;RW=0,寫(xie) 。指令執行時,要在DB7—DB0上先設置好要寫(xie) 入的數據,然後執行寫(xie) 命令。

11.從(cong) CGRAM或DDRAM讀數據指令(如圖25)


圖25

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

 

五.實例

下麵我們(men) 就以一個(ge) 實例來結束這篇文章。先介紹一下背景:單片機最小係統(擴充了外部RAM 62256)。采用STC89C52RC,晶振22.1184MHZ。以5×8點陣,16×2行,8位數據端口。首先在第一行顯示“I love MCU!”,第二行顯示“LCD1602 Test!”。延時一段時間,清屏。然後在第一行顯示自定義(yi) 字符:攝氏溫標標誌。第二行顯示圓周率(pai)標誌。再延時一段時間,清屏。最後在第一行顯示“Welcome to my blog!”,顯示方式是從(cong) 屏幕右麵移入,左麵移出。周而複始(如圖26)。


圖26

//File1

 

#ifndef __ZHANGTYPE_H__

#define __ZHANGTYPE_H__

 

#define uint8    unsigned char

#define uint16   unsigned short int

#define uint32   unsigned long int

#define int8     signed char

#define int16    signed short int

#define int32    signed long int

#define uint64   unsigned long long int

#define int64    signed long long int

 

#endif 

//File2

 

#ifndef __FUN_H__

#define __FUN_H__ 

#include "ZhangType.h"

#include  

void Delay(uint16 time); 

#endif 

//File3

 

#include "fun.h" 

void Delay(uint16 time)

{

    while(time--);

} 

//File4

 

#ifndef __1602_H__

#define __1602_H__

 

#include

#include "ZhangType.h"          //變量類型

#include "fun.h"            //常用函數 

 

#define    SETMODE    0x38          //16*2顯示,5*7點陣,8位數據接口

#define DISOPEN   0x0C          //顯示開,不顯示光標,光標不閃爍

#define DISMODE   0x06          //讀寫(xie) 字符後地址加1,屏顯不移動

#define    SETADDR    0x80          //設置數據地址指針初始值

#define CLEAR 0x01          //清屏,數據指針清零

#define RET       0x02          //回車,數據指針清零 

#define PORT  P2            //I/O口 

 

sbit RS = P1^0;

sbit RW = P1^1;

sbit E = P1^2; 

 

void Init1602(void);        //初始化1602

void Write1602_Com(uint8 com);  //寫(xie) 命令

void Write1602_Dat(uint8 dat);  //寫(xie) 數據

void CheckBusy(void);           //檢查忙

void Write1602_One_Dat(uint8 X,uint8 Y,uint8 dat);          //寫(xie) 一個(ge) 數據

void Write1602_Str(uint8 addr,uint8 length,uint8 *pbuf);    //寫(xie) 一個(ge) 數據串 

#endif//

//File5

 

#include "1602.h" 

 

void Write1602_Com(uint8 com)

{

    E=0;

    RS=0;                    //命令

    Delay(50);               //延時

    RW=0;                    //寫(xie)          

    Delay(50);

    PORT=com;                //端口賦值

    Delay(50);

    E=1;                     //高脈衝(chong)

    Delay(50);

    E=0;

}

 

void Write1602_Dat(uint8 dat)

{

    E=0;

    RS=1;                    //數據

    Delay(50);               //延時

    RW=0;                    //寫(xie)

    Delay(50);

    PORT=dat;                //端口賦值

    Delay(50);

    E=1;                     //高脈衝(chong)

    Delay(50);

    E=0;

} 

 

void CheckBusy(void)

{

    uint8 temp;

    RS=0;                    //命令

    RW=1;                    //讀

    E=0;

    while(1)

    {

       PORT=0xFF;           //端口為(wei) 輸入

       E=1;                 //高脈衝(chong)

       temp=PORT;

       E=0;

       if ((temp&0x80)==0)      //檢查BF位是否為(wei) 0

           break;

    }

} 

 

void Init1602(void)

{

    Write1602_Com(SETMODE);     //模式設置

    Delay(500);

    Write1602_Com(DISOPEN);     //顯示設置

    Delay(500);

    Write1602_Com(DISMODE);     //顯示模式

    Delay(500);

    Write1602_Com(CLEAR);       //清屏

    Delay(500);

} 

 

void Write1602_One_Dat(uint8 x,uint8 y,uint8 dat)

{

    x&=0x0f;

    y&=0x01;

    if(y)

       x|=0x40;

    x|=0x80;

    Write1602_Com(x);

    Write1602_Dat(dat);

} 

 

void Write1602_Str(uint8 addr,uint8 length,uint8 *pbuf)

{

    uint8 i; 

    Write1602_Com(addr);

    for(i=0;i

    {

       Write1602_Dat(pbuf[i]);

    }

} 

//File6

*******************************************************

*名稱:主文件(_main.c)

*功能:測試

*日期:2014/09/09

*******************************************************/

#include "1602.h"

#include "fun.h" 

uint8 code hot[8]={                                  //攝氏溫度字模

0x10,0x06,0x09,0x08,0x08,0x09,0x06,0x00

};

uint8 code pi[8]={                       

0x00,0x1f,0x0a,0x0a,0x0a,0x13,0x00,0x00                 //pai

}; 

uint8 code strMCU[]="I love MCU!";

uint8 code strTest[]="LCD1602 Test!";

uint8 code blog[]="Welcome to my blog!"; 

uint8 i; 

void main()

{

    Init1602();                                      //初始化1602 

    //自定義(yi) CGRAM

    Write1602_Str(0x40,8,hot);                       //攝氏溫標

    Write1602_Str(0x48,8,pi);                        //pai

 

    Write1602_Str(0x80,strlen(strMCU),strMCU);           //"I love MCU!"

    Write1602_Str(0x80+0x40,strlen(strTest),strTest);    //"LCD1602 Test!"

 

    for(i=0;i<50;i++)                             //延時一段時間

       Delay(10000);

 

    Write1602_Com(CLEAR);                            //指令執行時間較長

    Delay(500);                                      //多加一些延時

    for(i=0;i<16;i++)

       Write1602_Dat(0);

   

    Write1602_Com(0xc0);         &nnbsp;                //設置DDRAM地址

    for(i=0;i<16;i++)

       Write1602_Dat(1);

    for(i=0;i<50;i++)                             //延時一段時間

       Delay(10000);

   

    Write1602_Com(CLEAR);                            //指令執行時間較長

    Delay(500);                                      //多加一些延時

    Write1602_Str(0x80+0x10,strlen(blog),blog);          //寫(xie) 在顯示之外

    while(1)

    {

       Write1602_Com(0x18);                      //左移

       for(i=0;i<20;i++)                         //延時

           Delay(10000);

    }

} 

//## THE END ##

Tags:LCD1602,單片機驅動,單片機  
責任編輯:admin
  • 上一篇文章:
  • 下一篇文章: 沒有了
  • 請文明參與討論,禁止漫罵攻擊,不要惡意評論、違禁詞語。 昵稱:
    1分 2分 3分 4分 5分

    還可以輸入 200 個字
    [ 查看全部 ] 網友評論
    推薦文章
    • 此欄目下沒有推薦文章
    最新推薦
    熱門文章
    • 此欄目下沒有熱點文章
    關於我們 - 聯係我們 - 廣告服務 - 友情鏈接 - 網站地圖 - 版權聲明 - 在線幫助 - 文章列表
    返回頂部
    刷新頁麵
    下到頁底
    晶體管查詢