Связь Последовательного порта с Ардуино и C++

У меня есть проблема с коммуникацией Последовательного порта между Нано Ардуино и C++, даже при том, что проблема находится в стороне C++. В основном я хочу отправить целые числа (или долго...) от Ардуино до программы C++, которая будет обработана.

Сначала я сделал тестовую информацию об отправке от Ардуино до использующего компьютеры Matlab. Код Ардуино довольно прост:

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++ читает информацию из буфера, но нет принятого конца строки, которая подразумевает, что мои числа (целые числа) получены сокращение.

Например:

Я отправляю 8889 из Ардуино, который помещает его в COM-порт. И команда ReadFile сохраняет '88' в szBuff. При следующем повторении '89\n' сохраняется в sZBuff. В основном я не хочу выполнять последующую обработку sZBuff к concat '88' и '89\n'.

Кто-либо?Спасибо!

1
задан sergi 11 August 2010 в 03:12
поделиться

2 ответа

Как указали Ханс Пассан и dauphic , это не кажется общим решением моего вопроса. Однако я пишу код, которого пытался избежать, на случай, если кто-то сочтет его полезным или столкнется с той же проблемой, что и у меня:

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
ответ дан 2 September 2019 в 22:17
поделиться

Если я правильно понимаю ваш вопрос, один из способов избежать «пост-обработки» - переместить указатель, переданный в 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
ответ дан 2 September 2019 в 22:17
поделиться
Другие вопросы по тегам:

Похожие вопросы: