基本環境:
編程環境:VS2008 多位元組編碼
串口環境:手機AT命令 進行手機與pc通訊
串口類是網上 下載的一個 CSerialPort類, 很多有關串口編程都有其原始碼
相關代碼:
//清除接受緩衝區<br />void ClearInputBuffer()<br />{<br />if(IsOpen())<br />::PurgeComm(m_hComm, PURGE_RXABORT | PURGE_RXCLEAR );<br />}<br />//清除發送緩衝區<br />void ClearOutputBuffer()<br />{<br />if(IsOpen())<br />::PurgeComm(m_hComm, PURGE_TXABORT | PURGE_TXCLEAR );<br />}
void CSerialPort::SetTimeouts(COMMTIMEOUTS& timeouts)<br />{<br />ASSERT(IsOpen());<br />if (!SetCommTimeouts(m_hComm, &timeouts))<br />{<br />TRACE(_T("Failed in call to SetCommTimeouts/n"));<br />AfxThrowSerialException();<br />}<br />}<br />void CSerialPort::GetTimeouts(COMMTIMEOUTS& timeouts)<br />{<br />ASSERT(IsOpen());<br />if (!GetCommTimeouts(m_hComm, &timeouts))<br />{<br />TRACE(_T("Failed in call to GetCommTimeouts/n"));<br />AfxThrowSerialException();<br />}<br />}
void CSerialPort::GetState(DCB& dcb)<br />{<br />ASSERT(IsOpen());<br />if (!GetCommState(m_hComm, &dcb))<br />{<br />DWORD dwErr = GetLastError();<br />TRACE(_T("Failed in call to GetCommState/n"));<br />AfxThrowSerialException();<br />}<br />}<br />void CSerialPort::SetState(DCB& dcb)<br />{<br />ASSERT(IsOpen());<br />if (!SetCommState(m_hComm, &dcb))<br />{<br />DWORD dwErr = GetLastError();<br />TRACE(_T("Failed in call to SetCommState/n"));<br />AfxThrowSerialException();<br />}<br />}
BOOL Open(int nPort, DWORD dwBaud = 9600, Parity parity = NoParity, BYTE DataBits = 8,<br />StopBits stopbits = OneStopBit, FlowControl fc = NoFlowControl, BOOL bOverlapped = FALSE)<br />{<br />//Validate our parameters<br />ASSERT(nPort>0 && nPort<=255);<br />//Call CreateFile to open up the comms port<br />CString sPort;<br />sPort.Format(_T("////.//COM%d"), nPort);<br />m_hComm = CreateFile(sPort, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, bOverlapped ? FILE_FLAG_OVERLAPPED : 0, NULL);<br />if (m_hComm == INVALID_HANDLE_VALUE)<br />{<br />TRACE(_T("Failed to open up the comms port/n"));<br />return FALSE;<br />}<br />m_bOverlapped = bOverlapped;<br />//Get the current state prior to changing it<br />DCB dcb = {sizeof(DCB)};<br />GetState(dcb);<br />//Setup the baud rate<br />dcb.BaudRate = dwBaud;<br />//Setup the Parity<br />switch (parity)<br />{<br />case EvenParity: dcb.Parity = EVENPARITY; break;<br />case MarkParity: dcb.Parity = MARKPARITY; break;<br />case NoParity: dcb.Parity = NOPARITY; break;<br />case OddParity: dcb.Parity = ODDPARITY; break;<br />case SpaceParity: dcb.Parity = SPACEPARITY; break;<br />default: ASSERT(FALSE); break;<br />}<br />//Setup the data bits<br />dcb.ByteSize = DataBits;<br />//Setup the stop bits<br />switch (stopbits)<br />{<br />case OneStopBit: dcb.StopBits = ONESTOPBIT; break;<br />case OnePointFiveStopBits: dcb.StopBits = ONE5STOPBITS; break;<br />case TwoStopBits: dcb.StopBits = TWOSTOPBITS; break;<br />default: ASSERT(FALSE); break;<br />}<br />//Setup the flow control<br />dcb.fDsrSensitivity = FALSE;<br />switch (fc)<br />{<br />case NoFlowControl:<br />{<br />dcb.fOutxCtsFlow = FALSE;<br />dcb.fOutxDsrFlow = FALSE;<br />dcb.fOutX = FALSE;<br />dcb.fInX = FALSE;<br />break;<br />}<br />case CtsRtsFlowControl:<br />{<br />dcb.fOutxCtsFlow = TRUE;<br />dcb.fOutxDsrFlow = FALSE;<br />dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;<br />dcb.fOutX = FALSE;<br />dcb.fInX = FALSE;<br />break;<br />}<br />case CtsDtrFlowControl:<br />{<br />dcb.fOutxCtsFlow = TRUE;<br />dcb.fOutxDsrFlow = FALSE;<br />dcb.fDtrControl = DTR_CONTROL_HANDSHAKE;<br />dcb.fOutX = FALSE;<br />dcb.fInX = FALSE;<br />break;<br />}<br />case DsrRtsFlowControl:<br />{<br />dcb.fOutxCtsFlow = FALSE;<br />dcb.fOutxDsrFlow = TRUE;<br />dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;<br />dcb.fOutX = FALSE;<br />dcb.fInX = FALSE;<br />break;<br />}<br />case DsrDtrFlowControl:<br />{<br />dcb.fOutxCtsFlow = FALSE;<br />dcb.fOutxDsrFlow = TRUE;<br />dcb.fDtrControl = DTR_CONTROL_HANDSHAKE;<br />dcb.fOutX = FALSE;<br />dcb.fInX = FALSE;<br />break;<br />}<br />case XonXoffFlowControl:<br />{<br />dcb.fOutxCtsFlow = FALSE;<br />dcb.fOutxDsrFlow = FALSE;<br />dcb.fOutX = TRUE;<br />dcb.fInX = TRUE;<br />dcb.XonChar = 0x11;<br />dcb.XoffChar = 0x13;<br />dcb.XoffLim = 100;<br />dcb.XonLim = 100;<br />break;<br />}<br />default:<br />{<br />ASSERT(FALSE);<br />break;<br />}<br />}<br />//標記2<br />//Now that we have all the settings in place, make the changes<br />SetState(dcb);<br />this->ClearInputBuffer();<br />this->ClearOutputBuffer();<br />DWORD dwErr;<br />COMSTAT comstat;<br />ClearCommError(this->m_hComm, &dwErr, &comstat);<br />COMMTIMEOUTS time;<br />this->GetTimeouts(time);<br />//標記3<br />this->SetTimeouts(time);<br />return TRUE;<br />}
//測試函數<br />BOOL CSerialPort::SupportATCommand()<br />{<br />this->ClearInputBuffer();<br />this->ClearOutputBuffer();<br />CString command = _T("AT/r");<br />this->Write(command);<br />CString result;<br />result.Empty();<br />result = this->ReadExisting();<br />return result.Find(_T("OK")) >= 0;<br />}
問題描述:
用CSerialPort類進行串口通訊,出現這樣一個問題:
步驟1:當我開啟(或重啟)電腦並正確串連手機,
步驟2:運行自己的VC程式,正確開啟串口,調用測試函數,
現象1:程式運行在標記4位置處就運行不下去,永遠的停在這裡。
步驟3:當我用.NET 內建的類(SerialPort類)進行初始化的並且用.NET中的類進行串口通訊
現象2:正常的讀寫操作,可以發送命令,接收資料
重新執行步驟2, 出現現象2,現象1不出現,
多次執行步驟2,依然是出現現象2而不出現現象1.
執行步驟1,步驟2,出現現象1..........
這個奇怪的問題, 我發了個文章詢問了下:
文章連結地址:http://topic.csdn.net/u/20101109/22/bf1a0519-358e-4932-9321-8763071e56b4.html
根據網友的回答,我認為這個可能性很高導致出現這個問題:
原因大致是串口配置不正確,串口開啟後工作於最近起作用的配置,所以能正常工作。
因此我開始進行對串口配置參數進行跟蹤
首先是DCB 的參數:
如果執行步驟1,步驟2
在標記2處設下斷點後,dcb的資料只有 傳輸速率等參數
如果執行步驟3後,重新執行步驟2, dcb的資料多出以下的內容:
內容1:
dcb.fDtrControl = 1;
dcb.fErrorChar = 1;
dcb.fRtsControl = 1;
dcb.XonLim = 4096;
dcb.XoffLim = 4096;
dcb.XonChar = 0x11;
dcb.XoffChar = 0x13;
dcb.ErrorChar = 0x3F;
dcb.EofChar = 0x1A;
dcb.EvtChar = 0x1A;
因此可以設想,執行步驟1和步驟2,出現現象1肯定是這裡的參數忘記設定了
因此我把內容1的代碼添加到標記2位置處,
重新執行步驟1,步驟2, 依然出現錯誤
繼續考慮串口配置問題:
那現在就只剩下 time 這個參數了
同剛才找出dcb 參數之間差別一樣的辦法:
預設的是:
time.ReadIntervalTimeout = 0;
time.ReadTotalTimeoutMultiplier = 0;
time.ReadTotalTimeoutConstant = 0;
time.WriteTotalTimeoutMultiplier = 0;
time.WriteTotalTimeoutConstant = 0;
而正確的是:
內容2:
time.ReadIntervalTimeout = 4294967295;
time.ReadTotalTimeoutMultiplier = 4294967295;
time.ReadTotalTimeoutConstant = 100;//.net中設定 讀取逾時時間(串口開啟後工作於最近起作用的配置)
time.WriteTotalTimeoutMultiplier = 0;
time.WriteTotalTimeoutConstant = 2000;//.net中設定 寫入逾時時間
把內容2的代碼添加到標記3位置處,
重新執行步驟1,步驟2,這個錯誤消失了
這個問題就解決了。
不知道我這個分析的是否是正確的。。