Нашел неплохой пример для работы с протоколом Modbus RTU Code Project
Все бы ничего, но там нет реализации функции 0x06. Есть только 16 функция записи нескольких регистров. Как ее переделать в функцию 0х06
// sp это у меня SerialPort sp = new SerialPort private void
BuildMessage(byte address, byte type, ushort start, ushort registers,
ref byte[] message)
{
// Массив для CRC bytes:
byte[] CRC = new byte[2];
message[0] = address;
message[1] = type;
message[2] = (byte)(start >> 8);
message[3] = (byte)start;
message[4] = (byte)(registers >> 8);
message[5] = (byte)registers;
// Функция подсчета CRC
GetCRC(message, ref CRC);
message[message.Length - 2] = CRC[0];
message[message.Length - 1] = CRC[1];
}
public bool SendFc16(byte address, ushort start, ushort registers,
short[] values)
{
// Проверяю открыт ли порт
if (sp.IsOpen)
{
//Очишаю буфер
sp.DiscardOutBuffer();
sp.DiscardInBuffer();
//Сообщение 1 адрес + 1 функция + 2 старт + 2 регистр + 1 счетчик + 2 * значение регистров + 2 CRC
byte[] message = new byte[9 + 2 * registers];
//ответ 16 функции фиксированный и занимает 8 байт
byte[] response = new byte[8];
// Счетчик байт в сообщении:
message[6] = (byte)(registers * 2);
// Пишем:
for (int i = 0; i < registers; i++)
{
message[7 + 2 * i] = (byte)(values[i] >> 8);
message[8 + 2 * i] = (byte)(values[i]);
}
//Наше сообщение:
BuildMessage(address, (byte)16, start, registers, ref message);
}
if (ну тут организация проверки записи)
{
// Запись успешна;
return true;
}
else
{
// Ошибка CRC;
return false;
}
}
По идее тут:
BuildMessage(address, (byte)16, start, registers, ref message);
Заменить на так:
BuildMessage(address, (byte)6, start, registers, ref message);
И вот тут что-то надо поменять, в формировании посылки в сообщении, только что не могу разобрать:
// Счетчик байт в сообщении:
message[6] = (byte)(registers * 2);
// Пишем:
for (int i = 0; i < registers; i++)
{
message[7 + 2 * i] = (byte)(values[i] >> 8);
message[8 + 2 * i] = (byte)(values[i]);
}
Подскажите как тут сделать запись в один регистр. Заранее благодарен!
Функция 06 не имеет вариативной части в неё всегда передается значение одного регистра. Соотвествено размер пакета всегда равен 8 байтам. В вашем коде вы выделяете не правильное кол-во байт для пакета(new byte[9 + 2 * registers]).
Вот пример как создавать пакеты для функций 05 и 06
class AluCreator
{
// создает пакет для функции 05
public static byte[] CreateAlu05(byte address, byte function, ushort coilAddress, bool coilValue)
{
ushort coilValueShort = 0;
if (coilValue) {
coilValueShort = 0xFF00;
}
return CreateSingleValueWriteAlu(address, 0x05, coilAddress, coilValueShort);
}
// создает пакет для функции 06
public static byte[] CreateAlu06(byte address, byte function, ushort regAddress, ushort regValue)
{
return CreateSingleValueWriteAlu(address, 0x06, regAddress, regValue);
}
private static byte[] CreateSingleValueWriteAlu(byte address, byte function, ushort regAddress, ushort regValue)
{
var result = new byte[8];
result[0] = address;
result[1] = function;
result[2] = (byte)(regAddress >> 8);
result[3] = (byte)regAddress;
result[4] = (byte)(regValue >> 8);
result[5] = (byte)regValue;
var crc = GetCRC(result, 6);
result[6] = (byte)crc;
result[7] = (byte)(crc >> 8);
return result;
}
private static ushort GetCRC(byte[] data, int dataCount)
{
ushort crc = 0xFFFF;
for(int pos = 0; pos < dataCount; pos++) {
crc ^= (UInt16)data[pos];
for(int i = 8; i != 0; i--) {
if((crc & 0x0001) != 0) {
crc >>= 1;
crc ^= 0xA001;
}
else {
crc >>= 1;
}
}
}
return crc;
}
}
PS: Вообще на вики очень хорошо описана структура пакетов(посмотрите табличку PDU запроса и ответа для стандартных функций). Если сухое описание не очень понимается посмотрите примеры пакетов в интернете(например тут).
Апостиль в Лос-Анджелесе без лишних нервов и бумажной волокиты
Основные этапы разработки сайта для стоматологической клиники
Продвижение своими сайтами как стратегия роста и независимости