基本环境:
编程环境:VS2008 多字节编码
串口环境:手机AT命令 进行手机与pc通信 串口类是网上 下载的一个 CSerialPort类, 很多有关串口编程都有其源代码
相关代码:
//清除接受缓冲区 void ClearInputBuffer() { if(IsOpen()) ::PurgeComm(m_hComm, PURGE_RXABORT | PURGE_RXCLEAR ); } //清除发送缓冲区 void ClearOutputBuffer() { if(IsOpen()) ::PurgeComm(m_hComm, PURGE_TXABORT | PURGE_TXCLEAR ); }
void CSerialPort::SetTimeouts(COMMTIMEOUTS& timeouts) { ASSERT(IsOpen()); if (!SetCommTimeouts(m_hComm, &timeouts)) { TRACE(_T("Failed in call to SetCommTimeouts/n")); AfxThrowSerialException(); } } void CSerialPort::GetTimeouts(COMMTIMEOUTS& timeouts) { ASSERT(IsOpen()); if (!GetCommTimeouts(m_hComm, &timeouts)) { TRACE(_T("Failed in call to GetCommTimeouts/n")); AfxThrowSerialException(); } }
void CSerialPort::GetState(DCB& dcb) { ASSERT(IsOpen()); if (!GetCommState(m_hComm, &dcb)) { DWORD dwErr = GetLastError(); TRACE(_T("Failed in call to GetCommState/n")); AfxThrowSerialException(); } } void CSerialPort::SetState(DCB& dcb) { ASSERT(IsOpen()); if (!SetCommState(m_hComm, &dcb)) { DWORD dwErr = GetLastError(); TRACE(_T("Failed in call to SetCommState/n")); AfxThrowSerialException(); } }
BOOL Open(int nPort, DWORD dwBaud = 9600, Parity parity = NoParity, BYTE DataBits = 8, StopBits stopbits = OneStopBit, FlowControl fc = NoFlowControl, BOOL bOverlapped = FALSE) { //Validate our parameters ASSERT(nPort>0 && nPort<=255); //Call CreateFile to open up the comms port CString sPort; sPort.Format(_T("////.//COM%d"), nPort); m_hComm = CreateFile(sPort, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, bOverlapped ? FILE_FLAG_OVERLAPPED : 0, NULL); if (m_hComm == INVALID_HANDLE_VALUE) { TRACE(_T("Failed to open up the comms port/n")); return FALSE; } m_bOverlapped = bOverlapped; //Get the current state prior to changing it DCB dcb = {sizeof(DCB)}; GetState(dcb); //Setup the baud rate dcb.BaudRate = dwBaud; //Setup the Parity switch (parity) { case EvenParity: dcb.Parity = EVENPARITY; break; case MarkParity: dcb.Parity = MARKPARITY; break; case NoParity: dcb.Parity = NOPARITY; break; case OddParity: dcb.Parity = ODDPARITY; break; case SpaceParity: dcb.Parity = SPACEPARITY; break; default: ASSERT(FALSE); break; } //Setup the data bits dcb.ByteSize = DataBits; //Setup the stop bits switch (stopbits) { case OneStopBit: dcb.StopBits = ONESTOPBIT; break; case OnePointFiveStopBits: dcb.StopBits = ONE5STOPBITS; break; case TwoStopBits: dcb.StopBits = TWOSTOPBITS; break; default: ASSERT(FALSE); break; } //Setup the flow control dcb.fDsrSensitivity = FALSE; switch (fc) { case NoFlowControl: { dcb.fOutxCtsFlow = FALSE; dcb.fOutxDsrFlow = FALSE; dcb.fOutX = FALSE; dcb.fInX = FALSE; break; } case CtsRtsFlowControl: { dcb.fOutxCtsFlow = TRUE; dcb.fOutxDsrFlow = FALSE; dcb.fRtsControl = RTS_CONTROL_HANDSHAKE; dcb.fOutX = FALSE; dcb.fInX = FALSE; break; } case CtsDtrFlowControl: { dcb.fOutxCtsFlow = TRUE; dcb.fOutxDsrFlow = FALSE; dcb.fDtrControl = DTR_CONTROL_HANDSHAKE; dcb.fOutX = FALSE; dcb.fInX = FALSE; break; } case DsrRtsFlowControl: { dcb.fOutxCtsFlow = FALSE; dcb.fOutxDsrFlow = TRUE; dcb.fRtsControl = RTS_CONTROL_HANDSHAKE; dcb.fOutX = FALSE; dcb.fInX = FALSE; break; } case DsrDtrFlowControl: { dcb.fOutxCtsFlow = FALSE; dcb.fOutxDsrFlow = TRUE; dcb.fDtrControl = DTR_CONTROL_HANDSHAKE; dcb.fOutX = FALSE; dcb.fInX = FALSE; break; } case XonXoffFlowControl: { dcb.fOutxCtsFlow = FALSE; dcb.fOutxDsrFlow = FALSE; dcb.fOutX = TRUE; dcb.fInX = TRUE; dcb.XonChar = 0x11; dcb.XoffChar = 0x13; dcb.XoffLim = 100; dcb.XonLim = 100; break; } default: { ASSERT(FALSE); break; } } //标记2 //Now that we have all the settings in place, make the changes SetState(dcb); this->ClearInputBuffer(); this->ClearOutputBuffer(); DWORD dwErr; COMSTAT comstat; ClearCommError(this->m_hComm, &dwErr, &comstat); COMMTIMEOUTS time; this->GetTimeouts(time); //标记3 this->SetTimeouts(time); return TRUE; }
//测试函数 BOOL CSerialPort::SupportATCommand() { this->ClearInputBuffer(); this->ClearOutputBuffer(); CString command = _T("AT/r"); this->Write(command); CString result; result.Empty(); result = this->ReadExisting(); return result.Find(_T("OK")) >= 0; }
问题描述: 用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,这个错误消失了
这个问题就解决了。
不知道我这个分析的是否是正确的。。