Не получается опросить прибор ТРМ138 по протоколу modbus RTU через rs485
Скомпилировал программу для опроса прибора хоть какого-то регистра, что бы получить хоть какой то ответ. Но в консоль выводится "ожидание ответа прибора". Я так понимаю проблема в самой команде modbus? Вот код:
#include <iostream>
#include <windows.h>
#include <vector>
#include <iomanip>
#include <fstream>
#include <locale>
// Функция для открытия последовательного порта
HANDLE openSerialPort(const std::string& portName, int baudRate, int byteSize, int stopBits, int parity) {
HANDLE hSerial = CreateFile(portName.c_str(), GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
if (hSerial == INVALID_HANDLE_VALUE) {
std::wcerr << L"Ошибка открытия порта: " << GetLastError() << std::endl;
return INVALID_HANDLE_VALUE;
}
DCB dcbSerialParams = {0};
dcbSerialParams.DCBlength = sizeof(dcbSerialParams);
if (!GetCommState(hSerial, &dcbSerialParams)) {
std::wcerr << L"Ошибка получения состояния порта: " << GetLastError() << std::endl;
CloseHandle(hSerial);
return INVALID_HANDLE_VALUE;
}
dcbSerialParams.BaudRate = baudRate;
dcbSerialParams.ByteSize = byteSize;
dcbSerialParams.StopBits = stopBits;
dcbSerialParams.Parity = parity;
if (!SetCommState(hSerial, &dcbSerialParams)) {
std::wcerr << L"Ошибка установки параметров порта: " << GetLastError() << std::endl;
CloseHandle(hSerial);
return INVALID_HANDLE_VALUE;
}
return hSerial;
}
// Функция для отправки команды на устройство
bool sendCommand(HANDLE hSerial, const std::vector<uint8_t>& command) {
DWORD bytesWritten;
if (!WriteFile(hSerial, command.data(), command.size(), &bytesWritten, NULL)) {
std::wcerr << L"Ошибка отправки команды: " << GetLastError() << std::endl;
return false;
}
return bytesWritten == command.size();
}
// Функция для чтения ответа от устройства
std::vector<uint8_t> readResponse(HANDLE hSerial, size_t expectedSize) {
std::vector<uint8_t> response(expectedSize);
DWORD bytesRead;
if (!ReadFile(hSerial, response.data(), expectedSize, &bytesRead, NULL)) {
std::wcerr << L"Ошибка чтения ответа: " << GetLastError() << std::endl;
return {};
}
response.resize(bytesRead);
return response;
}
// Функция для вычисления контрольной суммы CRC
uint16_t calculateCRC(const std::vector<uint8_t>& data) {
uint16_t crc = 0xFFFF;
for (size_t i = 0; i < data.size(); i++) {
crc ^= data[i];
for (int j = 0; j < 8; j++) {
if (crc & 1)
crc = (crc >> 1) ^ 0xA001;
else
crc >>= 1;
}
}
return crc;
}
// Функция для записи ответа в файл
void logResponse(const std::vector<uint8_t>& response, const std::string& filename) {
std::ofstream file(filename);
if (file.is_open()) {
for (const auto& byte : response) {
file << std::hex << std::setw(2) << std::setfill('0') << static_cast<int>(byte) << " ";
}
file.close();
} else {
std::wcerr << L"Не удалось открыть файл для записи: " << std::wstring(filename.begin(), filename.end()) << std::endl;
}
}
int main() {
setlocale(LC_ALL, "Russian");
std::wcout.imbue(std::locale(""));
const std::string portName = "COM6";
int baudRate = 9600;
int byteSize = 8;
int stopBits = ONESTOPBIT;
int parity = NOPARITY;
uint8_t deviceAddress = 0x01; // Адрес устройства
uint16_t registerAddress = 0x0000; // Адрес регистра для чтения
const std::string logFilename = "modbus_log.txt";
std::wcout << L"Открытие порта " << std::wstring(portName.begin(), portName.end()) << L"..." << std::endl;
HANDLE hSerial = openSerialPort(portName, baudRate, byteSize, stopBits, parity);
if (hSerial == INVALID_HANDLE_VALUE) {
std::wcerr << L"Не удалось подключиться к порту " << std::wstring(portName.begin(), portName.end()) << std::endl;
system("pause");
return 1;
}
std::wcout << L"Порт открыт успешно." << std::endl;
// Формирование команды на чтение регистра
std::wcout << L"Формирование команды для чтения регистра..." << std::endl;
std::vector<uint8_t> command = {deviceAddress, 0x03, static_cast<uint8_t>(registerAddress >> 8), static_cast<uint8_t>(registerAddress & 0xFF), 0x00, 0x01};
uint16_t crc = calculateCRC(command);
command.push_back(crc & 0xFF);
command.push_back((crc >> 8) & 0xFF);
std::wcout << L"Отправка команды на устройство..." << std::endl;
if (!sendCommand(hSerial, command)) {
std::wcerr << L"Не удалось отправить команду." << std::endl;
CloseHandle(hSerial);
system("pause");
return 1;
}
std::wcout << L"Команда отправлена успешно." << std::endl;
// Ожидание ответа от устройства
std::wcout << L"Ожидание ответа от устройства..." << std::endl;
std::vector<uint8_t> response = readResponse(hSerial, 7);
if (response.empty()) {
std::wcerr << L"Не удалось получить ответ от устройства." << std::endl;
CloseHandle(hSerial);
system("pause");
return 1;
}
std::wcout << L"Ответ получен: ";
for (uint8_t byte : response) {
std::wcout << std::hex << std::setw(2) << std::setfill(L'0') << static_cast<int>(byte) << L" ";
}
std::wcout << std::endl;
std::wcout << L"Запись ответа в файл..." << std::endl;
logResponse(response, logFilename);
std::wcout << L"Ответ сохранен в файл: " << std::wstring(logFilename.begin(), logFilename.end()) << std::endl;
CloseHandle(hSerial);
std::wcout << L"Завершение работы программы." << std::endl;
system("pause");
return 0;
}
У меня вопрос, причина того что прибор не отвечает на мои команды в том что команды не корректны? Что получается лучше использовать библиотеку modbus? Но она же будет делать тоже самое? Или она в автомате сможет найти нужный подход к прибору? К слову прибор отлично опрашивается программой конфигуратор от завода изготовителя.
Вот какие настройки в приборе для обмена: Скорость обмена 9600 Длина слова данных 8 бит Контроль по чётности отсутствует Количество стоп битов в посылке 1 Длина сетевого адреса 8 бит. Базовый адрес прибора 0 Количество фильтров сообщений 0 Протокол выставил modbus RTU