VC 串口通信實現方式

利用師姐QT2440開發板控制機械臂, 串口通信出現問題, 找到usb轉串口後,任然找不到相應的驅動。初步打算用單片機實現。


1.基於Active控件的方式(MSComm)

        優點是:直接利用控件,在串口有數據到達時,會促發相應的事件響應函數,然後你可以在實踐響應函數裏,進行數據的讀取。

        缺點是:數據在發送和接受的過程中VARIANT、   COleSafeArray 類型的轉換,顯得繁瑣。

        步驟:

       ①插入控件

        選擇Project菜單下Add To Project子菜單中的 Components and Controls…選項,在彈出的對話框中雙擊Registered ActiveX Controls項,則所有註冊過的ActiveX控件出現在列表框中。 選擇Microsoft Communications Control, version 6.0,單擊Insert按鈕將它插入到我們的Project中來,接受缺省的選項。這時在ClassView視窗中就可以看到CMSComm類了,並且在控件工具欄Controls中出現了電話圖標,現在要做的是用鼠標將此圖標拖到對話框中,程序運行後,這個圖標是看不到的。

        ②爲拖入對話框的 CMSComm控件添加對應的控制變量 m_ctrlComm。

        ③添加對應的消息響應函數OnComm()

        打開ClassWizard->Message Maps,選擇類CSCommTestDlg,選擇IDC_MSCOMM1,雙擊消息OnComm,將彈出的對話框中將函數名改爲OnComm,這個函數是用來處理串口消息事件的,如每當串口接收到數據,就會產生一個串口接收數據緩衝區中有字符的消息事件,我們剛纔添加的函數就會執行,我們在OnComm()函數加入相應的處理代碼就能實現自已想要的功能了。請你在函數中加入如下代碼:

[cpp] view plain copy
  1. void CSCommTestDlg::OnComm()   
  2. {  
  3.     // TODO: Add your control notification handler code here  
  4.     VARIANT variant_inp;  
  5.     COleSafeArray safearray_inp;  
  6.     LONG len,k;  
  7.     BYTE rxdata[2048]; //設置BYTE數組 An 8-bit integerthat is not signed.  
  8.     CString strtemp;  
  9.     if(m_ctrlComm.GetCommEvent()==2) //事件值爲2表示接收緩衝區內有字符  
  10.     {             ////////以下你可以根據自己的通信協議加入處理代碼  
  11.         variant_inp=m_ctrlComm.GetInput(); //讀緩衝區  
  12.         safearray_inp=variant_inp; //VARIANT型變量轉換爲ColeSafeArray型變量  
  13.         len=safearray_inp.GetOneDimSize(); //得到有效數據長度  
  14.         for(k=0;k<len;k++)  
  15.             safearray_inp.GetElement(&k,rxdata+k);//轉換爲BYTE型數組  
  16.         for(k=0;k<len;k++) //將數組轉換爲Cstring型變量  
  17.         {  
  18.             BYTE bt=*(char*)(rxdata+k); //字符型  
  19.             strtemp.Format("%c",bt); //將字符送入臨時變量strtemp存放  
  20.             m_strRXData+=strtemp; //加入接收編輯框對應字符串   
  21.         }  
  22.     }  
  23.     UpdateData(FALSE); //更新編輯框內容  
  24. }  

      ④.打開串口和設置串口參數

       現在我們在主對話框的CSCommTestDlg::OnInitDialog()打開串口,加入如下代碼:

[cpp] view plain copy
  1. // TODO: Add extra initialization here  
  2. if(m_ctrlComm.GetPortOpen())  
  3. m_ctrlComm.SetPortOpen(FALSE);  
  4.   
  5. m_ctrlComm.SetCommPort(1); //選擇com1  
  6. if( !m_ctrlComm.GetPortOpen())  
  7. m_ctrlComm.SetPortOpen(TRUE);//打開串口  
  8. else  
  9. AfxMessageBox("cannot open serial port");  
  10.   
  11. m_ctrlComm.SetSettings("9600,n,8,1"); //波特率9600,無校驗,8個數據位,1個停止位  
  12.   
  13. m_ctrlComm.SetInputModel(1); //1:表示以二進制方式檢取數據  
  14. m_ctrlComm.SetRThreshold(1);   
  15. //參數1表示每當串口接收緩衝區中有多於或等於1個字符時將引發一個接收數據的OnComm事件  
  16. m_ctrlComm.SetInputLen(0); //設置當前接收區數據長度爲0  
  17. m_ctrlComm.GetInput();//先預讀緩衝區以清除殘留數據  

        ⑤.發送數據

        

[cpp] view plain copy
  1. CString m_send = _T("你想要發送的數據")  
  2.   
  3. m_ctrlComm.SetOutput(COleVariant(m_send ));  

2.基於win32 API的串口讀寫

        ①初始化打開串口

         優點:設置、使用更加靈活,因爲是基於win32的api函數。所以顯得更加通用,適用任何windows程序上引用,不僅僅限於MFC.

         缺點:需要主動的去讀取串口上的數據,沒有事件通知。

         這裏有一點需要注意的是,當COM號大於10的時候,會出現打開錯誤,一般解決的辦法是修改com的名稱讓它的com號是一位數。除此之外也有其他解決辦法,見網上。

[cpp] view plain copy
  1. HANDLE InitCom(char* comName)  
  2. {  
  3.     HANDLE hCom;  
  4.     hCom = CreateFile(comName,//COM7口  
  5.         GENERIC_READ|GENERIC_WRITE, //允許讀和寫  
  6.         0, //獨佔方式  
  7.         NULL,  
  8.         OPEN_EXISTING, //打開而不是創建  
  9.         0, //同步方式  
  10.         NULL);  
  11.     if(hCom == (HANDLE)-1)  
  12.     {  
  13.         return NULL;  
  14.     }  
  15.     SetupComm(hCom,100,100); //輸入緩衝區和輸出緩衝區的大小都是100  
  16.     COMMTIMEOUTS TimeOuts;  
  17.     //設定讀超時  
  18.     TimeOuts.ReadIntervalTimeout=MAXDWORD;  
  19.     TimeOuts.ReadTotalTimeoutMultiplier=0;  
  20.     TimeOuts.ReadTotalTimeoutConstant=0;  
  21.     //在讀一次輸入緩衝區的內容後讀操作就立即返回,  
  22.     //而不管是否讀入了要求的字符。  
  23.     //設定寫超時  
  24.     TimeOuts.WriteTotalTimeoutMultiplier=100;  
  25.     TimeOuts.WriteTotalTimeoutConstant=500;  
  26.     SetCommTimeouts(hCom,&TimeOuts); //設置超時  
  27.   
  28.     DCB dcb;  
  29.     GetCommState(hCom, &dcb);  
  30.     dcb.BaudRate=115200; //波特率爲9600  
  31.     dcb.ByteSize=8; //每個字節有8位  
  32.     dcb.Parity=NOPARITY; //無奇偶校驗位  
  33.     dcb.StopBits=1; //兩個停止位  
  34.     SetCommState(hCom, &dcb);  
  35.     PurgeComm(hCom, PURGE_TXCLEAR|PURGE_RXCLEAR);  
  36.     return hCom;  
  37. }  
        ②讀串口信息
[cpp] view plain copy
  1. int ReadData(HANDLE handler, char* buffer)  
  2. {  
  3.     char readBuffer[512];  
  4.     memset(readBuffer, 0, 512);  
  5.     DWORD wCount= 512;//讀取的字節數  
  6.     BOOL bReadStat;  
  7.   
  8.     bReadStat = ReadFile(handler, readBuffer, wCount, &wCount, NULL);  
  9.     if(!bReadStat)  
  10.     {  
  11.         AfxMessageBox("讀串口失敗!");  
  12.         return -1;  
  13.     }  
  14.     strcpy(buffer, readBuffer);  
  15.     PurgeComm(handler, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR);    
  16.     return 0;  
  17. }  

        ③寫串口信息
[cpp] view plain copy
  1. int WriteData(HANDLE handler, char* buffer)  
  2. {  
  3.     unsigned long dwBytesWrite;  
  4.     COMSTAT ComStat;  
  5.     DWORD dwErrorFlags;  
  6.     BOOL bWriteStat;  
  7.     ClearCommError(handler, &dwErrorFlags, &ComStat);  
  8.     dwBytesWrite = strlen(buffer);  
  9.     bWriteStat=WriteFile(handler, buffer, dwBytesWrite, &dwBytesWrite, NULL);  
  10.     if(!bWriteStat)  
  11.     {  
  12.         AfxMessageBox("寫串口失敗!");  
  13.         return -1;  
  14.     }  
  15.     return 0;  
  16. }  
	switch(arm_type){
		case ARM_DEVICE_COM:
			for(i=0; i<MAX_COM_NUM; i++){
				DCB com_config_back;
				COMSTAT comstat;
				DWORD errorcode;
				sprintf_s(comstr, "COM%d", i);
				// 1. 嘗試打開串口
				hcom = CreateFileA(comstr, GENERIC_READ | GENERIC_WRITE ,
					0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | 
					FILE_FLAG_OVERLAPPED, NULL);
				if(hcom==INVALID_HANDLE_VALUE){
					errorcode = GetLastError();
					continue;
				}
				// 2. 創建緩衝區
				SetupComm(hcom, 1024*8, 1024*8);
				// 3. 串口配置
				GetCommState(hcom, &com_config_back);
				SetCommState(hcom, &__arm_com_config__);
				// 4. 身份驗證
				ClearCommError(hcom,&errorcode,&comstat);
				if(arm_com_is_alive(hcom, 5000)>=0){
					break;
				}
				SetCommState(hcom, &com_config_back);
				CloseHandle(hcom);
			}

			if(i==MAX_COM_NUM){
				return NULL;
			}
			armctr	=	(arm_controller*)malloc(sizeof(*armctr));
			armctr->arm_com		=	hcom;
			break;
		case ARM_DEVICE_VIRTUAL_STD:
			armctr	=	(arm_controller*)malloc(sizeof(*armctr));
			armctr->arm_com=NULL;
			//armctr->arm_com=-1;
			break;
		default:
			return NULL;
	}
	armctr->arm_type	=	arm_type;
	printf("連接到串口設備:%s\n",comstr);
	return armctr;
}


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