В настоящее время я пытаюсь записать связь с последовательным портом в VC++ для передачи данных с ПК и робота через передатчик XBee. Но после того, как я написал несколько команд для опроса данных из робота, я ничего не получил от робота (вывод файла в 0 равен 0). Поскольку мой интерфейс MATLAB работает, так что проблема должна произойти в коде, а не в аппаратном или коммуникационном. Не могли бы вы мне помочь?
01/03/2014 Обновлено: я обновил свои коды. Он по-прежнему не может получать никаких данных от моего робота (вывод read равен 0). Когда я использую "cout << & read" в цикле while, я получаю "0041F01C1". Я также не знаю, как определить размер буфера, потому что я не знаю размер данных, которые я получу. В кодах я просто даю ему случайный размер, например, 103. Пожалуйста, помогите мне.
// This is the main DLL file.
#include "StdAfx.h"
#include <iostream>
#define WIN32_LEAN_AND_MEAN //for GetCommState command
#include "Windows.h"
#include <WinBase.h>
using namespace std;
int main(){
char init[]="";
HANDLE serialHandle;
// Open serial port
serialHandle = CreateFile("\\\\.\\COM8", GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
// Do some basic settings
DCB serialParams;
DWORD read, written;
serialParams.DCBlength = sizeof(serialParams);
if((GetCommState(serialHandle, &serialParams)==0))
{
printf("Get configuration port has a problem.");
return FALSE;
}
GetCommState(serialHandle, &serialParams);
serialParams.BaudRate = CBR_57600;
serialParams.ByteSize = 8;
serialParams.StopBits = ONESTOPBIT;
serialParams.Parity = NOPARITY;
//set flow control="hardware"
serialParams.fOutX=false;
serialParams.fInX=false;
serialParams.fOutxCtsFlow=true;
serialParams.fOutxDsrFlow=true;
serialParams.fDsrSensitivity=true;
serialParams.fRtsControl=RTS_CONTROL_HANDSHAKE;
serialParams.fDtrControl=DTR_CONTROL_HANDSHAKE;
if (!SetCommState(serialHandle, &serialParams))
{
printf("Set configuration port has a problem.");
return FALSE;
}
GetCommState(serialHandle, &serialParams);
// Set timeouts
COMMTIMEOUTS timeout = { 0 };
timeout.ReadIntervalTimeout = 30;
timeout.ReadTotalTimeoutConstant = 30;
timeout.ReadTotalTimeoutMultiplier = 30;
timeout.WriteTotalTimeoutConstant = 30;
timeout.WriteTotalTimeoutMultiplier = 30;
SetCommTimeouts(serialHandle, &timeout);
if (!SetCommTimeouts(serialHandle, &timeout))
{
printf("Set configuration port has a problem.");
return FALSE;
}
//write packet to poll data from robot
WriteFile(serialHandle,">*>p4",strlen(">*>p4"),&written,NULL);
//check whether the data can be received
char buffer[103];
do {
ReadFile (serialHandle,buffer,sizeof(buffer),&read,NULL);
cout << read;
} while (read!=0);
//buffer[read]="\0";
CloseHandle(serialHandle);
return 0;
}
GetFileSize документируется недействительным при использовании с дескриптором последовательного порта. Используйте функцию ReadFile для получения данных последовательного порта.
Вы должны использовать strlen
вместо sizeof
здесь:
WriteFile(serialHandle,init,strlen(init),&written,NULL)
Вам было бы еще лучше создать такую функцию:
function write_to_robot (const char * msg)
{
DWORD written;
BOOL ok = WriteFile(serialHandle, msg, strlen(msg), &written, NULL)
&& (written == strlen(msg));
if (!ok) printf ("Could not send message '%s' to robot\n", msg);
}
Но это только закуска. Главная проблема заключается в том, что MDN говорит:
Вы не можете использовать функцию GetFileSize с рукоятью nonseeking устройства, такие как трубы или устройство связи.
Если вы хотите читать из порта, вы можете просто использовать ReadFile
пока не вернет нулевые байты.
Если вы уже знаете максимальный размер вашего ответа робота, попробуйте прочитать много символов. Продолжайте чтение до тех пор, пока прочитанное не сообщит об истинном количестве прочитанных байтов, меньших размера буфера. Например:
#define MAX_ROBOT_ANSWER_LENGTH 1000 /* bytes */
const char * read_robot_response ()
{
static char buffer[MAX_ROBOT_ANSWER_LENGTH];
DWORD read;
if (!ReadFile (serialHandle, buffer, sizeof(buffer), &read, NULL))
{
printf ("something wrong with the com port handle");
exit (-1);
}
if (read == sizeof(buffer))
{
// the robot response is bigger than it should
printf ("this robot is overly talkative. Flushing input\n");
// read the rest of the input so that the next answer will not be
// polluted by leftovers of the previous one.
do {
ReadFile (serialHandle, buffer, sizeof(buffer), &read, NULL);
} while (read != 0);
// report error
return "error: robot response exceeds maximal length";
}
else
{
// add a terminator to string in case Mr Robot forgot to provide one
buffer[read] = '\0';
printf ("Mr Robot said '%s'\n", buffer);
return buffer;
}
}
Эта упрощенная функция возвращает статическую переменную, которая будет перезаписана при каждом вызове read_robot_response.
Разумеется, правильным способом делать вещи было бы использование блокирующих входов/выходов, а не ждать одну секунду, и молиться, чтобы робот отвечал вовремя, но для этого потребовалось бы гораздо больше усилий.
Если вы считаете себя предприимчивым, вы можете использовать перекрывающиеся ввода-вывода, поскольку эта статья MDN подробно исследует.
EDIT: посмотрев ваш код
// this reads at most 103 bytes of the answer, and does not display them
if (!ReadFile(serialHandle,buffer,sizeof(buffer),&read,NULL))
{
printf("Reading data to port has a problem.");
return FALSE;
}
// this could display the length of the remaining of the answer,
// provided it is more than 103 bytes long
do {
ReadFile (serialHandle,buffer,sizeof(buffer),&read,NULL);
cout << read;
}
while (read!=0);
Вы не видите ничего, кроме длины ответа за пределами первых 103 полученных символов.
Это должно сделать трюк:
#define BUFFER_LEN 1000
DWORD read;
char buffer [BUFFER_LEN];
do {
if (!ReadFile(
serialHandle, // handle
buffer, // where to put your characters
sizeof(buffer) // max nr of chars to read
-1, // leave space for terminator character
&read, // get the number of bytes actually read
NULL)) // Yet another blody stupid Microsoft parameter
{
// die if something went wrong
printf("Reading data to port has a problem.");
return FALSE;
}
// add a terminator after last character read,
// so as to have a null terminated C string to display
buffer[read] = '\0';
// display what you actually read
cout << buffer;
}
while (read!=0);
Я посоветовал вам обернуть фактические вызовы для доступа к последовательному порту в более простых функциях по какой-либо причине. Как я уже говорил, интерфейсы Microsoft - это катастрофа. Они многословны, громоздки и только умеренно последовательны. Использование их напрямую приводит к неудобному и запутанному коду.
Здесь, например, вы, похоже, запутались между read
и buffer
buffer
- это то, что вы хотите отобразить, чтобы увидеть, что робот ответил вам
Кроме того, у вас должна быть документация для вашего робота, в которой указывается, какие ответы вы должны ожидать. Это поможет узнать, как они отформатированы, например, являются ли они строками с нулевым символом или нет. Это может обойтись без добавления ограничителя строк.
read
. Код был задуман как иллюстрация общего принципа, а не как полностью рабочая программа.