读取设备modbus C#的响应

时间:2018-06-15 21:30:35

标签: c# modbus

大家下午好。遇到问题:必须使用modbus协议从设备读取数据。我无法理解如何从设备获得响应。

所以我调用了我的函数,但是如何从设备中获取数据?也许有人可以提供帮助。

P.S。请不要建议使用现成的库,比如nmodbus - 和他们一起做了我所做的一切,我想自己尝试一下。谢谢。

static void Main(string[] args)
    {
        var serial = new SerialPort("COM6", 19200);
        serial.Handshake = Handshake.None;
        serial.Parity = Parity.None;
        serial.DataBits = 8;
        serial.StopBits = StopBits.One;
        serial.Open();

        serial.Write(ReadHoldingRegister(2, 1024, 16), 0, 8);

        serial.Close();
        Console.ReadLine();
    }

    #region Function 3
    public static byte[] ReadHoldingRegister(int id, int startAddress, int length)
    {
        byte[] data = new byte[8];
        byte High, Low;

        data[0] = Convert.ToByte(id);
        data[1] = Convert.ToByte(3);

        byte[] _adr = BitConverter.GetBytes(startAddress - 1);

        data[2] = _adr[1];
        data[3] = _adr[0];

        byte[] _length = BitConverter.GetBytes(length);

        data[4] = _length[1];
        data[5] = _length[0];

        myCRC(data, 6, out High, out Low);

        data[6] = Low;
        data[7] = High;

        return data;
    }
    #endregion

    #region CRC
    public static void myCRC(byte[] message, int length, out byte CRCHigh, out byte CRCLow)
    {
        ushort CRCFull = 0xFFFF;
        for (int i = 0; i < length; i++)
        {
            CRCFull = (ushort)(CRCFull ^ message[i]);
            for (int j = 0; j < 8; j++)
            {
                if ((CRCFull & 0x0001) == 0)
                    CRCFull = (ushort)(CRCFull >> 1);
                else
                {
                    CRCFull = (ushort)((CRCFull >> 1) ^ 0xA001);
                }
            }
        }
        CRCHigh = (byte)((CRCFull >> 8) & 0xFF);
        CRCLow = (byte)(CRCFull & 0xFF);
    }
    #endregion
}

1 个答案:

答案 0 :(得分:0)

处理响应不是“简单”的,您确实需要考虑错误,字符间和包间定时等问题。它也可能应该在单独的高优先级线程上。 Modbus规范具有一些处理状态图,这些状态图说明了(至少)应执行的操作。但是,作为一个非常简单,强力的民意调查示例,您可以从以下内容开始:

static Queue<byte> GetResponse(SerialPort serial, int timeoutMSecs)
{
    Queue<byte> response = new Queue<byte>();

    Stopwatch stopwatch = new Stopwatch();
    stopwatch.Start();

    while (stopwatch.ElapsedMilliseconds < timeoutMSecs)
    {
        if (serial.BytesToRead == 0) continue;      // Nothing received, continue waiting

        response.Enqueue((byte)serial.ReadByte());  // Add rx byte to queue
        stopwatch.Reset();                          // Reset timeout

        if (response.Count > 255) break;            // Maximum RTU packet?
    }

    return response;
}

在主要功能中

static void Main(string[] args)
{
    ...
    serial.DiscardInBuffer(); // Clear any remaining rx bytes
    serial.Write(ReadHoldingRegister(2, 1024, 16), 0, 8);

    Queue<byte> response = GetResponse(serial, 5);

    if (response.Count > 0)
    {
        // Process Response
        // 1) check the CRC
        // 2) if crc ok, check if it is an exception response
        // 3) if not an exception check that it "matches" the request
        // ...
    }

    ...
}