This is all the code for polling the com port, according to the modbus-RTU protocol, the device does not respond. I can't figure out how to get the device to respond to me. The device address and the function code are enough to answer. These are the first two characters (0x15, 0x03 ...) I do not know what I am doing wrong!
There is a code:
#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;
}
CodePudding user response:
You don't need to heap-alloc a DCB; just use a stack variable. Also, you are using sizeof
on a pointer, so the DCBlength
field will not be populated accordingly. Simply do the following:
DCB dcbSerialParams = { 0 };
dcbSerialParams.DCBlength = sizeof(dcbSerialParams);
if (BuildCommDCB(L"baud=9600 parity=E data=8 stop=2", &dcbSerialParams))
....
Also in ReadCOM, although DWORD iSize;
is an OUT parameter, you should initialise it to zero to avoid a potential runtime error under debug ("variable x is used without being initialised")
CodePudding user response:
Did you check your request string with a terminal program f.e. hterm
?
As far as I know only two tx characters will not make an answer from the device, there is also a crc at end of a frame
https://www.der-hammer.info/pages/terminal.html
CodePudding user response:
The error was in the checksum, thanks for the help.
char data[] = { 0x15, 0x03, 0x00, 0x00, 0x00, 0x01, **0x87**, **0x1E**};