Невозможно правильно использовать windows.h ReadFile на COM-порту. WriteFile вроде нормально работает

Я пытаюсь использовать библиотеку 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. Используя HyperTerminal, я могу полностью обмениваться данными с устройством. Если я использую свою собственную программу для отправки команд, которые запрашивают что-то от устройства, например, "*IDN?\ N", мой собственный файл ReadFile, таким образом, ничего не вернет. Однако, когда я снова подключаю HyperTerminal, я могу нажать ENTER, чтобы получить запрошенную информацию.
  4. Измените размеры буфера с помощью SetupComm()
  5. Измените размер буфера ReadFile на 1 байт за раз
  6. Реализуйте метод OVERLAPPED, как описано в этом руководстве: https://msdn.microsoft.com/en-us/library/ff802693.aspx. Это дало точно такую ​​же проблему, что и неперекрытый код выше: функции windows не будут генерировать ошибок, но буфер чтения останется пустым.
  7. Я попытался установить связь с другим устройством, это было интересно: я снова смог полностью обмениваться данными, используя HyperTerminal. Всякий раз, когда я использовал свою собственную программу для отправки, я всегда получал точную строку, которую я отправил обратно, используя ReadFile. И снова актуальная запрошенная информация может быть получена путем повторного подключения HyperTerminal.

Мне кажется, что есть некоторые проблемы с буферами, но я не знаю что. Я также не уверен, что ожидается, что HyperTerminal сможет получать запрошенную информацию, которая была запрошена несколькими секундами ранее, через другое соединение COM-порта. Предположительно, проблема связана с моим кодированием, поскольку HyperTerminal работает нормально, но я не могу найти, что не так с моим кодом, если сравнить его с другим кодом, который я нахожу в сети.

Может ли кто-нибудь помочь мне здесь?

РЕДАКТИРОВАТЬ:

  1. Я создал новое тестовое приложение CLR/C++, используя следующий пример: https://msdn.microsoft.com/en-us/library/system.io.ports.serialport(v=vs.110).aspx. Это опять-таки создает ту же проблему невозможности получать запросы.
  2. Я пробовал кабель Roline USB к RS232: HyperTerminal работает, а программирование - нет. Базовое оборудование или драйверы, скорее всего, не являются проблемой здесь.

1 ответ

Я решил вопрос:

Я забыл отправить возврат каретки (\r) в конце моих команд. Очевидно, что устройства, которые я тестировал с обоими, ожидали комбинации \ r \ n, прежде чем на самом деле проанализировали запрос. Каким-то образом с помощью гипертерминала я смогу добавить \ r \ n к текущему выходному буферу COM-порта и получить результаты с такой задержкой.

Другие вопросы по тегам