3、讀寫串口
我們使用ReadFile和WriteFile讀寫串口,下面是兩個函數(shù)的聲明:
BOOL ReadFile( HANDLE hFile, //串口的句柄
// 讀入的數(shù)據(jù)存儲的地址,
// 即讀入的數(shù)據(jù)將存儲在以該指針的值為首地址的一片內(nèi)存區(qū)
LPVOID lpBuffer,
// 要讀入的數(shù)據(jù)的字節(jié)數(shù)
DWORD nNumberOfBytesToRead,
// 指向一個DWORD數(shù)值,該數(shù)值返回讀操作實際讀入的字節(jié)數(shù)
LPDWORD lpNumberOfBytesRead,
// 重疊操作時,該參數(shù)指向一個OVERLAPPED結(jié)構(gòu),同步操作時,該參數(shù)為NULL。
LPOVERLAPPED lpOverlapped );
BOOL WriteFile( HANDLE hFile, //串口的句柄
// 寫入的數(shù)據(jù)存儲的地址,
// 即以該指針的值為首地址的
LPCVOID lpBuffer,
//要寫入的數(shù)據(jù)的字節(jié)數(shù)
DWORD nNumberOfBytesToWrite,
// 指向指向一個DWORD數(shù)值,該數(shù)值返回實際寫入的字節(jié)數(shù)
LPDWORD lpNumberOfBytesWritten,
// 重疊操作時,該參數(shù)指向一個OVERLAPPED結(jié)構(gòu),
// 同步操作時,該參數(shù)為NULL。
LPOVERLAPPED lpOverlapped );
在用ReadFile和WriteFile讀寫串口時,既可以同步執(zhí)行,也可以重疊執(zhí)行。在同步執(zhí)行時,函數(shù)直到操作完成后才返回。這意味著同步執(zhí)行時線程會被阻塞,從而導致效率下降。在重疊執(zhí)行時,即使操作還未完成,這兩個函數(shù)也會立即返回,費時的I/O操作在后臺進行。
ReadFile和WriteFile函數(shù)是同步還是異步由CreateFile函數(shù)決定,如果在調(diào)用CreateFile創(chuàng)建句柄時指定了FILE_FLAG_OVERLAPPED標志,那么調(diào)用ReadFile和WriteFile對該句柄進行的操作就應(yīng)該是重疊的;如果未指定重疊標志,則讀寫操作應(yīng)該是同步的。ReadFile和WriteFile函數(shù)的同步或者異步應(yīng)該和CreateFile函數(shù)相一致。
ReadFile函數(shù)只要在串口輸入緩沖區(qū)中讀入指定數(shù)量的字符,就算完成操作。而WriteFile函數(shù)不但要把指定數(shù)量的字符拷入到輸出緩沖區(qū),而且要等這些字符從串行口送出去后才算完成操作。
如果操作成功,這兩個函數(shù)都返回TRUE。需要注意的是,當ReadFile和WriteFile返回FALSE時,不一定就是操作失敗,線程應(yīng)該調(diào)用GetLastError函數(shù)分析返回的結(jié)果。例如,在重疊操作時如果操作還未完成函數(shù)就返回,那么函數(shù)就返回FALSE,而且GetLastError函數(shù)返回ERROR_IO_PENDING。這說明重疊操作還未完成。
同步方式讀寫串口比較簡單,下面先例舉同步方式讀寫串口的代碼:
//同步讀串口
char str[100];
DWORD wCount;//讀取的字節(jié)數(shù)
BOOL bReadStat;
bReadStat=ReadFile(hCom,str,100,&wCount,NULL);
if(!bReadStat) { AfxMessageBox(“讀串口失??!”); return FALSE; } return TRUE; //同步寫串口
char lpOutBuffer[100];
DWORD dwBytesWrite=100;
COMSTAT ComStat;
DWORD dwErrorFlags;
BOOL bWriteStat;
ClearCommError(hCom,&dwErrorFlags,&ComStat);
bWriteStat=WriteFile(hCom,lpOutBuffer,dwBytesWrite,& dwBytesWrite,NULL);
if(!bWriteStat) { AfxMessageBox(“寫串口失??!”); }
PurgeComm(hCom, PURGE_TXABORT| PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR);
在重疊操作時,操作還未完成函數(shù)就返回。
重疊I/O非常靈活,它也可以實現(xiàn)阻塞(例如我們可以設(shè)置一定要讀取到一個數(shù)據(jù)才能進行到下一步操作)。有兩種方法可以等待操作完成:一種方法是用象WaitForSingleObject這樣的等待函數(shù)來等待OVERLAPPED結(jié)構(gòu)的hEvent成員;另一種方法是調(diào)用GetOverlappedResult函數(shù)等待,后面將演示說明。
下面我們先簡單說一下OVERLAPPED結(jié)構(gòu)和GetOverlappedResult函數(shù):
OVERLAPPED結(jié)構(gòu)
OVERLAPPED結(jié)構(gòu)包含了重疊I/O的一些信息,定義如下:
typedef struct _OVERLAPPED { // o
DWORD Internal;
DWORD InternalHigh;
DWORD Offset;
DWORD OffsetHigh;
HANDLE hEvent;
} OVERLAPPED;
在使用ReadFile和WriteFile重疊操作時,線程需要創(chuàng)建OVERLAPPED結(jié)構(gòu)以供這兩個函數(shù)使用。線程通過OVERLAPPED結(jié)構(gòu)獲得當前的操作狀態(tài),該結(jié)構(gòu)最重要的成員是hEvent。hEvent是讀寫事件。當串口使用異步通訊時,函數(shù)返回時操作可能還沒有完成,程序可以通過檢查該事件得知是否讀寫完畢。
當調(diào)用ReadFile, WriteFile 函數(shù)的時候,該成員會自動被置為無信號狀態(tài);當重疊操作完成后,該成員變量會自動被置為有信號狀態(tài)。
GetOverlappedResult函數(shù) BOOL GetOverlappedResult( HANDLE hFile, // 串口的句柄 // 指向重疊操作開始時指定的OVERLAPPED結(jié)構(gòu) LPOVERLAPPED lpOverlapped, // 指向一個32位變量,該變量的值返回實際讀寫操作傳輸?shù)淖止?jié)數(shù)。 LPDWORD lpNumberOfBytesTransferred, // 該參數(shù)用于指定函數(shù)是否一直等到重疊操作結(jié)束。 // 如果該參數(shù)為TRUE,函數(shù)直到操作結(jié)束才返回。 // 如果該參數(shù)為FALSE,函數(shù)直接返回,這時如果操作沒有完成, // 通過調(diào)用GetLastError()函數(shù)會返回ERROR_IO_INCOMPLETE。 BOOL bWait );
該函數(shù)返回重疊操作的結(jié)果,用來判斷異步操作是否完成,它是通過判斷OVERLAPPED結(jié)構(gòu)中的hEvent是否被置位來實現(xiàn)的。
異步讀串口的示例代碼:
char lpInBuffer[1024];
DWORD dwBytesRead=1024;
COMSTAT ComStat;
DWORD dwErrorFlags;
OVERLAPPED m_osRead;
memset(&m_osRead,0,sizeof(OVERLAPPED));
m_osRead.hEvent=CreateEvent(NULL,TRUE,F(xiàn)ALSE,NULL);
ClearCommError(hCom,&dwErrorFlags,&ComStat);
dwBytesRead=min(dwBytesRead,(DWORD)ComStat.cbInQue);
if(!dwBytesRead) return FALSE;
BOOL bReadStatus;
bReadStatus=ReadFile(hCom,lpInBuffer, dwBytesRead,&dwBytesRead,&m_osRead);
if(!bReadStatus)
//如果ReadFile函數(shù)返回FALSE
{
if(GetLastError()==ERROR_IO_PENDING)
//GetLastError()函數(shù)返回ERROR_IO_PENDING,表明串口正在進行讀操作
{
WaitForSingleObject(m_osRead.hEvent,2000);
//使用WaitForSingleObject函數(shù)等待,直到讀操作完成或延時已達到2秒鐘
//當串口讀操作進行完畢后,m_osRead的hEvent事件會變?yōu)橛行盘?/p>
PurgeComm(hCom, PURGE_TXABORT| PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR);
return dwBytesRead;
}
return 0;
}
PurgeComm(hCom, PURGE_TXABORT| PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR);
return dwBytesRead;
對以上代碼再作簡要說明:
在使用ReadFile 函數(shù)進行讀操作前,應(yīng)先使用ClearCommError函數(shù)清除錯誤。
ClearCommError函數(shù)的原型如下:
BOOL ClearCommError( HANDLE hFile, // 串口句柄
LPDWORD lpErrors, // 指向接收錯誤碼的變量
LPCOMSTAT lpStat // 指向通訊狀態(tài)緩沖區(qū) );
該函數(shù)獲得通信錯誤并報告串口的當前狀態(tài),同時,該函數(shù)清除串口的錯誤標志以便繼續(xù)輸入、輸出操作。
參數(shù)lpStat指向一個COMSTAT結(jié)構(gòu),該結(jié)構(gòu)返回串口狀態(tài)信息。
COMSTAT結(jié)構(gòu) COMSTAT結(jié)構(gòu)包含串口的信息,結(jié)構(gòu)定義如下:
typedef struct _COMSTAT { // cst DWORD fCtsHold : 1; // Tx waiting for CTS signal DWORD fDsrHold : 1; // Tx waiting for DSR signal DWORD fRlsdHold : 1; // Tx waiting for RLSD signal DWORD fXoffHold : 1; // Tx waiting, XOFF char rec‘’d DWORD fXoffSent : 1; // Tx waiting, XOFF char sent DWORD fEof : 1; // EOF character sent DWORD fTxim : 1; // character waiting for Tx DWORD fReserved : 25; // reserved DWORD cbInQue; // bytes in input buffer DWORD cbOutQue; // bytes in output buffer } COMSTAT, *LPCOMSTAT;
本文只用到了cbInQue成員變量,該成員變量的值代表輸入緩沖區(qū)的字節(jié)數(shù)。
最后用PurgeComm函數(shù)清空串口的輸入輸出緩沖區(qū)。
這段代碼用WaitForSingleObject函數(shù)來等待OVERLAPPED結(jié)構(gòu)的hEvent成員,下面我們再演示一段調(diào)用GetOverlappedResult函數(shù)等待的異步讀串口示例代碼:
char lpInBuffer[1024];
DWORD dwBytesRead=1024;
BOOL bReadStatus;
DWORD dwErrorFlags;
COMSTAT ComStat;
OVERLAPPED m_osRead;
ClearCommError(hCom,&dwErrorFlags,&ComStat);
if(!ComStat.cbInQue) return 0;
dwBytesRead=min(dwBytesRead,(DWORD)ComStat.cbInQue);
評論
查看更多