快速掌握——LCD1602液晶顯示(多組實驗,附帶源程序)

一、 LCD1602 簡介

簡介部分資料來源於百度百科:

實物圖:

在這裏插入圖片描述

Proteus器件圖:

器件號: LM016L

在這裏插入圖片描述

簡介:

LCD1602

16——表示每行顯示16個字符
02——表示顯示兩行

LCD1602是一種字符點陣型顯示模塊,如下圖 ,每個字符是由 5X8 的點陣組成。
在這裏插入圖片描述

引腳介紹:

這裏是引用

引腳1:VSS爲地電源。
引腳2:VDD接5V正電源。
引腳3:VL爲液晶顯示器對比度調整端,接正電源時對比度最弱,接地時對比度最高。

引腳4:RS爲寄存器選擇腳,高電平時選擇數據寄存器、低電平時選擇指令寄存器

引腳5:R/W爲讀/寫信號線,高電平時進行讀操作,低電平時進行寫操作
當RS和R/W共同 爲低電平時可以寫入指令或顯示地址;當RS爲低電平,R/W爲高電平時,可以讀忙信號;當 RS爲高電平,R/W爲低電平時,可以寫入數據。

引腳6:E端爲使能端,當E端由高電平跳變爲低電平時(下降沿有效),液晶模塊執行命令。

引腳7 ~ 14:D0~D7爲8位雙向數據線。

引腳15:背光源正極。
引腳16:背光源負極

指令集(11條指令):

表1這裏是引用

(1)指令1:清屏。指令碼01H,光標復位到地址00H。

(2)指令2:光標復位。光標復位到地址00H。

(3)指令3:輸入方式設置。
其中,I/D表示光標的移動方向,高電平右移,低電平左移;S表示顯示屏上所有文字是否左移或右移,高電平表示有效,低電平表示無效。

(4)指令4:顯示開關控制。
其中,D用於控制整體顯示的開與關,高電平表示開顯示,低電平表示關顯示;C用於控制光標的開與關,高電平表示有光標,低電平表示無光標;B用於控制光標是否閃爍,高電平閃爍,低電平不閃爍。

(5)指令5:光標或字符移位控制。
其中,S/C表示在高電平時移動顯示的文字,低電平時移動光標。

(6)指令6:功能設置命令。
其中,DL表示在高電平時爲4位總線,低電平時爲8位總線;N表示在低電平時爲單行顯示,高電平時雙行顯示;F表示在低電平時顯示5×7的點陣字符,高電平時顯示5×10的點陣字符。

(7)指令7:字符發生器RAM地址設置。

(8)指令8:DDRAM地址設置。

(9)指令9:讀忙信號和光標地址。
其中,BF爲忙標誌位,高電平表示忙,此時模塊不能接收命令或數據,如果爲低電平則表示不忙。

(10)指令10:寫數據。

(11)指令11:讀數據。

常用指令:

0x80+0xdd:dd爲地址,這條命令用於設置顯示起點座標

0x0c :開顯示,無光標,光標不閃爍 。一般做帶鍵盤輸入的才加入光標,如計算器。常用的計量顯示不顯示光標。

0x06 :寫一個數據,地址指針加1,由1602地址表可以看出,實際上就是設置成從左往右寫數據而已。

0x38 : 設置顯示模式,16x2顯示 5x7點陣,8位數據接口。端口不夠用時,這個命令也可以換用4位數據接口的。

0x01 :清屏。

表2在這裏插入圖片描述

二、顯示原理

在這裏插入圖片描述

如上圖,每個字符由 5X8 點陣組成(也可選用 5X10),想要實現顯示,只需如下圖:

例:以 5X7 點陣爲例, 顯示字符 A

0 代表滅,1 代表亮
只需將想要顯示的字符的對應位置1,就能顯示該字符
在這裏插入圖片描述

LCD1602 固化了字模寄存器,即 CGROM 和 CGRAM,存儲了192個常用字符的字模。

字模庫:

該表 行是低四位,列是高四位

想要顯示哪個字符,只需查表,換算爲十六進制,寫入LCD1602即可。
在這裏插入圖片描述

例: 想要顯示字符 A

需要向 LCD1602 寫入 0x41(0100 0001)

三、顯示位置

LCD1602 實際有80個字節的DDRAM,

只不過 LCD1602 只有 16X2 個位置,後面很多位置顯示不出來,可以使用 指令5“光標或顯示移動指令” 使字符慢慢移動到可見的顯示範圍內,看到字符的移動效果。

所以LCD1602的實際顯示位置是,第一行:00 ~ 0F,第二行:40 ~ 4F
在這裏插入圖片描述

注意:

如圖, 指令8,D7位恆爲 1,

在實際向LCD1602傳入數據顯示地址時,需要 < 地址+0x80 >

例:向LCD1602的第一行第一列寫數據,傳入的地址應爲: (0x00+0x80)
在這裏插入圖片描述

四、LCD1602 操作

①寫操作時序圖:

在這裏插入圖片描述

②讀操作時序圖:

在這裏插入圖片描述

③時序時間參數:

在這裏插入圖片描述

1、忙檢測

爲什麼需要忙檢測??

單片機和 LCD1602 的工作速度存在差異,單片機速度快,所以單片機向 LCD1602 傳數據時,LCD1602 可能正在處理上一次的數據,處在忙狀態,爲了防止數據丟失或出錯,所以單片機就需要等待,待 LCD1602 處理完時在進行下一次數據的傳送。

代碼:

由指令9,需判斷 BF 的狀態

/****************** 忙檢測 *********************
LCD_Data 與 0x80 進行或運算,判斷 bit7 位狀態

若 LCD_Data 的 bit7 位是 0,則 LCD 不忙
若 LCD_Data 的 bit7 位是 1,則 LCD 忙
***********************************************/
void LCD_Check_Busy(){

	uchar temp;

	LCD_Data = 0xff  // 十六進制:1111 1111
	LCD_RS = 0;  // 0 指令
	LCD_RW = 1;	 // 1 讀

	do{
		LCD_E = 1;		  // 拉高
		temp = LCD_Data;  // 將 LCD 狀態保存在 temp 中,用於判忙
		LCD_E = 0;		  // 負跳變使能 
	}while(temp & 0x80);  // 結果爲 1,LCD 忙,繼續循環;結果爲 0,LCD 不忙,可以進行後面的操作
}

2、初始化

爲什麼初始化?

在 LCD1602 進行顯示前,需要進行輸入方式設置,顯示開關設置,光標、畫面移位設置,功能設置等,確定 LCD1602 的工作方式。

代碼:

/****************** 初始化 *********************
指令1 ——清屏
指令3 ——AC加1,畫面不動 
指令4 ——顯示開,光標關,閃爍關 
指令6 ——8位數據接口,兩行顯示,5X7點陣
指令8 ——從第一行第一列開始顯示
***********************************************/
void LCD_Init(){

	LCD_Write_Cmd(0x01); // 指令1 ——清屏
	LCD_Write_Cmd(0x06); // 指令3 ——AC加1,畫面不動 
	LCD_Write_Cmd(0x0c); // 指令4 ——顯示開,光標關,閃爍關 
	LCD_Write_Cmd(0x38); // 指令6 ——8位數據接口,兩行顯示,5X7點陣
	LCD_Write_Cmd(0x80); // 指令8 ——從第一行第一列開始顯示
}

3、寫命令

代碼:

/****************** 寫命令 *********************
RS=0 指令
RW=0 寫操作
E=0 開始爲 0
寫入指令(給單片機 P3 端口)
延時 2ms
E=1 拉高
延時5ms,寫入指令有效
E=0 負跳變,指令寫入LCD
***********************************************/
void LCD_Write_Cmd(uchar Cmd){

	LCD_Check_Busy();  // 判忙

	LCD_RS = 0;  // 0 指令
	LCD_RW = 0;  // 0 寫

	LCD_E = 0;
	LCD_Data = Cmd;  // 送指令
	delay_1ms(2);
	
	LCD_E = 1;  // 拉高
	delay_1ms(5);

	LCD_E = 0;
}

4、寫數據

代碼:

/****************** 寫數據 *********************
RS=1 數據
RW=0 寫操作
E=0 開始爲 0
寫入數據(給單片機 P3 端口)
延時 2ms
E=1 拉高
延時 7ms,寫入數據有效
E=0 負跳變,數據寫入LCD
***********************************************/
void LCD_Write_Data(uchar Data){

	LCD_Check_Busy();  // 判忙

	LCD_RS = 1;  // 1 數據
	LCD_RW = 0;  // 0 寫

	LCD_E = 0;
	LCD_Data = Data;  // 送數據
	delay_1ms(2);
	
	LCD_E = 1;  // 拉高
	delay_1ms(7);

	LCD_E = 0;
}

實驗一:顯示Hello World !

結果展示:

在這裏插入圖片描述

代碼:

#include<reg51.h>

#define uchar unsigned char
#define uint unsigned int

#define LCD_Data P3  // 數據端口

sbit LCD_RS = P2^0;  // 數據(1)/ 指令(0)
sbit LCD_RW = P2^1;  // 讀(1) / 寫(0)
sbit LCD_E = P2^2;	 // 使能(負跳變起作用)

void delay_1ms(uint c){  // 延時函數,無誤差

	uchar a,b;
	for(;c>0;c--)
	{ 
		for(b=199;b>0;b--) 
		{ 
			for(a=1;a>0;a--);
		}
	}
}

/****************** 忙檢測 *********************
LCD_Data 與 0x80 進行或運算,判斷 bit7 位狀態

若 LCD_Data 的 bit7 位是 0,則 LCD 不忙
若 LCD_Data 的 bit7 位是 1,則 LCD 忙
***********************************************/
void LCD_Check_Busy(){

	uchar temp;

	LCD_Data = 0xff;  // 十六進制:1111 1111
	LCD_RS = 0;  // 0 指令
	LCD_RW = 1;	 // 1 讀

	do{
		LCD_E = 1;		  // 拉高
		temp = LCD_Data;  // 將 LCD 狀態保存在 temp 中,用於判忙
		LCD_E = 0;		  // 負跳變使能 
	}while(temp & 0x80);  // 結果爲 1,LCD 忙,繼續循環;結果爲 0,LCD 不忙,可以進行後面的操作
}

/****************** 寫指令 *********************
RS=0 指令
RW=0 寫操作
E=0 開始爲 0
寫入指令(給單片機 P3 端口)
延時 2ms
E=1 拉高
延時5ms,寫入指令有效
E=0 負跳變,指令寫入LCD
***********************************************/
void LCD_Write_Cmd(uchar Cmd){

	LCD_Check_Busy();  // 判忙

	LCD_RS = 0;  // 0 指令
	LCD_RW = 0;  // 0 寫

	LCD_E = 0;
	LCD_Data = Cmd;  // 送指令
	delay_1ms(2);

	LCD_E = 1;
	delay_1ms(5);

	LCD_E = 0;
}

/****************** 寫數據 *********************
RS=1 數據
RW=0 寫操作
E=0 開始爲 0
寫入數據(給單片機 P3 端口)
延時 2ms
E=1 拉高
延時 7ms,寫入數據有效
E=0 負跳變,數據寫入LCD
***********************************************/
void LCD_Write_Data(uchar Data){

	LCD_Check_Busy();  // 判忙

	LCD_RS = 1;  // 1 數據
	LCD_RW = 0;  // 0 寫

	LCD_E = 0;
	LCD_Data = Data;  // 送數據
	delay_1ms(2);
	
	LCD_E = 1;
	delay_1ms(7);

	LCD_E = 0;
}

/****************** 初始化 *********************
指令1 ——清屏
指令3 ——AC加1,畫面不動 
指令4 ——顯示開,光標關,閃爍關 
指令6 ——8位數據接口,兩行顯示,5X7點陣
指令8 ——從第一行第一列開始顯示
***********************************************/
void LCD_Init(){

	LCD_Write_Cmd(0x01); // 指令1 ——清屏
	LCD_Write_Cmd(0x06); // 指令3 ——AC加1,畫面不動 
	LCD_Write_Cmd(0x0c); // 指令4 ——顯示開,光標關,閃爍關 
	LCD_Write_Cmd(0x38); // 指令6 ——8位數據接口,兩行顯示,5X7點陣
	LCD_Write_Cmd(0x80); // 指令8 ——從第一行第一列開始顯示
}

/****************** 主函數 *********************

***********************************************/
void main()
{
	uchar code Data[]="Hello World !";  // 要顯示的數據
	
	uchar i;

	LCD_Init();  // LCD1602 初始化

	LCD_Write_Cmd(0x00+0x80);  // 第一行第一列地址,0x00 可以省去,爲了講明白故加上
	for(i=0; i<16; i++){
		LCD_Write_Data(Data[i]);
	}

	while(1);		
}

實驗二:兩行顯示

要求:
第一行顯示 0123456789012345
第二行顯示 abcdefghABCDEFGH

結果展示:

在這裏插入圖片描述

代碼:

#include<reg51.h>

#define uchar unsigned char
#define uint unsigned int

#define LCD_Data P3  // 數據端口

sbit LCD_RS = P2^0;  // 數據(1)/ 指令(0)
sbit LCD_RW = P2^1;  // 讀(1) / 寫(0)
sbit LCD_E = P2^2;	 // 使能(負跳變起作用)

void delay_1ms(uint c){  // 延時函數,無誤差

	uchar a,b;
	for(;c>0;c--)
	{ 
		for(b=199;b>0;b--) 
		{ 
			for(a=1;a>0;a--);
		}
	}
}

/****************** 忙檢測 *********************
LCD_Data 與 0x80 進行或運算,判斷 bit7 位狀態

若 LCD_Data 的 bit7 位是 0,則 LCD 不忙
若 LCD_Data 的 bit7 位是 1,則 LCD 忙
***********************************************/
void LCD_Check_Busy(){

	uchar temp;

	LCD_Data = 0xff;  // 十六進制:1111 1111
	LCD_RS = 0;  // 0 指令
	LCD_RW = 1;	 // 1 讀

	do{
		LCD_E = 1;		  // 拉高
		temp = LCD_Data;  // 將 LCD 狀態保存在 temp 中,用於判忙
		LCD_E = 0;		  // 負跳變使能 
	}while(temp & 0x80);  // 結果爲 1,LCD 忙,繼續循環;結果爲 0,LCD 不忙,可以進行後面的操作
}

/****************** 寫指令 *********************
RS=0 指令
RW=0 寫操作
E=0 開始爲 0
寫入指令(給單片機 P3 端口)
延時 2ms
E=1 拉高
延時5ms,寫入指令有效
E=0 負跳變,指令寫入LCD
***********************************************/
void LCD_Write_Cmd(uchar Cmd){

	LCD_Check_Busy();  // 判忙

	LCD_RS = 0;  // 0 指令
	LCD_RW = 0;  // 0 寫

	LCD_E = 0;
	LCD_Data = Cmd;  // 送指令
	delay_1ms(2);

	LCD_E = 1;
	delay_1ms(5);

	LCD_E = 0;
}

/****************** 寫數據 *********************
RS=1 數據
RW=0 寫操作
E=0 開始爲 0
寫入數據(給單片機 P3 端口)
延時 2ms
E=1 拉高
延時 7ms,寫入數據有效
E=0 負跳變,數據寫入LCD
***********************************************/
void LCD_Write_Data(uchar Data){

	LCD_Check_Busy();  // 判忙

	LCD_RS = 1;  // 1 數據
	LCD_RW = 0;  // 0 寫

	LCD_E = 0;
	LCD_Data = Data;  // 送數據
	delay_1ms(2);
	
	LCD_E = 1;
	delay_1ms(7);

	LCD_E = 0;
}

/****************** 初始化 *********************
指令1 ——清屏
指令3 ——AC加1,畫面不動 
指令4 ——顯示開,光標關,閃爍關 
指令6 ——8位數據接口,兩行顯示,5X7點陣
指令8 ——從第一行第一列開始顯示
***********************************************/
void LCD_Init(){

	LCD_Write_Cmd(0x01); // 指令1 ——清屏
	LCD_Write_Cmd(0x06); // 指令3 ——AC加1,畫面不動 
	LCD_Write_Cmd(0x0c); // 指令4 ——顯示開,光標關,閃爍關 
	LCD_Write_Cmd(0x38); // 指令6 ——8位數據接口,兩行顯示,5X7點陣
	LCD_Write_Cmd(0x80); // 指令8 ——從第一行第一列開始顯示
}


/****************** 主函數 *********************

***********************************************/
void main()
{
	uchar code Data_1[]="0123456789012345";  // 第一行要顯示的數據
	uchar code Data_2[]="abcdefghABCDEFGH";  // 第二行要顯示的數據

	uchar i;

	LCD_Init();  // LCD1602 初始化

	LCD_Write_Cmd(0x00+0x80);  // 第一行第一列地址
	for(i=0; i<16; i++){
		LCD_Write_Data(Data_1[i]);
	}

	LCD_Write_Cmd(0x40+0x80);  // 第二行第一列地址
	for(i=0; i<16; i++){
		LCD_Write_Data(Data_2[i]);
	}

	while(1);		
}

實驗三:溫度單位顯示

確定字模:

如圖,查字模表得:
溫度單位由 1101 1111 和 0100 0011 組成
換算位十六進制爲:0xdf0x43 組成
在這裏插入圖片描述

結果展示:

在這裏插入圖片描述

代碼:

直接替換爲以下主函數即可


/****************** 主函數 *********************

***********************************************/
void main()
{

	LCD_Init();  // LCD1602 初始化

	LCD_Write_Cmd(0x00+0x80);  // 第一行第一列地址
	LCD_Write_Data(0xdf);
	LCD_Write_Data(0x43);

	while(1);		
}

實驗四:單行滾動顯示

**要求:**在第一行滾動顯示字符串 “Good Good Study,Day Day Up !”

需要用到 指令5——0x18 //畫面左移一個字符位,光標不動

結果展示:

在這裏插入圖片描述

代碼:

直接替換位爲以下主函數即可

/****************** 主函數 *********************

***********************************************/
void main()
{
	uchar i;

	uchar code Data[]="Good Good Study,Day Day Up !";

	LCD_Init();  // LCD1602 初始化

	
	LCD_Write_Cmd(0x00+0x80);  // 第一行第一列地址
	for(i=0; i<28; i++){
		LCD_Write_Data(Data[i]);
	}

	while(1){
		delay_1ms(500);  // 控制移動速度
		LCD_Write_Cmd(0x18);  // 指令5 ——畫面左移一個字符位,光標不動
	}		
}

實驗五:一行不動,一行動

要求:
第一行顯示 " I Love You “,固定不動
第二行顯示"Good Good Study,Day Day Up !”, 實現向左移動效果

結果展示:

在這裏插入圖片描述

代碼:

直接替換位爲以下主函數即可

/****************** 主函數 *********************
不使用整屏左移命令

使用指針進行右移
***********************************************/
void main()
{
	uchar i, j=0, n=0;

	uchar code Data_1[]="   I Love You   ";  // 第一行顯示,共十六個字符
	uchar code Data_2[]="Good Good Study,Day Day Up !";  // 第二行顯示,共28個字符

	LCD_Init();  // LCD1602 初始化

	
	LCD_Write_Cmd(0x00+0x80);  // 第一行第一列地址
	for(i=0; i<16; i++){     
		LCD_Write_Data(Data_1[i]);  // 顯示第一行
	}

	while(1){

		LCD_Check_Busy();  // 判忙,若忙,不繼續執行

		LCD_Write_Cmd(0x40+0x80);  // 第二行第一列地址
		for(j=n; j<28+n; j++){     
			LCD_Write_Data(Data_2[j]);  // 顯示第二行
		}

		n++;

		if(n >= (28-15)){  // 當數據移動到最後時,n 重置 0,停頓 500 ms,重新開始移動顯示
			n = 0;
			delay_1ms(500);
		}

		delay_1ms(200);  // 控制移動速度
	}		
}

實驗六:自定義字模顯示

要求:
自定義數模
在第一行第一列顯示漢字 ——年
在第一行第三列顯示漢字 ——月
在第一行第五列顯示漢字 ——日

確定字模:

以 日 字爲例
在這裏插入圖片描述

結果展示:

在這裏插入圖片描述

代碼:

直接替換位爲以下主函數即可

/****************** 主函數 *********************
***********************************************/
void main(){

	uchar i;
	
	uchar code Data_0[]={0x0f, 0x12, 0x0f, 0x0a, 0x1f, 0x02, 0x02, 0x02};  // 漢字 年 的字模
	uchar code Data_1[]={0x0f, 0x09, 0x0f, 0x09, 0x0f, 0x09, 0x0b, 0x11};  // 漢字 月 的字模	
	uchar code Data_2[]={0x1f, 0x11, 0x11, 0x1f, 0x11, 0x11, 0x1f, 0x00};  // 漢字 日 的字模

	LCD_Init();  // LCD1602 初始化

	LCD_Write_Cmd(0x40);  // 0100 0000; 指令 0x40 向 CGRAM 地址0 寫入自定義數據
	for(i=0; i<8; i++){
		LCD_Write_Data(Data_0[i]);  // 寫入自定義字符字模
	}

	LCD_Write_Cmd(0x48);  // 0100 1000; 指令 0x48 向 CGRAM 地址1 寫入自定義數據
	for(i=0; i<8; i++){
		LCD_Write_Data(Data_1[i]);  // 寫入自定義字符字模
	}

	LCD_Write_Cmd(0x50);  // 0101 0000; 指令 0x50 向 CGRAM 地址2 寫入自定義數據
	for(i=0; i<8; i++){
		LCD_Write_Data(Data_2[i]);  // 寫入自定義字符字模
	}


	LCD_Write_Cmd(0x00+0x80);  // 在第一行第一列顯示 第一個字符
	LCD_Write_Data(0);

	LCD_Write_Cmd(0x02+0x80);  // 在第一行第三列顯示 第二個字符
	LCD_Write_Data(1);

	LCD_Write_Cmd(0x04+0x80);  // 在第一行第五列顯示 第一個字符
	LCD_Write_Data(2);
	
	while(1);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章