无法从串口接收数据

问题描述 投票:0回答:3

目前我尝试用VC++编写一个串口通信,通过XBee发射器从PC和机器人传输数据。但是在我编写了一些命令从机器人轮询数据后,我没有从机器人收到任何信息(代码中文件大小的输出为0)。因为我的 MATLAB 接口可以工作,所以问题应该发生在代码中,而不是硬件或通信中。请您帮我一下好吗?

01/03/2014 更新:我已经更新了我的代码。它仍然无法从我的机器人接收任何数据(读取的输出为0)。当我使用“cout<<&read" in the while loop, I obtain "0041F01C1". I also don't know how to define the size of buffer, because I don't know the size of data I will receive. In the codes, I just give it a random size like 103. Please help me.

// 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;
}
c++ serial-port robotics
3个回答
1
投票

GetFileSize 据记录在与串行端口句柄一起使用时无效。使用ReadFile函数接收串口数据。


0
投票

我的猜测是您在 while 循环中使用了错误的比较。串行通信总是需要一些时间,我不认为“ReadFile”功能旨在为数据接收增加一些延迟。因此,如果数据没有立即准备好,函数将返回“0”表示“读取”,并且您将离开 while 循环。在第一步中,我建议在循环条件中用“==”替换“!=”,然后考虑如何处理超时。

// assume that ReadFile will return '0' to the variable 'read' if no data is available on the serial interface or reception is ongoing
do {
    ReadFile(serialHandle, buffer, sizeof(buffer), &read, NULL);
    cout << read;
    // Repeat unless data is received on the serial port
    // NOTE: you are stuck here if no data is received on the serial port
} while (read == 0);

-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,如 这篇冗长的 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);

我建议您将对串行端口访问的实际调用包装在更简单的函数中是有原因的。 正如我之前所说,微软的界面是一场灾难。它们冗长、繁琐,而且一致性较差。直接使用它们会导致代码笨拙且混乱。

例如,在这里,您似乎对

read
buffer

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

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

此外,您应该为您的机器人准备一份文档,说明您应该期望哪种答案。了解它们的格式将有所帮助,例如它们是否是空终止字符串。这样就可以省去添加字符串终止符的麻烦。

© www.soinside.com 2019 - 2024. All rights reserved.