Невозможно правильно использовать 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
Вот что я пробовал до сих пор:
- Обновите драйверы Chipi-X VCOM
- Измените COMMTIMEOUTS на различные значения, как показано в руководствах онлайн
- Используя HyperTerminal, я могу полностью обмениваться данными с устройством. Если я использую свою собственную программу для отправки команд, которые запрашивают что-то от устройства, например, "*IDN?\ N", мой собственный файл ReadFile, таким образом, ничего не вернет. Однако, когда я снова подключаю HyperTerminal, я могу нажать ENTER, чтобы получить запрошенную информацию.
- Измените размеры буфера с помощью SetupComm()
- Измените размер буфера ReadFile на 1 байт за раз
- Реализуйте метод OVERLAPPED, как описано в этом руководстве: https://msdn.microsoft.com/en-us/library/ff802693.aspx. Это дало точно такую же проблему, что и неперекрытый код выше: функции windows не будут генерировать ошибок, но буфер чтения останется пустым.
- Я попытался установить связь с другим устройством, это было интересно: я снова смог полностью обмениваться данными, используя HyperTerminal. Всякий раз, когда я использовал свою собственную программу для отправки, я всегда получал точную строку, которую я отправил обратно, используя ReadFile. И снова актуальная запрошенная информация может быть получена путем повторного подключения HyperTerminal.
Мне кажется, что есть некоторые проблемы с буферами, но я не знаю что. Я также не уверен, что ожидается, что HyperTerminal сможет получать запрошенную информацию, которая была запрошена несколькими секундами ранее, через другое соединение COM-порта. Предположительно, проблема связана с моим кодированием, поскольку HyperTerminal работает нормально, но я не могу найти, что не так с моим кодом, если сравнить его с другим кодом, который я нахожу в сети.
Может ли кто-нибудь помочь мне здесь?
РЕДАКТИРОВАТЬ:
- Я создал новое тестовое приложение CLR/C++, используя следующий пример: https://msdn.microsoft.com/en-us/library/system.io.ports.serialport(v=vs.110).aspx. Это опять-таки создает ту же проблему невозможности получать запросы.
- Я пробовал кабель Roline USB к RS232: HyperTerminal работает, а программирование - нет. Базовое оборудование или драйверы, скорее всего, не являются проблемой здесь.
1 ответ
Я решил вопрос:
Я забыл отправить возврат каретки (\r) в конце моих команд. Очевидно, что устройства, которые я тестировал с обоими, ожидали комбинации \ r \ n, прежде чем на самом деле проанализировали запрос. Каким-то образом с помощью гипертерминала я смогу добавить \ r \ n к текущему выходному буферу COM-порта и получить результаты с такой задержкой.