2010-08-11 246 views
1

雖然問題出在C++端,但Arduino Nano和C++之間的串行端口通信存在問題。基本上我想從Arduino發送整數(或長,...)到C++程序進行處理。使用Arduino和C++進行串行端口通信

首先我做了一個測試,使用Matlab將信息從Arduino發送到計算機。 Arduino的代碼非常簡單:

int i = 0; 

void setup() { 

    // start serial port at 9600 bps: 
    Serial.begin(9600); 
    establishContact(); 
} 

void loop() { 
    Serial.println(i); 
    i=i+1; 
    delay(10); 
} 

void establishContact() { 
    while (Serial.available() <= 0) { 
    Serial.println('A', BYTE); 
    delay(10); 
    } 
} 

Matlab的側面也很簡單:

clc; 
clear all; 
numSec=2; 
t=[]; 
v=[]; 

s1 = serial('COM3'); % define serial port 
s1.BaudRate=9600;    % define baud rate 
set(s1, 'terminator', 'LF'); % define the terminator for println 
fopen(s1); 

try        % use try catch to ensure fclose 
           % signal the arduino to start collection 
    w=fscanf(s1,'%s');    % must define the input % d or %s, etc. 
    if (w=='A') 
     display(['Collecting data']); 
     fprintf(s1,'%s\n','A');  % establishContact just wants 
            % something in the buffer 
    end 

    i=0; 
    t0=tic; 
    while (toc(t0)<=numSec) 
     i=i+1; 
     t(i)=toc(t0); 
     t(i)=t(i)-t(1); 
     v(i)=fscanf(s1,'%d');  
    end 

    fclose(s1); 
    plot(t,v,'*r') 

catch me 
    fclose(s1);     
end  

我的目標是,用C++,這樣做是在Matlab使用的fscanf做了同樣的(S1, '%d')。

下面是當前的代碼,我使用(C++代碼):

void main() 
{ 
HANDLE hSerial; 
hSerial = CreateFile(TEXT("COM3"), 
    GENERIC_READ | GENERIC_WRITE, 
    0, 
    NULL, 
    OPEN_EXISTING, 
    FILE_ATTRIBUTE_NORMAL,//FILE_FLAG_OVERLAPPED, 
    NULL); 



if (hSerial == INVALID_HANDLE_VALUE) 
{ 
    printf("Error initializing handler"); 
} 
else 
{ 

    // Set the parameters of the handler to the serial port. 
    DCB dcb = {0}; 

    dcb.DCBlength = sizeof(dcb); 

    if (!GetCommState(hSerial, &dcb)) 
    { 
    printf("Error setting parameters"); 
    } 

    FillMemory(&dcb, sizeof(dcb), 0); 
    dcb.BaudRate = CBR_9600; 
    dcb.ByteSize = 8; 
    dcb.StopBits = ONESTOPBIT; 
    dcb.Parity = NOPARITY; 

    if (!SetCommState(hSerial, &dcb)) 
    { 
    // error setting serial port state. 
    } 

    // Tell the program not to wait for data to show up 
    COMMTIMEOUTS timeouts = {0}; 

    timeouts.ReadIntervalTimeout = 0;//20; 
    timeouts.ReadTotalTimeoutConstant = 0;//20; 
    timeouts.ReadTotalTimeoutMultiplier = 0;//50; 
    timeouts.WriteTotalTimeoutConstant = 0;//100; 
    timeouts.WriteTotalTimeoutMultiplier = 0;//100; 

    if (!SetCommTimeouts(hSerial, &timeouts)) 
    { 
    printf("Error setting the timeouts"); 

    } 

    char szBuff[5] = ""; 
    DWORD dwBytesRead = 0; 
    int i = 0; 
    char test[] = "B\n"; 
    int maxSamples = 10; 
    DWORD dwCommStatus; 

    WriteFile(hSerial, test, 2, &dwBytesRead, NULL); 

    SetCommMask(hSerial,EV_RXCHAR); 

    while (i < maxSamples) 
    { 
    WaitCommEvent (hSerial, &dwCommStatus, 0); 

    if (dwCommStatus & EV_RXCHAR) 
    { 
    memset(szBuff,0,sizeof(szBuff)); 
    ReadFile(hSerial, LPVOID(szBuff), 4, &dwBytesRead, NULL); 

    cout<<szBuff; 
    printf(" - %d - \n", atoi(szBuff)); 
    } 
    i++;  
    } 

    scanf("%d", &i); 

    CloseHandle(hSerial); 
} 
    } 

我的代碼的目標是像num = ReadSerialCOM(hSerial, "%d");

我當前的C++代碼從緩衝區讀取信息,但沒有一個可接受的行結束,這意味着我的數字(整數)被收到削減。

如:

我從Arduino的,哪些地方是在COM端口發送8889。命令ReadFile將'88'保存爲szBuff。在下一次迭代'89 \ n'被保存到sZBuff。基本上我想避免後處理sZBuff來連接'88'和'89 \ n'。

有人嗎? 謝謝!

+0

也許你曾在此格式它可能幫助? – 2010-08-11 02:29:31

+0

我在格式化文本時沒有問題,但我不確定您指的是什麼。代碼,「解釋」還是兩者? PS:注意引號的解釋。我不確定我是否很好地解釋了這個問題。 – sergi 2010-08-11 02:51:13

+0

只要使用原始API,就無法避免它。帶有實現ReadLine()的串口封裝器的類庫當然可用。 – 2010-08-11 02:58:21

回答

1

由於Hans Passantdauphic指出,它似乎不是我的問題的一般解決方案。我寫這封信,雖然,我試圖避免的代碼,以防萬一有人發現它有用或面對我有同樣的問題:

int i = 0; 
DWORD dwBytesRead = 0; 
DWORD dwCommStatus = 0; 
char szBuff[2] = "";     
int maxRead = 20; 
int sizeNum = 1;  
int *num = (int*)malloc(maxRead*sizeof(int)); 
char *currNum; 
char *pastNum; 

// Write something into the Serial Port to start receive 
// information from the Arduino 
WriteFile(hSerial, (LPCVOID)"A\0", 1, &dwBytesRead, NULL);  
SetCommMask(hSerial, EV_RXCHAR); 

// Start reading from the Serial Port 
while (i < maxRead) 
{ 
    WaitCommEvent (hSerial, &dwCommStatus, 0); 

    if (dwCommStatus & EV_RXCHAR) // if a char is received in the serial port 
    { 
     ReadFile(hSerial, LPVOID(szBuff), 1, &dwBytesRead, NULL); 

     if (szBuff[0] > 47 && szBuff[0] < 58) 
     { 
      sizeNum++; 
      if (sizeNum ==2) 
      { 
       currNum = (char*)malloc(sizeNum*sizeof(char)); 
       strcpy(currNum, szBuff); 
      } else 
      { 
       if (pastNum != NULL) 
        free(pastNum); 
       pastNum = currNum; 
       currNum = (char*)malloc(sizeNum*sizeof(char)); 
       strcpy(currNum, pastNum); 
       strcpy(currNum+(sizeNum-2)*sizeof(char), szBuff); 
      } 

      cout << szBuff<<endl; 
     } else if (szBuff[0] == '\n' && sizeNum > 1) // end of number 
     { 
      num[i] = atoi(currNum); 
      i++;      

      sizeNum = 1; 
      if (currNum!=NULL) 
       free(currNum); 
     } 
    } 
} 
1

如果我正確理解你的問題,避免「後期處理」的一種方法是將傳遞到ReadFile的指針移動到可用數據的末尾,以便ReadFile調用附加到緩衝區,而不是覆蓋。

基本上,你會有兩個指針。一個到緩衝區,另一個到緩衝區中數據的結尾。所以當你的程序啓動時,兩個指針都是一樣的。現在,你讀了前兩個字節。您將數據結束指針增加2。您執行另一次讀取,但不是szBuff,而是將指針傳遞到先前讀取的數據的末尾。您閱讀接下來的三個字節,並在szBuff中有完整的條目。

如果您需要等待某個分隔符來標記條目的結尾,您可以只搜索接收到的數據。如果它不在那裏,你會繼續閱讀直到找到它。如果它在那裏,你可以返回。

// Fill the buffer with 0 
char szBuff[256] = {0}; 
// We have no data in the buffer, so the end of data points to the beginning 
// of the buffer. 
char* szEndOfData = szBuff; 
while (i < maxSamples) 
{ 
    WaitCommEvent (hSerial, &dwCommStatus, 0); 

    if (dwCommStatus & EV_RXCHAR) 
    { 
     // Append up to 4 bytes from the serial port to the buffer 
     ReadFile(hSerial, LPVOID(szEndOfData), 4, &dwBytesRead, NULL); 
     // Increment the end of data pointer, so it points to the end of the 
     // data available in the buffer. 
     szEndOfData += dwBytesRead; 

     cout<<szBuff; 
     printf(" - %d - \n", atoi(szBuff)); 
    } 
    i++;  
} 

// Output, assuming what you mentioned happens: 
// - 88 - 
// - 8889 - 

如果這種方法對您來說是可以接受的,那就需要更多的工作。例如,你必須確保你不會溢出你的緩衝區。從緩衝區中刪除數據時,必須將刪除的段後的所有數據移動到開始處,並修復數據指針的結尾。或者,您可以使用循環緩衝區。

+0

謝謝你的回答。 這兩個系統(我現在正在使用的那個和你的解決方案)的問題是,在這兩種情況下,我將不得不繼續讀'char',直到我讀完行。然後把所有的char放在一起來重新創建初始的'int'。我確信,雖然看起來我錯了,但有一種類似於Matlab fscanf(h,'%d「)的解決方案已經解決了這個問題,儘管我還沒有發現類似的東西。在Matlab代碼中,這是通過終止符來完成的,我基本上想知道是否我錯過了函數的某些屬性。 – sergi 2010-08-11 03:02:00

+0

噢,我明白了,這基本上是fscanf的實現方式,但Windows不提供據我所知,任何可以做到的功能。 – 2010-08-11 03:29:43