我正在使用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);
}发布于 2013-09-05 12:41:33
问题在于ReadExisting()的使用。它不能以这种方式使用,因为缓冲区中充满了来自串行端口的无用数据。这个问题是由@glace在评论中发现的!
发布于 2013-08-29 16:58:09
您首先需要通过一些现有的MODBUS主应用程序(如 )与仪表建立通信。然后,一旦你有了有效的通信和来自你的设备的有效回复,那么就开始测试你的代码。这样可以确保问题只出现在您的代码中,而不会出现在其他代码中。
例如,为了同时连接到两个从设备,必须使用RS485而不是RS232,这就需要在PC端使用不同的接线和RS485到RS232转换器。
出于模拟目的,在RS232中连接RX和TX不是一个好主意,因为来自主机的每个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;这是一个工作中的嵌入式AVR设备的一句话,该设备实现了MODBUS RTU从协议。
https://stackoverflow.com/questions/18487800
复制相似问题