【问题标题】:Unable to use windows.h ReadFile correctly on COM port. WriteFile seems to work fine无法在 COM 端口上正确使用 windows.h ReadFile。 WriteFile 似乎工作正常
【发布时间】:2015-03-25 13:21:44
【问题描述】:

我正在尝试使用 windows.h 库通过 RS232 与设备进行通信(SCPI 通信)。我查看了几个关于如何设置的教程和指南,并认为我的代码应该可以正常工作。我可以使用 WriteFile 向设备发送数据。但是,我无法使用 ReadFile 接收任何数据(ReadFile 不会产生错误,但缓冲区大小为 0)。这是我的代码:

#include <stdio.h>
#include <windows.h>

void main ()
{
  // CreateFile
  HANDLE rs232 = CreateFileA ("\\\\.\\COM1", GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0);
  if (rs232 == INVALID_HANDLE_VALUE)
  {
    printf ("fail CreateFile: %d\n", GetLastError ()); system ("pause"); return;
  }

  // Get & Set CommState
  DCB port_configuration;
  int err = GetCommState (rs232, &port_configuration);
  if (err <= 0)
  {
    printf ("fail GetCommState: %d\n", GetLastError ()); CloseHandle (rs232); system ("pause"); return;
  }
  port_configuration.BaudRate = 19200;
  port_configuration.ByteSize = 8;
  port_configuration.Parity = 0;
  port_configuration.StopBits = 0;
  port_configuration.DCBlength = sizeof (port_configuration);
  err = SetCommState (rs232, &port_configuration);
  if (err <= 0)
  {
    printf ("fail SetCommState\n"); CloseHandle (rs232); system ("pause"); return;
  }

  // SetCommTimeouts
  COMMTIMEOUTS timeout_configuration;
  timeout_configuration.ReadIntervalTimeout = 1;// MAXDWORD;
  timeout_configuration.ReadTotalTimeoutMultiplier = 1;// 0;
  timeout_configuration.ReadTotalTimeoutConstant = 1;// 0;
  timeout_configuration.WriteTotalTimeoutMultiplier = 1;// 0;
  timeout_configuration.WriteTotalTimeoutConstant = 1;// 0;
  err = SetCommTimeouts (rs232, &timeout_configuration);
  if (err <= 0)
  {
    printf ("fail SetCommTimeouts: %d\n", GetLastError ()); CloseHandle (rs232); system ("pause"); return;
  }

  // WriteFile
  DWORD buffer_size_w;
  char buffer_w[128] = "*IDN?\n";
  err = WriteFile (rs232, buffer_w, strlen (buffer_w), &buffer_size_w, 0);
  if (err <= 0)
  {
    printf ("fail WriteFile: %d\n", GetLastError ()); CloseHandle (rs232); system ("pause"); return;
  }
  printf ("written %d characters: %s\n", buffer_size_w, buffer_w);

  // ReadFile
  for (int x = 0; x < 10; ++x)
  {
    DWORD buffer_size_r;
    char buffer_r[128] = {0};
    err = ReadFile (rs232, buffer_r, 128, &buffer_size_r, 0);
    if (err <= 0)
    {
      printf ("fail ReadFile: %d\n", GetLastError ()); Sleep (250); continue;
    }
    printf ("read %d characters: %s\n", buffer_size_r, buffer_r);
    Sleep (250);
  }

  CloseHandle (rs232);
  system ("pause");
}

以下是有关我的设置的更多信息:

  • 我使用的是 Windows 7 x64 和 Microsoft Visual Studio 2013
  • 项目编译为 Win32 控制台
  • 我使用 FTDI Chipi-X USB 到 COM 端口转换器电缆
  • 我已尝试连接 Newport 运动控制器和 Thorlabs 压电控制器

以下是我迄今为止尝试过的事情:

  1. 更新 Chipi-X VCOM 的驱动程序
  2. 将 COMMTIMEOUTS 更改为各种不同的值,如在线指南中所示
  3. 使用超级终端,我能够与设备完全来回通信。如果我使用自己的程序发送请求设备某些内容的命令,例如“*IDN?\n”,那么我自己的 ReadFile 将不会返回任何内容。但是,当我再次连接超级终端时,我可以按 ENTER 来接收请求的信息。
  4. 使用 SetupComm() 更改缓冲区大小
  5. 将 ReadFile 缓冲区大小更改为一次 1 个字节
  6. 按照本指南中的说明实施 OVERLAPPED 方法:https://msdn.microsoft.com/en-us/library/ff802693.aspx。它给出了与上面的非重叠代码完全相同的问题:windows 函数不会产生错误,但读取缓冲区会保持空。
  7. 我尝试与不同的设备通信,这很有趣:我再次能够使用超级终端完全来回通信。每当我使用自己的程序发送时,我总是会收到我使用 ReadFile 发回的确切字符串。同样,可以通过重新连接超级终端来检索实际请求的信息。

在我看来,缓冲区有一些问题,但我不知道是什么。我也不确定超级终端是否能够通过不同的 COM 端口连接获取几秒钟前请求的请求信息。可能问题与我的编码有关,因为超级终端工作正常,但如果我将它与我在网上找到的其他代码进行比较,我似乎无法找到我的代码有什么问题。

有人可以帮我吗?

编辑:

  1. 我使用以下示例创建了一个新的 CLR/C++ 测试应用程序:https://msdn.microsoft.com/en-us/library/system.io.ports.serialport(v=vs.110).aspx。这再次给出了无法接收请求的完全相同的问题。
  2. 我尝试了 Roline USB 到 RS232 电缆:超级终端可以正常工作,而我的编程却不行。底层硬件或驱动程序可能不是这里的问题。

【问题讨论】:

  • 您的超时时间太短了。不要忽略 DCB 中的握手配置。首先让它与另一个程序(如 Putty 或 Hyperterminal)一起工作,这样您就可以确保设备和电缆正常工作。如有必要,请使用 PortMon 等串行端口监控程序来重现完全相同的 DCB。
  • 我尝试过更长的超时时间,但它给出了同样的问题。我现在把它们设置得很短,因为我在 for 循环中使用了 ReadFile(它自己的睡眠时间为 250 毫秒)。正如我已经发布的那样,我使用了超级终端并且效果很好。此外,当我使用自己的程序进行连接并使用 GetCommState 时,它​​应该为我提供与超级终端中使用的完全相同的握手配置。我刚刚尝试了不同的握手配置,但这并没有解决它。我尝试使用 PortMon,但它无法在 Windows 7 x64 上运行,即使更改了兼容模式。

标签: c++ windows serial-port readfile


【解决方案1】:

我解决了这个问题:

我忘记在命令末尾发送回车符 (\r)。显然,我正在测试的设备在实际解析请求之前都在等待组合 \r\n 。 不知何故,通过使用超级终端,我可以将 \r\n 附加到当前的 COM 端口输出缓冲区并得到这样延迟的结果。

【讨论】:

    猜你喜欢
    • 2017-09-04
    • 2012-05-06
    • 2013-02-17
    • 2017-10-09
    • 2017-08-03
    • 2014-05-02
    • 2011-09-11
    • 2016-02-11
    • 1970-01-01
    相关资源
    最近更新 更多