描述:一個串口通訊類
應用平台:Windows
版本:v1.2
上次我做的“多線程,多接收模式串口類LsComm”,說實在的有不少的問題。好不容易有一段空閒的時間,把以前發現的Bugs修改了一下。
一、Bugs修正
1.ERR : 修改了98下 AutoReceiveBySignal 模式不能正常執行的bug
原因: CcomPort::m_WriteOverlapped.hEvent 沒有設置事件!!!!粗心,害人阿。導致在Win98下發送數據異常,不過奇怪在
Win2K正常,而且測試的時候忽略了測試環境平台的影響。
修改: 相應的代碼
if(this->IsOverlapped())
{
this->m_hWriteEvent= ::CreateEvent(NULL,true,false,NULL);
if(this->m_hCloseEvent==NULL) return false;
this->m_WriteOverlapped.hEvent = this->m_hWriteEvent;
}
2.ERR : 修改了 ManualReceiveByQuery 模式下,發送會出現不動的情況。
原因: 在dwWriteBytes= this->m_pPort->Write(pBuf,Count);
前,串口已經設置中斷,所以需要等待中斷事件發生。
修改: 去掉中斷設置的代碼 this->m_pPort->GetSerialPort()->SetMask(dwStoredFlags);
3.ERR : 打開一個計算機上不存在的串口的時候沒有異常捕獲。
原因: 沒有捕獲 CserialPort 拋出的 CserialException 異常
修改: 不過對於異常的處理改為不拋出異常,不知道是否妥當?
try
{
this->m_pPort->Open(nPort,dwBaud,spParity,DataBits,spStopbits,spFC,m_IsOverlapped);
}
catch(CSerialException* pE)
{
//AfxMessageBox(pE->GetErrorMessage());
pE->Delete();
return false;
}
4.ERR : 感覺 AutoReceiveByBreak 意義不大應該去掉
原因: 全部的事件都可以用AutoReceiveBySignal方式實現
修改: 暫時保留:DWORD dwStoredFlags = EV_BREAK | EV_CTS | EV_DSR | EV_ERR | EV_RING |EV_RLSD | EV_RXCHAR | EV_RXFLAG ;
//??| EV_TXEMPTY 添加後在首次執行時總是接收不到全部數據 ,以後就正常了。現在還搞不清楚是什麼原因。
5. ERR : 感覺 ManualReceiveByConst 意義不大應該去掉
原因: 實現方式不太好
修改: 暫時保留
二、遺留問題
1.ERR : 流控制模式下可能不正確,自己在這方面沒有經驗,沒有測試。
2.ERR : 結構問題,把 this->m_ComPort.GetSerialPort() 獲取 CserialPort 的指針好像不妥,如果類的使用者在程序中這樣用
this->m_ComPort.GetSerialPort()->Close();
收發數據的時候就會產生異常。但是由於使用別人的CserialPort類 ,比較
穩定,但有不能破壞別人代碼的完整性。
3.ERR : ManualReceiveByConst 方式受 CommTimeOUts 的影響可能不太准確。
其它問題:我的計算機上只有一個串口可用,所以是2-3口短接進行的測試,其它測試還不太完全。
三、由於前一段時間確實比較忙,有好多網友提出的問題,都沒有回復,實在非常抱歉,在這裡簡單的回復一下
1.風也飄飄:你好,我感覺這個類做的很好,但我想實現兩台電腦之間的實時數據傳輸(為字符型),不知道怎麼用,可否指點一二?
答: 感覺可以這樣寫: (1)首先:定義一個接收函數:
void OnReceiveData(LPVOID pSender,void* pBuf,DWORD InBufferCount)
{//在此處理要接收的數據
}
(2)然後,打開串口,監聽Com2this->m_ComPort.Open(2,LsComm::CComPort::AutoReceiveBySignal );
this->m_ComPort.SetReceiveFunc((FOnReceiveData)OnReceiveData,this);
(3)發送:char a[10000];//字符數組
BYTE b[10000];//字節數組
memset(a,''''a'''',sizeof(a));
memset(b,0x0b,sizeof(b));
this->m_ComPort.Output(a,sizeof(a)); //發送字符數組
this->m_ComPort.Output(b,sizeof(b)); //發送字節數組
感覺在C裡面是不分 char 和字節的,像 char c=’a’;和char c=0x61;是一樣的,只不過 char 只能取字符類型范圍,超過就被截短。
2. zkf00:中斷接收函數OnComBreak怎麼用? 答:試驗了一下
void OnComBreak(LPVOID pSender,DWORD dwMask,COMSTAT stat)
{
//deal with the break of com here
switch(dwMask)
{
case EV_BREAK:
{
break;
}
case EV_CTS: //在這裡處理CTS信號
{
break;
}
}
}
3. greatim:DataWaiting 是有什麼用的??在例子程序裡沒有引用到。而且在 Open 的函數裡,CreateEvent 被屏蔽了,是否代表 DataWaiting 這函數不能使用呢? DataWaiting 和 Attech 有什麼關系?
答:因為 DataWaiting 是 PJ Naughter 寫的,請仔細看他的源碼:
BOOL CSerialPort::DataWaiting(DWORD dwTimeout)
{
ASSERT(IsOpen());
ASSERT(m_hEvent);
//Setup to wait for incoming data
DWORD dwOldMask;
GetMask(dwOldMask);
SetMask(EV_RXCHAR);//1.設置接收中斷事件
//Setup the overlapped structure
OVERLAPPED o;
o.hEvent = m_hEvent;
//Assume the worst;
BOOL bSuccess = FALSE;
DWORD dwEvent;
bSuccess = WaitEvent(dwEvent, o);//2. 設置監聽
if (!bSuccess)
{//3.dwTimeOut為所等待的時間,有數據收到,返回發現數據
if (WaitForSingleObject(o.hEvent, dwTimeout) == WAIT_OBJECT_0)
{
DWORD dwBytesTransferred;
GetOverlappedResult(o, dwBytesTransferred, FALSE);
bSuccess = TRUE;
}
}
//Reset the event mask
SetMask(dwOldMask);
return bSuccess;
}
這好像與 Attach 沒什麼關系吧?
4. Sander:在win2000下能用no overlapped嗎?
答:查看了一下 MSDN 中 CreateFile 的說明,沒有在 Win2K 下的使用限制,應該是可以的。
5. Sander:當用 ExecuteByAutoSignalRecvMode,
BOOL bSuccess = ReadFile(m_hComm, lpBuf, dwCount, &dwBytesRead, &overlapped);
dwSignaledHandle=::WaitForMultipleObjects(3,WaitHandles,false,INFINITE);
或
this->m_pPort->GetSerialPort()->GetOverlappedResult(overlapped,this->m_InBufferCount,false)
這個兩個函數
WaitForMultipleObject
或
GetOverlappedResult)
它會以 COMMTIMEOUTS 中設置的 timeout 來返回嗎?也就是說 Overlapped 中的 Event 是在什麼時候激活的?
答:這個問題我以前沒有仔細考慮,真是不好意思。好像 COMMTIMEOUTS的TimeOut 僅對 ReadFile,WriteFile 起作用,具體可以看 MSDN 中 COMMTIMEOUTS 的描述。
WaitForSingleObject(m_ReadOverlapped.hEvent,dwMilliseconds)==WAIT_OBJECT_0)
會等待 m_ReadOverlapped.hEvent 事件置信號標志的時候返回。那麼讀取 時間什麼時候返回呢,找了下面的一段話:
When reading from a communications device, the behavior of ReadFile is governed by the current
communication time-outs as set and retrieved using the SetCommTimeouts and GetCommTimeouts
functions. Unpredictable results can occur if you fail to set the time-out values. For more
information about communication time-outs, see COMMTIMEOUTS.
可見 SetCommTimeouts 對這 ReadFile 起作用,也就是對 m_ReadOverlapped.hEvent 起作用。因此定時間接收模式在 COMMTIMEOUTS 時也會置讀事件的 hEvent,所以等待 時間的限制就有可能不太准確。
6. Hi_nihaoma:為什麼我使用重疊方式打開串口,根據示例:
for(int j= 0; j< 10; j++)
{
if (!port2.Write(pBuf, 10000, overlapped))
{
DWORD dwBytesWritten;
WaitForSingleObject(event, INFINITE);
port2.GetOverlappedResult(overlapped, dwBytesWritten, TRUE);
}
if (!port2.Read(pBuf, 10, overlapped))
{
DWORD dwBytesRead;
if (WaitForSingleObject(event,1000) == WAIT_OBJECT_0)
{
TRACE(_T("Data was read from the serial port\n"));
port2.GetOverlappedResult(overlapped,dwBytesRead,FALSE);
}
else
TRACE(_T("No data was read from the serial port\n"));
}
port2.SetMask(EV_TXEMPTY);
port2.WaitEvent(dwMask,overlapped);
}
port2.GetOverlappedResult(overlapped,dwBytesRead,FALSE);
dwByteRead= 4啊???急急急!!!
答:感覺可能是接收的問題,不能所有容納發送的全部數據,而引發異常吧。看你這行port2.Write(pBuf, 10000, overlapped);一次發送這麼大的數據量 ,是不是這的問題, 我的計算機上只有一個串口,把2,3口連接後收發數據測試了一下。一次發送超過100個就會發生讀地址錯誤,但是低於這個速率就沒問題。可能是接收的速度跟不上吧 。具體問題正在找。
結束語:
本來早就想要改一下,可實在是沒有時間,不是開玩笑,大概3個月沒有時間上網看看新聞了。寫程序,就是要認真仔細的面對自己寫的每一行代碼 ,不放過自己的每一個Bug。誰都希望自己的程序不出一個Bug,可這實在是說起來容易做起來難。希望大家看到Bugs要貼在下面,有時間我會努力改的。上面的一些問題自己的水平實在是太有限了 ,搞得還不是太清楚,希望如果誰知道,就告訴偶。有些問題就得擺出來,然後再一點點搞清楚才會有提高。如果只是默許的認為簡單,容易,不求甚解,相反會害了自己。
本文配套源碼