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();

        
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章