无法从串行端口接收数据

时间:2013-12-31 21:22:11

标签: c++ serial-port robotics

目前我尝试在VC ++中编写串口通信,通过XBee发送器从PC和机器人传输数据。但是在我写了一些命令来从机器人轮询数据后,我没有从机器人那里收到任何东西(在代码中,filesize的输出为0)。因为我的MATLAB接口有效,所以问题应该发生在代码而不是硬件或通信中。你能帮我一下吗?

01/03/2014更新:我更新了我的代码。它仍然无法从我的机器人接收任何数据(读取的输出为0)。当我在while循环中使用“cout<<& read”时,我获得“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;
}

2 个答案:

答案 0 :(得分:1)

当使用串行端口句柄时,记录GetFileSize无效。使用ReadFile函数接收串口数据。

答案 1 :(得分:-1)

您应该使用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时都会被覆盖。

当然,正确的做法是使用阻塞I / O而不是等待一秒钟并祈祷机器人及时回答,但这需要更多的努力。

如果您有冒险精神,可以使用重叠I / O,this lenghty MDN article进行彻底探讨。

编辑:看了你的代码后

// 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);

我建议你把更简单的函数中的实际调用包装到串口访问中是有原因的。 正如我之前所说,微软接口是一场灾难。它们冗长,繁琐且只是中等一致。直接使用它们会导致代码笨拙和混淆。

例如,您似乎在readbuffer之间感到困惑

  • read保存实际从串口读取的字节数
  • 缓冲区保存实际数据。

buffer是您想要显示以查看机器人对您的回答

的内容

此外,您应该有一份机器人文档,说明您应该期望哪种答案。它将有助于了解它们的格式,例如它们是否是以空字符结尾的字符串。这可以免除添加字符串终止符。