Использование библиотеки ArduinoModbus для чтения регистра хранения со значением -1
client.read() в библиотеке ArduinoModbus возвращает -1 при возникновении ошибки: https://www.arduino.cc/reference/en/libraries/arduinomodbus/client.read/. Как её использовать для чтения регистра хранения со значением -1?
Одним из вариантов было бы отслеживать client.lastError(), но, похоже, нет способа сбросить lastError, поэтому это будет работать только до первой ошибки.
Я предполагаю, что для регистра со значением знакового типа, например int16_t, необходимо извлечь младшие 16 бит из значения uint32_t, возвращаемого функцией client.read().
@Paul Jurczak, 👍0
Обсуждение2 ответа
Согласно описанию в Википедии данных Modbus
модель, «входные регистры» и «регистры хранения» содержат 16-битные
Беззнаковые числа в диапазоне 0–65 535 (0x0000–0xffff). Это
в соответствии с прототипом ArduinoModbus client.write(),
который принимает параметр unsigned int.
Функция client.read(), с другой стороны, возвращает
long. Обычно это 32-битное число, которое может содержать все возможные значения
допустимые значения, а также −1 для обозначения состояния ошибки.
Если, в отличие от модели данных Modbus, ваше устройство Modbus передает
знаковые значения, вам следует проверить его техническое описание, чтобы увидеть, как отрицательные значения
закодированы. Скорее всего, будет использоваться дополнительный код
Представление, которое используется внутри Arduino. Если это
в этом случае то, что устройство хранит как −1, будет прочитано библиотекой как
65 535. Вы можете легко получить правильное число, преобразовав его в
int16_t:
long result = client.read(); // используйте `long`, чтобы не потерять информацию
if (result == -1) {
handle_the_error();
return;
}
int16_t value = result; // преобразовать в тип устройства
if (value == -1) {
handle_a_legit_minus_one();
}
Вот мой код для решения этой проблемы и дополнительного отделения кода ошибки от считанного значения. Модель данных Modbus, упомянутая в другом ответе, недостаточна для современного оборудования, что вынудило многих производителей выйти за её рамки и использовать регистры int32_t, uint32_t и float.
template<typename T>
bool holdingRegisterWrite16(ModbusTCPClient &modbus, int addr, T arg) {
return modbus.holdingRegisterWrite(addr, arg);
}
template<typename T>
bool holdingRegisterRead16(ModbusTCPClient &modbus, int addr, T &arg) {
static_assert(sizeof(T) == 2, "arg has to be a 16-bit type");
auto res = modbus.holdingRegisterRead(addr);
if (res == -1)
return false;
memcpy(&arg, &res, 2);
return true;
}
template<typename T>
bool holdingRegisterWrite32(ModbusTCPClient &modbus, int addr, T arg) {
uint16_t word0, word1;
memcpy(&word0, &arg, 2);
memcpy(&word1, (char*)&arg+2, 2);
return
modbus.beginTransmission(HOLDING_REGISTERS, addr, 2) &&
modbus.write(word0) && modbus.write(word1) && modbus.endTransmission();
}
template<typename T>
bool holdingRegisterRead32(ModbusTCPClient &modbus, int addr, T &arg) {
static_assert(sizeof(T) == 4, "arg has to be a 32-bit type");
if (modbus.requestFrom(HOLDING_REGISTERS, addr, 2) != 2)
return false;
auto res0 = modbus.read();
auto res1 = modbus.read();
if (res0 == -1 || res1 == -1)
return false;
memcpy(&arg, &res0, 2);
memcpy((char*)&arg+2, &res1, 2);
return true;
}
- Основная связь Arduino ModBus RTU с проблемой измерителя мощности
- Мониторинг контроллера Modbus RTU с помощью Arduino и модуля RS485
- Как заставить I2C работать на RS485?
- Есть ли хорошая рабочая библиотека MODBUS TCP master для Arduino?
- Ведомая библиотека Modbus RTU
- Как соединить несколько Arduino с RPI для управления домашним освещением и выключателями
- Когда дело доходит до связи UART-RS485, в чем разница между модулем "MAX485" и модулем "HW-0519"?
- Modbus IP с Simply Modbus TCP
Разве Modus не передаёт только байты? ... у них нет знака, @jsotola
@jsotola Регистры Modbus могут иметь отрицательные значения, поэтому знак имеет значение., @Paul Jurczak
Я предполагаю, что данные будут считываться как беззнаковое целое число... данные могут занимать 2 байта, а значение, возвращаемое библиотекой, — 4 байта... верхние два байта используются для того, чтобы сделать число отрицательным., @jsotola
@jsotola Да, думаю, так. Я как раз добавлял комментарий к своему посту по этому поводу, а вы уже отправили свой., @Paul Jurczak
Вот пример того, как это работает... Первая строка будет сообщением об ошибке... Второе 32-битное значение не является отрицательным, но 16-битные данные отрицательны... https://wokwi.com/projects/403163467946550273, @jsotola
Существуют две ошибки, возвращающие -1. Для библиотеки Modbus Arduino ошибка клиента (-1) означает «Ошибка ввода-вывода». Для протокола Modbus исключение 1 означает «Недопустимый код функции». Вызов client.lastError() вернёт строковую интерпретацию кода ошибки. Пожалуйста, предоставьте свой код и то, что вы пытаетесь сбросить/установить через Modbus. Вы используете протокол TCP или RTU?, @hcheung
Как передать
int16_tв качестве кода функции Modbus? Почему для кода функции Modbus нужно использоватьint16_tвместоuint16_tили двух байтuint8_t? Знаете ли вы, что Modbus использует Big Endian при передаче, в то время как данные, хранящиеся в Arduino, — в Small Endian?, @hcheung@hcheung Я разместил свой код в качестве ответа., @Paul Jurczak