7

私はC#を使用してmodbus rs485 rs232、電源電圧を記録する2相メーターを介して通信しています。

測定値を受信できるように、バス経由でデータを送信する必要があります。
通常のワイヤを接続し、送信と受信をショートさせました。

データが受信され、このイベントが発生します。

private void port_DataReceived(object sender, SerialDataReceivedEventArgs e)
{
    SerialPort sp = (SerialPort)sender;
    byte[] buff = new byte[sp.BytesToRead];

    //Read the Serial Buffer
    sp.Read(buff, 0, buff.Length);
    string data= sp.ReadExisting();

    foreach (byte b in buff)
    {
        AddBuffer(b); //Add byte to buffer
    }
}

次に、このバッファーは、次の別の関数に送信されます。

private void AddBuffer(byte b)
{
    buffer.Add(b);

    byte[] msg =  buffer.ToArray();

    //Make sure that the message integrity is correct
    if (this.CheckDataIntegrity(msg))
    {
        if (DataReceived != null)
        {
            ModbusEventArgs args = new ModbusEventArgs();
            GetValue(msg, args);
            DataReceived(this, args);
        }
        buffer.RemoveRange(0, buffer.Count);

    }
}

問題はデータの整合性チェックにあると思います:

public bool CheckDataIntegrity(byte[] data)
{
    if (data.Length < 6)
        return false;
    //Perform a basic CRC check:
    byte[] CRC = new byte[2];
    GetCRC(data, ref CRC);
    if (CRC[0] == data[data.Length - 2] && CRC[1] == data[data.Length - 1])
        return true;
    else
        return false;
}

CRC チェックがあり、奇妙なのはそれが真にならないことです。CRC 計算:

private void GetCRC(byte[] message, ref byte[] CRC)
{

    ushort CRCFull = 0xFFFF;
    byte CRCHigh = 0xFF, CRCLow = 0xFF;
    char CRCLSB;

    for (int i = 0; i < (message.Length) - 2; i++)
    {
        CRCFull = (ushort)(CRCFull ^ message[i]);

        for (int j = 0; j < 8; j++)
        {
            CRCLSB = (char)(CRCFull & 0x0001);
            CRCFull = (ushort)((CRCFull >> 1) & 0x7FFF);

            if (CRCLSB == 1)
                CRCFull = (ushort)(CRCFull ^ 0xA001);
        }
    }
    CRC[1] = CRCHigh = (byte)((CRCFull >> 8) & 0xFF);
    CRC[0] = CRCLow = (byte)(CRCFull & 0xFF);
}
4

2 に答える 2

2

問題は、ReadExisting() の使用です。バッファがシリアルポートからの無用なデータで満たされていたため、そのように使用することはできませんでした。この問題は、コメントの @glace によって特定されました。

于 2013-09-05T04:41:33.340 に答える
1

最初に、 MODPOLLなどの既存の MODBUS マスター アプリケーションを使用して、メーターとの通信を確立する必要があります。次に、通信が機能し、デバイスから有効な応答が得られたら、コードのテストを開始します。このようにして、問題がコードだけにあり、他には何もないことを確認します。

たとえば、同時に 2 つのスレーブ デバイスに接続するには、RS232 の代わりに RS485 を使用する必要があり、これには別の配線と PC 側の RS485 から RS232 へのコンバーターが必要です。

RX と TX をシミュレーション目的で RS232 に接続することは、マスターからの各 MODBUS メッセージ (ブロードキャスト メッセージを除く) が単なるメッセージ エコーとは異なる応答を必要とするため、良い考えではありません。また、マスターからの各 MODBUS メッセージには MODBUS クライアント アドレスが埋め込まれており、単一のクライアントのみがそれに応答する必要があります (MODBUS は単一マスター複数スレーブ プロトコルです)。

CRC 計算に関しては、これは MODBUS RTU プロトコルに役立つ可能性があります (ASCII は異なります)。

function mb_CalcCRC16(ptr: pointer to byte; ByteCount: byte): word;
var
  crc: word;
  b, i, n: byte;
begin
  crc := $FFFF;
  for i := 0 to ByteCount do
    if i = 0 then           // device id is 1st byte in message, and it is not in the buffer
      b := mb_GetMessageID; // so we have to calculate it and put it as 1st crc byte
    else
      b := ptr^;
      Inc(ptr);
    endif;
    crc := crc xor word(b);
    for n := 1 to 8 do
      if (crc and 1) = 1 then
        crc := (crc shr 1) xor $A001;
      else
        crc := crc shr 1;
      endif;
    endfor;
  endfor;
  Return(crc);
end;

function mb_CalcCRC: word; // Calculate CRC for message in mb_pdu
begin // this message can be one that is just received, or in a reply we have just composed
  Return(mb_CalcCRC16(@mb_pdu[1], mb_GetEndOfData));
end;

これは、実装された MODBUS RTU スレーブ プロトコルを備えた動作中の組み込み AVR デバイスからの引用です。

于 2013-08-29T08:58:08.533 に答える