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;
}
...全文
509 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;
}
内容概要:本文围绕基于电感电容电流环PI与前馈补偿矩阵构造的跟网型储能变流器,开展dq坐标系下的阻抗理论建模与Simulink仿真对比研究。通过建立储能变流器在dq域的数学模型,设计包含电感电流内环、电容电流中间环和电压外环的多环控制结构,并引入前馈补偿矩阵以提升系统的动态响应能力和稳定性。在此基础上,采用小信号分析法推导系统的输出阻抗模型,构建完整的dq域阻抗理论框架,并利用Simulink平台搭建高保真仿真模型进行频域扫频验证,实现理论建模与仿真结果的精确对比,深入分析控制参数对系统阻抗特性的影响规律,揭示其在抑制并网系统振荡、提升稳定性方面的关键作用,为新能源并网系统的稳定性分析与优化设计提供坚实的理论支撑和技术路径。; 适合人群:具备电力电子、自动控制理论基础,从事新能源发电、储能系统、微电网或电力系统稳定性研究的研究生、科研人员及工程技术人员。; 使用场景及目标:①掌握跟网型储能变流器在dq域的阻抗建模方法;②理解多环控制与前馈补偿对系统阻抗特性的影响机制;③实现理论阻抗模型与Simulink仿真扫频结果的对比验证,支撑并网稳定性分析。; 阅读建议:学习者应结合控制理论与电力电子变换器知识,重点关注数学推导与仿真建模的一致性,建议动手复现Simulink仿真模型并进行参数敏感性分析,以深化对阻抗重塑机理的理解。
内容概要:本文介绍了基于Matlab实现的基本雷达与干扰机仿真系统,旨在通过代码实践帮助读者深入理解雷达系统的工作原理及其在复杂电磁环境中与干扰机的相互作用机制。内容涵盖雷达信号的发射、传播、目标回波接收、微多普勒效应建模、干扰信号的生成与影响分析等关键环节,结合具体的Matlab代码实现了完整的仿真流程,并提供了详尽的结果可视化与性能评估,重点展示了目标探测、时频特征提取、干扰抑制策略等关键技术的实现方法,有助于掌握雷达系统动态特性与抗干扰能力的分析手段。; 适合人群:具备一定Matlab编程基础,对雷达系统、信号处理、电子对抗或通信工程等领域感兴趣的高校学生、科研人员及工程技术人员。; 使用场景及目标:①学习雷达系统的基本构成与工作流程;②掌握雷达回波信号与典型干扰信号(如噪声干扰、欺骗干扰)的数学建模方法;③通过Matlab仿真深入理解微多普勒特征、时频分析技术(如STFT、小波变换)及干扰抑制算法;④为开展雷达目标识别、抗干扰算法设计或电子战系统仿真等前沿研究奠定实践基础。; 阅读建议:建议读者结合提供的Matlab代码逐段运行并调试,重点关注雷达信号模型、目标运动建模、干扰生成模块及信号处理流程,配合文中仿真结果进行对比分析;同时可延伸学习现代信号处理技术如压缩感知、机器学习在雷达中的应用,以提升综合科研与工程实践能力。
基于星形耦合自均流机制的双三相LLC变换器变频调压与多模式切换控制策略研究(Simulink仿真实现)内容概要:本文研究了一种基于星形耦合自均流机制的双三相LLC变换器,重点探讨其变频调压与多模式切换控制策略,并通过Simulink进行仿真实现。该研究旨在解决双三相LLC变换器在不同工作模式下电流不均衡、电压调节不稳定等问题,通过引入星形耦合结构实现自动均流,提升系统效率与可靠性。文中详细分析了变频控制对谐振变换器输出电压的调节机理,设计了多模式平滑切换策略以适应负载变化,确保系统在轻载、重载及瞬态工况下的高效稳定运行。同时,建立了完整的Simulink仿真模型,验证了所提控制策略在动态响应、稳态精度和抗干扰能力方面的优越性。; 适合人群:从事电力电子与电力传动、新能源变换技术及相关领域研究的研究生、科研人员及工程技术人员。; 使用场景及目标:①用于高效率、高可靠性的直流电源系统设计,如电动汽车充电、数据中心供电等;②为多相LLC谐振变换器的均流控制与模式切换提供理论支持和技术方案;③适用于需要高性能电源变换器的工业应用场景,推动先进控制策略在实际系统中的落地应用。; 阅读建议:读者应具备一定的电力电子电路与控制系统基础知识,建议结合Simulink仿真模型同步学习,深入理解控制逻辑的设计细节与参数整定方法,并可通过修改仿真参数验证不同工况下的系统性能,以增强实践理解和创新能力。
内容概要:WiFiSupply斯普莱WFS7000-52AX5是一款高性能、高负载型工业级双射频无线AP基站,支持2.4G和5.8G双频段WiFi6(802.11ax)标准,采用OFDMA、MIMO 4T4R架构及射频合路技术,实现最大1974Mbps的双频合并带宽。设备具备29dBm高发射功率、-96dBm高接收灵敏度,支持Fast Roaming快速漫游(切换延迟≤30ms)、多链路聚合、主备链路备份、巨量安全隧道等核心技术,保障低延迟、零丢包的稳定通信。配备5个千兆网口(含1个2.5G口)、支持POE/DC/端子多种供电方式,具备IP54防护、-45~85℃宽温运行、防浪涌防静电等工业级设计,适用于复杂恶劣环境。支持胖瘦一体模式、云端/本地/图形化多方式管理,并提供API接口便于第三方平台集成。; 适合人群:工业自动化、智能制造、智慧物流等领域中从事无线网络部署与运维的工程师和技术人员,具备基本网络知识和工业通信需求的专业用户。; 使用场景及目标:①用于AMR/AGV/RGV小车、无人叉车、穿梭车、天车、堆垛机等移动设备的无线联网;②满足无人机遥控、车载、船载、火车视频传输、分拣机PLC控制等高移动性、高可靠性场景的无线桥接与覆盖需求;③实现工业4.0环境下大规模终端接入、无缝漫游、安全传输的无线网络建设。; 阅读建议:本文档技术参数详尽,建议结合实际部署场景重点关注设备的射频性能、漫游切换、供电安装方式及管理功能,以便充分发挥其在高负载、强干扰工业环境下的优势。

16,550

社区成员

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

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

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