VC MFC 串口通信(多线程)

VC  MFC  串口通信(多线程)

现在一般用VC写串口通信,大多数人会采取下面的三种方式:
一.直接利用VC 里面的MSComm类进行编程。
二.网上也有一个比较好的类,大多数人也喜欢采用SerialPort(此类其实也比较好用)
三.应用API函数进行串口编程。
        以上三种方式编程,我都用过的。。。(当然都不是很深入)。其实前两种用起来比较简单一点。就是对串口初始化,在调用MSComm(SerialPort)的函数就可以了。我只是简单的看过上面两个类的定义,其中也有线程的使用。 但是在我使用的时候,我是通过串口接收一副图像,但有时候界面会出现卡死的情况,到此论坛上求助,有人告诉我要创建一个线程,,,这里我到现在都不是很了解,因为我觉得本来就是一个线程吧! 为什么还要创建了。。)于是就学应用API函数进行编程了。
API 函数:API(Application Programming Interface,应用编程接口)其实就是操作系统留给应用程序的一个调用接口,应用程序通过调用操作系统的 API 而使操作系统去执行应用程序的命令(只要是在windows环境下编程都可以调用API函数)
利用API函数进行串口编程的步骤:
(1)打开串口:CreatFile()函数              
m_hcom=CreateFile(
					"COM1",//COM1口
					GENERIC_READ|GENERIC_WRITE, //允许读和写
					0, //独占方式
					NULL,
					OPEN_EXISTING, //打开
					FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED, //重叠方式
					NULL
	             	);
            创建一个关于串口的句柄
(2)创建串口通信事件:CreatEvent()函数
这里涉及到了一个重要的结构体OVERLAPPED:OVERLAPPED是一个包含了用于异步输入输出的信息的结构体,在这个结构体中最重要的一个成员为hEvent,线程利用CreatEvent函数为hEvent创建一个手工重置事,hEvent将作为线程的同步对象使用,初始化的hEvent为有信号的,当读写事件完成操作之后,hEvent会变为有信号。对这一结构,请看这里http://blog.csdn.net/pofenglangguayunfan/article/month/2013/10。
(3)串口的初始化,设置串口参数
	/********************输入缓冲区和输出缓冲区的大小***********/
    SetupComm(m_hcom,1024,1024);
	/*********************超时结构(读一次缓冲区就返回)****************************/
    COMMTIMEOUTS TimeOuts;
	TimeOuts.ReadIntervalTimeout=MAXDWORD;//两个字节之间的间隔时间
	TimeOuts.ReadTotalTimeoutMultiplier=0;//读时间系数
	TimeOuts.ReadTotalTimeoutConstant=0;//读时间常数
	TimeOuts.WriteTotalTimeoutMultiplier=100;//设定写超时
	TimeOuts.WriteTotalTimeoutConstant=500;
	SetCommTimeouts(m_hcom,&TimeOuts);
   /******************串口参数的配置*******************/
	DCB dcb;
	GetCommState(m_hcom,&dcb);//获得参数
	dcb.BaudRate=4800;
	dcb.ByteSize=8;//每个字节8位
	dcb.Parity=NOPARITY;//无奇偶检验
	dcb.StopBits=ONESTOPBIT;//两个停止位
    SetCommState(m_hcom,&dcb);
(4)建立读数据的线程:
一般写数据我们是可以控制的,但读数据的时候,我们不知道数据什么时候会到,所以要建立一个专门的线程,其中用到的函数有:WaitCommEvent,ClearCommError,WaitForSingleObject,ReadFile
OVERLAPPED os;//异状态步输入/输出的
    COMSTAT comStat;//通信设备控制块
	os.hEvent=NULL;
	os.hEvent=CreateEvent(NULL, TRUE, FALSE, NULL);
	os.Offset=0;
	os.OffsetHigh=0;
	m_osRead.hEvent=CreateEvent(NULL, TRUE, FALSE, NULL);
    char czReceiveBuffer[100];
	DWORD dErrInformation;
	memset(czReceiveBuffer,0,sizeof(czReceiveBuffer));
	SetCommMask(m_hcom, EV_RXCHAR);//
	/*if(os.hEvent=NULL)
	{
		AfxMessageBox("无法创建事件对象!");
		return (UINT)-1;
	}*/
	/****************** 在通信之前清除掉错误信息**************/
	if(m_hcom!=NULL)
	{
		ClearCommError(m_hcom,&dErrInformation,&comStat);
	}
	while(TRUE)
	{
     DWORD wEven;
	 INT bResult=WaitCommEvent(m_hcom,&wEven,&os);
	 //DWORD BytesRead;
		if(!bResult)
			 {
		    	 switch(GetLastError())
					 {
				 case ERROR_IO_PENDING:
						  break;
				 case 87:
						  break;
					  default:
						  break;
					 }
			 }
			 else 
			 {
				 ClearCommError(m_hcom,&dErrInformation,&comStat);
				 if(comStat.cbInQue==0)
				 {
					 continue;
				 }
			 }
		 INT nEvent=WaitForSingleObject(os.hEvent,INFINITE);
         if(nEvent==WAIT_OBJECT_0)
		 {
            DWORD CommEvent=0;
			GetCommMask(m_hcom,&CommEvent);
			if(CommEvent&EV_RXCHAR==EV_RXCHAR)//输入缓冲区接收到新字符
			{
              BOOL bread=TRUE;
			  BOOL bresult=TRUE;
			  DWORD deError=0;
			  DWORD BytesRead=0;
			  /
			  COMSTAT comstat;
			  for(;;)
			  {
				  DWORD dRBufferSize=100;
				 INT bResult=ClearCommError(m_hcom,&deError,&comstat);//成功返回值非0
			      if(comstat.cbInQue==0)
				  {
					  break;
				  }
				  if(bread)
                  {
					  strRec="";
					  bresult=ReadFile(m_hcom,czReceiveBuffer,100,&dRBufferSize,&m_osRead);
					  if(!bresult)
					  {
                        switch(deError=GetLastError())
						{
						case ERROR_IO_PENDING:
							{
								bread=FALSE;
								break;
							}
						default:
							{
								break;
							}
						}
					  }
					  else
					  {
						  bread=TRUE;
					  }
				  }
              if(!bread)
				  {
                    bread=TRUE;
					bresult=GetOverlappedResult
						(
						m_hcom,
						&os,
					    &BytesRead,
                        TRUE
							);
                    if(!bresult)
					{
					}
				  }
                 PurgeComm(m_hcom, PURGE_TXABORT|PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR);
				 for(DWORD k=0;k<dRBufferSize;k++)
				 {
					 strRec+=czReceiveBuffer[k];
				 }
				 ::PostMessage(m_hVieWnd,WM_RECEDATA,(unsigned int)czReceiveBuffer,dRBufferSize);
			  }
			}
		 }
		if(nEvent!=WAIT_OBJECT_0)
		{
			GetLastError();
		}
	}
	return TRUE;
(5)写数据:用WriteFile()函数
    OVERLAPPED m_osWriter;
	memset(&m_osWriter,0,sizeof(OVERLAPPED));
	m_osWriter.hEvent=CreateEvent(NULL,TRUE,FALSE,NULL);
	UpdateData(true);
//	m_strSend += "/n";
	COMSTAT ComStat;
	DWORD dwErrorFlags;
	BOOL  bWriterStat;
	DWORD dwBytesWrite=0;
	ClearCommError(m_hcom,&dwErrorFlags,&ComStat);
	bWriterStat = WriteFile(m_hcom,m_strSend,m_strSend.GetLength(),
		&dwBytesWrite,&m_osWriter
		);
	if(!bWriterStat)
	{
       if(GetLastError()==ERROR_IO_PENDING)
	   {
		   WaitForSingleObject(m_osWriter.hEvent,1000);
	   }
	}
(6)
终止线程CloseHandle();

        
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页