本文帶你詳細的了解下LCD1602液晶的工作原理以及代碼編寫
-
- LCD1602液晶顯示屏
-
- LCD1602主要參數
- LCD發光原理
-
- LCD螢幕的組成:
- LCD和OLED差別:
- LCD1602引腳接線:
- LCD1602的RAM位址映射及标準字庫表
- LCD1602讀寫操作
- LCD1602的指令操作
-
- LCD初始化
- LCD寫位址
- LCD寫資料
- 代碼及使用執行個體:
LCD1602液晶顯示屏
LCD ( Liquid Crystal Display 的簡稱)液晶顯示器。能夠同時顯示16x2,32個字元,是一種專門用來顯示字母、數字、符号等的點陣型液晶子產品。
LCD1602液晶顯示器是廣泛使用的一種字元型液晶顯示子產品。它是由字元型液晶顯示屏(LCD)、控制驅動主電路HD44780及其擴充驅動電路HD44100,以及少量電阻、電容元件和結構件等裝配在PCB闆上而組成。該顯示屏的優點是耗電量低、體積小、輻射低。
LCD1602主要用來顯示數字、字母、圖形以及少量自定義字元。可以顯示2行16個字元,擁有16個引腳,其中8位資料總線D0-D7,和RS、R/W、EN三個控制端口,工作電壓為5V,并且帶有字元對比度調節V0和背光源AK。
注:
我們所用的LCD屏的命名,基本都是按照其分辨率來進行命名的 比如lcd1602 就是分辨率為16×2 lcd12864 就是分辨率為128×64
LCD1602主要參數
- 顯示字元:16×2個字元
- 工作電壓:4.5~5V
- 工作電流:2.0mA
- 工作溫度:-20°C~70°C
- 子產品最佳工作電壓:5.0V
- 單個字元尺寸2.95×4.35(W×Hmm)
- 引腳:16腳
LCD發光原理
首先要知道:
- 液晶:液晶是液态晶體,是一種幾乎透明的物質,是不能發光的
- 光源:LCD螢幕的光來自于螢幕最下面的背光闆發出的光源
- 偏光片:一種鏡片,隻有特定方向的光線(垂直偏振光)才能通過,而其它方向的光線不能通過
- 兩塊偏光片的栅欄角度互相垂直時光線就完全無法通過
液晶的實體特性是:液晶控制光線通過的程度是由加在液晶上的電壓強弱來控制的。當通電時導通,排列變的有秩序,使光線容易通過,光的路徑不改變;不通電時排列混亂,阻止光線通過,改變光的路徑。
LCD螢幕的組成:
上偏光片,和下偏光片,使背光源的光隻能通過下偏光片,不能通過下偏光片
彩色濾光片: 不同強度的光經過紅綠藍三色濾光片之後,會形成各種各樣的顔色
液晶層: 通過通電方式來控制液晶的分子排列,進而改變背光源發出的光的路徑,如果通電則不改變路徑,光不能通過上偏光片,如果不通電則改變光的路徑,光可以通過上偏光片,進而進行顯示。
TFT基闆:排列有序的薄膜半導體,每一個薄膜半導體都可以調整其電壓,進而使單個半導體範圍内液晶進行不同的亮度和顔色顯示,也就是我們說的像素點
背光源: 提供均勻的背景光源
也就是說:如果想要LCD螢幕不顯示,那麼隻需要背光源的光不穿過上偏光片即可,如果需要LCD螢幕顯示字元,需要背光源的光穿過上偏光片,而是否能穿過上偏光片,需要看液晶層的分子排列,而液晶層的分子排列,是由加在液晶上的電壓強弱來控制的,
也就是最後我們隻需要控制每個像素點的電壓,就可以達到LCD螢幕顯示的效果。這樣就可以通過不同區域的電壓控制使液體水晶重新排列來顯示出各種圖形圖像以及字元。
LCD和OLED差別:
LCD ( Liquid Crystal Display 的簡稱)液晶顯示器。
OLED(Organic Light-Emitting Diode, OLED)本質是LED發光二極管,當兩端加上正向電壓,半導體中的載流子發生複合引起光子發射而産生光,又稱為有機電雷射顯示。
簡單地說,LCD與LED是兩種不同的顯示技術,LCD是由液态晶體組成的顯示屏,而LED則是由發光二極管組成的顯示屏。本質差別二是LCD需要背光源才能亮,OLED是發光二極管自發光,不需要額外的光源.
LCD1602引腳接線:
各引腳的功能介紹如下:
- 引腳1(VSS/GND)::地引腳
- 引腳2(VDD/VCC):電源引腳
- 引腳3(VL):液晶顯示器對比度引腳,接正電源時對比度最弱,接地時對比度最高,使用時可以通過外接一個電位器調整其對比度。
- 引腳4(RS):寄存器選擇腳,高電平時選擇資料寄存器、低電平時選擇指令寄存器。
- 引腳5(R/W):讀(read)/寫(write)信号線,高電平時進行讀操作,低電平時進行寫操作。當RS和R/W共同為低電平時可以寫入指令或顯示位址;當RS為低電平,R/W為高電平時,可以讀忙信号;當RS為高電平,R/W為低電平時,可以寫入資料。
- 引腳6(E):使能端,當E端由高電平跳變為低電平時,液晶子產品執行指令。
- 引腳7-14(D0~D7): 8位雙向資料線 用于單片機向1602寫入資料和從1602讀取資料
- 引腳15:背光源正極
- 引腳16:背光源負極
LCD1602共16個管腳,但分類很好分類,
其中一個VCC和GND用于給1602供電,
一個VCC和GND用于給背光源供電,
剩下三個功能引腳:RS(資料指令選擇端),R/W(讀寫選擇端),E(使能信号),
還有8個D0~D7分别為8位雙向資料線傳輸資料。
- RS為寄存器選擇,高電平選擇資料寄存器,低電平選擇指令寄存器。
- R/W為讀寫選擇,高電平進行讀操作,低電平進行寫操作。
- E端為使能端,後面和時序聯系在一起。
LCD1602的RAM位址映射及标準字庫表
LCD1602,總共顯示為16行2列,對應着32個RAM位址,在使用的時候,需要在哪個位置顯示,就寫入對應的RAM位址,然後再寫入需要的字元,對應就會顯示該字元。
液晶顯示子產品是一個慢顯示器件,是以在執行每條指令之前一定要确認子產品的忙标志為低電平,表示LCD此時不忙,這時才能寫指令和資料,否則此指令失效。要顯示字元時要先輸入顯示字元位址(寫指令),也就是告訴子產品在,哪裡顯示字元,然後再寫入需要顯示的字元(寫資料),才能夠正常顯示字元
下圖是1602的内部顯示位址
一共32個位址,對應2行16列
标準字庫表(CGROM):
這個ROM中固化了一些我們常用的ASCII字元以及部分日文字元的點陣資料,需要寫入那個字元,就直接設定對應進制碼就可以,比如大寫的字母A,代碼是0100 0001(41H) 與ASCII碼一緻。也就是表中的ASCII碼字元的位址和實際的ASCII碼字元是一樣的
LCD1602讀寫操作
LCD1602分為讀操作和寫操作
其中讀操作可以分為讀狀态和讀資料,寫操作可以分為寫指令和寫資料。
讀狀态: 讀取LCD引腳狀态,傳回為狀态字,D0-D6為目前LCD資料指針的位址 D7為是否允許讀寫操作(即檢查LCD是否處于忙狀态)
讀資料:讀取D0-07内的資料
寫指令: 寫入LCD的控制指令,比如清屏,顯示開關等
寫資料: 寫入需要顯示的資料,比方說要顯示字元a,就寫入0100 0001(41H)
讀狀态 | |
---|---|
引腳電平:RS=L,RW=H,E=H | 輸出:D0~D7=狀态字 |
讀資料 | |
---|---|
引腳電平:RS=H,RW=H,E=H | 輸出:D0~D7的資料 |
寫指令 | |
---|---|
引腳電平:RS=L,RW=L,D0~D7=指令碼,E=高脈沖 | 輸出:無 |
寫資料 | |
---|---|
引腳電平:RS=H,RW=L,D0~D7=資料,E=高脈沖 | 輸出:無 |
以51單片機為例,D0-D7接到P0口 RW RW EN接到任意兩個口
讀寫操作的時序圖如下:
讀操作時序:
寫操作時序:
我們來分析一下時序圖,當我們要寫指令的時候,RS置為低電平,RW置為低電平,EN置為低電平,然後将指令資料送到資料口D0~D7,延時tsp1,讓1602準備接收資料,這時候将EN拉高,産生一個上升沿,這時候指令就開始寫入LCD,延時一段時間,将EN置低電平。
當我們要寫資料的時候,RS置為低電平,RW置為高電平,EN置為低電平,然後将指令資料送到資料口D0~D7,延時tsp1,讓1602準備接收資料,這時候将EN拉高,産生一個上升沿,這時候資料就開始寫入LCD,延時一段時間,将EN置低電平。
我們以51單片機為例,D0-D7接到P0口上,RW RW EN任意三個引腳,則寫指令和寫資料代碼如下:
寫指令:
/*********************************************************/
// 1602液晶寫指令函數,cmd就是要寫入的指令
/*********************************************************/
void LcdWriteCmd(uchar cmd)
{
LcdRs_P = 0; //選擇寫指令
LcdRw_P = 0; //選擇寫
LcdEn_P = 0; //E使能拉低
P0=cmd; //把指令送入P0
DelayMs(2); //延時一小會兒,讓1602準備接收資料
LcdEn_P = 1; //使能線電平變化上升沿,指令送入1602的8位資料口
DelayMs(2);//延時,讓資料發送
LcdEn_P = 0; //使能線拉低
}
寫資料:
/*********************************************************/
// 1602液晶寫資料函數,dat就是要寫入的資料
/*********************************************************/
void LcdWriteData(uchar dat)
{
LcdRs_P = 1; //選擇寫資料
LcdRw_P = 0; //選擇寫
LcdEn_P = 0; //E使能拉低
P0=dat; //把資料送入P0
DelayMs(2); //延時一小會兒,讓1602準備接收資料
LcdEn_P = 1; //使能線電平變化上升沿,指令送入1602的8位資料口
DelayMs(2);//延時,讓資料發送
LcdEn_P = 0;//使能線拉低
}
LCD1602的指令操作
LCD1602一共有11條指令,下面我們一一解讀,
1602液晶子產品的讀寫操作,螢幕和光标的操作都是通過指令來實作的。(1為高電平,0為低電平)
指令1:清顯示,指令碼01H,
功能:
- 光标複位到位址00H位置,
- LCD顯示DDRAM的内容全部寫入” “的ASCII碼20H
指令2:光标複位,光标傳回到位址00H
功能:
- 光标複位到位址00H位置
- LCD顯示DDRAM的内容不變
指令3:光标和顯示位置設定
功能:
- I/D,寫入新資料後光标移動方向,高電平右移,低電平左移,
- S:寫入新資料後顯示屏字元是否整體左移或右移一個字元,高電平表示有效,低電平表示無效
指令4:顯示開關控制
功能:
- D(Dispaly):控制整體的顯示開與關,高電平表示開顯示屏,低電平表示關顯示屏
- C(Cursor):控制光标的開與關,高電平表示有光标,低電平表示無光标
- B(Blink):控制光标是否閃爍,高電平閃爍,低電平不閃爍
指令5:光标或顯示移位
- SC=0,RL=0 :光标左移
- SC=0,RL=1 : 光标右移
- SC=1,RL=0時,字元和光标都左移
- SC=1,RL=1時字元和光标都右移
指令6:功能設定指令
- DL:DL=1代表資料長度為8位,DL=0代表資料長度為4位
- N:低電平時隻有一行可以顯示,高電平時兩行都可以顯示,
- F:低電平時一個字元大小為5X7的點陣字元,高電平時一個字元大小為5X10的點陣字元。
指令7:CGRAM位址設定
功能:
- LCD1602的CGRAM可以設定存儲自定義字元,它共有6位,一共可以表示64個位址,即64個位元組。一個5×8點陣字元共占用8個位元組,那麼這64個位元組一共可以自定義8個字元。
指令8:DDRAM位址設定
- 指定DDRAM位址
指令9:讀忙信号和光标位址
- BF:忙标志位,高電平表示忙,此時子產品不能接收指令或資料,如果為低電平表示不忙
指令10:寫資料到CGRAM或DDRAM指令
- 指令11·:從CGRAM或DDRAM讀資料指令 功能:
- 讀取DDRAM或CGRAM中的内容
LCD初始化
LCD初始化的過程,也就是對LCD進行寫指令的過程,具體的指令如下:
- 寫指令38H:162顯示,57點陣,8位資料口 (指令6)
- 寫指令0CH:開啟顯示屏,關光标,光标不閃爍 (指令4)
- 寫指令0x06:顯示位址位址加1,即寫一個資料後,顯示位置右移一位 (指令3)
- 寫指令01H:顯示清屏
/*********************************************************/
// 1602液晶功能初始化
/*********************************************************/
void LcdInit()
{
LcdWriteCmd(0x38); // 16*2顯示,5*7點陣,8位資料口
LcdWriteCmd(0x0C); // 開顯示,不顯示光标
LcdWriteCmd(0x06); // 位址加1,當寫入資料後光标右移
LcdWriteCmd(0x01); // 清屏
}
LCD寫位址
其實本質也就是指令8,隻不過我們在寫的時候,最高位D7是要求必須要為1 ,也就是實際是7位位址
比方說我們想要寫入第二行第一列,那麼位址是40H(0100 0000),是不是直接寫就行了呢?,顯然是不行的,因為最高位D7不是1.是以需要加上一個80H(1000 0000),也就是實際寫入的為40H(0100 0000)+80H(1000 0000)=C0H(1100 0000)
那這樣子的話,第一行起始位址就是(1000 0000)80H,第二行起始位址是(1100 0000)C0H
代碼如下:
/*********************************************************/
// 液晶光标定位函數
/*********************************************************/
void LcdGotoXY(uchar line,uchar column)
{
// 第一行
if(line==0)
LcdWriteCmd(0x80+column);
// 第二行
if(line==1)
LcdWriteCmd(0x80+0x40+column);
}
LCD寫資料
這個就相對比較簡單,直接用一個指針,判斷字元是否結束,然後寫入資料就可以
/*********************************************************/
// 液晶輸出字元串函數
/*********************************************************/
void LcdPrintStr(uchar *str)
{
while(*str!='\0')
LcdWriteData(*str++);
}
代碼及使用執行個體:
這裡我們用Proteus仿真做示範
功能:LCD1602英文顯示字元
代碼如下:
#include <reg52.h>
#include <intrins.h>
#define uchar unsigned char // 以後unsigned char就可以用uchar代替
#define uint unsigned int // 以後unsigned int 就可以用uint 代替
sbit LcdRs_P = P1^1; // 1602液晶的RS管腳
sbit LcdRw_P = P1^2; // 1602液晶的RW管腳
sbit LcdEn_P = P1^3; // 1602液晶的EN管腳
/*********************************************************/
// 毫秒級的延時函數,time是要延時的毫秒數
/*********************************************************/
void DelayMs(uint time)
{
uint i,j;
for(i=0;i<time;i++)
for(j=0;j<112;j++);
}
/*********************************************************/
// 1602液晶寫指令函數,cmd就是要寫入的指令
/*********************************************************/
void LcdWriteCmd(uchar cmd)
{
LcdRs_P = 0;
LcdRw_P = 0;
LcdEn_P = 0;
P0=cmd;
DelayMs(2);
LcdEn_P = 1;
DelayMs(2);
LcdEn_P = 0;
}
/*********************************************************/
// 1602液晶寫資料函數,dat就是要寫入的資料
/*********************************************************/
void LcdWriteData(uchar dat)
{
LcdRs_P = 1;
LcdRw_P = 0;
LcdEn_P = 0;
P0=dat;
DelayMs(2);
LcdEn_P = 1;
DelayMs(2);
LcdEn_P = 0;
}
/*********************************************************/
// 液晶光标定位函數
/*********************************************************/
void LcdGotoXY(uchar line,uchar column)
{
// 第一行
if(line==0)
LcdWriteCmd(0x80+column);
// 第二行
if(line==1)
LcdWriteCmd(0x80+0x40+column);
}
/*********************************************************/
// 液晶輸出字元串函數
/*********************************************************/
void LcdPrintStr(uchar *str)
{
while(*str!='\0')
LcdWriteData(*str++);
}
/*********************************************************/
// 1602液晶功能初始化
/*********************************************************/
void LcdInit()
{
LcdWriteCmd(0x38); // 16*2顯示,5*7點陣,8位資料口
LcdWriteCmd(0x0C); // 開顯示,不顯示光标
LcdWriteCmd(0x06); // 位址加1,當寫入資料後光标右移
LcdWriteCmd(0x01); // 清屏
}
/*********************************************************/
// 開啟LCD1602顯示
/*********************************************************/
void LcdOn() //開顯示器,關光标與閃爍
{
LcdWriteCmd(0x0c);
}
/*********************************************************/
//關閉LCD1602顯示,但DDRAM中内容不丢失,重開後将恢複内容
/*********************************************************/
void LcdOff()
{
LcdWriteCmd(0x08);
}
/*********************************************************/
// 1602液晶顯示内容初始化
/*********************************************************/
void LcdShowInit()
{
LcdGotoXY(0,0); // 定位到第0行第0列
LcdPrintStr(" LCD Test "); // 第0行顯示“ ”
LcdGotoXY(1,0); // 定位到第1行第0列
LcdPrintStr("ABCDEFGHIJKLMNOP"); // 第1行顯示“ ”
}
/*********************************************************/
// 主函數
/*********************************************************/
void main()
{
LcdInit(); // 液晶功能初始化
LcdShowInit();
while(1)
{
}
}
測試效果如下: