串行端口与Arduino和C ++的通信

时间:2010-08-11 02:27:05

标签: c++ serial-port arduino

我遇到了Arduino Nano和C ++之间的串口通信问题,即使问题出在C ++方面。基本上我想将Arduino中的整数(或long,...)发送到要处理的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 ++,使用fscanf(s1,'%d')在Matlab中完成相同的操作。

以下是我正在使用的当前代码(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发送8889,它将它放在COM端口。命令ReadFile将'88'保存到szBuff。在下一次迭代'89 \ n'保存到sZBuff。基本上我想避免后续处理sZBuff以连接'88'和'89 \ n'。

任何? 谢谢!

2 个答案:

答案 0 :(得分:1)

如果我正确理解你的问题,避免必须'后处理'的一种方法是将传递给ReadFile的指针移动到可用数据的末尾,这样ReadFile调用就是附加到缓冲区,而不是覆盖。

基本上,你会有两个指针。一个到缓冲区,另一个到缓冲区中的数据末尾。所以当你的程序启动时,两个指针都是一样的。现在,您读取前2个字节。将数据结束指针递增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 -

如果您接受这种方法,则需要更多工作。例如,您必须确保不会溢出缓冲区。从缓冲区中删除数据时,您必须将删除的段之后的所有数据移动到开头,并修复数据指针的结尾。或者,您可以使用循环缓冲区。

答案 1 :(得分: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);
        }
    }
}