【问题标题】:how to poll a com port in c++如何在 C++ 中轮询 com 端口
【发布时间】:2022-01-03 13:42:30
【问题描述】:

这是所有轮询com口的代码,根据modbus-RTU协议,设备没有响应。我不知道如何让设备响应我。设备地址和功能码足以回答。这些是前两个字符(0x15、0x03 ...) 我不知道我做错了什么!

有一个代码:

#include <windows.h>
#include <stdio.h>
#include <iostream>
#include <TCHAR.h>
using namespace std;
#pragma warning(disable:4996)
//обработчик COM порта
HANDLE hSerial;
//название порта
LPCTSTR sPortName = L"COM3";
int ReadCOM()
{
    int a = 0;
    DWORD iSize;
    char sReceivedChar = { 0 };
    char recBuf[100] = { 0 };
    recBuf[0] = '\0';
    while (!a)
    {
        //получение ответа
        ReadFile(hSerial, &sReceivedChar, 1, &iSize, 0);  // получаем 1 байт

        if (iSize > 0)   // если что-то принято, выводим
        {
            cout << "Answer: " << sReceivedChar;
            strcat(recBuf, &sReceivedChar);
        }
        else
        {
            cin >> a;
        }
    }
    CloseHandle(hSerial);
    return 0;
}
int _tmain(int argc, _TCHAR* argv[])
{

    //настройка параметров соединения (В данном случае COM порта)
    DCB *dcbSerialParams = (DCB*)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(DCB));;
    dcbSerialParams->DCBlength = sizeof(dcbSerialParams);
    if (BuildCommDCB(L"baud=9600 parity=E data=8 stop=2", dcbSerialParams))
    {
        std::cout << "success 1" << std::endl;
    }
    else
    {
        std::cout << "failure 1" << std::endl;
    }
    dcbSerialParams->fNull = TRUE;


    //установка таймаута приема и передачи порта
    COMMTIMEOUTS CommTimeOuts;
    CommTimeOuts.ReadIntervalTimeout = 1000;
    CommTimeOuts.ReadTotalTimeoutConstant = CommTimeOuts.ReadTotalTimeoutMultiplier = 100;
    CommTimeOuts.WriteTotalTimeoutConstant = CommTimeOuts.WriteTotalTimeoutMultiplier = 100;


    //открытие порта для чтения/записи
    hSerial = CreateFile(sPortName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
    //проверка роботоспособности (не работает)
    if (hSerial == INVALID_HANDLE_VALUE)
    {
        if (GetLastError() == ERROR_FILE_NOT_FOUND)
        {
            cout << "wrn::Serial port does NOT exist.\n";
        }
        else
        {
            cout << "wrn::Some other error occurred.\n";
        }
    }
    //(работает) пишем соответствующее сообщение
    else
    {
        cout << "suc::Serial port DOES exist.\n";
    }
    //запись свойств порта
    if (!SetCommState(hSerial, dcbSerialParams))
    {
        cout << "faulure 2" << endl;
    }
    if (!SetCommTimeouts(hSerial, &CommTimeOuts))
    {
        cout << "failure 3" << endl;
    }
    //Освобождение DCB
    HeapFree(GetProcessHeap(), 0, dcbSerialParams);

    //char data[] = { 0x15, 0x03, 0x6B, 0x03, 0x37, 0x7E };
    char data[] = { 0x15, 0x03, 0x00, 0x00, 0x00, 0x01, 0x84, 0x0A};
 
    DWORD dwSize = sizeof(data);            // размер этой строки
    DWORD dwBytesWritten;               // тут будет количество собственно переданных байт
    BOOL iRet = WriteFile(hSerial, data, dwSize, &dwBytesWritten, NULL);
    //нормальная работа
    if (iRet)
    {
        cout << "nor :: " << dwSize << " Bytes in string. " << dwBytesWritten << " Bytes sended. " << endl;
    }
    //ошибка передачи
    else
    {
        cout << "wrn :: " << "db = " << dwBytesWritten << "\nds = " << dwSize << endl;
    }


    ReadCOM();
    return 0;
}

【问题讨论】:

  • 对二进制数据使用字符串操作函数(例如strcat)肯定会在您第一次读取值为零的字节时失败。更合适的方法是使用std::vector。如果您的其余代码准备好处理嵌入了 NUL 字符的字符串,即使 std::string 也可以工作。

标签: c++ winapi


【解决方案1】:

您不需要堆分配 DCB;只需使用堆栈变量。此外,您在指针上使用 sizeof,因此不会相应地填充 DCBlength 字段。只需执行以下操作:

DCB dcbSerialParams = { 0 };
dcbSerialParams.DCBlength = sizeof(dcbSerialParams);
if (BuildCommDCB(L"baud=9600 parity=E data=8 stop=2", &dcbSerialParams))
....

同样在ReadCOM中,虽然DWORD iSize;是一个OUT参数,但你应该将其初始化为零以避免在调试时出现潜在的运行时错误(“变量x在没有被初始化的情况下被使用”)

【讨论】:

    【解决方案2】:

    您是否使用终端程序 f.e. 检查了您的请求字符串? hterm? 据我所知,只有两个 tx 字符不会从设备做出应答,帧末尾还有一个 crc

    https://www.der-hammer.info/pages/terminal.html

    【讨论】:

      【解决方案3】:

      错误在校验和中,感谢您的帮助。

      char data[] = { 0x15, 0x03, 0x00, 0x00, 0x00, 0x01, **0x87**, **0x1E**};
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-06-23
        • 1970-01-01
        • 2010-12-04
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多