WaitaCommEvent,GetOverlappedResult,SetCommMask、GetCommMask

雪蚊子 2014-09-24 02:08:36
最近在搞COM串口,使用的是 在网上找到的一个CSerialPort类,Win7,VS2008,
在弄的过程中主要遇到了一个问题,在通讯过程中断,最后研究发现,是因为当接收到数据后,在触发IO事件的时候,不准确,和不及时所致。具体的原因,不知道是自己代码的问题,还是本事COM处理机制的问题?

下面说一个显现,当运行到下面这个线程函数里时,会阻塞到GetOverlappedResult(port->m_hComm,&port->m_overlapped,&ComEvent,true);,代码里也已经标红,这时候我没有任何关于串口的操作,但是接收单数据后,这个阻塞函数,就不会在阻塞,而ComEvent的返回值为4,这里等待的是WaitCommEvent的结果,4表示EV_TXEMPTY,The last character in the output buffer was sent.(输出缓冲区的数据全部发送出去),这里的问题就是我还没有发送过任何数据,为什么返回的是4,按照我的想法应该返回1,即为EV_RXCHAR,A character was received and placed in the input buffer.(输入缓冲区不为空),我去接收数据的
当然关于这段代码还有好多想不通的地方,求好心人解答~!


以下代码,不是原有的CSerialPort类的代码,自己有改动。




UINT CSerialPort::CommThread(LPVOID pParam)
{
CSerialPort *port = (CSerialPort*)pParam;
port->m_bThreadAlive = TRUE;
DWORD BytesTransfered = 0;
DWORD MultipleEvent = 0;
DWORD dwError = 0;
COMSTAT comstat;
memset(&comstat, 0 , sizeof(COMSTAT));
BOOL bResult = TRUE;
DWORD couts = 0;
// Clear comm buffers at startup 清空缓冲区
if (port->m_hComm) // check if the port is opened
PurgeComm(port->m_hComm, PURGE_RXCLEAR | PURGE_TXCLEAR | PURGE_RXABORT | PURGE_TXABORT);
// begin forever loop. This loop will run as long as the thread is alive.
for (;;)
{
ResetEvent(port->m_overlapped.hEvent);
//成功返回非0值,否则返回0
//如果异步操作不能马上完成,那么该函数会返回一个FALSE,同时GetLastError函数可以截获错误码ERROR_IO_PENDING(#define ERROR_IO_PENDING 997),表示操作转到后台运行。在WaitCommEvent函数返回之前,系统将OVERLAPPED结构中的hEven句柄设置为无信号状态;当WaitCommEvent函数所等待的任何一个Event发生后,系统将OVERLAPPED结构中的hEven句柄设置为有信号状态,同时将所发生事件赋给lpEvtMask。
DWORD ComEvent = 0;
couts++;
bResult = WaitCommEvent(port->m_hComm, &ComEvent, &port->m_overlapped);
//调用失败
if (!bResult)
{
dwError = GetLastError();
switch (dwError)
{
case ERROR_IO_PENDING:
{
GetOverlappedResult(port->m_hComm,&port->m_overlapped,&ComEvent,true);
break;
}
case 87:
{
break;
}
default:
{
port->ProcessErrorMessage(_T("WaitCommEvent()"));
break;
}
}
}
else
{
bResult = ClearCommError(port->m_hComm, &dwError, &comstat);
if (comstat.cbInQue == 0)
continue;
}
DWORD ThreadID = GetCurrentThreadId();//获取当前线程ID
TRACE("%s:Com Thread %04x 运行第 %d 次~!\n",_GetTime(),ThreadID,couts);
MultipleEvent = WaitForMultipleObjects(3, port->m_hEventArray, FALSE, INFINITE);
TRACE("%s:WaitForMultipleObjects 返回值为:%d~!\n",_GetTime(),MultipleEvent);
switch (MultipleEvent)
{
//结束线程
case 0:
{
port->m_bThreadAlive = FALSE;
::PostMessage(port->m_pOwner->m_hWnd,MY_COMM_KILLPORTTHREAD,(WPARAM)0,(LPARAM)0);
TRACE("%s:Com Thread %04x is ended by Event\n",_GetTime(),ThreadID);
AfxEndThread(100);
break;
}
case 1:
{
DWORD CommEvent = 0;
GetCommMask(port->m_hComm, &CommEvent);
if (CommEvent & EV_RXCHAR)
{
// Receive character event from port.
TRACE("%s:接收数据处理,GetCommMask:%d,GetWaitCommEvent: %d ~!\n",
_GetTime(),
CommEvent,
ComEvent);
LONG Thread_Prio = GetThreadPriority(port->m_Thread->m_hThread);
if (Thread_Prio != THREAD_PRIORITY_ERROR_RETURN)
{
SetThreadPriority(port->m_Thread->m_hThread,THREAD_PRIORITY_HIGHEST);
}
port->ReceiveChar(port);
SetThreadPriority(port->m_Thread->m_hThread,Thread_Prio);
}
else
{
TRACE("%s:异常结束,GetCommMask:%d,GetWaitCommEvent: %d ~!\n",
_GetTime(),
CommEvent,
ComEvent);
}
break;
}
case 2:
{
CWinThread* m_WriteThread;
if (!(m_WriteThread = AfxBeginThread(WriteCharThread, port)))
{
TRACE("%s:WriteCharThread 启动失败,原因:%s ~!\n",
_GetTime(),
_GetErrorCodeCause(GetLastError()));
break;
}
ResetEvent(port->m_hWriteEvent);
TRACE("%s:WriteThread %04x started\n",_GetTime(),m_WriteThread->m_nThreadID);
break;
}
}
}
return 111;
}
...全文
285 1 打赏 收藏 转发到动态 举报
写回复
用AI写文章
1 条回复
切换为时间正序
请发表友善的回复…
发表回复
雪蚊子 2014-09-24
  • 打赏
  • 举报
回复
自己先顶个,再加一段COM初始化和设置的代码。 另外在这在体格问题,上面说的问题其实主要是WaitCommEvent(),和WaitForMultipleObjects(),而这两个函数等待的事件和返回值就决定了,线程的执行方向。 现在LZ最不明白的是WaitCommEvent()这个函数,有么有人用过这个,他等待的事件是否可以设置,根据自己查阅的资料SetCommMask可以设置,但是自己只设置EV_RXCHAR,但是WaitCommEvent()还会返回其他的值,不知道上面原因。 设置的代码在下面。
BOOL CSerialPort::InitPort(CWnd* pPortOwner,	// the owner (CWnd) of the port (receives message)
						   UINT  portnr,		// portnumber (1..4)
						   UINT  baud,			// baudrate
						   TCHAR parity,		// parity 
						   UINT  databits,		// databits 
						   UINT  stopbits,		// stopbits 
						   DWORD dwCommEvents,	// EV_RXCHAR, EV_CTS etc
						   UINT  writebuffersize)	// size to the writebuffer
{
	//assert(portnr > 0 && portnr < 5);
	assert(pPortOwner != NULL);

	// if the thread is alive: Kill
	//KillPortThread();
	if (m_bThreadAlive)
	{
		do
		{
			if (SetEvent(m_hShutdownEvent))
			{
				TRACE("%s:ShutdownEvent ComThread by InitPort!\n",_GetTime());
			}
		} 
		while (m_bThreadAlive);
		TRACE("%s:Thread ended int InitPort!\n",_GetTime());
	}

	// create events
	if (m_overlapped.hEvent != NULL)
		ResetEvent(m_overlapped.hEvent);
	m_overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);

	if (m_hWriteEvent != NULL)
		ResetEvent(m_hWriteEvent);
	m_hWriteEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
	
	if (m_hShutdownEvent != NULL)
		ResetEvent(m_hShutdownEvent);
	m_hShutdownEvent = CreateEvent(NULL, TRUE, FALSE, NULL);

	// initialize the event objects
	m_hEventArray[0] = m_hShutdownEvent;	// 串口关闭事件,自己控制触发
	m_hEventArray[1] = m_overlapped.hEvent;	// 串口接收到数据事件,由串口驱动触发
	m_hEventArray[2] = m_hWriteEvent;		// 串口写数据事件,自己控制触发

	// initialize critical section
	InitializeCriticalSection(&m_csCommunicationSync);//临界区初始化
	
	// set buffersize for writing and save the owner
	//m_pOwner = dynamic_cast<CMainFrame*>(pPortOwner); 
	m_pOwner = pPortOwner; 
	m_nPortNr = portnr;

	m_nWriteBufferSize = writebuffersize;
	m_dwCommEvents = dwCommEvents;

	BOOL bResult = FALSE;
	TCHAR* szPort = new TCHAR[50];
	TCHAR* szBaud = new TCHAR[50];

	// now it critical!
	EnterCriticalSection(&m_csCommunicationSync);

	// if the port is already opened: close it
	if (m_hComm != NULL)
	{
		CloseHandle(m_hComm);
		m_hComm = NULL;
	}

	// prepare port strings
	wsprintf(szPort, _T("COM%d"), portnr);
	//sprintf(szBaud, "baud=%d parity=%c data=%d stop=%d", baud, parity, databits, stopbits);
	wsprintf(szBaud, _T("baud=%d parity=%c data=%d stop=%d"), baud, parity, databits, stopbits);

	// get a handle to the port
	m_hComm = CreateFile(szPort,				// communication port string (COMX)													//modify by leo
					     GENERIC_READ|GENERIC_WRITE,	// read/write types
					     0,								// comm devices must be opened with exclusive access
					     NULL,							// no security attributes
					     OPEN_EXISTING,					// comm devices must use OPEN_EXISTING
						 FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED,// Async I/O
					     0);			// template must be 0 for comm devices

	if (m_hComm == INVALID_HANDLE_VALUE)
	{
		//DWORD nErrer =  GetLastError();
		TRACE("%s:CreateFile Com%d Error ,%s~\n",_GetTime(),m_nPortNr,_GetErrorCodeCause(GetLastError()));
		// port not found
		delete [] szPort;
		delete [] szBaud;
		return FALSE;
	}

	// set the timeout values
	m_CommTimeouts.ReadIntervalTimeout = -1;
	m_CommTimeouts.ReadTotalTimeoutMultiplier = 0;
	m_CommTimeouts.ReadTotalTimeoutConstant = 1000;
	m_CommTimeouts.WriteTotalTimeoutMultiplier = 0;
	m_CommTimeouts.WriteTotalTimeoutConstant = 1000;
	
	SetupComm(m_hComm,4096,2048);
	// configure
	if (SetCommTimeouts(m_hComm, &m_CommTimeouts))
	{						   
		//if (SetCommMask(m_hComm, dwCommEvents))EV_RXCHAR
		if (SetCommMask(m_hComm, EV_RXCHAR))
		{
			if (GetCommState(m_hComm, &m_dcb))
			{
				m_dcb.EofChar = 89;
				m_dcb.ErrorChar = 88;
				m_dcb.EvtChar = 89;
				//m_dcb.EvtChar = 30;
				m_dcb.XonChar = 89;
				m_dcb.XoffChar =89;

				m_dcb.fRtsControl = RTS_CONTROL_DISABLE;
				m_dcb.fDtrControl = DTR_CONTROL_DISABLE;
				m_dcb.fDsrSensitivity = FALSE;
				m_dcb.XonLim = 2048;
				m_dcb.XoffLim = 512;

				if (BuildCommDCB(szBaud, &m_dcb))           
				{
					if (SetCommState(m_hComm, &m_dcb))
						; // normal operation... continue
					else
						ProcessErrorMessage(_T("SetCommState()"));
				}
				else
					ProcessErrorMessage(_T("BuildCommDCB()"));
			}
			else
				ProcessErrorMessage(_T("GetCommState()"));
		}
		else
			ProcessErrorMessage(_T("SetCommMask()"));
	}
	else
		ProcessErrorMessage(_T("SetCommTimeouts()"));

	delete [] szPort;
	delete [] szBaud;
	// flush the port
	//PurgeComm(m_hComm, PURGE_RXCLEAR | PURGE_TXCLEAR | PURGE_RXABORT | PURGE_TXABORT);
	// release critical section
	LeaveCriticalSection(&m_csCommunicationSync);
	TRACE("%s:Initialisation for communicationport %d completed.\nUse Startmonitor to communicate.\n", _GetTime(),portnr);
	return TRUE;
}

16,471

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC相关问题讨论
社区管理员
  • 基础类社区
  • Web++
  • encoderlee
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

        VC/MFC社区版块或许是CSDN最“古老”的版块了,记忆之中,与CSDN的年龄几乎差不多。随着时间的推移,MFC技术渐渐的偏离了开发主流,若干年之后的今天,当我们面对着微软的这个经典之笔,内心充满着敬意,那些曾经的记忆,可以说代表着二十年前曾经的辉煌……
        向经典致敬,或许是老一代程序员内心里面难以释怀的感受。互联网大行其道的今天,我们期待着MFC技术能够恢复其曾经的辉煌,或许这个期待会永远成为一种“梦想”,或许一切皆有可能……
        我们希望这个版块可以很好的适配Web时代,期待更好的互联网技术能够使得MFC技术框架得以重现活力,……

试试用AI创作助手写篇文章吧