LCD1602 液晶顯示實驗
????????來介紹一種非常簡單且常用的顯示裝置——LCD1602 液晶顯示器,使用它可以顯示更多的字符數(shù)字。這將有助于我們清晰的觀察程序的運行結(jié)果,更加方便我們的后續(xù)調(diào)試和開發(fā)。
????????我們的開發(fā)板上集成了一個 LCD1602 液晶顯示器接口,將LCD1602 液晶對應插入即可。
????????本章要實現(xiàn)的功能是:系統(tǒng)運行時,在 LCD1602 液晶上顯示字符信息。
????????本章節(jié)可分為如下幾部分內(nèi)容:
????????一、 LCD1602 介紹
????????二、 硬件設(shè)計
????????三、 軟件設(shè)計
????????四、 實驗現(xiàn)象
?保姆級燒錄教程
?一些有趣的LCD1602顯示實驗
點擊在線瀏覽本文檔,支持在線評論和互動。
本實驗所有文檔資料下載(藍奏云)密碼:9drm
本實驗所有教學視頻及PPT資源下載(百度云)
一、LCD1602介紹
1.1 LCD1602簡介和引腳定義
????????LCD1602 液晶也叫 LCD1602 字符型液晶,它能顯示 2 行字符信息,每行又能顯示 16 個字符。它是一種專門用來顯示字母、數(shù)字、符號的點陣型液晶模塊。它是由若干個
5x7
或者5x10
的點陣字符位組成,每個點陣字符位都可以用顯示一個字符, 每位之間有一個點距的間隔,每行之間也有間隔,起到了字符間距和行間距的作用,正因為如此,它不能很好的顯示圖片。其實物圖如下所示:

????????大家手上拿到的 LCD1602 外觀可能和圖1不一樣,這是由于不同廠家設(shè)計所致,但使用方法是一樣的。在上圖可以看到有 16 個管腳孔,從左至右管腳編號是 1-16,其功能定義如下所示:
????????1 腳:VSS,接地。
????????2 腳:VDD,電源正極(4.5~5.5V都可)。
????????3 腳:VO,對比度調(diào)節(jié)。液晶顯示偏壓信號,用于調(diào)整 LCD1602 的顯示對比度,一般會外接電位器用以調(diào)整偏壓信號,注意此腳電壓為 0 時可以得到最強的對比度。
????????4 腳:RS,數(shù)據(jù)/指令選擇端,1為數(shù)據(jù),0為指令。當此腳為高電平時,可以對 1602 進行數(shù)據(jù)字節(jié)的傳輸操作,而為低電平時,則是進行命令字節(jié)的傳輸操作。命令字節(jié),即是用來對 LCD1602 的一些工作方式作設(shè)置的字節(jié);數(shù)據(jù)字節(jié),即使用以在 1602 上顯示的字節(jié)。值得一提的是,LCD1602 的數(shù)據(jù)是 8 位的。
????????5 腳:R/W,讀/寫選擇端,1為讀,0為寫。當此腳為高電平可對 LCD1602 進行讀數(shù)據(jù)操作, 反之進行寫數(shù)據(jù)操作。
????????6 腳:E,使能信號,1為數(shù)據(jù)有效,下降沿執(zhí)行命令。其實是 LCD1602 的數(shù)據(jù)控制時鐘信號,利用該信號的上升沿實現(xiàn)對 LCD1602 的數(shù)據(jù)傳輸。
????????7~14 腳:數(shù)據(jù)輸入/輸出。8 位并行數(shù)據(jù)口,而 51 單片機一組 IO 也是 8 位,使得對 LCD1602 的數(shù)據(jù)讀寫大為方便。
????????15 腳:A,背光燈電源正極。
????????16 腳:K,背光燈電源負極。
????????下面給出各引腳功能速覽表和其內(nèi)部原理圖:


1.2 LCD1602內(nèi)部結(jié)構(gòu)

??????DDRAM(Data Display Random Access Memory ):數(shù)據(jù)顯示存儲器。
可讀取,可寫入。如圖5所示,可顯示位置為40*2,共計80個字符。即是第一行?
00H~27H
,和第二行的40H~67H
。

?????CGRAM(Character Generation Random Access Memory):用戶字符發(fā)生器。
可以自定義用戶的字模庫(最多八個字符)。
??????CGROM(Character Generation Read Only Memory):字符發(fā)生器。
出廠默認設(shè)置的字模庫,與標準ASCII碼基本一致。并在此基礎(chǔ)上加入片假名和部分特殊符號的支持。具體支持范圍如圖六所示:

????????讀取方式也很簡單,例如想獲得"A"在字模庫中的位置,由圖6可知,其二進制位置為
0100 0000B
,轉(zhuǎn)換為16進制是40H
。
????????屏幕顯示:顯示字符數(shù)據(jù),16*2。

?????????由圖5和圖7對比可知:不是所有的地址都可以直接用來顯示字符數(shù)據(jù),只有第一行中的
00-0F
,第二行中的40-4F
才能顯示,其他地址只能用于存儲。????????要顯示字符時要先輸入顯示字符地址,也就是告訴模塊在哪里顯示字符,例如第二行第一個字符的地址是 40H,那么是否直接寫入 40H 就可以將光標定位在第二行第一個字符的位置呢?這樣不行,因為寫入顯示地址時要求最高位 D7 恒定為高電平 1 所以實際寫入的數(shù)據(jù)應該是
01000000B(40H)+10000000B(80H)=11000000B(C0H)
。????????在 1602 中我們就用前 16 個就行了。第二行也一樣用前 16 個地址。
??????AC(Aid Carry):輔助進位,即光標位置。
?指向下一位字符的位置,并在顯示完畢后,自動加一。
1.3 LCD1602常用指令

? ? ? 在使用 LCD1602 時,我們要掌握一些常用指令,這些指令對于 LCD1602 初始化是必須的。
(1)清屏指令

功能:
<1> 清除液晶顯示器,即將 DDRAM 的內(nèi)容全部填入"空白"的 ASCII 碼
20H
;<2> 光標歸位,即將光標撤回液晶顯示屏的左上方;
<3> 將地址計數(shù)器(AC)的值設(shè)為 0。
也就是說 清屏指令是
0x01
(2)模式設(shè)置指令

功能:
設(shè)定每次寫入 1 位數(shù)據(jù)后光標的移位方向,并且設(shè)定每次寫入的一個字符是否移動。
I/D:0=寫入新數(shù)據(jù)后光標左移 1=寫入新數(shù)據(jù)后光標右移
S:0=寫入新數(shù)據(jù)后顯示屏不移動 1=寫入新數(shù)據(jù)后顯示屏整體右移1 個字符
也就是說 寫入新數(shù)據(jù)后光標右移,顯示屏不移動的命令是
0x06
(3)顯示開關(guān)控制指令

功能:
控制顯示器開/關(guān)、光標顯示/關(guān)閉以及光標是否閃爍。
D:0=顯示功能關(guān) 1=顯示功能開
C:0=無光標 1=有光標
B:0=光標閃爍 1=光標不閃爍
也就是說 顯示開,光標關(guān),閃爍關(guān)的指令是
0x0c
(4)功能設(shè)定指令

功能:
設(shè)定數(shù)據(jù)總線位數(shù)、顯示的行數(shù)及字型。
DL:0=數(shù)據(jù)總線為 4 位 1=數(shù)據(jù)總線為 8 位
N:0=顯示 1 行 1=顯示 2 行
F:0=5×7 點陣/每字符 1=5×10 點陣/每字符
也就是說 數(shù)據(jù)總線8位,顯示2行,5*7點陣/字符的命令是
0x38
1.4 LCD1602的使用
????????要使用 LCD1602,首先需要對其初始化,即通過寫入一些特定的指令實現(xiàn)。然后選擇要在 LCD1602 的哪個位置顯示,并將所要顯示的數(shù)據(jù)發(fā)送到 LCD 的 DDRAM。使用 LCD1602 通常都是用于寫數(shù)據(jù)進去,很少使用讀功能。LCD1602 操作步驟如下所示:
(1)初始化
發(fā)送指令0x38 //八位數(shù)據(jù)接口,兩行顯示,5*7點陣
發(fā)送指令0x0C //顯示開,光標關(guān),閃爍關(guān)
發(fā)送指令0x06 //數(shù)據(jù)讀寫操作后,光標自動加一,畫面不動
發(fā)送指令0x01 //清屏
(2)寫命令(RS=0),設(shè)置顯示坐標
(3)寫數(shù)據(jù)(RS=1)
/**
* @brief LCD1602初始化函數(shù)
* @param 無
* @retval 無
*/
void LCD_Init()
{
LCD_WriteCommand(0x38);//八位數(shù)據(jù)接口,兩行顯示,5*7點陣
LCD_WriteCommand(0x0c);//顯示開,光標關(guān),閃爍關(guān)
LCD_WriteCommand(0x06);//數(shù)據(jù)讀寫操作后,光標自動加一,畫面不動
LCD_WriteCommand(0x01);//光標復位,清屏
}
????????下面給出LCD1602 的時序圖和時序參數(shù)圖:

????????在此,不需要讀出它的數(shù)據(jù)的狀態(tài)或者數(shù)據(jù)本身。所以只需要看圖13寫時序:
? 1. 當要寫指令字,設(shè)置 LCD1602 的工作方式時:需要把 RS 置為低電平,RW 置為低電平,然后將數(shù)據(jù)送到數(shù)據(jù)口
D0~D7
,最后 E 引腳一個高脈沖將數(shù)據(jù)寫入。也就是:
/**
* @brief LCD1602寫命令
* @param Command 要寫入的命令
* @retval 無
*/
void LCD_WriteCommand(unsigned char Command)
{
LCD_RS=0; //寫命令置0
LCD_RW=0; //1為讀,0為寫
P0=Command; //把命令通過P0口傳送(D0~D7連到P0口的情況下)
LCD_EN=1; //拉高使能引腳
LCD_Delay(); //1ms 延時
LCD_EN=0; //拉低使能引腳,數(shù)據(jù)寫入完畢
LCD_Delay(); //1ms 延時
}
2.當要寫入數(shù)據(jù)字,在 1602 上實現(xiàn)顯示時:需要把 RS 置為高電平,RW 置為低電平,然后將數(shù)據(jù)送到數(shù)據(jù)口
D0~D7
,最后 E 引腳一個高脈沖將數(shù)據(jù)寫入。也就是:
/**
* @brief LCD1602寫數(shù)據(jù)
* @param Data 要寫入的數(shù)據(jù)
* @retval 無
*/
void LCD_WriteData(unsigned char Data)
{
LCD_RS=1; //寫數(shù)據(jù)置1
LCD_RW=0; //1為讀,0為寫
P0=Data; //把數(shù)據(jù)通過P0口傳送(D0~D7連到P0口的情況下)
LCD_EN=1; //拉高使能引腳
LCD_Delay(); //1ms 延時
LCD_EN=0; //拉低使能引腳,數(shù)據(jù)寫入完畢
LCD_Delay(); //1ms 延時
}
????????寫指令和寫數(shù)據(jù),差別僅僅在于 RS 的電平不一樣而已。
????????當要寫命令字節(jié)的時候,時間由左往右,RS 變?yōu)榈碗娖?,R/W 變?yōu)榈碗娖剑?注意看是 RS 的狀態(tài)先變化完成。然后這時,DB0~DB7
上數(shù)據(jù)進入有效階段,接著 E 引腳有一個整脈沖的跳變,接著要維持時間最小值為tpw=400ns
的 E 脈沖寬度。然后E 引腳負跳變,RS 電平變化,R/W 電平變化。這樣便是一個完整的LCD1602寫命令的時序。
?從圖13可以看到,以上給的時間參數(shù)全部是 ns 級別的,而 51 單片機的機器周期是 1us,指令周期是 2-4 個機器周期,所以理論上即便在程序里不加延時程序,也可以很好的配合 LCD1602 的時序要求了。但實際上在使能E拉高時要延時1ms左右,不然寫入數(shù)據(jù)會失敗,這個要多加注意。
二、 硬件設(shè)計
????????本實驗使用到硬件資源如下:
????????(1)LCD1602 液晶
????????開發(fā)板上集成了一個 LCD1602 液晶接口,下面來看下開發(fā)板上 LCD1602 液晶接口電路,如下圖所示:

????????從上圖中可知,LCD1602 的 8 位數(shù)據(jù)口 DB0-DB7
與單片機的 P0.0-P0.7 管腳連接,LCD1602 的 RS、RW、E 腳與單片機的 P2.6、P2.5、P2.7 管腳連接。RJ1 是一個電位器,用來調(diào)節(jié) LCD1602 對比度即顯示亮度。
注意:這里原理圖是使用的 8 位 LCD1602 接口設(shè)計,是可以兼容 4 位 LCD1602 的。對于非標準接口的 LCD1602,我們也會通過轉(zhuǎn)接板將其轉(zhuǎn)接為對應開發(fā)板接口的。對于 4 位 LCD1602 在傳輸數(shù)據(jù)的時候需要將 8 位的數(shù)據(jù)截成兩段,先發(fā)送高四位,在發(fā)送低四位。其它引腳操作方法不變。
三、 軟件設(shè)計
????????本章所要實現(xiàn)的功能是:在 LCD1602 液晶上顯示字符信息。程序框架如下:
????????(1)編寫 LCD1602 顯示函數(shù)
????????(2)編寫主函數(shù)
????????本章軟件的重點是如何對 LCD1602 進行寫命令和數(shù)據(jù)。
????????3.1 LCD1602驅(qū)動函數(shù)
????????在第一步 1.4 LCD1602的使用 我們已經(jīng)了解到了LCD1602的初始化,寫命令及寫數(shù)據(jù)操作,現(xiàn)在我們給出寫命令和寫數(shù)據(jù)時,11.0592MHz
調(diào)用可延時1ms
的代碼(此代碼可由輔助軟件計算寫出):
//函數(shù)定義:
/**
* @brief LCD1602延時函數(shù),11.0592MHz調(diào)用可延時1ms
* @param 無
* @retval 無
*/
void LCD_Delay()
{
unsigned char i, j;
i = 2;
j = 199;
do
{
while (--j);
} while (--i);
}
????????3.2 LCD1602顯示函數(shù)
????????(1) LCD1602設(shè)置光標位置
? ? ? ? 因為寫入顯示地址時要求最高位 D7 恒定為高電平 1,所以命令的最高位要全賦為1,而顯示位是從0開始的,所以第一行的寫入命令是
0x80| (lie-1)
。? ? ? ? 而LCD1602的存儲是每行40個字符,所以第二行第一位是在第一行的基礎(chǔ)上加
0x40
。
/**
* @brief LCD1602設(shè)置光標位置
* @param hang 行位置,范圍:1~2
* @param lie 列位置,范圍:1~16
* @retval 無
*/
void LCD_SetCursor(unsigned char hang,unsigned char lie) //設(shè)置光標位置
{
if(hang==1)
{
LCD_WriteCommand(0x80|(lie-1)); //因為寫入顯示地址時要求最高位 D7 恒定為高電平 1
}
else if(hang==2)
{
LCD_WriteCommand(0x80|(lie-1+0x40)); //LCD的存儲是每行40,所以第二行第一位是在第一行的基礎(chǔ)上加0x40
}
}
????????(2) 在LCD1602指定位置上顯示一個字符
/**
* @brief 在LCD1602指定位置上顯示一個字符
* @param hang 行位置,范圍:1~2
* @param lie 列位置,范圍:1~16
* @param Char 要顯示的字符
* @retval 無
*/
void LCD_ShowChar(unsigned char hang,unsigned char lie,char Char)
{
LCD_SetCursor(hang,lie);
LCD_WriteData(Char);
}
????????(3) 在LCD1602指定位置開始顯示所給字符串
/**
* @brief 在LCD1602指定位置開始顯示所給字符串
* @param hang 起始行位置,范圍:1~2
* @param lie 起始列位置,范圍:1~16
* @param String 要顯示的字符串
* @retval 無
*/
void LCD_ShowString(unsigned char hang,unsigned char lie,char *String)
{
unsigned char i;
LCD_SetCursor(hang,lie);
for(i=0;String[i]!='\0';i++)
{
LCD_WriteData(String[i]);
}
}
????????(4) 在LCD1602指定位置開始顯示所給數(shù)字
789 這是最初的數(shù) |
把各個數(shù)分開之后的數(shù) |
i指數(shù)字的個數(shù) |
i 和標紅文字的關(guān)系 |
789/100%10 |
7 |
3 |
10^(3-1) |
789/10%10 |
8 |
2 |
10^(2-1) |
789/1%10 |
9 |
1 |
10^(1-1) |
/**
* @brief 返回值=X的Y次方
*/
int LCD_Pow(int X,int Y)
{
unsigned char i;
int Result=1;
for(i=0;i<Y;i++)
{
Result*=X;
}
return Result;
}
/**
* @brief 在LCD1602指定位置開始顯示所給數(shù)字
* @param hang 起始行位置,范圍:1~2
* @param lie 起始列位置,范圍:1~16
* @param Number 要顯示的數(shù)字,范圍:0~65535
* @param Length 要顯示數(shù)字的長度,范圍:1~5
* @retval 無
*/
void LCD_ShowNum(unsigned char hang,unsigned char lie,unsigned int Number,unsigned char Length)
{
unsigned char i;
LCD_SetCursor(hang,lie);
for(i=Length;i>0;i--)
{
LCD_WriteData(Number/LCD_Pow(10,i-1)%10+'0');//加'0'是因為要轉(zhuǎn)換成數(shù)字格式,不然會顯示ASCII碼
}
}
????????3.3 主程序
????????將上述代碼整合在main.c
(主程序)里面,得到如下完整代碼:
#include <REGX52.H>
//引腳配置:
sbit LCD_RS=P2^6;
sbit LCD_RW=P2^5;
sbit LCD_EN=P2^7;
void LCD_Delay() //11.0592MHz調(diào)用可延時1ms
{
unsigned char i, j;
i = 2;
j = 199;
do
{
while (--j);
} while (--i);
}
void LCD_WriteCommand(unsigned char Command) //LCD1602寫命令
{
LCD_RS=0; //寫命令置0
LCD_RW=0; //1為讀,0為寫
P0=Command; //把命令通過P0口傳送(D0~D7連到P0口的情況下)
LCD_EN=1; //拉高使能引腳
LCD_Delay(); //1ms 延時
LCD_EN=0; //拉低使能引腳,數(shù)據(jù)寫入完畢
LCD_Delay(); //1ms 延時
}
void LCD_Init() //LCD1602初始化函數(shù)
{
LCD_WriteCommand(0x38);//八位數(shù)據(jù)接口,兩行顯示,5*7點陣
LCD_WriteCommand(0x0c);//顯示開,光標關(guān),閃爍關(guān)
LCD_WriteCommand(0x06);//數(shù)據(jù)讀寫操作后,光標自動加一,畫面不動
LCD_WriteCommand(0x01);//光標復位,清屏
}
void LCD_WriteData(unsigned char Data) //LCD1602寫數(shù)據(jù)
{
LCD_RS=1; //寫數(shù)據(jù)置1
LCD_RW=0; //1為讀,0為寫
P0=Data; //把數(shù)據(jù)通過P0口傳送(D0~D7連到P0口的情況下)
LCD_EN=1; //拉高使能引腳
LCD_Delay(); //1ms 延時
LCD_EN=0; //拉低使能引腳,數(shù)據(jù)寫入完畢
LCD_Delay(); //1ms 延時
}
void LCD_SetCursor(unsigned char hang,unsigned char lie) //設(shè)置光標位置
{
if(hang==1)
{
LCD_WriteCommand(0x80|(lie-1)); //因為寫入顯示地址時要求最高位 D7 恒定為高電平 1
}
else if(hang==2)
{
LCD_WriteCommand(0x80|(lie-1+0x40)); //LCD的存儲是每行40,所以第二行第一位是在第一行的基礎(chǔ)上加0x40
}
}
void LCD_ShowChar(unsigned char hang,unsigned char lie,char Char)//指定位置顯示一個字符
{
LCD_SetCursor(hang,lie);
LCD_WriteData(Char);
}
void LCD_ShowString(unsigned char hang,unsigned char lie,char *String)//指定位置開始顯示所給字符串
{
unsigned char i;
LCD_SetCursor(hang,lie);
for(i=0;String[i]!='\0';i++)
{
LCD_WriteData(String[i]);
}
}
int LCD_Pow(int X,int Y)//返回值=X的Y次方
{
unsigned char i;
int Result=1;
for(i=0;i<Y;i++)
{
Result*=X;
}
return Result;
}
//在LCD1602指定位置開始顯示所給數(shù)字
void LCD_ShowNum(unsigned char hang,unsigned char lie,unsigned int Number,unsigned char Length)
{
unsigned char i;
LCD_SetCursor(hang,lie);
for(i=Length;i>0;i--)
{
LCD_WriteData(Number/LCD_Pow(10,i-1)%10+'0');//加'0'是因為要轉(zhuǎn)換成數(shù)字格式,不然會顯示ASCII碼
}
}
void main()
{
LCD_Init(); //LCD初始化
LCD_ShowChar(1,1,'A'); //在1行1列顯示字符A
LCD_ShowString(1,3,"Hello"); //在1行3列顯示字符串Hello
LCD_ShowNum(1,9,66,2); //在1行9列顯示數(shù)字66,長度為2
LCD_ShowString(2,1,"ZhangFuGong"); //在2行1列顯示字符串ZhangFuGong
LCD_ShowChar(2,13,0xDF); //在2行13列顯示編碼為0xDF的字符
LCD_ShowChar(2,14,'C'); //在2行14列顯示字符C
while(1)
{
}
}
四、 實驗現(xiàn)象
????????使用 USB 線將開發(fā)板和電腦連接成功后(電腦能識別開發(fā)板上 CH340 串口), 把編譯后產(chǎn)生的
.hex
文件燒入到芯片內(nèi),實現(xiàn)現(xiàn)象如下:在 LCD1602 液晶上顯示字符信息。

注意:LCD1602 液晶要正確插入到 LCD1602 接口 J2 位置,插反或者差錯都會導致顯示不正常。如果出現(xiàn)顯示看不清的情況,可調(diào)節(jié)板子 LCD1602 接口下的 RJ1 電位器。如果 LCD1602 無法顯示,可重啟電源或復位。

保姆級燒錄教程
????????本章節(jié)實驗到此已經(jīng)完畢,考慮到大家的基礎(chǔ)差異較大,剛接觸51單片機的小伙伴可能對燒錄過程有些困惑,作者便在篇末給大家提供保姆級燒錄教程,幫助大家快速掌握單片機程序燒錄技巧,希望對大家有所幫助!
本教程所需軟件下載(win系統(tǒng))
????????1. 開發(fā)板準備工作(以普中A2開發(fā)板為例)
????????(1)檢查單片機芯片型號是否為 STC89C52RC

????????(2)單片機與計算機建立通信


????????2. 燒錄軟件的準備操作
????????(1)下載并打開上述鏈接所提供的軟件。
????????下載完成后。鼠標右鍵軟件圖標,選擇 以管理員身份運行 ,在彈出的對話框中選擇 是 ,軟件開始運行。(沒有管理員選項的直接鼠標左鍵雙擊運行也可)。

????????(2)芯片型號選擇
????????如果芯片型號與圖17一致,直接按照圖示箭頭依次選擇即可。不同的話則依據(jù)各自型號選擇相應系列。

????????(3)檢查串口
????????檢查串口是否有紅框圈中的 USB-SERIAL CH340 字樣(后面的COM口不用管,每臺電腦都可能不一致)。有的話證明你的電腦已經(jīng)裝了CH340驅(qū)動;沒有的話也沒關(guān)系,下載下面鏈接的驅(qū)動安裝軟件,雙擊運行,按照提示操作即可。CH340驅(qū)動軟件下載(win系統(tǒng))

????????(4)打開程序文件
????????按照圖示操作,找到已經(jīng)編譯生成的
.hex
文件,單擊選中后點擊打開。

? ? ??

?3. 燒錄程序
????????(1)點擊 下載/編程 按鈕
????點擊 下載/編程 按鈕,看到軟件右側(cè)顯示,正在檢測單片機。

????????
(2)開關(guān)單片機開發(fā)板
?此時找到圖26中,開發(fā)板的 POWER 白色按鍵:
?1. 若此時是上電狀態(tài),則按兩下白色按鍵,即關(guān)機后重新開機。
?2. 若此時是斷電狀態(tài),則按一下白色按鍵,即重新開機。

????????(3)燒錄成功
? 軟件顯示操作成功,此時程序已經(jīng)燒錄進單片機,單片機將按照程序開始執(zhí)行操作。

一些有趣的LCD1602顯示實驗(基于普中A2開發(fā)板)
????????1. 溫度傳感器讀取實驗(利用DS18B20芯片)
????????(1) 實驗代碼
#include <REGX52.H>
//引腳配置:
sbit LCD_RS=P2^6;
sbit LCD_RW=P2^5;
sbit LCD_EN=P2^7;
#define LCD_DataPort P0
float T;
void Delay(unsigned int xms)
{
unsigned char i, j;
while(xms--)
{
i = 2;
j = 239;
do
{
while (--j);
} while (--i);
}
}
void LCD_Delay() //11.0592MHz調(diào)用可延時1ms
{
unsigned char i, j;
i = 2;
j = 199;
do
{
while (--j);
} while (--i);
}
/**
* @brief LCD1602寫命令
* @param Command 要寫入的命令
* @retval 無
*/
void LCD_WriteCommand(unsigned char Command)
{
LCD_RS=0;
LCD_RW=0;
LCD_DataPort=Command;
LCD_EN=1;
LCD_Delay();
LCD_EN=0;
LCD_Delay();
}
/**
* @brief LCD1602寫數(shù)據(jù)
* @param Data 要寫入的數(shù)據(jù)
* @retval 無
*/
void LCD_WriteData(unsigned char Data)
{
LCD_RS=1;
LCD_RW=0;
LCD_DataPort=Data;
LCD_EN=1;
LCD_Delay();
LCD_EN=0;
LCD_Delay();
}
/**
* @brief LCD1602設(shè)置光標位置
* @param Line 行位置,范圍:1~2
* @param Column 列位置,范圍:1~16
* @retval 無
*/
void LCD_SetCursor(unsigned char Line,unsigned char Column)
{
if(Line==1)
{
LCD_WriteCommand(0x80|(Column-1));
}
else if(Line==2)
{
LCD_WriteCommand(0x80|(Column-1+0x40));
}
}
/**
* @brief LCD1602初始化函數(shù)
* @param 無
* @retval 無
*/
void LCD_Init()
{
LCD_WriteCommand(0x38);//八位數(shù)據(jù)接口,兩行顯示,5*7點陣
LCD_WriteCommand(0x0c);//顯示開,光標關(guān),閃爍關(guān)
LCD_WriteCommand(0x06);//數(shù)據(jù)讀寫操作后,光標自動加一,畫面不動
LCD_WriteCommand(0x01);//光標復位,清屏
}
/**
* @brief 在LCD1602指定位置上顯示一個字符
* @param Line 行位置,范圍:1~2
* @param Column 列位置,范圍:1~16
* @param Char 要顯示的字符
* @retval 無
*/
void LCD_ShowChar(unsigned char Line,unsigned char Column,char Char)
{
LCD_SetCursor(Line,Column);
LCD_WriteData(Char);
}
/**
* @brief 在LCD1602指定位置開始顯示所給字符串
* @param Line 起始行位置,范圍:1~2
* @param Column 起始列位置,范圍:1~16
* @param String 要顯示的字符串
* @retval 無
*/
void LCD_ShowString(unsigned char Line,unsigned char Column,char *String)
{
unsigned char i;
LCD_SetCursor(Line,Column);
for(i=0;String[i]!='\0';i++)
{
LCD_WriteData(String[i]);
}
}
/**
* @brief 返回值=X的Y次方
*/
int LCD_Pow(int X,int Y)
{
unsigned char i;
int Result=1;
for(i=0;i<Y;i++)
{
Result*=X;
}
return Result;
}
/**
* @brief 在LCD1602指定位置開始顯示所給數(shù)字
* @param Line 起始行位置,范圍:1~2
* @param Column 起始列位置,范圍:1~16
* @param Number 要顯示的數(shù)字,范圍:0~65535
* @param Length 要顯示數(shù)字的長度,范圍:1~5
* @retval 無
*/
void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{
unsigned char i;
LCD_SetCursor(Line,Column);
for(i=Length;i>0;i--)
{
LCD_WriteData(Number/LCD_Pow(10,i-1)%10+'0');
}
}
sbit OneWire_DQ=P3^7;
/**
* @brief 單總線初始化
* @param 無
* @retval 從機響應位,0為響應,1為未響應
*/
unsigned char OneWire_Init(void)
{
unsigned char i;
unsigned char AckBit;
OneWire_DQ=1;
OneWire_DQ=0;
i = 247;while (--i); //Delay 500us
OneWire_DQ=1;
i = 32;while (--i); //Delay 70us
AckBit=OneWire_DQ;
i = 247;while (--i); //Delay 500us
return AckBit;
}
/**
* @brief 單總線發(fā)送一位
* @param Bit 要發(fā)送的位
* @retval 無
*/
void OneWire_SendBit(unsigned char Bit)
{
unsigned char i;
OneWire_DQ=0;
i = 4;while (--i); //Delay 10us
OneWire_DQ=Bit;
i = 24;while (--i); //Delay 50us
OneWire_DQ=1;
}
/**
* @brief 單總線接收一位
* @param 無
* @retval 讀取的位
*/
unsigned char OneWire_ReceiveBit(void)
{
unsigned char i;
unsigned char Bit;
OneWire_DQ=0;
i = 2;while (--i); //Delay 5us
OneWire_DQ=1;
i = 2;while (--i); //Delay 5us
Bit=OneWire_DQ;
i = 24;while (--i); //Delay 50us
return Bit;
}
/**
* @brief 單總線發(fā)送一個字節(jié)
* @param Byte 要發(fā)送的字節(jié)
* @retval 無
*/
void OneWire_SendByte(unsigned char Byte)
{
unsigned char i;
for(i=0;i<8;i++)
{
OneWire_SendBit(Byte&(0x01<<i));
}
}
/**
* @brief 單總線接收一個字節(jié)
* @param 無
* @retval 接收的一個字節(jié)
*/
unsigned char OneWire_ReceiveByte(void)
{
unsigned char i;
unsigned char Byte=0x00;
for(i=0;i<8;i++)
{
if(OneWire_ReceiveBit()){Byte|=(0x01<<i);}
}
return Byte;
}
//DS18B20指令
#define DS18B20_SKIP_ROM 0xCC
#define DS18B20_CONVERT_T 0x44
#define DS18B20_READ_SCRATCHPAD 0xBE
/**
* @brief DS18B20開始溫度變換
* @param 無
* @retval 無
*/
void DS18B20_ConvertT(void)
{
OneWire_Init();
OneWire_SendByte(DS18B20_SKIP_ROM);
OneWire_SendByte(DS18B20_CONVERT_T);
}
/**
* @brief DS18B20讀取溫度
* @param 無
* @retval 溫度數(shù)值
*/
float DS18B20_ReadT(void)
{
unsigned char TLSB,TMSB;
int Temp;
float T;
OneWire_Init();
OneWire_SendByte(DS18B20_SKIP_ROM);
OneWire_SendByte(DS18B20_READ_SCRATCHPAD);
TLSB=OneWire_ReceiveByte();
TMSB=OneWire_ReceiveByte();
Temp=(TMSB<<8)|TLSB;
T=Temp/16.0;
return T;
}
void main()
{
DS18B20_ConvertT(); //上電先轉(zhuǎn)換一次溫度,防止第一次讀數(shù)據(jù)錯誤
Delay(1000); //等待轉(zhuǎn)換完成
LCD_Init();
LCD_ShowString(1,1,"Temperature:");
while(1)
{
DS18B20_ConvertT(); //轉(zhuǎn)換溫度
T=DS18B20_ReadT(); //讀取溫度
if(T<0) //如果溫度小于0
{
LCD_ShowChar(2,1,'-'); //顯示負號
T=-T; //將溫度變?yōu)檎龜?shù)
}
else //如果溫度大于等于0
{
LCD_ShowChar(2,1,'+'); //顯示正號
}
LCD_ShowNum(2,2,T,3); //顯示溫度整數(shù)部分
LCD_ShowChar(2,5,'.'); //顯示小數(shù)點
LCD_ShowNum(2,6,(unsigned long)(T*10000)%10000,4);//顯示溫度小數(shù)部分
}
}
????????(2) 實驗現(xiàn)象
????????燒錄程序后,LCD1602上顯示當前溫度。圖28中箭頭所指為溫度傳感器,當用手捏住芯片,LCD1602上溫度會上升,松開手溫度會下降。

????????2. 密碼鎖實驗
????????(1) 實驗代碼
#include <REGX52.H>
unsigned char KeyNum;
unsigned int Password,Count;
void Delay(unsigned int xms)
{
unsigned char i, j;
while(xms--)
{
i = 2;
j = 239;
do
{
while (--j);
} while (--i);
}
}
/**
* @brief 矩陣鍵盤讀取按鍵鍵碼
* @param 無
* @retval KeyNumber 按下按鍵的鍵碼值
如果按鍵按下不放,程序會停留在此函數(shù),松手的一瞬間,返回按鍵鍵碼,沒有按鍵按下時,返回0
*/
unsigned char MatrixKey()
{
unsigned char KeyNumber=0;
P1=0xFF;
P1_3=0;
if(P1_7==0){Delay(20);while(P1_7==0);Delay(20);KeyNumber=1;}
if(P1_6==0){Delay(20);while(P1_6==0);Delay(20);KeyNumber=5;}
if(P1_5==0){Delay(20);while(P1_5==0);Delay(20);KeyNumber=9;}
if(P1_4==0){Delay(20);while(P1_4==0);Delay(20);KeyNumber=13;}
P1=0xFF;
P1_2=0;
if(P1_7==0){Delay(20);while(P1_7==0);Delay(20);KeyNumber=2;}
if(P1_6==0){Delay(20);while(P1_6==0);Delay(20);KeyNumber=6;}
if(P1_5==0){Delay(20);while(P1_5==0);Delay(20);KeyNumber=10;}
if(P1_4==0){Delay(20);while(P1_4==0);Delay(20);KeyNumber=14;}
P1=0xFF;
P1_1=0;
if(P1_7==0){Delay(20);while(P1_7==0);Delay(20);KeyNumber=3;}
if(P1_6==0){Delay(20);while(P1_6==0);Delay(20);KeyNumber=7;}
if(P1_5==0){Delay(20);while(P1_5==0);Delay(20);KeyNumber=11;}
if(P1_4==0){Delay(20);while(P1_4==0);Delay(20);KeyNumber=15;}
P1=0xFF;
P1_0=0;
if(P1_7==0){Delay(20);while(P1_7==0);Delay(20);KeyNumber=4;}
if(P1_6==0){Delay(20);while(P1_6==0);Delay(20);KeyNumber=8;}
if(P1_5==0){Delay(20);while(P1_5==0);Delay(20);KeyNumber=12;}
if(P1_4==0){Delay(20);while(P1_4==0);Delay(20);KeyNumber=16;}
return KeyNumber;
}
//引腳配置:
sbit LCD_RS=P2^6;
sbit LCD_RW=P2^5;
sbit LCD_EN=P2^7;
#define LCD_DataPort P0
//函數(shù)定義:
/**
* @brief LCD1602延時函數(shù),11.0592MHz調(diào)?可延時1ms
* @param ?
* @retval ?
*/
void LCD_Delay()
{
unsigned char i, j;
i = 2;
j = 199;
do
{
while (--j);
} while (--i);
}
/**
* @brief LCD1602寫命令
* @param Command 要寫入的命令
* @retval 無
*/
void LCD_WriteCommand(unsigned char Command)
{
LCD_RS=0;
LCD_RW=0;
LCD_DataPort=Command;
LCD_EN=1;
LCD_Delay();
LCD_EN=0;
LCD_Delay();
}
/**
* @brief LCD1602寫數(shù)據(jù)
* @param Data 要寫入的數(shù)據(jù)
* @retval 無
*/
void LCD_WriteData(unsigned char Data)
{
LCD_RS=1;
LCD_RW=0;
LCD_DataPort=Data;
LCD_EN=1;
LCD_Delay();
LCD_EN=0;
LCD_Delay();
}
/**
* @brief LCD1602設(shè)置光標位置
* @param Line 行位置,范圍:1~2
* @param Column 列位置,范圍:1~16
* @retval 無
*/
void LCD_SetCursor(unsigned char Line,unsigned char Column)
{
if(Line==1)
{
LCD_WriteCommand(0x80|(Column-1));
}
else if(Line==2)
{
LCD_WriteCommand(0x80|(Column-1+0x40));
}
}
/**
* @brief LCD1602初始化函數(shù)
* @param 無
* @retval 無
*/
void LCD_Init()
{
LCD_WriteCommand(0x38);//八位數(shù)據(jù)接口,兩行顯示,5*7點陣
LCD_WriteCommand(0x0c);//顯示開,光標關(guān),閃爍關(guān)
LCD_WriteCommand(0x06);//數(shù)據(jù)讀寫操作后,光標自動加一,畫面不動
LCD_WriteCommand(0x01);//光標復位,清屏
}
/**
* @brief 在LCD1602指定位置上顯示一個字符
* @param Line 行位置,范圍:1~2
* @param Column 列位置,范圍:1~16
* @param Char 要顯示的字符
* @retval 無
*/
void LCD_ShowChar(unsigned char Line,unsigned char Column,char Char)
{
LCD_SetCursor(Line,Column);
LCD_WriteData(Char);
}
/**
* @brief 在LCD1602指定位置開始顯示所給字符串
* @param Line 起始行位置,范圍:1~2
* @param Column 起始列位置,范圍:1~16
* @param String 要顯示的字符串
* @retval 無
*/
void LCD_ShowString(unsigned char Line,unsigned char Column,char *String)
{
unsigned char i;
LCD_SetCursor(Line,Column);
for(i=0;String[i]!='\0';i++)
{
LCD_WriteData(String[i]);
}
}
/**
* @brief 返回值=X的Y次方
*/
int LCD_Pow(int X,int Y)
{
unsigned char i;
int Result=1;
for(i=0;i<Y;i++)
{
Result*=X;
}
return Result;
}
/**
* @brief 在LCD1602指定位置開始顯示所給數(shù)字
* @param Line 起始行位置,范圍:1~2
* @param Column 起始列位置,范圍:1~16
* @param Number 要顯示的數(shù)字,范圍:0~65535
* @param Length 要顯示數(shù)字的長度,范圍:1~5
* @retval 無
*/
void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{
unsigned char i;
LCD_SetCursor(Line,Column);
for(i=Length;i>0;i--)
{
LCD_WriteData(Number/LCD_Pow(10,i-1)%10+'0');
}
}
void main()
{
LCD_Init();
LCD_ShowString(1,1,"Password:");
while(1)
{
KeyNum=MatrixKey();
if(KeyNum)
{
if(KeyNum<=10) //如果S1~S10按鍵按下,輸入密碼
{
if(Count<4) //如果輸入次數(shù)小于4
{
Password*=10; //密碼左移一位
Password+=KeyNum%10; //獲取一位密碼
Count++; //計次加一
}
LCD_ShowNum(2,1,Password,4); //更新顯示
}
if(KeyNum==11) //如果S11按鍵按下,確認
{
if(Password==2345) //如果密碼等于正確密碼
{
LCD_ShowString(1,14,"OK "); //顯示OK
Password=0; //密碼清零
Count=0; //計次清零
LCD_ShowNum(2,1,Password,4); //更新顯示
Delay(500);
LCD_ShowString(1,14," ");
}
else //否則
{
LCD_ShowString(1,14,"ERR"); //顯示ERR
Password=0; //密碼清零
Count=0; //計次清零
LCD_ShowNum(2,1,Password,4); //更新顯示
Delay(500);
LCD_ShowString(1,14," ");
}
}
if(KeyNum==12) //如果S12按鍵按下,取消
{
Password=0; //密碼清零
Count=0; //計次清零
LCD_ShowNum(2,1,Password,4); //更新顯示
}
if(KeyNum==13) //如果s13按鍵按下,退位
{
Password/=10; //密碼退位
if(Count>0)
{
Count--; //計次減一
LCD_ShowNum(2,1,Password,4);
LCD_ShowString(1,14," ");
}
else
{
LCD_ShowNum(2,1,Password,4);
LCD_ShowString(1,14," ");
}
}
}
}
}
????????(2) 實驗現(xiàn)象
????????S1到S9分別是1~9,S10是數(shù)字0,S11是確定,S12是重新輸入,S13密碼退位,正確密碼是2345,輸入正確會顯示0.5s
OK
,輸入錯誤會顯示0.5sERR
。文章來源:http://www.zghlxwxcb.cn/news/detail-429982.html????????密碼可在代碼第231行設(shè)置。文章來源地址http://www.zghlxwxcb.cn/news/detail-429982.html

到了這里,關(guān)于【51單片機】LCD1602 液晶顯示實驗指導書的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!