LCD1602是一種工業(yè)字符型液晶,能夠同時(shí)顯示16x02即32個(gè)字符。LCD1602液晶顯示的原理是利用液晶的物理特性,通過電壓對其顯示區(qū)域進(jìn)行控制,即可以顯示出圖形。在這一章我們就來討論LCD1602液晶顯示屏驅(qū)動(dòng)的設(shè)計(jì)與實(shí)現(xiàn)。
1、功能概述
??LCD1602液晶又被稱作1602字符型液晶,這是一種只用來顯示字母、數(shù)字、符號等的點(diǎn)陣型液晶模塊。LCD1602里面存儲器一般有三種:CGROM、CGRAM、DDRAM。其中DDRAM(Display Data RAM)就是顯示數(shù)據(jù)RAM,用來寄存待顯示的字符代碼。共80個(gè)字節(jié),其地址和屏幕的對應(yīng)關(guān)系如下如圖所示:
??LCD1602使用三條控制線:EN、RW、RS。 其中EN的作用其實(shí)就是中線的功能,RW和RS指示了讀、它寫的是寫的方向和內(nèi)容。在讀數(shù)據(jù)(或者Busy標(biāo)志)期間,EN線必須保持高電平;而在寫指令(或者數(shù)據(jù))過程中,EN線上必須送出一個(gè)正脈沖。RW、RS的組合一共有四種情況,分別對應(yīng)四種操作:
??(1)、RS=0、RW=0——表示向LCD寫入指令。
??(2)、RS=0、RW=1——表示讀取Busy標(biāo)志。
??(3)、RS=1、RW=0——表示向LCD寫入數(shù)據(jù)。
??(4)、RS=1、RW=1——表示從LCD讀取數(shù)據(jù)。
??LCD1602利用指令碼來區(qū)分不同的操作,主要的有兩類:一是用于初始化配置的指令碼;二是用于數(shù)據(jù)控制的指令碼。第一類用于LCD初始化配置的指令碼基本上都是在系統(tǒng)啟動(dòng)時(shí),用于對LCD1602的一次性配置。而第二類數(shù)據(jù)操作的指令碼主要用于設(shè)置數(shù)據(jù)指針的位置,現(xiàn)實(shí)信息的實(shí)現(xiàn)與清楚等。這兩類指令碼從使用上并無太大區(qū)別,后續(xù)我們將詳細(xì)說明。
2、驅(qū)動(dòng)設(shè)計(jì)與實(shí)現(xiàn)
??我們已經(jīng)了解了LCD1602的基本情況,接下來我們將給予對LCD1602的基本了解設(shè)計(jì)LCD602的驅(qū)動(dòng)程序。
2.1、對象定義
??在使用一個(gè)對象之前我們需要獲得一個(gè)對象。同樣的我們想要LCD1602液晶顯示屏就需要先定義LCD1602液晶顯示屏的對象。
2.1.1、對象的抽象
??我們要得到LCD1602液晶顯示屏對象,需要先分析其基本特性。一般來說,一個(gè)對象至少包含兩方面的特性:屬性與操作。接下來我們就來從這兩個(gè)方面思考一下LCD1602液晶顯示屏的對象。
??先來考慮屬性,作為屬性肯定是用于標(biāo)識或記錄對象特征的東西。我們來考慮LCD1602液晶顯示屏對象屬性。對于LCD1602顯示屏,它主要的功能就是顯示信息,為了標(biāo)識當(dāng)前的狀態(tài),我們將狀態(tài)寄存器的值作為對象的屬性。
??接著我們還需要考慮LCD1602液晶顯示屏對象的操作問題。首先我們需要控制LCD1602的3個(gè)控制引腳以實(shí)現(xiàn)對LCD1602的控制,但這些控制引腳的操作都與具體的操作平臺相關(guān),所以我們將其作為對象的操作來實(shí)現(xiàn)。同樣的我們還需要向LCD1602發(fā)送命令和數(shù)據(jù)以及從LCD1602獲取消息,而讀取和發(fā)送都是依賴于具體的操作平臺的所以我們將其作為LCD1602的兩個(gè)操作。我們對LCD1602進(jìn)行操作,免不了要進(jìn)行時(shí)序控制,所以我們需要有延時(shí)操作,但我們都明白演示操作依賴于具體的軟硬件平臺,所以我們將延時(shí)處理函數(shù)也作為對象的操作。
??根據(jù)上述我們對LCD1602液晶顯示屏的分析,我們可以定義LCD1602液晶顯示屏的對象類型如下:
/* 定義LCD1602的對象類型 */
typedef struct LCD1602Object {
uint8_t status;
LCD1602PinSetType *PinHandle;
void(*SendByte)(uint8_t data);
uint8_t(*GetByte)(void);
void (*Delayus)(volatile uint32_t period); //微秒延時(shí)函數(shù)
void (*Delayms)(volatile uint32_t nTime); //毫秒秒延時(shí)函數(shù)
}LCD1602ObjectType;
2.1.2、對象初始化
??我們知道,一個(gè)對象僅作聲明是不能使用的,我們需要先對其進(jìn)行初始化,所以這里我們來考慮LCD1602液晶顯示屏對象的初始化函數(shù)。一般來說,初始化函數(shù)需要處理幾個(gè)方面的問題。一是檢查輸入參數(shù)是否合理;二是為對象的屬性賦初值;三是對對象作必要的初始化配置。據(jù)此我們設(shè)計(jì)LCD1602液晶顯示屏對象的初始化函數(shù)如下:
/*對顯示屏作初始化配置*/
void LCD1602Initialization(LCD1602ObjectType *lcd, //LCD1602對象指針
LCD1602PinSetType *PinHandle, //控制引腳操作函數(shù)指針數(shù)組
LCD1602SendByteType sendByte, //發(fā)送一個(gè)字節(jié)函數(shù)指針
LCD1602GetByteType getByte, //讀取一個(gè)字節(jié)函數(shù)指針
LCD1602DelayType delayus, //微秒延時(shí)函數(shù)指針
LCD1602DelayType delayms //毫秒延時(shí)函數(shù)指針
)
{
if((lcd==NULL)||(PinHandle==NULL)||(sendByte==NULL)||(getByte==NULL)||(delayus==NULL)||(delayms==NULL))
{
return;
}
lcd->PinHandle=PinHandle;
lcd->SendByte=sendByte;
lcd->GetByte=getByte;
lcd->Delayus=delayus;
lcd->Delayms=delayms;
lcd->Delayus(15);
WriteCommandToLCD1602(lcd,0x38);
lcd->Delayms(5);
WriteCommandToLCD1602(lcd,0x38);
lcd->Delayms(5);
WriteCommandToLCD1602(lcd,0x38);
/*后續(xù)需要檢測BUSY,等待10Mms*/
lcd->Delayms(10);
WriteCommandToLCD1602(lcd,0x38);//顯示模式設(shè)置
lcd->Delayms(10);
WriteCommandToLCD1602(lcd,0x08);//顯示關(guān)閉
lcd->Delayms(10);
WriteCommandToLCD1602(lcd,0x01);//顯示清屏
lcd->Delayms(10);
WriteCommandToLCD1602(lcd,0x06);//顯示光標(biāo)移動(dòng)位置
lcd->Delayms(10);
WriteCommandToLCD1602(lcd,0x0C);//顯示開及光標(biāo)設(shè)置
lcd->PinHandle[LCD1602_EN](Low);
lcd->status=ReadStatusFromLCD1602(lcd);
}
2.2、對象操作
我們已經(jīng)完成了LCD1602液晶顯示屏對象類型的定義和對象初始化函數(shù)的設(shè)計(jì)。但我們的主要目標(biāo)是獲取對象的信息,接下來我們還要實(shí)現(xiàn)面向LCD1602液晶顯示屏的各類操作。
2.2.1、讀數(shù)據(jù)操作
??我們需要從LCD1602液晶顯示屏獲取一定的數(shù)據(jù),包括讀取狀態(tài)信息和數(shù)據(jù)信息,唯一的區(qū)別只是RS控制引腳的電平,其他的操作都一樣,讀取數(shù)據(jù)的時(shí)序圖如下所示:
??根據(jù)我們前面的描述及上面的時(shí)序圖,我們可以實(shí)現(xiàn)獲取狀態(tài)信息及數(shù)據(jù)的操作函數(shù)如下:
/*從LCD1602讀狀態(tài)*/
static uint8_t ReadStatusFromLCD1602(LCD1602ObjectType *lcd)
{
uint8_t status;
lcd->PinHandle[LCD1602_RS](Low);
lcd->PinHandle[LCD1602_RW](High);
lcd->PinHandle[LCD1602_EN](High);
lcd->Delayus(20);
status=lcd->GetByte();
lcd->PinHandle[LCD1602_EN](Low);
lcd->Delayus(5);
return status;
}
/*從LCD1602讀數(shù)據(jù)*/
static uint8_t ReadDataFromLCD1602(LCD1602ObjectType *lcd)
{
uint8_t data;
lcd->PinHandle[LCD1602_RS](High);
lcd->PinHandle[LCD1602_RW](High);
lcd->PinHandle[LCD1602_EN](High);
lcd->Delayus(20);
data=lcd->GetByte();
lcd->PinHandle[LCD1602_EN](Low);
lcd->Delayus(5);
return data;
}
2.2.2、寫數(shù)據(jù)操作
??我們想要在LCD1602顯示屏上顯示我們想要的消息就需要向LCD1602顯示屏發(fā)送命令和數(shù)據(jù)。發(fā)送數(shù)據(jù)和發(fā)送命令的區(qū)別僅是RS控制引腳的操作電平不同,具體的操作時(shí)序如下所示:
/*向LCD1602寫指令*/
static void WriteCommandToLCD1602(LCD1602ObjectType *lcd,uint8_t command)
{
lcd->PinHandle[LCD1602_RS](Low);
lcd->PinHandle[LCD1602_RW](Low);
lcd->SendByte(command);
lcd->PinHandle[LCD1602_EN](High);
lcd->Delayus(20);
lcd->PinHandle[LCD1602_EN](Low);
lcd->Delayus(5);
}
/*向LCD1602寫數(shù)據(jù)*/
static void WriteDatatoLCD1602(LCD1602ObjectType *lcd,uint8_t data)
{
lcd->PinHandle[LCD1602_RS](High);
lcd->PinHandle[LCD1602_RW](Low);
lcd->SendByte(data);
lcd->PinHandle[LCD1602_EN](High);
lcd->Delayus(20);
lcd->PinHandle[LCD1602_EN](Low);
lcd->Delayus(5);
}
3、驅(qū)動(dòng)的使用
??我們已經(jīng)實(shí)現(xiàn)了LCD1602液晶顯示屏驅(qū)動(dòng)程序,在接下來我們還需要設(shè)計(jì)一個(gè)簡單的應(yīng)用驗(yàn)證這一驅(qū)動(dòng)設(shè)計(jì)是否正確。
3.1、聲明并初始化對象
??使用基于對象的操作我們需要先得到這個(gè)對象,所以我們先要使用前面定義的LCD1602液晶顯示屏對象類型聲明一個(gè)LCD1602液晶顯示屏對象變量,具體操作格式如下:
??LCD1602ObjectType lcd;
??聲明了這個(gè)對象變量并不能立即使用,我們還需要使用驅(qū)動(dòng)中定義的初始化函數(shù)對這個(gè)變量進(jìn)行初始化。這個(gè)初始化函數(shù)所需要的輸入?yún)?shù)如下:
LCD1602ObjectType *lcd, //LCD1602對象指針
LCD1602PinSetType *PinHandle, //控制引腳操作函數(shù)指針數(shù)組
LCD1602SendByteType sendByte, //發(fā)送一個(gè)字節(jié)函數(shù)指針
LCD1602GetByteType getByte, //讀取一個(gè)字節(jié)函數(shù)指針
LCD1602DelayType delayus, //微秒延時(shí)函數(shù)指針
LCD1602DelayType delayms //毫秒延時(shí)函數(shù)指針
??對于這些參數(shù),對象變量我們已經(jīng)定義了。主要的是我們需要定義幾個(gè)函數(shù),并將函數(shù)指針作為參數(shù)。這幾個(gè)函數(shù)的類型如下:
/*定義引腳操作函數(shù)指針類型*/
typedef void (*LCD1602PinSetType)(uint8_t value);
/*定義發(fā)送一個(gè)字節(jié)操作函數(shù)指針*/
typedef void(*LCD1602SendByteType)(uint8_t data);
/*定義讀取一個(gè)字節(jié)操作函數(shù)指針*/
typedef uint8_t(*LCD1602GetByteType)(void);
/*定義延時(shí)操作函數(shù)指針*/
typedef void (*LCD1602DelayType)(volatile uint32_t time);
??對于這幾個(gè)函數(shù)我們根據(jù)樣式定義就可以了,具體的操作可能與使用的硬件平臺有關(guān)系??刂埔_的操作函數(shù)實(shí)際是3個(gè),組成一個(gè)函數(shù)指針數(shù)組,分別對應(yīng)RS、RW、EN控制引腳。具體函數(shù)定義如下:
LCD1602PinSetType pinSets[3]={RsPinOperation,RwPinOperation,EnPinOperation};
/*RS控制引腳操作*/
static void RsPinOperation(uint8_t value)
{
HAL_GPIO_WritePin(GPIOD,GPIO_PIN_7,(GPIO_PinState)value);
}
/*RW控制引腳操作*/
static void RwPinOperation(uint8_t value)
{
HAL_GPIO_WritePin(GPIOD,GPIO_PIN_8,(GPIO_PinState)value);
}
/*EN控制引腳操作*/
static void EnPinOperation(uint8_t value)
{
HAL_GPIO_WritePin(GPIOD,GPIO_PIN_9,(GPIO_PinState)value);
}
/*從LCD1602讀一個(gè)字節(jié)*/
static uint8_t ReadByteFromLCD(void)
{
uint8_t data=0;
data=(uint8_t)(GPIOD->IDR);
return data;
}
/*向LCD1602寫一個(gè)字節(jié)*/
static void WriteByteToLCD(uint8_t data)
{
uint16_t value=GPIOD->ODR;
value=(value&&0xFF00)||data;
GPIOD->ODR=value;
}
??對于延時(shí)函數(shù)我們可以采用各種方法實(shí)現(xiàn)。我們采用的STM32平臺和HAL庫,所以毫秒延時(shí)函數(shù)可以直接使用HAL_Delay()函數(shù)。微秒延時(shí)函數(shù)采用我們編寫的delayus于是我們可以調(diào)用初始化函數(shù)如下:
LCD1602Initialization(&lcd, //LCD1602對象指針
pinSets, //控制引腳操作函數(shù)指針數(shù)組
WriteByteToLCD, //發(fā)送一個(gè)字節(jié)函數(shù)指針
ReadByteFromLCD, //讀取一個(gè)字節(jié)函數(shù)指針
Delayus, //微秒延時(shí)函數(shù)指針
HAL_Delay //毫秒延時(shí)函數(shù)指針
);
3.2、基于對象進(jìn)行操作
??我們定義了對象變量并使用初始化函數(shù)給其作了初始化。接著我們就來考慮操作這一對象獲取我們想要的數(shù)據(jù)。我們在驅(qū)動(dòng)中已經(jīng)將獲取數(shù)據(jù)并轉(zhuǎn)換為轉(zhuǎn)換值的比例值,接下來我們使用這一驅(qū)動(dòng)開發(fā)我們的應(yīng)用實(shí)例。
/*在LCD1602中顯示數(shù)據(jù)*/
void LCD1602Display(void)
{
float temp=20.5;
float pres=101.35;
float humi=34.6;
LCD1602DisplayClear(&lcd,LCD1602_AllLine),
Lcd1602ContentDisplay(&lcd,0x80, "T%0.1fC,P%0.1fKPa,H%0.1f%%", temp,pres, humi);
Lcd1602ContentDisplay(&lcd,0xC0, "T%0.1fC,P%0.1fKPa,H%0.1f%%", temp,pres, humi);
}
??我們將顯示器清屏,然后再每一行都顯示溫度、壓力和濕度數(shù)據(jù)。
4、應(yīng)用總結(jié)
??我們已經(jīng)設(shè)計(jì)并實(shí)現(xiàn)了LCD1602的驅(qū)動(dòng)程序,并在此基礎(chǔ)上設(shè)計(jì)了簡單的驗(yàn)證應(yīng)用。我們可以正常讀寫LCD1602顯示屏,并且在LCD1602顯示屏正確心事我們想要的信息,說明我們的驅(qū)動(dòng)設(shè)計(jì)是沒有問題的。
??在使用驅(qū)動(dòng)時(shí),有一點(diǎn)需要注意。因?yàn)樵诔跏蓟瘮?shù)中,對控制引腳的操作采用的時(shí)函數(shù)指針數(shù)組,但這個(gè)數(shù)組元素的順序不是隨意的,而是必須與枚舉類型LCD1602PinType中定義的順序一致才能正確操作。
-
顯示屏
+關(guān)注
關(guān)注
28文章
4511瀏覽量
74765 -
驅(qū)動(dòng)設(shè)計(jì)
+關(guān)注
關(guān)注
1文章
111瀏覽量
15320 -
LCD1602
+關(guān)注
關(guān)注
14文章
607瀏覽量
52727 -
液晶顯示屏
+關(guān)注
關(guān)注
1文章
208瀏覽量
27798
發(fā)布評論請先 登錄
相關(guān)推薦
評論