有些時(shí)候嵌入式系統(tǒng)也需要顯示更為復(fù)雜的圖形,需要更豐富的數(shù)據(jù)展示。為此,我們需要更大,色彩更豐富,帶觸屏的顯示屏,當(dāng)然性價(jià)比更高就最好了。在我們的項(xiàng)目中遇到此類需求,我們有時(shí)會(huì)選擇DWIN觸摸屏。在本篇中,我們就來(lái)設(shè)計(jì)并實(shí)現(xiàn)DWIN觸摸屏的驅(qū)動(dòng)。
1、功能概述
??我們這里所說(shuō)的是迪文的串口屏,該屏有多種接口類型,有使用RS485接口的屏,也有可通過(guò)跳線實(shí)現(xiàn)TTL接口或RS232接口的屏。但不論什么接口均采用相同的通訊協(xié)議。迪文串口屏采用的通訊協(xié)議的完整指令結(jié)構(gòu)如下圖所示:
??其中,CRC校驗(yàn)不包括幀頭和數(shù)據(jù)長(zhǎng)度,僅針對(duì)指令和數(shù)據(jù)進(jìn)行校驗(yàn)。CRC 校驗(yàn)采用 ANSI CRC-16 (X16+X15+X2+1)格式。當(dāng)啟用 CRC 幀校驗(yàn)并開啟自動(dòng)應(yīng)答功能后(R2.4=1,RC.3=1),DGUS 屏?xí)?CRC 校驗(yàn)完成后自動(dòng)應(yīng)答校驗(yàn)情況,返回指令結(jié)構(gòu)如下:
幀頭 +02+(DGUS 屏接收的)指令 +數(shù)據(jù)(0xFF 表示CRC校驗(yàn)正確,0x00 **表示**CRC 校驗(yàn)錯(cuò)誤) +CRC。
??迪文的DGUS 把用戶圖形界面的每一個(gè)頁(yè)面分解成多個(gè)控件變量,即 DGUS 屏采用變量驅(qū)動(dòng)模式工作,屏的工作模式和GUI的狀態(tài)完全由數(shù)據(jù)變量來(lái)控制。因此,串口指令也只需要對(duì)變量進(jìn)行讀、寫即可,指令集非常簡(jiǎn)單,一共只有5條指令。讀寫指令集如下圖所示:
??配置寄存器空間是用于存放指令狀態(tài)的,比如RTC(實(shí)時(shí)時(shí)間)、背光亮度等實(shí)時(shí)的狀態(tài)。了解寄存器的地址以及各寄存器的功能,就可以通過(guò)串口指令來(lái)實(shí)現(xiàn)上位機(jī)與DGUS屏信息傳輸及控制。寄存器地址0x00~0xFF,具體功能查看迪文寄存器功能說(shuō)明。
2、驅(qū)動(dòng)設(shè)計(jì)與實(shí)現(xiàn)
??已經(jīng)了解了迪文屏的通訊協(xié)議,我們就可以據(jù)此編寫迪文屏的驅(qū)動(dòng)程序。我們知道迪文屏的通訊協(xié)議有5個(gè)指令,我們的驅(qū)動(dòng)就是通過(guò)這5個(gè)指令操作迪文屏。
2.1、對(duì)象定義
??我們們依然采用基于對(duì)象的操作方式來(lái)實(shí)現(xiàn),所以首先我們依然是定義迪文屏的對(duì)象類型。具體定義如下:
/* 定義迪文串口屏對(duì)象類型 */
typedef struct DwinObject {
DwinCheckCodeType checkMode; //校驗(yàn)方式
void (*SendData)(uint8_t *txData,uint16_t length); //發(fā)送數(shù)據(jù)
void (*GetRegister)(struct DwinObject *dwin,uint8_t regAddress,uint8_t readByteLength);
void (*SetRegister)(struct DwinObject *dwin,uint8_t regAddress,uint8_t *txData,uint16_t length);
}DwinObjectType;
??迪文屏對(duì)象類型我們并沒(méi)有抽象出太多屬性,因?yàn)槠磷鳛閺脑O(shè)備并沒(méi)有返回太多信息,也沒(méi)有什么選擇特性。考慮到通訊信息的校驗(yàn)可以選擇是否啟用,所以我們將其抽象為屬性以區(qū)別于不同的情況。
??在對(duì)象使用之前同樣需要對(duì)其初始化,所以我們需要對(duì)象初始化函數(shù)。初始化函數(shù)如下:
/* 初始化迪文串口屏對(duì)象 */
void DwinInitialization(DwinObjectType *dwin,DwinCheckCodeType checkMode,SendDataForDwinType SendData)
{
if((dwin==NULL)||(SendData==NULL))
{
return;
}
dwin->checkMode=checkMode;
dwin->SendData=SendData;
dwin->GetRegister=GetRegisterDataFromDwinLCD;
dwin->SetRegister=SetRegisterDataToDwinLCD;
}
2.2、對(duì)象操作
??定義并初始化過(guò)的對(duì)象就可以對(duì)其進(jìn)行操作。我們已經(jīng)說(shuō)過(guò),迪文屏通訊協(xié)議有5個(gè)操作碼。分別是:0x80、寫寄存器;0x81,讀寄存器;0x82,寫數(shù)據(jù)存儲(chǔ)器;0x83,讀數(shù)據(jù)存儲(chǔ)器;0x84,寫曲線緩沖區(qū)。我們對(duì)屏的操作就是實(shí)現(xiàn)對(duì)這5個(gè)操作碼的使用。
2.2.1、寫寄存器
??向指定的寄存器地址寫入數(shù)據(jù),指令碼為0x80。該命令支持多個(gè)寄存器的連續(xù)寫操作,但最多只能寫入16個(gè)字節(jié)的數(shù)據(jù)。我們按照前面說(shuō)的消息幀的格式編寫操作函數(shù)如下:
/*寫寄存器數(shù)據(jù),一次最多允許寫16個(gè)字節(jié),即length<=16*/
static void SetRegisterDataToDwinLCD(DwinObjectType *dwin,uint8_t regAddress,uint8_t *txData,uint16_t length)
{
/*命令的長(zhǎng)度由幀頭(2個(gè)字節(jié))+數(shù)據(jù)長(zhǎng)度(1個(gè)字節(jié))+指令(1個(gè)字節(jié))+寄存器地址(1個(gè)字節(jié))+寫的數(shù)據(jù)(最多16字節(jié))+CRC校驗(yàn)(2個(gè)字節(jié))*/
uint16_t cmd_Length=length+5;
uint8_t cmd_Reg_Write[23];
cmd_Reg_Write[0]=0x5A;
cmd_Reg_Write[1]=0xA5;
cmd_Reg_Write[2]=(uint8_t)(length+2);
cmd_Reg_Write[3]= FC_REG_Write;
cmd_Reg_Write[4]=regAddress;
for(int dataIndex=0;dataIndex5]=txData[dataIndex];
}
if(dwin->checkMode>DwinNone)
{
uint16_t checkCode=CalcDwinCRC16(&cmd_Reg_Write[3],length+2);
cmd_Reg_Write[length+5]=(uint8_t)checkCode;
cmd_Reg_Write[length+6]=(uint8_t)(checkCode>>8);
cmd_Length=cmd_Length+2;
}
dwin->SendData(cmd_Reg_Write,cmd_Length);
}
2.2.2、讀寄存器
??從指定的寄存器地址開始讀取指定字節(jié)長(zhǎng)度的數(shù)據(jù),指令碼為0x81。一次讀取一到多個(gè)寄存器。由于寄存器地址是0x00到0xFF,所以理論上可以一次讀取全部寄存器。我們可以根據(jù)消息格式編寫操作函數(shù)如下:
/*讀寄存器數(shù)據(jù)*/
static void GetRegisterDataFromDwinLCD(DwinObjectType *dwin,uint8_t regAddress,uint8_t readByteLength)
{
/*命令的長(zhǎng)度由幀頭(2個(gè)字節(jié))+數(shù)據(jù)長(zhǎng)度(1個(gè)字節(jié))+指令(1個(gè)字節(jié))+寄存器地址(1個(gè)字節(jié))+讀取寄存器的字節(jié)長(zhǎng)度(1個(gè)字節(jié))+CRC校驗(yàn)(2個(gè)字節(jié))*/
uint16_t cmd_Length=6;
uint8_t cmd_Reg_Read[]={0x5A,0xA5,0x03,F(xiàn)C_REG_Read,0x00,0x00,0x00,0x00};//讀數(shù)據(jù)命令
cmd_Reg_Read[4]=regAddress;
cmd_Reg_Read[5]=readByteLength;
if(dwin->checkMode>DwinNone)
{
uint16_t checkCode=CalcDwinCRC16(&cmd_Reg_Read[3],3);
cmd_Reg_Read[6]=(uint8_t)checkCode;
cmd_Reg_Read[7]=(uint8_t)(checkCode>>8);
cmd_Length=cmd_Length+2;
}
dwin->SendData(cmd_Reg_Read,cmd_Length);
}
2.2.3、寫存儲(chǔ)器
??從指定的變量存儲(chǔ)器地址開始寫入數(shù)據(jù)串(字?jǐn)?shù)據(jù))到變量存儲(chǔ)區(qū),指令碼為0x82。存儲(chǔ)區(qū)與寄存器不一樣,地址和數(shù)據(jù)都是16位的。理論上說(shuō)一次可寫差不多100個(gè)字的數(shù)據(jù),事實(shí)上通常不建議這種極限方式。所以我們將長(zhǎng)度限制在100個(gè)字節(jié)以內(nèi)。我們可以根據(jù)消息格式編寫操作函數(shù)如下:
/*寫數(shù)據(jù)變量存儲(chǔ)器,一次最多允許寫47個(gè)字,即length<=94*/
void WriteFlashDataToDwinLCD(DwinObjectType *dwin,uint16_t startAddress,uint8_t *txData,uint16_t length)
{
/*命令的長(zhǎng)度由幀頭(2個(gè)字節(jié))+數(shù)據(jù)長(zhǎng)度(1個(gè)字節(jié))+指令(1個(gè)字節(jié))+起始地址(2個(gè)字節(jié))+數(shù)據(jù)(長(zhǎng)度為length)+CRC校驗(yàn)(2個(gè)字節(jié))*/
uint16_t cmd_Length=length+6;
uint8_t cmd_VAR_Write[102];
cmd_VAR_Write[0]=0x5A;
cmd_VAR_Write[1]=0xA5;
cmd_VAR_Write[2]=(uint8_t)(length+3);
cmd_VAR_Write[3]= FC_VAR_Write;
cmd_VAR_Write[4]=(uint8_t)(startAddress>>8);//起始地址
cmd_VAR_Write[5]=(uint8_t)startAddress;//起始地址
for(int dataIndex=0;dataIndex6]=txData[dataIndex];
}
if(dwin->checkMode>DwinNone)
{
uint16_t checkCode=CalcDwinCRC16(&cmd_VAR_Write[3],length+2);
cmd_VAR_Write[length+6]=(uint8_t)checkCode;
cmd_VAR_Write[length+7]=(uint8_t)(checkCode>>8);
cmd_Length=cmd_Length+2;
}
dwin->SendData(cmd_VAR_Write,cmd_Length);
}
2.2.4、讀存儲(chǔ)器
??從變量存儲(chǔ)區(qū)指定地址開始讀取指定字長(zhǎng)度的字?jǐn)?shù)據(jù),指令碼為0x83。讀取操作理論也可以讀取256個(gè)字節(jié),其實(shí)顯示屏主要用于數(shù)據(jù)展示,主要是接收主機(jī)發(fā)來(lái)的數(shù)據(jù)。需要發(fā)送給主站的數(shù)據(jù)很有限。我們可以根據(jù)消息格式編寫操作函數(shù)如下:
/*讀變量存儲(chǔ)器數(shù)據(jù)*/
void ReadFlashDataFromDwinLCD(DwinObjectType *dwin,uint16_t startAddress,uint8_t readWordLength)
{
/*命令的長(zhǎng)度由幀頭(2個(gè)字節(jié))+數(shù)據(jù)長(zhǎng)度(1個(gè)字節(jié))+指令(1個(gè)字節(jié))+起始地址(2個(gè)字節(jié))+讀取的字長(zhǎng)度(1個(gè)字節(jié))+CRC校驗(yàn)(2個(gè)字節(jié))*/
uint16_t cmd_Length=7;
uint8_t cmd_VAR_Read[]={0x5A,0xA5,0x04,F(xiàn)C_VAR_Read,0x00,0x00,0x00,0x00,0x00};//讀數(shù)據(jù)命令
cmd_VAR_Read[4]=(uint8_t)(startAddress>>8);//起始地址
cmd_VAR_Read[5]=(uint8_t)startAddress;//起始地址
cmd_VAR_Read[6]=readWordLength;//讀取長(zhǎng)度
if(dwin->checkMode>DwinNone)
{
uint16_t checkCode=CalcDwinCRC16(&cmd_VAR_Read[3],4);
cmd_VAR_Read[7]=(uint8_t)checkCode;
cmd_VAR_Read[8]=(uint8_t)(checkCode>>8);
cmd_Length=cmd_Length+2;
}
dwin->SendData(cmd_VAR_Read,cmd_Length);
}
2.2.5、寫曲線緩沖區(qū)
??DGUS屏有一個(gè)16KB、可存儲(chǔ)8條曲線趨勢(shì)圖的曲線緩沖區(qū),用于用戶簡(jiǎn)單、快速顯示曲線。曲線緩沖區(qū)的數(shù)據(jù)都是16位無(wú)符號(hào)數(shù)。寫曲線緩沖區(qū)的指令碼為0x84。我們可以根據(jù)消息格式編寫操作函數(shù)如下:
/*寫曲線緩沖區(qū),一次最多允許寫8個(gè)字,即length<=16*/
void WriteCurveToDwinLCD(DwinObjectType *dwin,uint8_t *txData,uint16_t length,uint8_t channelMode)
{
/*命令的長(zhǎng)度由幀頭(2個(gè)字節(jié))+數(shù)據(jù)長(zhǎng)度(1個(gè)字節(jié))+指令(1個(gè)字節(jié))+通道模式(1個(gè)字節(jié))+數(shù)據(jù)(length,最多8個(gè)字)+CRC校驗(yàn)(2個(gè)字節(jié))*/
uint16_t cmd_Length=length+5;
uint8_t cmd_Curve_Write[23];//寫曲線緩沖區(qū)命令
cmd_Curve_Write[0]=0x5A;
cmd_Curve_Write[1]=0xA5;
cmd_Curve_Write[2]=(uint8_t)(length+2);
cmd_Curve_Write[3]= FC_Curve_Write;
cmd_Curve_Write[4]=channelMode;
for(int dataIndex=0;dataIndex5]=txData[dataIndex];
}
if(dwin->checkMode>DwinNone)
{
uint16_t checkCode=CalcDwinCRC16(&cmd_Curve_Write[3],length+2);
cmd_Curve_Write[length+5]=(uint8_t)checkCode;
cmd_Curve_Write[length+6]=(uint8_t)(checkCode>>8);
cmd_Length=cmd_Length+2;
}
dwin->SendData(cmd_Curve_Write,cmd_Length);
}
3、驅(qū)動(dòng)的使用
??我們已經(jīng)實(shí)現(xiàn)了迪文觸摸屏的驅(qū)動(dòng),接下來(lái)我們就使用驅(qū)動(dòng)開發(fā)應(yīng)用。驅(qū)動(dòng)的使用并不復(fù)雜,依然是定義對(duì)象,然后根據(jù)需要操作對(duì)象。
3.1、聲明并初始化對(duì)象
??首先我們需要使用DwinObjectType類型聲明一個(gè)迪文觸摸屏的對(duì)象變量。這就是一個(gè)具體的屏對(duì)象,具體如下:
??DwinObjectType lcd;
??當(dāng)然這個(gè)對(duì)象還不能使用,因?yàn)槠鞑⑽促x值。所以我們還要使用DwinInitialization函數(shù)初始化這個(gè)對(duì)象。在初始化之前我們必須定義一個(gè)形如void (*SendDataForDwinType)(uint8_t *txData,uint16_t length)的函數(shù),具體如下:
//數(shù)據(jù)發(fā)送
void SendData(uint8_t *txData,uint16_t length)
{
uint16_t i;
for(i=0;i//傳送寄存器不為空,等待傳送結(jié)束
while(USART_GetFlagStatus(USART3, USART_FLAG_TXE) == RESET)
{
}
// 寫一個(gè)字節(jié)到對(duì)應(yīng)的串口傳送數(shù)據(jù)寄存器
USART_SendData(USART3, txData[i]);
}
}
??并將函數(shù)指針傳遞作為參數(shù)傳遞給初始化函數(shù)。除了屏對(duì)象和發(fā)送數(shù)據(jù)函數(shù)指針外,初始化函數(shù)還有一個(gè)參數(shù)是校驗(yàn)方式。這里我們選擇無(wú)校驗(yàn)碼,所以初始化函數(shù)調(diào)用如下:
??DwinInitialization(&lcd,DwinNone,SendData);
??到這里對(duì)象的定義及初始化就完成了。
3.2、調(diào)用函數(shù)操作對(duì)象
??初始化之后的對(duì)象就可對(duì)其進(jìn)行操作了。我們?cè)谇懊嬉呀?jīng)針對(duì)5個(gè)操作碼實(shí)現(xiàn)了對(duì)對(duì)象的驅(qū)動(dòng)。那么我們要操作對(duì)象時(shí),就是調(diào)用這5個(gè)函數(shù)來(lái)實(shí)現(xiàn)的。
??向屏的數(shù)據(jù)存儲(chǔ)區(qū)寫數(shù)據(jù)時(shí),需要調(diào)用WriteFlashDataToDwinLCD函數(shù),如我們要向0x0000地址開始寫入8個(gè)字節(jié)的數(shù)據(jù)則:
??WriteFlashDataToDwinLCD(&lcd,0x0000,txData,8);
??從屏的數(shù)據(jù)存儲(chǔ)區(qū)讀取數(shù)據(jù)時(shí),需要調(diào)用ReadFlashDataFromDwinLCD函數(shù),如我們從0x000A地址開始讀取4個(gè)字長(zhǎng)度的數(shù)據(jù)則:
??ReadFlashDataFromDwinLCD(&lcd,0x000A,4);
??向曲線緩沖區(qū)寫數(shù)據(jù),總共有8個(gè)通道,一次最多允許寫8個(gè)字。通道模式用于選擇向哪些通道寫數(shù)據(jù),每一位代表一個(gè)通道。所以我們?cè)谑褂肳riteCurveToDwinLCD函數(shù)寫曲線緩沖區(qū)時(shí)需要配置通道。比如我們要向8個(gè)通道寫8個(gè)字的數(shù)據(jù)則:
??WriteCurveToDwinLCD(&lcd,txData,16,0xFF);
??對(duì)于寄存器的讀寫操作,我們封裝了一些常用的,如讀取LCD系統(tǒng)時(shí)間、校準(zhǔn)LCD系統(tǒng)時(shí)間等。
??讀取LCD系統(tǒng)時(shí)間:GetDateTimeFromDwinLCD(&lcd);
??校準(zhǔn)LCD系統(tǒng)時(shí)間:CalibrationDateTimeForDwinLCD(&lcd,dateTime);
??音樂(lè)播放控制:HandleDwinLCDToPlayMusic(&l'c'd,playStart,playNum,volume);當(dāng)playNum為0時(shí)表示停止播放。
??設(shè)置屏顯示畫面:SetDwinLCDDisplay(&lcd,picID);
??對(duì)于沒(méi)有封裝的寄存器操作,可以直接在對(duì)象中調(diào)用寄存器讀寫函數(shù)實(shí)現(xiàn)。如:
??lcd.GetRegister(&lcd, regAddress,readByteLength);
??lcd.SetRegister(&lcd,regAddress,txData,length);
4、應(yīng)用總結(jié)
??我們通過(guò)實(shí)測(cè),驅(qū)動(dòng)迪文觸摸屏的操作結(jié)果與預(yù)期一致。我們讓MCU給顯示屏發(fā)送一些數(shù)據(jù),并在屏上顯示出來(lái):
??再來(lái)看看對(duì)傳感器做一下擾動(dòng)時(shí)(用配氣儀和小型氣泵向傳感器管道送不同的氣)數(shù)據(jù)的變化,傳感器檢測(cè)對(duì)象變化是屏幕顯示也變化。
??再來(lái)改變一下氣體成分和氣泵的轉(zhuǎn)速看看數(shù)據(jù)的變化:
??經(jīng)過(guò)以上實(shí)驗(yàn),迪文串口屏驅(qū)動(dòng)已經(jīng)達(dá)到預(yù)期。至于一些更復(fù)雜的操作方式也都可以以此為基礎(chǔ)實(shí)現(xiàn)之。
-
觸摸屏
+關(guān)注
關(guān)注
42文章
2325瀏覽量
117194 -
驅(qū)動(dòng)設(shè)計(jì)
+關(guān)注
關(guān)注
1文章
111瀏覽量
15374 -
DWIN
+關(guān)注
關(guān)注
0文章
1瀏覽量
1833
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
STM32 SPI驅(qū)動(dòng)觸摸屏(XPT2046)(上)

C8051F020觸摸屏驅(qū)動(dòng)控制

電阻式觸摸屏,什么是電阻式觸摸屏
觸摸屏的實(shí)現(xiàn)原理及在android上的實(shí)現(xiàn)
手機(jī)觸摸屏驅(qū)動(dòng)的研究與設(shè)計(jì)張欣
組態(tài)王和觸摸屏哪個(gè)好_組態(tài)王和觸摸屏區(qū)別
Linux下的觸摸屏驅(qū)動(dòng)
Android4.2觸摸屏驅(qū)動(dòng)與4.0有哪些不同

基于觸摸屏的LED驅(qū)動(dòng)電路設(shè)計(jì)

觸摸屏與PLC如何實(shí)現(xiàn)通訊?
modbus觸摸屏

評(píng)論