利用師姐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()函數加入相應的處理代碼就能實現自已想要的功能了。請你在函數中加入如下代碼:
- void CSCommTestDlg::OnComm()
- {
- // TODO: Add your control notification handler code here
- VARIANT variant_inp;
- COleSafeArray safearray_inp;
- LONG len,k;
- BYTE rxdata[2048]; //設置BYTE數組 An 8-bit integerthat is not signed.
- CString strtemp;
- if(m_ctrlComm.GetCommEvent()==2) //事件值爲2表示接收緩衝區內有字符
- { ////////以下你可以根據自己的通信協議加入處理代碼
- variant_inp=m_ctrlComm.GetInput(); //讀緩衝區
- safearray_inp=variant_inp; //VARIANT型變量轉換爲ColeSafeArray型變量
- len=safearray_inp.GetOneDimSize(); //得到有效數據長度
- for(k=0;k<len;k++)
- safearray_inp.GetElement(&k,rxdata+k);//轉換爲BYTE型數組
- for(k=0;k<len;k++) //將數組轉換爲Cstring型變量
- {
- BYTE bt=*(char*)(rxdata+k); //字符型
- strtemp.Format("%c",bt); //將字符送入臨時變量strtemp存放
- m_strRXData+=strtemp; //加入接收編輯框對應字符串
- }
- }
- UpdateData(FALSE); //更新編輯框內容
- }
④.打開串口和設置串口參數
現在我們在主對話框的CSCommTestDlg::OnInitDialog()打開串口,加入如下代碼:
- // TODO: Add extra initialization here
- if(m_ctrlComm.GetPortOpen())
- m_ctrlComm.SetPortOpen(FALSE);
- m_ctrlComm.SetCommPort(1); //選擇com1
- if( !m_ctrlComm.GetPortOpen())
- m_ctrlComm.SetPortOpen(TRUE);//打開串口
- else
- AfxMessageBox("cannot open serial port");
- m_ctrlComm.SetSettings("9600,n,8,1"); //波特率9600,無校驗,8個數據位,1個停止位
- m_ctrlComm.SetInputModel(1); //1:表示以二進制方式檢取數據
- m_ctrlComm.SetRThreshold(1);
- //參數1表示每當串口接收緩衝區中有多於或等於1個字符時將引發一個接收數據的OnComm事件
- m_ctrlComm.SetInputLen(0); //設置當前接收區數據長度爲0
- m_ctrlComm.GetInput();//先預讀緩衝區以清除殘留數據
⑤.發送數據
- CString m_send = _T("你想要發送的數據")
- m_ctrlComm.SetOutput(COleVariant(m_send ));
2.基於win32 API的串口讀寫
①初始化打開串口
優點:設置、使用更加靈活,因爲是基於win32的api函數。所以顯得更加通用,適用任何windows程序上引用,不僅僅限於MFC.
缺點:需要主動的去讀取串口上的數據,沒有事件通知。
這裏有一點需要注意的是,當COM號大於10的時候,會出現打開錯誤,一般解決的辦法是修改com的名稱讓它的com號是一位數。除此之外也有其他解決辦法,見網上。
- HANDLE InitCom(char* comName)
- {
- HANDLE hCom;
- hCom = CreateFile(comName,//COM7口
- GENERIC_READ|GENERIC_WRITE, //允許讀和寫
- 0, //獨佔方式
- NULL,
- OPEN_EXISTING, //打開而不是創建
- 0, //同步方式
- NULL);
- if(hCom == (HANDLE)-1)
- {
- return NULL;
- }
- SetupComm(hCom,100,100); //輸入緩衝區和輸出緩衝區的大小都是100
- COMMTIMEOUTS TimeOuts;
- //設定讀超時
- TimeOuts.ReadIntervalTimeout=MAXDWORD;
- TimeOuts.ReadTotalTimeoutMultiplier=0;
- TimeOuts.ReadTotalTimeoutConstant=0;
- //在讀一次輸入緩衝區的內容後讀操作就立即返回,
- //而不管是否讀入了要求的字符。
- //設定寫超時
- TimeOuts.WriteTotalTimeoutMultiplier=100;
- TimeOuts.WriteTotalTimeoutConstant=500;
- SetCommTimeouts(hCom,&TimeOuts); //設置超時
- DCB dcb;
- GetCommState(hCom, &dcb);
- dcb.BaudRate=115200; //波特率爲9600
- dcb.ByteSize=8; //每個字節有8位
- dcb.Parity=NOPARITY; //無奇偶校驗位
- dcb.StopBits=1; //兩個停止位
- SetCommState(hCom, &dcb);
- PurgeComm(hCom, PURGE_TXCLEAR|PURGE_RXCLEAR);
- return hCom;
- }
- int ReadData(HANDLE handler, char* buffer)
- {
- char readBuffer[512];
- memset(readBuffer, 0, 512);
- DWORD wCount= 512;//讀取的字節數
- BOOL bReadStat;
- bReadStat = ReadFile(handler, readBuffer, wCount, &wCount, NULL);
- if(!bReadStat)
- {
- AfxMessageBox("讀串口失敗!");
- return -1;
- }
- strcpy(buffer, readBuffer);
- PurgeComm(handler, PURGE_TXABORT | PURGE_RXABORT | PURGE_TXCLEAR | PURGE_RXCLEAR);
- return 0;
- }
③寫串口信息
- int WriteData(HANDLE handler, char* buffer)
- {
- unsigned long dwBytesWrite;
- COMSTAT ComStat;
- DWORD dwErrorFlags;
- BOOL bWriteStat;
- ClearCommError(handler, &dwErrorFlags, &ComStat);
- dwBytesWrite = strlen(buffer);
- bWriteStat=WriteFile(handler, buffer, dwBytesWrite, &dwBytesWrite, NULL);
- if(!bWriteStat)
- {
- AfxMessageBox("寫串口失敗!");
- return -1;
- }
- return 0;
- }
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;
}