前言
有一個(gè)項(xiàng)目使用的是西門子的PLC,你開發(fā)了一個(gè)上位機(jī),現(xiàn)在有一個(gè)第三方軟件也想要獲取西門子PLC的數(shù)據(jù),希望你能提供一個(gè)接口,該如何實(shí)現(xiàn)。
我相信你們應(yīng)該會(huì)遇到這種問題,其實(shí)解決方案很多,今天跟大家分享一種方式——提供ModbusTCP接口,提供ModbusTCP接口其實(shí)就是開發(fā)ModbusTCP服務(wù)器。
首先我們要清楚ModbusTCP服務(wù)器的本質(zhì)就是Socket服務(wù)器,只是創(chuàng)建了4個(gè)集合或數(shù)組作為4個(gè)存儲(chǔ)區(qū),當(dāng)接收到ModbusTCP客戶端的報(bào)文請(qǐng)求時(shí),將對(duì)應(yīng)的存儲(chǔ)區(qū)數(shù)據(jù)返回給客戶端。
雖然原理很容易理解,但是自己開發(fā)還是需要一點(diǎn)時(shí)間的,今天跟大家分享,如何基于NModbus4這個(gè)開源庫(kù)來快速實(shí)現(xiàn)。
實(shí)現(xiàn)
方便起見,這里用控制臺(tái)應(yīng)用程序來做。
首先創(chuàng)建一個(gè)控制臺(tái)應(yīng)用程序,然后通過Nuget添加兩個(gè)通信庫(kù),分別是xktComm和NModbus4。
然后創(chuàng)建幾個(gè)靜態(tài)對(duì)象:
//西門子通信
public static SiemensS7 siemensS7 = new SiemensS7();
//ModbusTcpSlave對(duì)象
public static ModbusTcpSlave modbusTcpSlave = null;
//TcpListener對(duì)象
public static TcpListener tcpListener;
在Main方法里編寫代碼如下:
static void Main(string[] args)
{
//連接西門子PLC
bool siemensconn = siemensS7.Connect("192.168.1.200", CPU_Type.S71200, 0, 0);
if (siemensconn)
{
Console.WriteLine("西門子PLC連接成功");
}
else
{
Console.WriteLine("西門子PLC連接失敗");
}
//創(chuàng)建ModbusTCP服務(wù)器
bool slaveconn = false;
try
{
tcpListener = new TcpListener(IPAddress.Parse("127.0.0.1"), 502);
modbusTcpSlave = ModbusTcpSlave.CreateTcp(1, tcpListener);
modbusTcpSlave.Listen();
slaveconn = true;
Console.WriteLine("ModbusTCP服務(wù)開啟成功");
}
catch (Exception ex)
{
slaveconn = false;
Console.WriteLine("ModbusTCP服務(wù)開啟失。" + ex.Message);
}
//西門子PLC連接成功且ModbusTCP服務(wù)器創(chuàng)建成功
if (siemensconn && slaveconn)
{
while (true)
{
//讀取PLC的數(shù)據(jù),寫入到ModbusTCP里
float value = Convert.ToSingle(siemensS7.Read("DB1.DBD0", VarType.Real));
//顯示出來
Console.WriteLine("讀取數(shù)據(jù):" + value);
//寫入Modbus服務(wù)器
SetFloatValue(1, value);
Thread.Sleep(500);
}
}
Console.ReadLine();
}
其中SetFloatValue方法是往ModbusTCP服務(wù)器的保持型寄存器中寫入浮點(diǎn)數(shù)據(jù),這里要注意,索引是從1開始的,這里就是將PLC的DB1.DBD0的數(shù)據(jù)讀取之后,以浮點(diǎn)數(shù)的方式寫入到40001和40002兩個(gè)寄存器中。
public static void SetFloatValue(int offset, float value)
{
byte[] buffer = BitConverter.GetBytes(value);
ushort highValue = BitConverter.ToUInt16(buffer, 0);
ushort lowValue = BitConverter.ToUInt16(buffer, 2);
//獲取保持型寄存器存儲(chǔ)區(qū)
ModbusDataCollection<ushort> data = modbusTcpSlave.DataStore.HoldingRegisters;
data[offset] = lowValue;
data[offset + 1] = highValue;
}