初步認(rèn)識(shí)51單片機(jī)-2.2單片機(jī)控制LCD1602液晶顯示模塊
顯示容量:16×2個(gè)字符
本文引用地址:http://m.butianyuan.cn/article/201611/319543.htm芯片工作電壓:4.5—5.5V
工作電流:2.0mA(5.0V)
模塊最佳工作電壓:5.0V
字符尺寸:2.95×4.35(W×H)mm
引腳功能說(shuō)明
1602LCD采用標(biāo)準(zhǔn)的14腳(無(wú)背光)或16腳(帶背光)接口,各引腳接口說(shuō)明如表1所示:
第1腳:VSS為地電源。
第2腳:VDD接5V正電源。
第3腳:VL為液晶顯示器對(duì)比度調(diào)整端,接正電源時(shí)對(duì)比度最弱,接地時(shí)對(duì)比度最高,對(duì)比度過(guò)高時(shí)會(huì)產(chǎn)生“鬼影”,使用時(shí)可以通過(guò)一個(gè)10K的電位器調(diào)整對(duì)比度。
第4腳:RS為寄存器選擇,高電平時(shí)選擇數(shù)據(jù)寄存器、低電平時(shí)選擇指令寄存器。
第5腳:R/W為讀寫(xiě)信號(hào)線(xiàn),高電平時(shí)進(jìn)行讀操作,低電平時(shí)進(jìn)行寫(xiě)操作。當(dāng)RS和R/W共同為低電平時(shí)可以寫(xiě)入指令或者顯示地址,當(dāng)RS為低電平R/W為高電平時(shí)可以讀忙信號(hào),當(dāng)RS為高電平R/W為低電平時(shí)可以寫(xiě)入數(shù)據(jù)。
第6腳:E端為使能端,當(dāng)E端由高電平跳變成低電平時(shí),液晶模塊執(zhí)行命令。
第7~14腳:D0~D7為8位雙向數(shù)據(jù)線(xiàn)。
第15腳:背光源正極。
第16腳:背光源負(fù)極。
我們來(lái)看看如何使用這兩招控制LCD1602液晶模塊。既然是用單片機(jī)控制LCD1602,那么根據(jù)前面的分析思想,首先要搞清楚誰(shuí)是控制對(duì)象,誰(shuí)是被控制對(duì)象。很顯然,LCD1602是被控制對(duì)象,那么我們就先從LCD1602開(kāi)始分析。所謂控制也可以理解為溝通,那么如何與LCD1602溝通呢?可以想一想,平時(shí)人與人是如何溝通的?溝通之前先要打個(gè)招呼吧,比如“你好”之類(lèi)的,電話(huà)里面要先講個(gè)“喂?”,之后才進(jìn)入溝通正題了。其實(shí)單片機(jī)與LCD1602的溝通方式也一樣,“喂?”在這個(gè)例子里面就叫初始化。后面也會(huì)經(jīng)常碰到這個(gè)“初始化”的概念。其實(shí)器件也是人設(shè)計(jì)的,所以他的工作方式從某種程度上講,也是人的溝通方式。打完招呼后,就開(kāi)始進(jìn)入真正主題了。什么主題呢?LCD1602是顯示模塊,主要作用當(dāng)然是顯示了。那么顯示什么呢?很明顯,顯示內(nèi)容當(dāng)然來(lái)自于單片機(jī)了,單片機(jī)讓它顯示什么它就顯示什么。這個(gè)‘顯示什么’就是傳送的數(shù)據(jù)。那么怎么往1602傳送數(shù)據(jù)呢?1602什么意思,表示2行16個(gè)字符,也就是有不同的顯示地點(diǎn),那么如何確定顯示地點(diǎn)呢?因此前面的分析可以總結(jié)為三個(gè)問(wèn)題,如何初始化,如何傳送顯示的內(nèi)容(顯示什么),在哪里顯示。這三個(gè)問(wèn)題如何解答呢?當(dāng)然要去看芯片手冊(cè)了。
為了解決這三個(gè)問(wèn)題,我們先來(lái)看看人與人之間是如何溝通的,如果當(dāng)面溝通,你的信號(hào)(聲音)能夠直接傳到對(duì)方,而且能讓對(duì)方聽(tīng)懂。如果相距比較遠(yuǎn),那么就使用電話(huà)等通信工具。前者信號(hào)傳遞載體是空氣,后者是電話(huà)線(xiàn)。那么我們來(lái)看看MCU與LCD1602的信號(hào)傳遞載體是什么樣的。查看原理圖。因?yàn)槭荕CU與1602之間的溝通,當(dāng)然這里我們只查看與單片機(jī)相連接的部分。
從圖中我們看到,單片機(jī)通過(guò)P2.7,P2.6分別與RS,EN連接,P0端口與D0到D7連接,一共10根線(xiàn)。那么也就是說(shuō),單片機(jī)的所有指令,數(shù)據(jù)等都是通過(guò)這10根線(xiàn)來(lái)完成的。怎么樣去控制LCD呢,當(dāng)然是閱讀LCD的說(shuō)明手冊(cè)。這里來(lái)個(gè)比喻,房間內(nèi)一個(gè)人規(guī)定,敲三下門(mén),屋內(nèi)的人才把門(mén)打開(kāi)。如果你要進(jìn)入屋內(nèi),就必須敲三下,如果你不知道這個(gè)規(guī)則,敲了四下,或者大喊大叫,門(mén)也開(kāi)不了。這個(gè)規(guī)定可以是多樣化,比如一共敲兩下,第一下要敲重一點(diǎn),第二下要敲輕一點(diǎn)。或者重敲三下,輕敲一下,等等。而且這里你不需要問(wèn)為什么,照著做就行了。其實(shí)LCD1602包括后面會(huì)講到的其他模塊同樣如此,你要與它溝通,當(dāng)然必須按照它的規(guī)則來(lái)。下面我們就來(lái)解讀它的規(guī)則,來(lái)解決前面提到的三個(gè)問(wèn)題,
LCD1602初始化;在哪里顯示;顯示什么。
(1)LCD1602初始化
關(guān)于這一點(diǎn),說(shuō)明手冊(cè)上已經(jīng)告訴我們了,這里全盤(pán)復(fù)制過(guò)來(lái)。
延時(shí)15ms
寫(xiě)指令38H
延時(shí)5ms
寫(xiě)指令38H
寫(xiě)指令08H
寫(xiě)指令01H
寫(xiě)指令06H
寫(xiě)指令0CH
以上為初始化過(guò)程,延時(shí)部分好解決,前面講過(guò)了。這里就看如何寫(xiě)指令了。寫(xiě)指令這個(gè)過(guò)程肯定是通過(guò)上圖中10根線(xiàn)來(lái)完成的。D0-D7一共八根線(xiàn)應(yīng)該是用來(lái)存放指令的內(nèi)容。問(wèn)題來(lái)了,1602怎么知道單片機(jī)給我的是命令還是數(shù)據(jù)。(命令是什么,在哪里顯示,屏幕清零;數(shù)據(jù)是什么,顯示什么內(nèi)容,顯示A還是B)。LCD1602看到RS為高時(shí),就明白了,哦,你要通過(guò)P0端口給我數(shù)據(jù)了,于是LCD1602就把這些數(shù)據(jù)拿過(guò)來(lái)了??吹絉S為低時(shí),就知道你要給我指令了。通過(guò)這種方式,單片機(jī)能準(zhǔn)確的傳遞指令或者數(shù)據(jù)信息,實(shí)現(xiàn)與LCD1602的溝通。是不是這樣就能讓LCD1602正常執(zhí)行了。不是的。回到我們前面講的那個(gè)例子,這里加個(gè)條件,屋內(nèi)人聽(tīng)到敲門(mén)三下后,判斷暗號(hào)正確了,但是沒(méi)有直接開(kāi)門(mén),而是通知了他的上級(jí),得到上級(jí)的授權(quán)后,才開(kāi)門(mén)。也就是兩個(gè)條件,暗號(hào)正確和上級(jí)授權(quán)。LCD1602也一樣,收到指令沒(méi)有立即執(zhí)行,還要等另外一個(gè)信號(hào),就是EN使能信號(hào)。此時(shí)EN給個(gè)一定寬度的脈沖,LCD1602開(kāi)始執(zhí)行。
時(shí)序圖如上圖所示,這里少了R/W信號(hào),用于控制從LCD1602讀取還是寫(xiě)入的,為了簡(jiǎn)化過(guò)程,在硬件上把R/W接地了,也就是只能寫(xiě)不能讀。同時(shí),讀忙信號(hào)也不能操作,這里采用延時(shí)的方法替代。根據(jù)前面的分析很容易的寫(xiě)出寫(xiě)指令的代碼:
?void write_com(unsigned char mycmd)
{
delayMs(5);//注意這里需要延時(shí)5ms比較保險(xiǎn) 代替判斷忙信號(hào)
P0=mycmd; //準(zhǔn)備好指令
RS=0; //告訴LCD1602,P0中放的是指令不是數(shù)據(jù)
EN=1;
delayUs(5); //根據(jù)時(shí)序圖,脈沖要有一定寬度
EN=0; //使指令有效,開(kāi)始執(zhí)行
}
同樣的道理,以上代碼中,只需改一下RS信號(hào)為1,就是寫(xiě)數(shù)據(jù)的代碼了
void write_com(unsigned char mydata)
{
delayMs(5);//注意這里需要延時(shí)5ms比較保險(xiǎn) 代替判斷忙信號(hào)
P0=mycmd; //準(zhǔn)備好指令
RS=1; //告訴LCD1602,P0中放的是數(shù)據(jù)不是指令
EN=1;
delayUs(5); //根據(jù)時(shí)序圖,脈沖要有一定寬度
EN=0; //使指令有效,開(kāi)始執(zhí)行
}
講到這里,LCD1602初始化代碼應(yīng)該能寫(xiě)出了。同時(shí)我們也已經(jīng)寫(xiě)出了傳遞指令的代碼,那么現(xiàn)在我們只要知道指令內(nèi)容就可以了。
1602LCD的指令說(shuō)明及時(shí)序
1602液晶模塊內(nèi)部的控制器共有11條控制指令,如表2所示:
1602液晶模塊的讀寫(xiě)操作、屏幕和光標(biāo)的操作都是通過(guò)指令編程來(lái)實(shí)現(xiàn)的。(說(shuō)明:1為高電平、0為低電平)
指令1:清顯示,指令碼01H,光標(biāo)復(fù)位到地址00H位置。
指令2:光標(biāo)復(fù)位,光標(biāo)返回到地址00H。
指令3:光標(biāo)和顯示模式設(shè)置 I/D:光標(biāo)移動(dòng)方向,高電平右移,低電平左移 S:屏幕上所有文字是否左移或者右移。高電平表示有效,低電平則無(wú)效。
指令4:顯示開(kāi)關(guān)控制。 D:控制整體顯示的開(kāi)與關(guān),高電平表示開(kāi)顯示,低電平表示關(guān)顯示 C:控制光標(biāo)的開(kāi)與關(guān),高電平表示有光標(biāo),低電平表示無(wú)光標(biāo) B:控制光標(biāo)是否閃爍,高電平閃爍,低電平不閃爍。
指令5:光標(biāo)或顯示移位 S/C:高電平時(shí)移動(dòng)顯示的文字,低電平時(shí)移動(dòng)光標(biāo)。
指令6:功能設(shè)置命令 DL:高電平時(shí)為4位總線(xiàn),低電平時(shí)為8位總線(xiàn) N:低電平時(shí)為單行顯示,高電平時(shí)雙行顯示 F: 低電平時(shí)顯示5x7的點(diǎn)陣字符,高電平時(shí)顯示5x10的點(diǎn)陣字符。
指令7:字符發(fā)生器RAM地址設(shè)置。
指令8:DDRAM地址設(shè)置。
指令9:讀忙信號(hào)和光標(biāo)地址 BF:為忙標(biāo)志位,高電平表示忙,此時(shí)模塊不能接收命令或者數(shù)據(jù),如果為低電平表示不忙。
指令10:寫(xiě)數(shù)據(jù)。
指令11:讀數(shù)據(jù)。
你需要給LCD1602什么指令,只需要傳遞給void write_com(unsignedchar mycmd)函數(shù)中的mycmd參數(shù)就行了。
(2)在哪里顯示
知道了這個(gè),現(xiàn)在我們就能解決前面提到的第二個(gè)問(wèn)題,在哪里顯示,
例如第二行第一個(gè)字符的地址是40H,那么是不是它的地址就是40H了。注意表2中第8條數(shù)據(jù)存儲(chǔ)地址,D7已經(jīng)被寫(xiě)死了。最終的顯示地址是40H+10000000B,因此我們只要把這個(gè)值傳給mycom,LCD1602就知道在第二行第一個(gè)位置顯示了。
(3)顯示什么
前面講了,如果傳送數(shù)據(jù)就是要顯示的內(nèi)容。比如我要顯示字母A,怎么操作呢。
以上圖中可以知道,如果你要顯示A,那么數(shù)據(jù)的高位為0100,低位為0001,因此為01000001。把這個(gè)數(shù)據(jù)傳送給LCD1602,它就知道要顯示A了。
現(xiàn)在回過(guò)頭來(lái)看看,我們?cè)谑褂脝纹瑱C(jī)控制LCD1602這個(gè)過(guò)程中用到了單片機(jī)的哪些知識(shí)?;厝タ纯磮D1,10根連接線(xiàn),P2.6和P2.7引腳,再加上P0端口,主要是通過(guò)P2.6和P2.7高低變化來(lái)發(fā)出指令或數(shù)據(jù),P0的變化反映指令或數(shù)據(jù)的內(nèi)容??梢?jiàn),這個(gè)過(guò)程中我們只用到了IO口控制和延時(shí)。其他很長(zhǎng)的部分我們用在理解1602的使用規(guī)則了。注意這里是使用規(guī)則,談不上原理。比如你給LCD1602發(fā)送清屏指令時(shí),你明白LCD1602收到這個(gè)指令是如何操作清屏的嗎?不知道,也沒(méi)有必要知道。液晶模塊說(shuō)明書(shū)也不告訴你。好比你使用手機(jī)時(shí),你點(diǎn)擊一下某個(gè)應(yīng)用程序就打開(kāi)了,然后按照它的規(guī)則去使用就行了,比如聽(tīng)歌,上網(wǎng)等等,你不用關(guān)心它們是怎么實(shí)現(xiàn)的。其實(shí)手機(jī)也是個(gè)模塊,我們只要學(xué)會(huì)操作就行了,不管它里面發(fā)生了什么事情。
附參考代碼如下:
#include
void LCD_init(void);
void delayUs(unsigned char t);
void delayMs(unsigned char t);
void write_com(unsigned char mycmd);
void write_data(unsigned char mydata);
sbit RS=P2^7;
sbit EN=P2^6;
void main (void)
{
LCD_init();
write_com(0x0f);
write_data(0x41);
while(1);
}
void LCD_init(void)
{
delayMs(15);
write_com(0x38);
delayMs(5);
write_com(0x38);
write_com(0x08);
write_com(0x01);
write_com(0x06);
write_com(0x0c);
}
void delayUs(unsigned char t)
{
while(--t);
}
void delayMs(unsigned char t)
{
while(--t)
{
delayUs(245);
delayUs(245);
}
}
void write_com(unsigned char mycmd)
{
delayMs(5);//注意這里需要延時(shí)5ms比較保險(xiǎn)代替判斷忙信號(hào)
P0=mycmd; //準(zhǔn)備好指令
RS=0; //告訴LCD1602,P0中放的是指令不是數(shù)據(jù)
EN=1;
delayUs(5); //根據(jù)時(shí)序圖,脈沖要有一定寬度
EN=0; //使指令有效,開(kāi)始執(zhí)行
}
void write_data(unsigned char mydata)
{
delayMs(5);//注意這里需要延時(shí)5ms比較保險(xiǎn)
P0=mydata;
RS=1;
EN=1;
delayUs(5);
EN=0;
}
評(píng)論