1、项目背景
很多工控环境,数据集中在OPC服务器上, 终端设备需要opc_da采集,很困难,即便终端是Windows系统,OPC的环境配置也及其麻烦,而终端若非Windows系统,基本上不太可能实现。现有能找见的转换工具要么付费;要么破解的老版本,很多bug。靠人不如靠自己,还是自己写的更方便。
2、引用库
OPC库,测试多个,最终选定:OpcNetApi
Modbus库,还选用顺手的 NModbus4
Json解析 Newtonsoft
3、为以后用起来灵活方便,采用Json配置文件
{
"opc_da_host": "192.168.100.101",
"opc_da_server": "Kepware.KEPServerEX.V6",
"opc_da_items": [
"SL1.TEST.YWCCQCKYL",
"SL1.TEST.YWCCQJKYL",
"SL1.TEST.YWCCQYC",
"TX1.TEST.TXSSTXHYJYL",
"YT1.TEST.CCSSDCCQRCDL",
"YW1.TEST.SCDJLL",
"YW1.TEST.YSWD"
],
"modbus_slave_tcp_ip": "0.0.0.0",
"modbus_slave_tcp_port": 502,
"modbus_slave_id": 1,
"modbus_slave_registers": [
3043,
3045,
3021,
3027,
3019,
3015,
3017
],
"interval": 1000
}
4、建立Modbus TCP服务
var jt_conf = JToken.Parse(File.ReadAllText($@"{AppDomain.CurrentDomain.BaseDirectory}config.json")); //读取上面的配置文件
//******************************* 建立 Modbus TCP Slave ***************************************
byte slaveId = ((byte)jt_conf["modbus_slave_id"]);
int port = ((int)jt_conf["modbus_slave_tcp_port"]);
IPAddress address = IPAddress.Parse(jt_conf["modbus_slave_tcp_ip"].ToString());
var regs = jt_conf["modbus_slave_registers"].ToArray();
TcpListener slaveTcpListener = new TcpListener(address, port);
slave = ModbusTcpSlave.CreateTcp(slaveId, slaveTcpListener);
slave.DataStore = store = DataStoreFactory.CreateDefaultDataStore();
slave.ModbusSlaveRequestReceived += Slave_ModbusSlaveRequestReceived;
var th_0 = new Thread(() =>
{
slave.Listen();
})
{
IsBackground = true
};
th_0.Start();
5、连接OPC服务器
//******************************* 连接OPC服务器 ***************************************
var host = jt_conf["opc_da_host"].ToString();
var node = jt_conf["opc_da_server"].ToString();
var keys = jt_conf["opc_da_items"].ToArray();
Item[] items = new Item[keys.Length];
for (int i = 0; i < keys.Length; i++)
{
items[i] = new Item()
{
ItemName = keys[i].ToString(),
};
}
server = new Server(fact, null)
{
Url = new Opc.URL($@"opcda://{host}/{node}")
};
server.Connect();
6、从读OPC服务器读取数据,并转换填充到Modbus数据块
//******************************* 获取数据,更新数据 ***************************************
while (true)
{
Console.Clear();
try
{
Console.ForegroundColor = ConsoleColor.Green;
var values = server.Read(items);
foreach (ItemValueResult itemValue in values)
{
store.HoldingRegisters[(int)regs[Array.IndexOf(keys, itemValue.ItemName)]] = BitConverter.ToUInt16(BitConverter.GetBytes((float)itemValue.Value), 2);
store.HoldingRegisters[(int)regs[Array.IndexOf(keys, itemValue.ItemName)] + 1] = BitConverter.ToUInt16(BitConverter.GetBytes((float)itemValue.Value), 0);
Console.WriteLine($@"{itemValue.ItemName}@{regs[Array.IndexOf(keys, itemValue.ItemName)]}={itemValue.Value}");
}
}
catch (Exception ex)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine(ex.Message);
//throw;
}
Thread.Sleep(((int)jt_conf["interval"]));
}