12 LCD1602液晶屏
[toc]
注:筆記主要參考B站江科大自化協(xié)教學(xué)視頻“51單片機入門教程-2020版 程序全程純手打 從零開始入門”。
注:工程及代碼文件放在了本人的Github倉庫。
12.1 LCD1602介紹
LCD1602(Liquid Crystal Display)液晶顯示屏是一種字符型液晶顯示模塊,可以顯示ASCII碼的標(biāo)準(zhǔn)字符和其它的一些內(nèi)置特殊字符,還可以有8個自定義字符。
顯示容量:16×2個字符,每個字符為5*7點陣


LCD1602控制的關(guān)鍵,在于中間這幾個加粗的引腳。優(yōu)先級最高的是 使能引腳EN,DB0~DB7位數(shù)據(jù),通過RS和RW的配合就可以完成對于液晶屏數(shù)據(jù)/指令的讀寫。目前主要關(guān)心寫指令(怎么顯示,在哪里顯示)、寫數(shù)據(jù)(寫什么)。

- 屏幕(16*2)。
- CGRAM+CGROM(字模庫):“CG”表示“Character Generator”,即字模生成。用于存放需要顯示的字符與液晶屏上像素點的對應(yīng)關(guān)系,相當(dāng)于數(shù)碼管顯示中的“段碼表”。
上面左側(cè)的CGRAM所示的8個寄存器可以自定義,下面的8個和上面8個地址相同,相當(dāng)于重復(fù)。后面的字模都放在CGROM中。- DDRAM(40*2):用于存放屏幕上需要顯示的數(shù)據(jù)。注意其一般只顯示前16列元素到液晶屏上,剩余的區(qū)域不會顯示。但是也可以利用這些區(qū)域做滾動顯示。
![]()
- 控制器:尤其注意AC(光標(biāo)位置):“AC”意為Address Counter。即對于DDRAM進行操作時要格外關(guān)心所操作的地址。
對LCD顯示進行操作的基本流程為:
1. LCD初始化:
發(fā)送指令0x38 //八位數(shù)據(jù)接口,兩行顯示,5*7點陣
發(fā)送指令0x0C //顯示開,光標(biāo)關(guān),閃爍關(guān)
發(fā)送指令0x06 //數(shù)據(jù)讀寫操作后,光標(biāo)自動加一,畫面不動
發(fā)送指令0x01 //清屏
2. 顯示字符:
發(fā)送指令0x80|AC //設(shè)置光標(biāo)位置
發(fā)送數(shù)據(jù) //發(fā)送要顯示的字符數(shù)據(jù)
發(fā)送數(shù)據(jù) //發(fā)送要顯示的字符數(shù)據(jù)
……

下面給出讀寫操作的時序圖:
- 寫操作時序圖及時間要求:
![]()
- 讀操作時序圖及時間要求:
![]()
- 注意,最重要的點在于使能信號
EN
不僅拉高時有延時要求,拉低后同樣也有時間要求。 另外經(jīng)實測,時間要求也都寫的不對,建議使能信號EN
拉高和拉低的持續(xù)時間都為1ms。
下面介紹一些有關(guān)C語言語法的知識:
- 字符:根據(jù)一定規(guī)則建立的數(shù)字到字符的映射 (ASCII碼表)
例如:0x21=’!’,0x41=’A’,0x00=’\0’
定義方法:char x=‘A’;
(等效于char x=0x41;
)- 字符數(shù)組:存儲字符變量的一個數(shù)組
定義方法:char y[]={’A’, ’B’, ’C’};
(等效于char y[]={0x41,0x42,0x43};
)- 字符串:在字符數(shù)組后加一個字符串結(jié)束標(biāo)志,本質(zhì)上是字符數(shù)組
定義方法:char z[]=”ABC”;
(等效于char z[]={’A’, ’B’, ’C’, ’\0’};
)
12.2 實驗:LCD1602功能代碼
需求:在液晶屏上依次顯示:
- 一個字符 ‘A’
- 一個字符串 “Hello”
- 一個無符號數(shù)字 88
- 一個有符號數(shù)字 -00
- 一個十六進制數(shù)字 0xFE
- 一個二進制數(shù)字 01011100
- 顯示特殊符號℃上面的“句號”

代碼展示:
- main.c
#include <REGX52.H>
#include "LCD1602.h"
void Delay500ms(){//@11.0592MHz
unsigned char i, j, k;
i = 4;
j = 129;
k = 119;
do{
do{
while (--k);
}while (--j);
}while (--i);
}
void main(){
//LCD初始化
LCD1602_Init();
// LCD顯示
LCD1602_DispChar(1,1,'A');//顯示單個字符
LCD1602_DispString(1,3,"$_$");//顯示字符串
LCD1602_DispUnInt(1,7,99,3);//顯示無符號數(shù)字
LCD1602_DispInt(1,11,-32768,6);//顯示有符號數(shù)字
LCD1602_DispUnInt_Hex(2,1,255,2);//顯示無符號整型的16進制表示
LCD1602_DispUnInt_Bin(2,4,3,3);//顯示無符號整型的2進制表示
LCD1602_DispFloat(2,8,-20.99,7,3);//顯示單精度浮點數(shù)-20.99
LCD1602_DispChar(2,15,0xdf);//顯示特殊符號(主要就是查看字模表)
//LCD移屏
LCD1602_DispString(1,20,"Fries on the pier!");
while(1){
LCD1602_WriteCommd(0x18);
Delay500ms();
Delay500ms();
}
}
- LCD1602.h
#ifndef __LCD1602_H__
#define __LCD1602_H__
// LCD1602寫指令
void LCD1602_WriteCommd(unsigned char wByte);
// LCD1602寫數(shù)據(jù)
void LCD1602_WriteData(unsigned char wByte);
// 初始化函數(shù)
void LCD1602_Init(void);
//顯示單個字符
void LCD1602_DispChar(unsigned char Row,unsigned char Column,unsigned char wChar);
//顯示字符串
void LCD1602_DispString(unsigned char Row,unsigned char Column,char wString[]);
//顯示無符號數(shù)字
void LCD1602_DispUnInt(unsigned char Row, unsigned char Column, unsigned int wNum, unsigned char Length);
//顯示有符號數(shù)字
void LCD1602_DispInt(unsigned char Row, unsigned char Column,int wNum, unsigned char Length);
//顯示無符號整型的16進制表示
void LCD1602_DispUnInt_Hex(unsigned char Row, unsigned char Column, unsigned int wNum, unsigned char Length);
//顯示無符號整型的2進制表示
void LCD1602_DispUnInt_Bin(unsigned char Row, unsigned char Column, unsigned int wNum, unsigned char Length);
//顯示單精度浮點數(shù)(有符號)
void LCD1602_DispFloat(unsigned char Row, unsigned char Column, float wNum, unsigned char Total_Len, unsigned char Frac_len);
#endif
- LCD1602.c文章來源:http://www.zghlxwxcb.cn/news/detail-500191.html
#include <REGX52.H>
//下面這些有可能需要更改
/***************************************************************/
// 重新命名端口
sbit LCD1602_RS = P2^6;
sbit LCD1602_RW = P2^5;
sbit LCD1602_EN = P2^7;
#define LCD1602_DB P0
// LCD1602專用延時函數(shù),晶振11.0592MHz,延時1ms
void LCD1602_Delay1ms(void){//@11.0592MHz
unsigned char i, j;
i = 2;
j = 199;
do{
while (--j);
}while (--i);
}
/***************************************************************/
/***************************************************************/
/**
* @brief :LCD1602寫指令。
* @param :wByte指令。
* @retval :無。
*/
void LCD1602_WriteCommd(unsigned char wByte){// LCD1602寫指令
LCD1602_EN = 0;
LCD1602_RS = 0;
LCD1602_RW = 0;
LCD1602_DB = wByte;
LCD1602_EN = 1;
LCD1602_Delay1ms();//延時1ms
LCD1602_EN = 0;
LCD1602_Delay1ms();//延時1ms
}
/**
* @brief :LCD1602寫數(shù)據(jù)。
* @param :wByte數(shù)據(jù)。
* @retval :無。
*/
void LCD1602_WriteData(unsigned char wByte){// LCD1602寫數(shù)據(jù)
LCD1602_EN = 0;
LCD1602_RS = 1;
LCD1602_RW = 0;
LCD1602_DB = wByte;
LCD1602_EN = 1;
LCD1602_Delay1ms();//延時1ms
LCD1602_EN = 0;
LCD1602_Delay1ms();//延時1ms
}
/**
* @brief :設(shè)置光標(biāo)位置。
* @param :Row行,范圍1~2。
* @param :Column列,范圍1~40。
* @retval :無。
*/
void LCD1602_SetCursor(unsigned char Row,unsigned char Column){
unsigned char LCD_AC=0x00;
// 更新坐標(biāo)位置
if(Row==1){LCD_AC += (Column-1);}
else {LCD_AC += (0x40+Column-1);}
// 設(shè)置光標(biāo)位置
LCD1602_WriteCommd(0x80|LCD_AC);
}
/**
* @brief :無符號數(shù)的指數(shù)運算。
* @param :x無符號整數(shù)基底。
* @param :y無符號整數(shù)冪次。
* @retval :result無符號整數(shù)運算結(jié)果。
*/
int LCD1602_Pow(int x, int y){//無符號數(shù)的指數(shù)運算
unsigned int i;
unsigned int result = 1;
for(i=0;i<y;i++){
result *= x;
}
return result;
}
/**
* @brief :初始化函數(shù)。
* @param :無。
* @retval :無。
*/
void LCD1602_Init(void){// 初始化函數(shù)
LCD1602_WriteCommd(0x38);//八位數(shù)據(jù)接口,兩行顯示,5*7點陣
LCD1602_WriteCommd(0x0c);//顯示開,光標(biāo)關(guān),閃爍關(guān)
LCD1602_WriteCommd(0x06);//數(shù)據(jù)讀寫操作后,光標(biāo)自動加一,畫面不動
LCD1602_WriteCommd(0x01);//清屏
}
/**
* @brief :顯示字符
* @param :Row行,范圍1~2。
* @param :Column列,范圍1~40。
* @param :wChar待顯示的字符。
* @retval :無。
*/
void LCD1602_DispChar(unsigned char Row,unsigned char Column,unsigned char wChar){//顯示單個字符
// 首先保證行列的位置有效,才運行函數(shù)
if((Row==1 || Row==2) && Column>=1 && Column<=40){
// 更新光標(biāo)位置
LCD1602_SetCursor(Row,Column);
// 發(fā)送要顯示的數(shù)據(jù)
LCD1602_WriteData(wChar);
}
}
/**
* @brief :顯示字符串
* @param :Row行,范圍1~2。
* @param :Column列,范圍1~40。
* @param :wString[]待顯示的字符串。
* @retval :無。
*/
void LCD1602_DispString(unsigned char Row,unsigned char Column,char wString[]){//顯示字符串
unsigned char i=0;
// 首先保證行列的位置有效,才運行函數(shù)
if((Row==1 || Row==2) && Column>=1 && Column<=40){
// 更新光標(biāo)位置
LCD1602_SetCursor(Row,Column);
// 發(fā)送要顯示的數(shù)據(jù)
while(wString[i]!='\0'){
LCD1602_WriteData(wString[i]);
i++;
}
}
}
/**
* @brief :顯示無符號數(shù)字
* @param :Row行,范圍1~2。
* @param :Column列,范圍1~40。
* @param :wNum待顯示的無符號數(shù)字,范圍0~65535。
* @param :Length在屏幕上顯示的長度,范圍1~16。
* @retval :無。
*/
void LCD1602_DispUnInt(unsigned char Row, unsigned char Column,
unsigned int wNum, unsigned char Length){//顯示無符號數(shù)字
unsigned char i=0;
unsigned char temp=0;//存儲單個位上的數(shù)據(jù)
// 首先保證行、列、顯示長度有效,才運行函數(shù)
if((Row==1 || Row==2) && Column>=1 && Column<=40 && Length>=1){
// 1. 更新光標(biāo)位置
LCD1602_SetCursor(Row,Column);
// 2.發(fā)送要顯示的數(shù)據(jù)
// 2.1 超過5位的長度都顯示0
if(Length>16){Length=16;}
while(Length>5){
LCD1602_WriteData(0x30);//直接發(fā)送'0'的ASCII碼
Length--;
}
// 2.2 5位以內(nèi)的真實數(shù)值
for(i=0;i<Length;i++){
temp = (wNum/LCD1602_Pow(10,Length-1-i))%10;
LCD1602_WriteData(0x30|temp);//直接計算ASCII碼
}
}
}
/**
* @brief :顯示有符號數(shù)字
* @param :Row行,范圍1~2。
* @param :Column列,范圍1~40。
* @param :wNum待顯示的有符號數(shù)字,范圍-32768~32767。
* @param :Length在屏幕上顯示的數(shù)字長度(包括正負號),范圍1~16。
* @retval :無。
*/
void LCD1602_DispInt(unsigned char Row, unsigned char Column,
int wNum, unsigned char Length){//顯示有符號數(shù)字
unsigned char i=0;
unsigned char temp=0;//存儲單個位上的數(shù)據(jù)
unsigned int un_wNum=0;
// 首先保證行、列、顯示長度有效,才運行函數(shù)
if((Row==1 || Row==2) && Column>=1 && Column<=40 && Length>=2){
// 1. 更新光標(biāo)位置
LCD1602_SetCursor(Row,Column);
// 2. 發(fā)送要顯示的數(shù)據(jù)
// 2.1 顯示正負號,并將原來的數(shù)字轉(zhuǎn)換成正數(shù)
if(Length>16){Length=16;}
if(wNum>=0){LCD1602_WriteData('+'); un_wNum=wNum;}
else {LCD1602_WriteData('-'); un_wNum=-wNum;}
Length--;
// 2.2 超過5位的長度都顯示0
while(Length>5){
LCD1602_WriteData(0x30);//直接發(fā)送'0'的ASCII碼
Length--;
}
// 2.3 5位以內(nèi)的真實數(shù)值
for(i=0;i<Length;i++){
temp = (un_wNum/LCD1602_Pow(10,Length-1-i))%10;
LCD1602_WriteData(0x30|temp);//直接計算ASCII碼
}
}
}
/**
* @brief :顯示無符號整型的16進制表示。
* @param :Row行,范圍1~2。
* @param :Column列,范圍1~40。
* @param :wNum待顯示的無符號數(shù)字,范圍0~65535。
* @param :Length在屏幕上顯示的16進制長度,范圍1~4。
* @retval :無。
*/
void LCD1602_DispUnInt_Hex(unsigned char Row, unsigned char Column,
unsigned int wNum, unsigned char Length){//顯示無符號整型的16進制表示
unsigned char i=0;
unsigned char temp=0;//存儲單個位上的數(shù)據(jù)
// 首先保證行、列、顯示長度有效,才運行函數(shù)
if((Row==1 || Row==2) && Column>=1 && Column<=40&& Length>=1){
// 1. 更新光標(biāo)位置
LCD1602_SetCursor(Row,Column);
// 2. 發(fā)送要顯示的數(shù)據(jù)
if(Length>4){Length=4;}
else {wNum = (wNum<<(4*(4-Length)))>>(4*(4-Length));}//根據(jù)要顯示的長度截取有用的位
for(i=0;i<Length;i++){
temp = (wNum>>((Length-1-i)*4))%16;
if(temp>=0 && temp<=9){LCD1602_WriteData('0' + temp);}
else {LCD1602_WriteData('A' + temp - 10);}
}
}
}
/**
* @brief :顯示無符號整型的2進制表示。
* @param :Row行,范圍1~2。
* @param :Column列,范圍1~40。
* @param :wNum待顯示的無符號數(shù)字,范圍0~65535。
* @param :Length在屏幕上顯示的2進制長度,范圍1~16。
* @retval :無。
*/
void LCD1602_DispUnInt_Bin(unsigned char Row, unsigned char Column,
unsigned int wNum, unsigned char Length){//顯示無符號整型的2進制表示
unsigned char i=0;
// 首先保證行、列、顯示長度有效,才運行函數(shù)
if((Row==1 || Row==2) && Column>=1 && Column<=40&& Length>=1){
// 1. 更新光標(biāo)位置
LCD1602_SetCursor(Row,Column);
// 2. 發(fā)送要顯示的數(shù)據(jù)
if(Length>16){Length=16;}
for(i=0;i<Length;i++){
if(wNum&(0x0001<<(Length-1-i))) {LCD1602_WriteData('1');}
else {LCD1602_WriteData('0');}
}
}
}
/**
* @brief :顯示單精度浮點數(shù)(有符號)。
* @param :Row行,范圍1~2。
* @param :Column列,范圍1~40。
* @param :wNum待顯示的小數(shù),范圍-3.4E38~3.4E38。
* @param :Total_Len在屏幕上顯示的總長度長度(包括正負號),范圍3~16。
* @param :Frac_len在屏幕上顯示的小數(shù)部分的長度,范圍1~16。
* @retval :無。
* 說明:優(yōu)先顯示小數(shù)部分。
*/
void LCD1602_DispFloat(unsigned char Row, unsigned char Column,
float wNum, unsigned char Total_Len,
unsigned char Frac_len){//顯示單精度浮點數(shù)(有符號)
unsigned char Int_len = Total_Len-2-Frac_len; //整數(shù)段長度
unsigned int Int_part=0, Fra_part=0;
// 首先保證行、列、顯示長度有效,才運行函數(shù)
if((Row==1 || Row==2) && Column>=1 && Column<=40 && Total_Len>=3){
//1. 顯示正負號,并將原來的數(shù)字轉(zhuǎn)化成絕對值
if(wNum>=0){LCD1602_DispChar(Row,Column,'+');}
else {LCD1602_DispChar(Row,Column,'-'); wNum=-wNum;}
//2. 獲取整數(shù)部分、小數(shù)部分
Int_part=(unsigned int)wNum;
Fra_part = ((unsigned int)(wNum*LCD1602_Pow(10,Frac_len)))%LCD1602_Pow(10,Frac_len);
//3. 顯示整數(shù)部分
LCD1602_DispUnInt(Row,Column+1,Int_part,Int_len);
//4. 顯示小數(shù)點
LCD1602_DispChar(Row,Column+1+Int_len,'.');
//5. 顯示小數(shù)部分
LCD1602_DispUnInt(Row,Column+2+Int_len,Fra_part,Frac_len);
}
}
編程感想:文章來源地址http://www.zghlxwxcb.cn/news/detail-500191.html
- 關(guān)于
sbit
和sfr
:sbit
可以直接在等式右邊使用端口名,而sfr
在等式右邊只能寫地址。所以一般使用宏定義#define
來完成對于一個寄存器的重命名。- 函數(shù)定義時聲明的簡寫:51單片機用的C89沒有簡寫,只要沒寫就默認(rèn)為
int
型。- 傳遞字符串:直接將字符串給函數(shù),那么形參定義是應(yīng)使用
char 形參名[]
或者char *形參名
的形式。另外,在主函數(shù)中傳遞數(shù)組形式的變量進函數(shù)時,都是傳遞的數(shù)組首元素地址。在函數(shù)中,數(shù)組的調(diào)用格式形參名[i]
與解引用格式*(形參名+i)
相同。- 天坑:LCD讀寫數(shù)據(jù)的時序中,使能信號
EN
持續(xù)的時間,不能按照器件手冊中的us級別,而是要延時大約1ms。- C語言沒有自帶的指數(shù)運算符,
^
表示的按位異或。而頭文件<Math.h>中的pow(x,y)
函數(shù),兩個操作數(shù)都是float
類型。- 關(guān)于移屏:有兩種可能,一是移為速度過快;二是VLCD驅(qū)動電壓過高。但目前暫未找到解決方法。
到了這里,關(guān)于51單片機學(xué)習(xí)筆記-12LCD1602液晶屏的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!