В настоящее время я пытаюсь написать последовательный порт связи в VC ++ для передачи данных с ПК и робота через передатчик XBee. Но после того, как я написал несколько команд для опроса данных от робота, я ничего не получил от робота (выходной размер файла равен 0 в коде.). Поскольку мой интерфейс MATLAB работает, проблема должна возникать в коде, а не в аппаратном обеспечении или связи. Не могли бы вы мне помочь?
01.01.2014 Обновлено: Я обновил свои коды. Он все еще не может получить никаких данных от моего робота (результат чтения равен 0). Когда я использую «Cout<<&прочитайте «в цикле 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 работать с ручкой незнакомого устройства, такого как трубка или устройство связи.
Если вы хотите читать из порта, вы можете просто использовать 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 тщательно исследует
РЕДАКТИРОВАТЬ: после просмотра вашего кода
// 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
это то, что вы хотите отобразить, чтобы увидеть, что робот ответил вам
Кроме того, у вас должна быть документация для вашего робота с указанием того, какие ответы вы должны ожидать. Было бы полезно знать, как они форматируются, например, являются ли они строками с нулевым символом в конце или нет. Это может обойтись без добавления терминатора строки.