? ?Modbus是一個(gè)免費(fèi)的協(xié)議,協(xié)議設(shè)計(jì)簡(jiǎn)單,有很多成熟的庫(kù)支持。比如C#版本的NModubs4就很好,入門(mén)簡(jiǎn)單,使用方便。
首先,在工程中使用NuGet添加NModbus4的包。
在使用文件中,添加引用。不同的接口模式,引用對(duì)象不同,Modbus Slave TCP模型需要以下幾項(xiàng):
using System.Net;
using System.Net.Sockets;
using Modbus.Data;
using Modbus.Device;
初始化大概有幾個(gè)步驟:創(chuàng)建TCP Listener對(duì)象、創(chuàng)建ModbusTcpSalve對(duì)象、啟動(dòng)偵聽(tīng)服務(wù)。
TcpListener listener = new TcpListener(IPAddress.Parse("0.0.0.0"), 502);
listener.Start();
ModbusTcpSlave modbusSlave = ModbusTcpSlave.CreateTcp(1, listener);
//創(chuàng)建寄存器存儲(chǔ)對(duì)象
modbusSlave.DataStore = DataStoreFactory.CreateDefaultDataStore();
Modbus有個(gè)DataStore對(duì)象,用來(lái)存儲(chǔ)數(shù)據(jù),對(duì)應(yīng)的狀態(tài)的地址如下:
//01 Coil Status, Addr: 00001
ModbusDataCollection<bool> coilDiscretes = modbusSlave.DataStore.InputDiscretes;
//02 Input Status, Addr: 10001
ModbusDataCollection<bool> inputDiscretes = modbusSlave.DataStore.CoilDiscretes;
//03 Holding Register, Addr: 40001
ModbusDataCollection<ushort> holdingRegisters = modbusSlave.DataStore.HoldingRegisters;
//04 Input Register, Addr: 30001
ModbusDataCollection<ushort> InputRegisters = modbusSlave.DataStore.InputRegisters;
定義之后,就可以直接通過(guò)這些對(duì)象讀寫(xiě)數(shù)據(jù)了。
NModbus4庫(kù)已經(jīng)封裝了對(duì)于TCP訪(fǎng)問(wèn)數(shù)據(jù)的封裝,服務(wù)端只需要維護(hù)數(shù)據(jù)更新即可。
受Modbus協(xié)議限制,HoldingRegisters和InputRegisters每個(gè)地址僅16位2個(gè)字節(jié)長(zhǎng)度。當(dāng)實(shí)際數(shù)據(jù)值超過(guò)2個(gè)字節(jié)時(shí),需要占用多個(gè)地址空間。比如int32,float都需要4個(gè)字節(jié),兩個(gè)地址。這些數(shù)據(jù)怎么存放,高低位怎么對(duì)齊,就產(chǎn)生了所謂的ABCD、CDAB等轉(zhuǎn)換,這個(gè)Master與Slave一致就可以。
Int32等類(lèi)型數(shù)據(jù)更新時(shí),需要同時(shí)對(duì)多個(gè)存儲(chǔ)地址進(jìn)行更新,而master可能還在高速并發(fā)讀數(shù)據(jù),需要注意使用一個(gè)同步鎖,避免數(shù)據(jù)更新一半就被讀取,產(chǎn)生數(shù)據(jù)不一致問(wèn)題。文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-532825.html
//將float類(lèi)型分解成兩個(gè)ushort類(lèi)型
public void SetValue32(ModbusDataCollection<ushort>data,int offset, float value)
{
lock (modbusSlave.DataStore.SyncRoot)
{
data[offset] = BitConverter.ToUInt16(BitConverter.GetBytes(value), 0);
data[offset + 1] = BitConverter.ToUInt16(BitConverter.GetBytes(value), 2);
}
}
//將int32類(lèi)型分解成兩個(gè)ushort類(lèi)型
public void SetValue32(ModbusDataCollection<ushort> data, int offset, Int32 value)
{
lock (modbusSlave.DataStore.SyncRoot)
{
data[offset] = BitConverter.ToUInt16(BitConverter.GetBytes(value), 0);
data[offset + 1] = BitConverter.ToUInt16(BitConverter.GetBytes(value), 2);
}
}
Modbus對(duì)于字符串,并沒(méi)有明確約定。推進(jìn)使用Unicode編碼,首先是與OPC的默認(rèn)字符串編碼格式一致,其次的每個(gè)中英文都占用一個(gè)地址2個(gè)字節(jié),方便計(jì)算長(zhǎng)度。文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-532825.html
public void SetValueString(ModbusDataCollection<ushort> data, int offset, string value)
{
const int maxStringLen = 20;
lock (modbusSlave.DataStore.SyncRoot)
{
byte[] dst = new byte[appConfigModbus.StringLen * 2];
byte[] bb = Encoding.Unicode.GetBytes(value);
for (int i = 0; i < bb.Length && i < dst.Length; i++)
{
dst[i] = bb[i];
}
for (int i = 0; i < maxStringLen; i += 2)
{
data[offset + i / 2] = BitConverter.ToUInt16(dst, i);
}
}
}
到了這里,關(guān)于C#使用NModbus4讀寫(xiě)Modbus數(shù)據(jù)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!