⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 serial.cpp

📁 从串口读取数据
💻 CPP
📖 第 1 页 / 共 2 页
字号:
	//读取串口事件、退出线程信号
	HANDLE handle[2];
	handle[0] = pSerial->m_end_analysis_thread;
	handle[1] = pSerial->m_event_come_event;

	//保存WaitForMultipleObjects返回值
	DWORD dwRet;

	//用来判断之前是否有过字符消息,两个字符消息之间是否超时
	bool bHasMessageBefore		 = false;

	::WaitForSingleObject(pSerial->m_start_analysis_thread,INFINITE);

	TRACE("analysis event thread start!\n");

	SetEvent(pSerial->m_start_event_thread);//启动接收事件线程

	while(!bQuit)
	{
//		bHasMessageBefore=false;//在下边已经变为FALSE了
		dwRet=::WaitForMultipleObjects(2,handle,false,INFINITE);
		
		switch(dwRet-WAIT_OBJECT_0)
		{
		case 0://退出
			{
				bQuit=true;
			}
			continue;
		case 1://数据到来,进入下一级循环
			{
				TRACE0("一个数据包的第一个字符到达!\n");
				ResetEvent(handle[1]);
				if(!bHasMessageBefore)bHasMessageBefore=true;
			}
			break;
		default:
			{
				ResetEvent(handle[0]);
				ResetEvent(handle[1]);
			}
			continue;
		}
		while(!bQuit && bHasMessageBefore )
		{
			dwRet=::WaitForMultipleObjects(2,handle,false,DATA_READ_TIMEOUT);
			if(dwRet==WAIT_TIMEOUT)//成功接收到一个数据包
			{
				if(bHasMessageBefore)
				{
					TRACE0("完整地接收到了一个数据包!通知数据接收线程进行接收!\n");
					bHasMessageBefore=false;
					SetEvent(pSerial->m_data_come_event);//通知数据接收线程接收数据
				}
				continue;
			}
			switch(dwRet-WAIT_OBJECT_0)
			{
			case 0://退出
				{
					bQuit=true;
				}
				break;
			case 1://数据到来
				{
//					TRACE0("事件分析线程接收到了一个字符!\n");
					ResetEvent(handle[1]);
				}
				break;
			default://出错了
				{
					ResetEvent(handle[0]);
					ResetEvent(handle[1]);
				}
				break;
			}
		}
	}

	TRACE("analysis event thread end\n");
//AfxMessageBox("analysis event thread end");
	SetEvent(pSerial->m_end_data_thread);
	SetEvent(pSerial->m_analysis_thread_end);
	return 1;
}
/******************************************************************************
*功能:读取数据线程
*说明:	成功收到一个数据包后,这个线程会得到消息。开始读取这个数据包
		成功读取一包数据后,会把数据放到g_read_data_group中,同时向调用者发出一个消息
		此消息由调用者初始化时传入.
*参数:lpParam:即:CSerial类对象本身
*返回:0
******************************************************************************/
UINT CSerial::ReadDataProc(LPVOID lpParam)
{
	CSerial * pSerial = (CSerial *)lpParam;

	bool bQuit=false;

	DWORD dwEventMask=0;

	//接收到重叠消息
	OVERLAPPED ov;
	memset(&ov,0,sizeof(OVERLAPPED));
	ov.hEvent	= CreateEvent(0,true,0,0);

	//读取串口事件、退出线程信号
	HANDLE event_handle[2];
	event_handle[0] = pSerial->m_end_data_thread;
	event_handle[1] = pSerial->m_data_come_event;
	HANDLE read_handle[2];
	read_handle[0] = pSerial->m_end_data_thread;
	read_handle[1] = ov.hEvent;

	//想要读取的字节数
	BOOL  bRet;
	DWORD dwBytesWantRead;
	DWORD dwBytesRead;
	char  temp_buf[2*MAX_COMM_BUF_LEN];
	bool bReadOverlapping = false;
	bool bReadDataSuccess = false;

	//想知道系统读缓冲区里共有多少字节
	DWORD   dwErrors=0;//需要这个参数,但是根本没有使用它的返回值,我们不关心它的返回值.
	COMSTAT comstate;
	memset(&comstate,0,sizeof(COMSTAT));

	//保存WaitForMultipleObjects返回值
	DWORD dwRet;

	::WaitForSingleObject(pSerial->m_start_data_thread,INFINITE);

	TRACE("read data thread start\n");

	SetEvent(pSerial->m_start_analysis_thread);//启动分析线程

	while(!bQuit)
	{
		dwRet=::WaitForMultipleObjects(2,event_handle,false,INFINITE);
		switch(dwRet-WAIT_OBJECT_0)
		{
		case 0://退出
			{
				bQuit=true;
			}
			break;
		case 1://数据到来
			{
				ResetEvent(event_handle[1]);//每次都是先恢复信号
				//得到总计有多少字节在系统接收缓冲区里
				bRet=::ClearCommError(pSerial->m_hCommPort,&dwErrors,&comstate);
				if(!bRet)
				{
					continue;//失败就丢弃!
				}
				dwBytesWantRead=comstate.cbInQue;//得到在系统读缓冲区中共有多少字节。
				bRet=::ReadFile(pSerial->m_hCommPort,temp_buf,dwBytesWantRead,&dwBytesRead,&ov);
				if(bRet)	//成功读取数据
				{
					bReadDataSuccess=true;
				}
				else		//看看是否开始了重叠操作?
				{
					if(GetLastError()==ERROR_IO_PENDING)
					{
						bReadOverlapping=true;
					}
					else//发生错误
					{
						TRACE("ReadFile(pSerial->m_hCommPort,temp_buf,dwBytesWantRead,&dwBytesRead,&ov);\n");
						continue;
					}
				}
				if(bReadOverlapping)
				{
					bReadOverlapping=false;
					dwRet=::WaitForMultipleObjects(2,read_handle,false,DATA_READ_TIMEOUT);
					if(dwRet==WAIT_TIMEOUT)
					{
						continue;//如果读取数据超时,就认为是错误数据,丢弃!
					}
					switch(dwRet-WAIT_OBJECT_0)
					{
					case 0://退出
						{
							bQuit=true;
						}
						break;
					case 1://读数据重叠操作完成
						{
//							ResetEvent(read_handle[1]);//恢复读取数据信号
							//需要判断是否成功读取了数据
							bRet=::GetOverlappedResult(pSerial->m_hCommPort,&ov,&dwBytesRead,false);
							if(!bRet)//读重叠操作失败!
							{
								TRACE0("读重叠操作失败!\n");
							}
							else
							{
								bReadDataSuccess=true;//成功读取了数据
							}
						}
						break;
					default:
						{
						}
						break;
					}
				}
				if(bReadDataSuccess)//如果成功读取了数据
				{
					bReadDataSuccess=false;//恢复状态
					if(dwBytesWantRead==dwBytesRead)//如果没有少读取数据字节数,才是真正的正确读取了数据
					{
						LPDATA lpdata=g_read_data_group.GetBlank();

						//如果读取的字节数超过了MAX_COMM_BUF_LEN-1,则只能接收到MAX_COMM_BUF_LEN-1个字节了
						lpdata->m_n_len=dwBytesRead>MAX_COMM_BUF_LEN-1?MAX_COMM_BUF_LEN-1:dwBytesRead;
						memcpy(lpdata->m_sz_buf,temp_buf,lpdata->m_n_len);
						lpdata->m_sz_buf[lpdata->m_n_len]=0;
						pSerial->NotifyReadData();

						TRACE("数据接收线程接收到了一个数据包!len=[%d]\n",lpdata->m_n_len);
					}
					else
					{
						TRACE0("少读取数据字节数\n");
					}
				}
				continue;//成功读取了数据
			}
			break;
		default:
			{
			}
			break;
		}	
	}
	pSerial->CloseAndCleanHandle(ov.hEvent);

	TRACE("read data thread end\n");
//	AfxMessageBox("read data thread end");
	SetEvent(pSerial->m_data_thread_end);

	return 2;
}
/******************************************************************************
*功能:通知调用都,成功读取了一个数据包
*说明:
*参数:
*返回:
******************************************************************************/
void CSerial::NotifyReadData()
{
	::PostMessage(m_h_father_wnd,m_u_message,MSG_READ,0);
}
/******************************************************************************
*功能:通知调用都,成功发送了一个数据包
*说明:
*参数:
*返回:
******************************************************************************/
void CSerial::NotifyWriteData(void*lpdata)
{
	::PostMessage(m_h_father_wnd,m_u_message,MSG_WRITE,(LPARAM)lpdata);
}

void CSerial::ClearSysReadBufferContent()
{
	int nRet;
	DWORD dwErrors=0;
	COMSTAT comstate;
	memset(&comstate,0,sizeof(COMSTAT));

	nRet=::ClearCommError(m_hCommPort,&dwErrors,&comstate);
	if(!nRet)return;
	
	char buf[4096];
	DWORD dwBytesRead;
	::ReadFile(m_hCommPort,buf,comstate.cbInQue,&dwBytesRead,NULL);

	TRACE("已经清空了系统接收缓冲区!len=[%ld]\n",comstate.cbInQue);

	//也清空一下保存数据的缓冲区
	g_read_data_group.PutToBlank();
	g_send_data_group.PutToBlank();
}

UINT CSerial::SendDataProc(LPVOID lpParam)
{
	CSerial * pSerial = (CSerial *)lpParam;

	//一些返回值
	BOOL  bRet;
	DWORD dwError=0;
	DWORD dwRet;

	//重叠结构
	OVERLAPPED ov;
	memset(&ov,0,sizeof(OVERLAPPED));
	ov.hEvent=CreateEvent(0,true,0,0);

	HANDLE event_handle[2],handle[2];
	event_handle[0]=pSerial->m_end_send_thread;
	event_handle[1]=pSerial->m_send_data_event;
	handle[0]=pSerial->m_end_send_thread;
	handle[1]=ov.hEvent;

	//错误处理用的
	COMSTAT comstate;
	memset(&comstate,0,sizeof(COMSTAT));

	//是否开始了重叠操作?
	bool bWantToSendSomething=false;
	bool bHasOverlapped=false;
	bool bHasFinishedOverlapped=false;

	//一共写了多少字节?
	DWORD dwBytesWrite=0;

	bool bQuit=false;
	
	TRACE0("send data thread start!!!!!\n");

	while(!bQuit)
	{
		dwRet=::WaitForMultipleObjects(2,event_handle,false,INFINITE);
		switch(dwRet-WAIT_OBJECT_0)
		{
		case 0:
			{
				bQuit=true;
			}
			continue;
		case 1:
			{
				bWantToSendSomething=true;
			}
			break;
		default:
			{
			}
			continue;
		}
		if(!bWantToSendSomething)continue;
		bWantToSendSomething=false;
		//得到要发送的数据结点
		LPDATA lpdata=g_send_data_group.GetNext();
		
		//一直把所有需要发送的数据全都发送完
		while(lpdata!=NULL)
		{
			bRet=::WriteFile(pSerial->m_hCommPort,lpdata->m_sz_buf,lpdata->m_n_len,&dwBytesWrite,&ov);
			
			if(!bRet)
			{
				if(GetLastError()==ERROR_IO_PENDING)
				{
					bHasOverlapped=true;
				}
				else//出错处理,必须,否则所有IO操作都会被锁死!
				{
					::ClearCommError(pSerial->m_hCommPort,&dwError,&comstate);
				}
			}
			if(bHasOverlapped)
			{
				bHasOverlapped=false;
				dwRet=::WaitForMultipleObjects(2,handle,false,INFINITE);
				switch(dwRet-WAIT_OBJECT_0)
				{
				case 0://退出
					{
						bQuit=true;
					}
					continue;
				case 1://数据到来
					{
						TRACE0("发送数据重叠操作完成\n");
						bHasFinishedOverlapped=true;
					}
					break;
				default://出错了
					{
					}
					continue;
				}
			}
			if(bHasFinishedOverlapped)
			{
				bHasFinishedOverlapped=false;
				bRet=::GetOverlappedResult(pSerial->m_hCommPort,&ov,&dwBytesWrite,false);
				if(bRet)
				{
					TRACE("重叠操作完成!发送了[%d]字节数据\n",dwBytesWrite);
					pSerial->NotifyWriteData(lpdata->m_sz_buf);
				}
				else
				{
					TRACE("没有得到重叠操作结果!\n");
				}
			}
			//再取没有发送的数据
			lpdata=g_send_data_group.GetNext();
		}
		//恢复发送数据的信号,以便再接收发送数据的消息
		ResetEvent(event_handle[1]);
	}

	pSerial->CloseAndCleanHandle(ov.hEvent);
	TRACE0("send data thread end!\n");
	SetEvent(pSerial->m_send_thread_end);

	return 3;
}

bool CSerial::ReadData(char szData[], int &len)
{
	LPDATA lpdata=g_read_data_group.GetNext();
	if(lpdata==NULL)return false;
	
	len=len>lpdata->m_n_len+1?lpdata->m_n_len+1:len;
	memcpy(szData,lpdata->m_sz_buf,len);
	szData[len]=0;

	return true;
}

bool CSerial::SendData(char szData[], int len)
{
	LPDATA lpdata=g_send_data_group.GetBlank();

	lpdata->m_n_len=len;
	memcpy(lpdata->m_sz_buf,szData,len);
	lpdata->m_sz_buf[len]=0;

	SetEvent(m_send_data_event);
	return true;
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -