異步串口(UART)通訊是嵌入式設(shè)備中最常見(jiàn)的通訊方式之一。本文主要針對(duì)預(yù)裝Windows CE操作系統(tǒng)的英創(chuàng)主板,分析用戶層程序在使用UART進(jìn)行發(fā)送時(shí)的幾個(gè)有關(guān)問(wèn)題,供客戶在設(shè)計(jì)應(yīng)用程序時(shí)參考。
問(wèn)題1:數(shù)據(jù)是否發(fā)送出去了?
WriteFile函數(shù)是發(fā)送串口數(shù)據(jù)的基本API,具體函數(shù)形式及參數(shù)定義如下:
BOOLWriteFile(
HANDLE hFile,//CreateFile返回函數(shù)Handle
LPCVOID lpBuffer,//裝載發(fā)送數(shù)據(jù)的Buffer指針
DWORD nNumberOfBytesToWrite,//待發(fā)送數(shù)據(jù)的字節(jié)長(zhǎng)度
LPDWORD lpNumberOfBytesWritten,//返回的實(shí)際發(fā)送的字節(jié)數(shù)
LPOVERLAPPED lpOverlapped// = NULL,CE未使用該參數(shù)
);
WriteFile的返回值為TRUE并不代表發(fā)送Buffer中的數(shù)據(jù)已全部發(fā)送出去了,需要檢查返回的實(shí)際字節(jié)長(zhǎng)度lpNumberOfBytesWritten。所以推薦的調(diào)用方法為
// 發(fā)送緩沖區(qū)pTxBuff, 發(fā)送長(zhǎng)度dwLen
DWORD dwNumberOfBytesWritten = 0;
BOOL bRet = WrietFile(hFile, pTxBuf, dwLen, &dwNumberOfBytesWritten, NULL);
if(bRet && (dwLen == dwNumberOfBytesWritten))
{
//發(fā)送緩沖區(qū)中的數(shù)據(jù)已成功送入U(xiǎn)ART硬件的發(fā)送端口,大多數(shù)情況數(shù)據(jù)已從
//物理端口發(fā)送出去,但此時(shí)可能還有若干字節(jié)還在UART的硬件TX FIFO中,等
//待硬件控制器順序發(fā)送。
//… 發(fā)送成功 …
}
else
{
//發(fā)送出錯(cuò)處理。。。。
}
問(wèn)題2:WriteFile函數(shù)的阻塞問(wèn)題
CE串口驅(qū)動(dòng)的執(zhí)行數(shù)據(jù)發(fā)送時(shí),為了保持代碼的高效率,沒(méi)有在驅(qū)動(dòng)程序中層另外分配Buffer,把應(yīng)用層需發(fā)送的數(shù)據(jù)先Copy到內(nèi)部再發(fā)送,而是直接利用用戶層的pTxBuf。因此原則上說(shuō),當(dāng)數(shù)據(jù)沒(méi)有發(fā)送完前,WriteFile函數(shù)是不會(huì)返回,處于阻塞掛起狀態(tài)的。進(jìn)一步,可能存在某種原因,數(shù)據(jù)始終沒(méi)有發(fā)送完畢,則WriteFile將永遠(yuǎn)阻塞而不會(huì)返回。不少應(yīng)用程序并不希望這樣的永遠(yuǎn)阻塞,而是希望WriteFile能在一定時(shí)間內(nèi)返回,即使出錯(cuò),也讓應(yīng)用程序有機(jī)會(huì)進(jìn)行出錯(cuò)處理。CE驅(qū)動(dòng)為此專門設(shè)置了超時(shí)機(jī)制,其數(shù)據(jù)結(jié)構(gòu)如下:
typedefstruct_COMMTIMEOUTS {
DWORD ReadIntervalTimeout; //與接收有關(guān),本文不討論
DWORD ReadTotalTimeoutMultiplier; //與接收有關(guān),本文不討論
DWORD ReadTotalTimeoutConstant; //與接收有關(guān),本文不討論
DWORD WriteTotalTimeoutMultiplier; //發(fā)送超時(shí)倍數(shù)因子
DWORD WriteTotalTimeoutConstant; //發(fā)送超時(shí)固定常數(shù)值
} COMMTIMEOUTS,*LPCOMMTIMEOUTS;
實(shí)際在驅(qū)動(dòng)中,發(fā)送超時(shí)的計(jì)算及使用方法如下:
DWORD dwTimeout =
CommTimeouts.WriteTotalTimeoutMultiplier*dwLen +
CommTimeouts.WriteTotalTimeoutConstant;
if( !dwTimeout )
dwTimeout = INFINITE;
//等待來(lái)自發(fā)送中斷線程的發(fā)送結(jié)束事件
ULONG WaitReturn = WaitForSingleObject(hTransmitEvent, dwTimeout);
上面的代碼中dwTimeout的單位為ms,在第一次打開串口驅(qū)動(dòng)”COM#”時(shí),超時(shí)數(shù)據(jù)結(jié)構(gòu)中的WriteTotalTimeoutMultiplier和WriteTotalTimeoutConstant均為0,所以就有發(fā)送超時(shí)無(wú)窮的問(wèn)題。為了讓dwTimeout為有限值,需要設(shè)置超時(shí)參數(shù)如下:
COMMTIMEOUTS CommTimeouts; //定義局部變量
GetCommTimeouts(hFile, &CommTimeouts); //讀取串口的超時(shí)參數(shù)
//假設(shè)應(yīng)用程序設(shè)置的串口波特率為baud
CommTimeouts. WriteTotalTimeoutConstant = baud / BR9600 + 1;
CommTimeouts. WriteTotalTimeoutMultiplier =
CommTimeouts.WriteTotalTimeoutConstant * 2;
SetCommTimeouts(hFile, &CommTimeouts); //重新設(shè)置串口超時(shí)參數(shù)
上述代碼大致設(shè)置了一個(gè)2倍發(fā)送時(shí)間長(zhǎng)度的超時(shí)時(shí)間,其中選取BR9600為單位時(shí)間,是因?yàn)?600bps波特率基本對(duì)應(yīng)一個(gè)字節(jié)的發(fā)送時(shí)間為1ms。
-
WINDOWS
+關(guān)注
關(guān)注
4文章
3623瀏覽量
92815 -
嵌入式主板
+關(guān)注
關(guān)注
7文章
6107瀏覽量
36807
發(fā)布評(píng)論請(qǐng)先 登錄
【道生物聯(lián)TKB-623評(píng)估板試用】TKB-623評(píng)估板雙機(jī)通訊測(cè)試_程序開發(fā)
易華錄入選國(guó)家級(jí)信息技術(shù)應(yīng)用創(chuàng)新典型解決方案
佛瑞亞如何通過(guò)信息技術(shù)推動(dòng)業(yè)務(wù)增長(zhǎng)
飛騰主板為信創(chuàng)產(chǎn)業(yè)發(fā)展提高硬實(shí)力
DEKRA德凱成為沙特通信和信息技術(shù)設(shè)備技術(shù)法規(guī)認(rèn)證機(jī)構(gòu)
京能信息蒞臨中軟國(guó)際數(shù)字電力科創(chuàng)中心調(diào)研
科普|信創(chuàng)是什么?一文讀懂“信息技術(shù)應(yīng)用創(chuàng)新”戰(zhàn)略

英創(chuàng)信息技術(shù)串口通訊中數(shù)據(jù)發(fā)送的有關(guān)問(wèn)題分析
評(píng)論