快速掌握——LCD1602液晶显示(多组实验,附带源程序)
快速掌握—— LCD1602液晶顯示
- 一、 LCD1602 簡介
- 實物圖:
- Proteus器件圖:
- 簡介:
- 引腳介紹:
- 指令集(11條指令):
- 二、顯示原理
- 字模庫:
- 三、顯示位置
- 四、LCD1602 操作
- ①寫操作時序圖:
- ②讀操作時序圖:
- ③時序時間參數:
- 1、忙檢測
- 為什么需要忙檢測??
- 代碼:
- 2、初始化
- 為什么初始化?
- 代碼:
- 3、寫命令
- 代碼:
- 4、寫數據
- 代碼:
- 實驗一:顯示Hello World !
- 結果展示:
- 代碼:
- 實驗二:兩行顯示
- 結果展示:
- 代碼:
- 實驗三:溫度單位顯示
- 確定字模:
- 結果展示:
- 代碼:
- 實驗四:單行滾動顯示
- 結果展示:
- 代碼:
- 實驗五:一行不動,一行動
- 結果展示:
- 代碼:
- 實驗六:自定義字模顯示
- 確定字模:
- 結果展示:
- 代碼:
一、 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 1111LCD_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 1111LCD_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 1111LCD_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 組成
換算位十六進制為:0xdf 和 0x43 組成
結果展示:
代碼:
直接替換為以下主函數即可
/****************** 主函數 ********************************************************************/ 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); }總結
以上是生活随笔為你收集整理的快速掌握——LCD1602液晶显示(多组实验,附带源程序)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 手机知识:手机蓝牙有6个使用场景,你都知
- 下一篇: element中select默认选中第一