Found a good example for working with the Modbus RTU Code Project protocol

All anything, but there is no implementation of the function 0x06. There are only 16 function to write multiple registers. How to convert it into 0x06 function

// 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; } } 

In theory here:

 BuildMessage(address, (byte)16, start, registers, ref message); 

Replace with:

 BuildMessage(address, (byte)6, start, registers, ref message); 

And here something needs to be changed, in the formation of the parcel in the message, I just can not make out:

 // Счетчик байт в сообщении: 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]); } 

Tell me how to make an entry in one register. Thanks in advance!

    1 answer 1

    Function 06 has no variable part. The value of one register is always transferred to it. The appropriate packet size is always 8 bytes. In your code, you allocate an incorrect number of bytes for the package ( new byte[9 + 2 * registers] ).

    Here is an example of how to create packages for functions 05 and 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: In general, the wiki structure is very well described (see the request and response PDU label for standard functions ). If the dry description is not very understood, see the examples of packages on the Internet (for example, here ).

    • Thank you so much for your help and guidance! I will smoke and fill cones. Thanks again. - JDo