VC MFC 串口通信(多線程)
現在一般用VC寫串口通信,大多數人會採取下面的三種方式:
一.直接利用VC 裏面的MSComm類進行編程。
二.網上也有一個比較好的類,大多數人也喜歡採用SerialPort(此類其實也比較好用)
三.應用API函數進行串口編程。
以上三種方式編程,我都用過的。。。(當然都不是很深入)。其實前兩種用起來比較簡單一點。就是對串口初始化,在調用MSComm(SerialPort)的函數就可以了。我只是簡單的看過上面兩個類的定義,其中也有線程的使用。(但是在我使用的時候,我是通過串口接收一副圖像,但有時候界面會出現卡死的情況,到此論壇上求助,有人告訴我要創建一個線程,,,這裏我到現在都不是很瞭解,因爲我覺得本來就是一個線程吧!
爲什麼還要創建了。。)於是就學應用API函數進行編程了。
API 函數:API(Application
Programming Interface,應用編程接口)其實就是操作系統留給應用程序的一個調用接口,應用程序通過調用操作系統的
API 而使操作系統去執行應用程序的命令(只要是在windows環境下編程都可以調用API函數)
利用API函數進行串口編程的步驟:
(1)打開串口:CreatFile()函數
m_hcom=CreateFile(
"COM1",//COM1口
GENERIC_READ|GENERIC_WRITE, //允許讀和寫
0, //獨佔方式
NULL,
OPEN_EXISTING, //打開
FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED, //重疊方式
NULL
);
創建一個關於串口的句柄
(2)創建串口通信事件:CreatEvent()函數
這裏涉及到了一個重要的結構體OVERLAPPED:OVERLAPPED是一個包含了用於異步輸入輸出的信息的結構體,在這個結構體中最重要的一個成員爲hEvent,線程利用CreatEvent函數爲hEvent創建一個手工重置事,hEvent將作爲線程的同步對象使用,初始化的hEvent爲有信號的,當讀寫事件完成操作之後,hEvent會變爲有信號。對這一結構,請看這裏http://blog.csdn.net/pofenglangguayunfan/article/month/2013/10。
(3)串口的初始化,設置串口參數
/********************輸入緩衝區和輸出緩衝區的大小***********/
SetupComm(m_hcom,1024,1024);
/*********************超時結構(讀一次緩衝區就返回)****************************/
COMMTIMEOUTS TimeOuts;
TimeOuts.ReadIntervalTimeout=MAXDWORD;//兩個字節之間的間隔時間
TimeOuts.ReadTotalTimeoutMultiplier=0;//讀時間係數
TimeOuts.ReadTotalTimeoutConstant=0;//讀時間常數
TimeOuts.WriteTotalTimeoutMultiplier=100;//設定寫超時
TimeOuts.WriteTotalTimeoutConstant=500;
SetCommTimeouts(m_hcom,&TimeOuts);
/******************串口參數的配置*******************/
DCB dcb;
GetCommState(m_hcom,&dcb);//獲得參數
dcb.BaudRate=4800;
dcb.ByteSize=8;//每個字節8位
dcb.Parity=NOPARITY;//無奇偶檢驗
dcb.StopBits=ONESTOPBIT;//兩個停止位
SetCommState(m_hcom,&dcb);
(4)建立讀數據的線程:
一般寫數據我們是可以控制的,但讀數據的時候,我們不知道數據什麼時候會到,所以要建立一個專門的線程,其中用到的函數有:WaitCommEvent,ClearCommError,WaitForSingleObject,ReadFile
OVERLAPPED os;//異狀態步輸入/輸出的
COMSTAT comStat;//通信設備控制塊
os.hEvent=NULL;
os.hEvent=CreateEvent(NULL, TRUE, FALSE, NULL);
os.Offset=0;
os.OffsetHigh=0;
m_osRead.hEvent=CreateEvent(NULL, TRUE, FALSE, NULL);
char czReceiveBuffer[100];
DWORD dErrInformation;
memset(czReceiveBuffer,0,sizeof(czReceiveBuffer));
SetCommMask(m_hcom, EV_RXCHAR);//
/*if(os.hEvent=NULL)
{
AfxMessageBox("無法創建事件對象!");
return (UINT)-1;
}*/
/****************** 在通信之前清除掉錯誤信息**************/
if(m_hcom!=NULL)
{
ClearCommError(m_hcom,&dErrInformation,&comStat);
}
while(TRUE)
{
DWORD wEven;
INT bResult=WaitCommEvent(m_hcom,&wEven,&os);
//DWORD BytesRead;
if(!bResult)
{
switch(GetLastError())
{
case ERROR_IO_PENDING:
break;
case 87:
break;
default:
break;
}
}
else
{
ClearCommError(m_hcom,&dErrInformation,&comStat);
if(comStat.cbInQue==0)
{
continue;
}
}
INT nEvent=WaitForSingleObject(os.hEvent,INFINITE);
if(nEvent==WAIT_OBJECT_0)
{
DWORD CommEvent=0;
GetCommMask(m_hcom,&CommEvent);
if(CommEvent&EV_RXCHAR==EV_RXCHAR)//輸入緩衝區接收到新字符
{
BOOL bread=TRUE;
BOOL bresult=TRUE;
DWORD deError=0;
DWORD BytesRead=0;
/////////////////////
COMSTAT comstat;
for(;;)
{
DWORD dRBufferSize=100;
INT bResult=ClearCommError(m_hcom,&deError,&comstat);//成功返回值非0
if(comstat.cbInQue==0)
{
break;
}
if(bread)
{
strRec="";
bresult=ReadFile(m_hcom,czReceiveBuffer,100,&dRBufferSize,&m_osRead);
if(!bresult)
{
switch(deError=GetLastError())
{
case ERROR_IO_PENDING:
{
bread=FALSE;
break;
}
default:
{
break;
}
}
}
else
{
bread=TRUE;
}
}
if(!bread)
{
bread=TRUE;
bresult=GetOverlappedResult
(
m_hcom,
&os,
&BytesRead,
TRUE
);
if(!bresult)
{
}
}
PurgeComm(m_hcom, PURGE_TXABORT|PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR);
for(DWORD k=0;k<dRBufferSize;k++)
{
strRec+=czReceiveBuffer[k];
}
::PostMessage(m_hVieWnd,WM_RECEDATA,(unsigned int)czReceiveBuffer,dRBufferSize);
}
}
}
if(nEvent!=WAIT_OBJECT_0)
{
GetLastError();
}
}
return TRUE;
(5)寫數據:用WriteFile()函數
OVERLAPPED m_osWriter;
memset(&m_osWriter,0,sizeof(OVERLAPPED));
m_osWriter.hEvent=CreateEvent(NULL,TRUE,FALSE,NULL);
UpdateData(true);
// m_strSend += "/n";
COMSTAT ComStat;
DWORD dwErrorFlags;
BOOL bWriterStat;
DWORD dwBytesWrite=0;
ClearCommError(m_hcom,&dwErrorFlags,&ComStat);
bWriterStat = WriteFile(m_hcom,m_strSend,m_strSend.GetLength(),
&dwBytesWrite,&m_osWriter
);
if(!bWriterStat)
{
if(GetLastError()==ERROR_IO_PENDING)
{
WaitForSingleObject(m_osWriter.hEvent,1000);
}
}
(6)
終止線程CloseHandle();