2013-08-28 48 views
6

Tôi đang sử dụng C# để giao tiếp qua modbus rs485 rs232 đến 2 pha mét trong số các nhật ký khác điện áp nguồn.Giao tiếp Modbus

Tôi phải gửi dữ liệu qua xe buýt để tôi có thể nhận được các bài đọc.
Tôi đã kết nối một dây thông thường và rút ngắn việc gửi và nhận.

Dữ liệu được nhận được và sự kiện này là bắn:

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

Sau đó, bộ đệm này sẽ được gửi đến chức năng khác đó là một trong này:

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); 

    } 
} 

Tôi nghĩ rằng vấn đề nằm ở dữ liệu kiểm tra tính toàn vẹn:

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

Có một kiểm tra CRC và điều lạ lẫm là nó không bao giờ omes đúng. Việc tính toán 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); 
} 
+0

Có tài nguyên trực tuyến nào có bảng điểm của phiên giao tiếp điển hình, hoàn chỉnh với CRC không? Sau đó, bạn ít nhất có thể áp dụng thuật toán của bạn cho các thông điệp mẫu đó và xem liệu bạn có đưa ra cùng một CRC hay không. –

+1

Biến "bộ đệm" là gì? Đây có phải là Danh sách không? Bạn có chắc rằng biến "msg" của bạn lớn hơn 6 không? Tại sao không chỉ sử dụng bộ đệm ra khỏi Cổng nối tiếp thay vì phá vỡ nó trong một vòng lặp bằng byte, xây dựng lại nó trong một Danh sách, sau đó chuyển đổi nó trở lại một mảng byte toàn cầu? Bạn cũng gọi ReadExisting trên Cổng Nối tiếp ngay lập tức sau khi đọc nội dung của bộ đệm, tại sao? –

+0

CRC có vẻ đúng @AndyzSmith. bạn có ý gì khi gọi điện thoại có sẵn trong thực tế, nơi tôi có thể gọi nó?và có bộ đệm là một danh sách – Combinu

Trả lời

2

Vấn đề là việc sử dụng ReadExisting(). Nó không được sử dụng theo cách đó vì bộ đệm đã được lấp đầy với dữ liệu vô dụng từ cổng nối tiếp. Vấn đề này đã được xác định bởi @glace trong các ý kiến!

1

Trước tiên, bạn cần phải thiết lập liên lạc với mét của bạn thông qua một số ứng dụng MODBUS hiện như MODPOLL. Sau đó, khi bạn có hoạt động liên lạc và có các câu trả lời hợp lệ từ thiết bị của mình, thì chỉ sau đó bắt đầu kiểm tra mã của bạn. Bằng cách này, bạn đảm bảo rằng vấn đề có thể chỉ trong mã của bạn và không có gì khác.

Ví dụ, để kết nối với hai thiết bị nô lệ cùng một lúc, RS485 phải được sử dụng thay cho RS232, và điều này yêu cầu hệ thống dây điện khác nhau và bộ chuyển đổi RS485 sang RS232 ở phía PC.

Có kết nối RX và TX trong RS232 cho mục đích mô phỏng không phải là một ý tưởng tốt vì mỗi thông điệp MODBUS từ một bản gốc (ngoại trừ tin nhắn phát sóng) cần trả lời khác với thông báo echo. Ngoài ra, mỗi thông điệp MODBUS từ một bậc thầy có địa chỉ máy khách MODBUS được nhúng vào trong nó và chỉ có một máy khách duy nhất phải trả lời nó (MODBUS là một giao thức đa luồng chủ duy nhất).

Đối với một tính toán CRC, điều này có thể giúp cho giao thức MODBUS RTU (ASCII là khác nhau):

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; 

Đó là một trích dẫn từ một thiết bị AVR nhúng làm việc với thực hiện giao thức nô lệ MODBUS RTU.

+0

cảm ơn sự giúp đỡ của bạn tôi thực sự đã có vấn đề làm việc ... có vẻ như tôi đã đọc sai từ cổng nối tiếp! ... nhưng vẫn giúp nhiều appriciated !! – Combinu

+0

@ MysticJay có thể thêm giải pháp của bạn làm câu trả lời (bạn có thể trả lời câu hỏi của riêng mình) và chấp nhận câu hỏi đó không? Tôi nghĩ rằng điều này sẽ giúp độc giả trong tương lai nếu họ chạy vào các vấn đề tương tự. (Tôi tham khảo [xkcd] (http://xkcd.com/979/) để tham khảo) – Default

+0

tôi không nghĩ rằng đây là C# – mrid