我遇到了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'。
任何? 谢谢!
答案 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 Passant和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);
}
}
}