C#Modbus串口通信

03请求读

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
ushort startAddr = 0;
ushort readLen = 2;

List<byte> command = new List<byte>();
//从站地址
command.Add(0x01);
//功能码,读保持寄存器
command.Add(0x03);
//起始地址
command.Add(BitConverter.GetBytes(startAddr)[1]);
command.Add(BitConverter.GetBytes(startAddr)[0]);
//读取数量
command.Add(BitConverter.GetBytes(readLen)[1]);
command.Add(BitConverter.GetBytes(readLen)[0]);
//CRC校验
command = CRC16(command);

serialPort.Write(command.ToArray(), 0, command.Count);

//固定请求读
Task.Run(() =>
{
byte[] respBytes1 = {0x01, 0x03, 0x4e, 0x20, 0x00, 0x0A, 0xd3, 0x25};
byte[] respBytes2 = {0x02, 0x03, 0x4e, 0x20, 0x00, 0x0A, 0xd3, 0x25};
serialPort1.Write(respBytes1, 0, 8);
Thread.Sleep(1000);
serialPort1.Write(respBytes2, 0, 8);
Thread.Sleep(1000);
});

获取数据

1
2
3
4
5
6
7
8
9
10
11
byte[] respBytes = new byte[serialPort.BytesToRead];
serialPort.Read(respBytes, 0, respBytes.Length);
List<byte> respList = new List<byte>(respBytes);

respList.RemoveRange(0, 3);//截去:从站地址 功能码 字节计数
respList.RemoveRange(respList.Count - 2, 2);//截去:校验位

byte[] data = new byte[2];//获取需要的2个字节数据
data[0] = respList[N * 2 + 1];//N为第N+1个字节数据
data[1] = respList[N * 2];
string value = BitConverter.ToUInt16(data, 0).ToString();//将其转化为字符型

10请求写

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
private void correct(string text, ushort slave)
{
ushort startAddr = 0;//写入地址
ushort writeLen = 1;//写入数量
ushort value = ushort.Parse(text);//写入值

List<byte> command = new List<byte>();

command.Add((byte)slave);//从站地址
command.Add(0x10);//功能码,写多个寄存器
//写入地址
command.Add(BitConverter.GetBytes(startAddr)[1]);
command.Add(BitConverter.GetBytes(startAddr)[0]);
//写入数量
command.Add(BitConverter.GetBytes(writeLen)[1]);
command.Add(BitConverter.GetBytes(writeLen)[0]);
//字节数
byte[] valueBytes = BitConverter.GetBytes(value);
command.Add((byte)valueBytes.Length);
//写入值
command.Add(BitConverter.GetBytes(value)[1]);
command.Add(BitConverter.GetBytes(value)[0]);
//CRC校验
command = CRC16(command);

serialPort.Write(command.ToArray(), 0, command.Count);

}

CRC校验

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
 static List<byte> CRC16(List<byte> value, ushort poly = 0xA001, ushort crcInit = 0xFFFF)
{
if (value == null || !value.Any())
throw new ArgumentException("");

//运算
ushort crc = crcInit;
for (int i = 0; i < value.Count; i++)
{
crc = (ushort)(crc ^ (value[i]));
for (int j = 0; j < 8; j++)
{
crc = (crc & 1) != 0 ? (ushort)((crc >> 1) ^ poly) : (ushort)(crc >> 1);
}
}
byte hi = (byte)((crc & 0xFF00) >> 8); //高位置
byte lo = (byte)(crc & 0x00FF); //低位置

List<byte> buffer = new List<byte>();
//添加校验原始值
buffer.AddRange(value);
//添加校验位值
buffer.Add(lo);
buffer.Add(hi);

//加上原始校验值返回
return buffer;
}