cs
using HslCommunication;
using HslCommunication.Profinet.Omron;
using System;
using System.Collections.Generic;
namespace LineBase.Device
{
/// <summary>
/// 欧姆龙PLC通信类,通过FINS/UDP协议与欧姆龙PLC进行数据交换
/// </summary>
public class OmronPlcCommunicator
{
private OmronFinsUdp _plcClient;
public string IpAddress { get; private set; }
/// <summary>
/// 连接至欧姆龙PLC
/// </summary>
/// <param name="ipAddress">PLC的IP地址</param>
/// <returns>连接成功返回true,失败返回false</returns>
public bool ConnectToPlc(string ipAddress)
{
try
{
IpAddress = ipAddress;
//填对应版本的激活码
Authorization.SetAuthorizationCode("");
_plcClient = new OmronFinsUdp(ipAddress, 9600);
return true;
}
catch (Exception ex)
{
return false;
}
}
/// <summary>
/// 写入32位整数到DM区(自动转换为16位)
/// </summary>
/// <param name="dmAddress">DM区地址</param>
/// <param name="value">要写入的整数值</param>
/// <returns>写入成功返回true,失败返回false</returns>
public bool WriteIntToDm(short dmAddress, int value)
{
try
{
var result = _plcClient.Write("D" + dmAddress, (short)value);
return result.IsSuccess;
}
catch (Exception e)
{
return false;
}
}
/// <summary>
/// 写入16位整数到DM区
/// </summary>
/// <param name="dmAddress">DM区地址</param>
/// <param name="value">要写入的16位整数值</param>
/// <returns>写入成功返回true,失败返回false</returns>
public bool WriteShortToDm(short dmAddress, short value)
{
try
{
var result = _plcClient.Write("D" + dmAddress, value);
return result.IsSuccess;
}
catch (Exception e)
{
return false;
}
}
/// <summary>
/// 写入字符串到DM区
/// </summary>
/// <param name="dmAddress">DM区起始地址</param>
/// <param name="charCount">要写入的字符数量</param>
/// <param name="text">要写入的字符串</param>
/// <returns>写入成功返回true,失败返回false</returns>
/// <remarks>字符串将被自动补齐空字符并转换为大端序格式</remarks>
public bool WriteStringToDm(short dmAddress, short charCount, string text)
{
try
{
// 补齐字符串到指定长度
text = text.PadRight(charCount, '\0');
char[] chars = text.ToCharArray();
List<short> wordValues = new List<short>();
byte[] byteBuffer = new byte[2];
// 每两个字符组合成一个16位字(大端序)
for (int i = 0; i < chars.Length; i += 2)
{
byteBuffer[0] = (byte)chars[i + 1]; // 低字节
byteBuffer[1] = (byte)chars[i]; // 高字节
wordValues.Add(BitConverter.ToInt16(byteBuffer, 0));
}
var result = _plcClient.Write("D" + dmAddress, wordValues.ToArray());
return result.IsSuccess;
}
catch (Exception e)
{
return false;
}
}
/// <summary>
/// 从DM区读取单个16位整数
/// </summary>
/// <param name="dmAddress">DM区地址</param>
/// <param name="value">读取到的16位整数值</param>
/// <returns>读取成功返回true,失败返回false</returns>
public bool ReadShortFromDm(short dmAddress, out short value)
{
try
{
value = 0;
var result = _plcClient.ReadInt16("D" + dmAddress);
if (result.IsSuccess)
{
value = result.Content;
return true;
}
return false;
}
catch (Exception e)
{
value = 0;
return false;
}
}
/// <summary>
/// 从DM区批量读取16位整数
/// </summary>
/// <param name="dmAddress">DM区起始地址</param>
/// <param name="count">要读取的数据数量</param>
/// <param name="values">读取到的16位整数数组</param>
/// <returns>读取成功返回true,失败返回false</returns>
public bool ReadMultipleShortsFromDm(short dmAddress, short count, out short[] values)
{
try
{
var result = _plcClient.ReadInt16("D" + dmAddress, (ushort)count);
values = result.Content;
return result.IsSuccess;
}
catch (Exception e)
{
values = new short[count];
return false;
}
}
/// <summary>
/// 从DM区读取单个浮点数
/// </summary>
/// <param name="dmAddress">DM区地址</param>
/// <param name="value">读取到的浮点数值</param>
/// <returns>读取成功返回true,失败返回false</returns>
public bool ReadFloatFromDm(short dmAddress, out float value)
{
try
{
var result = _plcClient.ReadFloat("D" + dmAddress);
value = result.Content;
return result.IsSuccess;
}
catch (Exception e)
{
value = 0;
return false;
}
}
/// <summary>
/// 从DM区批量读取浮点数
/// </summary>
/// <param name="dmAddress">DM区起始地址</param>
/// <param name="count">要读取的浮点数数量</param>
/// <param name="values">读取到的浮点数数组</param>
/// <returns>读取成功返回true,失败返回false</returns>
public bool ReadMultipleFloatsFromDm(short dmAddress, short count, out float[] values)
{
try
{
var result = _plcClient.ReadFloat("D" + dmAddress, (ushort)count);
values = result.Content;
return result.IsSuccess;
}
catch (Exception e)
{
values = new float[count];
return false;
}
}
/// <summary>
/// 从DM区读取字符串(大端序格式)
/// </summary>
/// <param name="dmAddress">DM区起始地址</param>
/// <param name="charCount">要读取的字符数量</param>
/// <param name="text">读取到的字符串</param>
/// <returns>读取成功返回true,失败返回false</returns>
/// <remarks>自动处理空字符和特殊长度截断</remarks>
public bool ReadStringBigEndianFromDm(short dmAddress, short charCount, out string text)
{
try
{
var result = _plcClient.ReadInt16("D" + dmAddress, (ushort)charCount);
if (!result.IsSuccess)
{
text = null;
return false;
}
List<char> charList = new List<char>();
foreach (var word in result.Content)
{
byte[] bytes = BitConverter.GetBytes(word);
// 大端序:高位字节在前,低位字节在后
charList.Add((char)(bytes[1])); // 高位字节
charList.Add((char)(bytes[0])); // 低位字节
}
text = new string(charList.ToArray());
text = text.Trim('\0');
// 特殊处理:当读取4个字且字符串超过5个字符时,截断为5个字符
if (charCount == 4 && text.Length > 5)
{
text = text.Substring(0, 5);
}
return result.IsSuccess;
}
catch (Exception e)
{
text = "";
return false;
}
}
/// <summary>
/// 从DM区读取字符串(小端序格式)
/// </summary>
/// <param name="dmAddress">DM区起始地址</param>
/// <param name="charCount">要读取的字符数量</param>
/// <param name="text">读取到的字符串</param>
/// <returns>读取成功返回true,失败返回false</returns>
/// <remarks>自动处理空字符和特殊长度截断</remarks>
public bool ReadStringLittleEndianFromDm(short dmAddress, short charCount, out string text)
{
try
{
var result = _plcClient.ReadInt16("D" + dmAddress, (ushort)charCount);
if (!result.IsSuccess)
{
text = null;
return false;
}
List<char> charList = new List<char>();
foreach (var word in result.Content)
{
byte[] bytes = BitConverter.GetBytes(word);
// 小端序:低位字节在前,高位字节在后
charList.Add((char)(bytes[0])); // 低位字节
charList.Add((char)(bytes[1])); // 高位字节
}
text = new string(charList.ToArray());
text = text.Trim('\0');
// 特殊处理:当读取4个字且字符串超过5个字符时,截断为5个字符
if (charCount == 4 && text.Length > 5)
{
text = text.Substring(0, 5);
}
return result.IsSuccess;
}
catch (Exception e)
{
text = "";
return false;
}
}
}
}
完整的测试程序
cs
using System;
using LineBase.Device;
class OmronPlcTestProgram
{
static void Main()
{
Console.WriteLine("欧姆龙PLC通信测试程序");
Console.WriteLine("======================");
// PLC配置
string plcIp = "192.168.1.10";
OmronPlcCommunicator plc = new OmronPlcCommunicator();
// 1. 连接测试
Console.WriteLine($"尝试连接到 PLC: {plcIp}");
if (!plc.ConnectToPlc(plcIp))
{
Console.WriteLine("连接失败,请检查:");
Console.WriteLine("1. PLC电源是否打开");
Console.WriteLine("2. 网络连接是否正常");
Console.WriteLine("3. IP地址是否正确");
Console.WriteLine("4. 防火墙设置");
return;
}
Console.WriteLine("连接成功!");
// 2. 运行各个测试
TestBasicOperations(plc);
TestProductionScenario(plc);
TestErrorScenarios(plc);
Console.WriteLine("\n测试完成!");
Console.ReadKey();
}
static void TestBasicOperations(OmronPlcCommunicator plc)
{
Console.WriteLine("\n--- 基本功能测试 ---");
// 测试整数读写
Console.WriteLine("测试整数读写...");
short testAddress = 100;
short testValue = 1234;
if (plc.WriteShortToDm(testAddress, testValue))
{
short readValue;
if (plc.ReadShortFromDm(testAddress, out readValue))
{
Console.WriteLine($"✓ 整数读写测试通过: 写入{testValue},读取{readValue}");
}
}
// 测试字符串读写
Console.WriteLine("测试字符串读写...");
short stringAddress = 200;
string testString = "TEST123";
if (plc.WriteStringToDm(stringAddress, 10, testString))
{
string readString;
if (plc.ReadStringBigEndianFromDm(stringAddress, 10, out readString))
{
Console.WriteLine($"✓ 字符串读写测试通过: 写入'{testString}',读取'{readString}'");
}
}
}
static void TestProductionScenario(OmronPlcCommunicator plc)
{
Console.WriteLine("\n--- 生产场景模拟测试 ---");
// 模拟生产数据
ProductionDataSimulator simulator = new ProductionDataSimulator(plc);
simulator.SimulateProductionCycle();
}
static void TestErrorScenarios(OmronPlcCommunicator plc)
{
Console.WriteLine("\n--- 错误场景测试 ---");
// 测试无效地址
Console.WriteLine("测试无效地址处理...");
short invalidValue;
bool result = plc.ReadShortFromDm(99999, out invalidValue);
Console.WriteLine($"无效地址读取结果: {result} (预期为 false)");
}
}
// 生产数据模拟器
class ProductionDataSimulator
{
private OmronPlcCommunicator _plc;
public ProductionDataSimulator(OmronPlcCommunicator plc)
{
_plc = plc;
}
public void SimulateProductionCycle()
{
Console.WriteLine("开始生产模拟...");
// 1. 写入产品信息
_plc.WriteStringToDm(1000, 20, "产品A-2024");
// 2. 写入生产参数
_plc.WriteShortToDm(1020, 1000); // 速度
_plc.WriteShortToDm(1021, 250); // 温度
// 3. 模拟读取生产状态
short speed, temp;
_plc.ReadShortFromDm(1020, out speed);
_plc.ReadShortFromDm(1021, out temp);
Console.WriteLine($"当前生产参数: 速度={speed}, 温度={temp}");
// 4. 模拟生产计数
for (int i = 1; i <= 5; i++)
{
_plc.WriteShortToDm(1022, (short)i); // 更新产品计数
Console.WriteLine($"生产第 {i} 个产品...");
System.Threading.Thread.Sleep(100);
}
Console.WriteLine("生产模拟完成");
}
}
cs
using HslCommunication;
using HslCommunication.Profinet.Omron;
using LineBase.Util;
using System;
using System.Collections.Generic;
namespace LineBase.Device
{
/// <summary>
/// 欧姆龙PLC通信类(基于HSL的TCP协议实现)
/// 提供与欧姆龙PLC的FINS/TCP协议通信功能
/// </summary>
public class OmronFinsTcpCommunicator
{
private OmronFinsNet _plcClient;
public string IpAddress { get; private set; }
/// <summary>
/// 连接到欧姆龙PLC
/// </summary>
/// <param name="ipAddress">PLC的IP地址</param>
/// <returns>连接成功返回true,失败返回false</returns>
public bool ConnectToPlc(string ipAddress)
{
try
{
IpAddress = ipAddress;
//使用对应的版本激活码
Authorization.SetAuthorizationCode("");
_plcClient = new OmronFinsNet(ipAddress, 9600);
OperateResult connectResult = _plcClient.ConnectServer();
return connectResult.IsSuccess;
}
catch (Exception ex)
{
LogUtil.WriteErrLog($"PLC连接失败: {ex}");
return false;
}
}
/// <summary>
/// 写入32位整数到DM区
/// </summary>
/// <param name="dmAddress">DM区地址</param>
/// <param name="value">要写入的32位整数值</param>
/// <returns>写入成功返回true,失败返回false</returns>
/// <remarks>自动将32位整数转换为16位整数</remarks>
public bool WriteIntToDm(short dmAddress, int value)
{
try
{
var result = _plcClient.Write("D" + dmAddress, (short)value);
return result.IsSuccess;
}
catch (Exception e)
{
LogUtil.WriteErrLog($"写入整数到DM{dmAddress}失败: {e}");
return false;
}
}
/// <summary>
/// 写入16位整数到DM区
/// </summary>
/// <param name="dmAddress">DM区地址</param>
/// <param name="value">要写入的16位整数值</param>
/// <returns>写入成功返回true,失败返回false</returns>
public bool WriteShortToDm(short dmAddress, short value)
{
try
{
var result = _plcClient.Write("D" + dmAddress, value);
return result.IsSuccess;
}
catch (Exception e)
{
LogUtil.WriteErrLog($"写入短整数到DM{dmAddress}失败: {e}");
return false;
}
}
/// <summary>
/// 写入字符串到DM区
/// </summary>
/// <param name="dmAddress">DM区起始地址</param>
/// <param name="characterCount">要写入的字符数量</param>
/// <param name="text">要写入的字符串</param>
/// <returns>写入成功返回true,失败返回false</returns>
/// <remarks>字符串将被自动补齐空字符并转换为大端序格式存储</remarks>
public bool WriteStringToDm(short dmAddress, short characterCount, string text)
{
try
{
// 补齐字符串到指定长度
text = text.PadRight(characterCount, '\0');
char[] chars = text.ToCharArray();
List<short> wordValues = new List<short>();
byte[] byteBuffer = new byte[2];
// 每两个字符组合成一个16位字(大端序)
for (int i = 0; i < chars.Length; i += 2)
{
byteBuffer[0] = (byte)chars[i + 1]; // 低字节
byteBuffer[1] = (byte)chars[i]; // 高字节
wordValues.Add(BitConverter.ToInt16(byteBuffer, 0));
}
var result = _plcClient.Write("D" + dmAddress, wordValues.ToArray());
return result.IsSuccess;
}
catch (Exception e)
{
LogUtil.WriteErrLog($"写入字符串到DM{dmAddress}失败: {e}");
return false;
}
}
/// <summary>
/// 从DM区读取原始字节数据
/// </summary>
/// <param name="dmAddress">DM区起始地址</param>
/// <param name="byteLength">要读取的字节长度</param>
/// <param name="data">读取到的字节数组</param>
/// <returns>读取成功返回true,失败返回false</returns>
public bool ReadBytesFromDm(short dmAddress, short byteLength, out byte[] data)
{
try
{
data = new byte[0];
var result = _plcClient.Read("D" + dmAddress, (ushort)byteLength);
if (result.IsSuccess)
{
data = result.Content;
return true;
}
return false;
}
catch (Exception e)
{
data = new byte[0];
LogUtil.WriteErrLog($"从DM{dmAddress}读取字节失败: {e}");
return false;
}
}
/// <summary>
/// 从DM区读取单个16位整数
/// </summary>
/// <param name="dmAddress">DM区地址</param>
/// <param name="value">读取到的16位整数值</param>
/// <returns>读取成功返回true,失败返回false</returns>
public bool ReadShortFromDm(short dmAddress, out short value)
{
try
{
value = 0;
var result = _plcClient.ReadInt16("D" + dmAddress);
if (result.IsSuccess)
{
value = result.Content;
return true;
}
return false;
}
catch (Exception e)
{
value = 0;
LogUtil.WriteErrLog($"从DM{dmAddress}读取短整数失败: {e}");
return false;
}
}
/// <summary>
/// 从DM区批量读取16位整数
/// </summary>
/// <param name="dmAddress">DM区起始地址</param>
/// <param name="count">要读取的数据数量</param>
/// <param name="values">读取到的16位整数数组</param>
/// <returns>读取成功返回true,失败返回false</returns>
public bool ReadMultipleShortsFromDm(short dmAddress, short count, out short[] values)
{
try
{
var result = _plcClient.ReadInt16("D" + dmAddress, (ushort)count);
values = result.Content;
return result.IsSuccess;
}
catch (Exception e)
{
values = new short[count];
LogUtil.WriteErrLog($"从DM{dmAddress}批量读取短整数失败: {e}");
return false;
}
}
/// <summary>
/// 从DM区读取单个浮点数
/// </summary>
/// <param name="dmAddress">DM区地址</param>
/// <param name="value">读取到的浮点数值</param>
/// <returns>读取成功返回true,失败返回false</returns>
public bool ReadFloatFromDm(short dmAddress, out float value)
{
try
{
var result = _plcClient.ReadFloat("D" + dmAddress);
value = result.Content;
return result.IsSuccess;
}
catch (Exception e)
{
value = 0;
LogUtil.WriteErrLog($"从DM{dmAddress}读取浮点数失败: {e}");
return false;
}
}
/// <summary>
/// 从DM区批量读取浮点数
/// </summary>
/// <param name="dmAddress">DM区起始地址</param>
/// <param name="count">要读取的浮点数数量</param>
/// <param name="values">读取到的浮点数数组</param>
/// <returns>读取成功返回true,失败返回false</returns>
public bool ReadMultipleFloatsFromDm(short dmAddress, short count, out float[] values)
{
try
{
var result = _plcClient.ReadFloat("D" + dmAddress, (ushort)count);
values = result.Content;
return result.IsSuccess;
}
catch (Exception e)
{
values = new float[count];
LogUtil.WriteErrLog($"从DM{dmAddress}批量读取浮点数失败: {e}");
return false;
}
}
/// <summary>
/// 从DM区读取字符串
/// </summary>
/// <param name="dmAddress">DM区起始地址</param>
/// <param name="characterCount">要读取的字符数量</param>
/// <param name="text">读取到的字符串</param>
/// <returns>读取成功返回true,失败返回false</returns>
/// <remarks>自动处理空字符和特殊长度截断,使用大端序格式</remarks>
public bool ReadStringFromDm(short dmAddress, short characterCount, out string text)
{
try
{
var result = _plcClient.ReadInt16("D" + dmAddress, (ushort)characterCount);
if (!result.IsSuccess)
{
text = null;
return false;
}
List<char> charList = new List<char>();
foreach (var word in result.Content)
{
byte[] bytes = BitConverter.GetBytes(word);
// 大端序格式:高位字节在前,低位字节在后
charList.Add((char)(bytes[1])); // 高位字节
charList.Add((char)(bytes[0])); // 低位字节
}
text = new string(charList.ToArray());
text = text.Trim('\0');
// 特殊处理:当读取4个字且字符串超过5个字符时,截断为5个字符
if (characterCount == 4 && text.Length > 5)
{
text = text.Substring(0, 5);
}
return result.IsSuccess;
}
catch (Exception e)
{
text = "";
LogUtil.WriteErrLog($"从DM{dmAddress}读取字符串失败: {e}");
return false;
}
}
}
}
使用示例
cs
using LineBase.Device;
using System;
class OmronFinsTcpExample
{
static void Main()
{
Console.WriteLine("欧姆龙PLC FINS/TCP通信示例");
Console.WriteLine("==========================");
// 1. 创建通信对象并连接PLC
OmronFinsTcpCommunicator plc = new OmronFinsTcpCommunicator();
string plcIp = "192.168.1.100"; // PLC的实际IP地址
if (plc.ConnectToPlc(plcIp))
{
Console.WriteLine($"成功连接到PLC: {plcIp}");
RunAllTests(plc);
}
else
{
Console.WriteLine($"连接PLC失败: {plcIp}");
}
Console.WriteLine("\n按任意键退出...");
Console.ReadKey();
}
static void RunAllTests(OmronFinsTcpCommunicator plc)
{
Console.WriteLine("\n=== 1. 基本数据读写测试 ===");
TestBasicDataOperations(plc);
Console.WriteLine("\n=== 2. 生产数据监控测试 ===");
TestProductionMonitoring(plc);
Console.WriteLine("\n=== 3. 字符串处理测试 ===");
TestStringOperations(plc);
Console.WriteLine("\n=== 4. 批量数据处理测试 ===");
TestBatchDataOperations(plc);
Console.WriteLine("\n=== 5. 原始字节数据测试 ===");
TestRawByteOperations(plc);
}
static void TestBasicDataOperations(OmronFinsTcpCommunicator plc)
{
// 测试1:写入和读取16位整数
short testAddress1 = 100;
short testValue1 = 1234;
if (plc.WriteShortToDm(testAddress1, testValue1))
{
Console.WriteLine($"✓ 写入 DM{testAddress1} = {testValue1}");
short readValue1;
if (plc.ReadShortFromDm(testAddress1, out readValue1))
{
Console.WriteLine($" 读取 DM{testAddress1} = {readValue1}");
Console.WriteLine($" 验证结果: {(readValue1 == testValue1 ? "通过" : "失败")}");
}
}
// 测试2:写入和读取浮点数
short testAddress2 = 102;
float testValue2 = 25.75f;
if (plc.WriteShortToDm(testAddress2, (short)testValue2))
{
Console.WriteLine($"✓ 写入 DM{testAddress2} = {testValue2}");
float readValue2;
if (plc.ReadFloatFromDm(testAddress2, out readValue2))
{
Console.WriteLine($" 读取 DM{testAddress2} = {readValue2}");
Console.WriteLine($" 验证结果: {(Math.Abs(readValue2 - testValue2) < 0.01 ? "通过" : "失败")}");
}
}
}
static void TestProductionMonitoring(OmronFinsTcpCommunicator plc)
{
Console.WriteLine("模拟生产监控数据...");
// 定义生产参数地址
const short STATUS_ADDRESS = 200; // 设备状态
const short TEMP_ADDRESS = 202; // 温度
const short PRESSURE_ADDRESS = 204; // 压力
const short SPEED_ADDRESS = 206; // 速度
// 模拟写入生产数据
short[] productionData = { 1, 250, 100, 1500 }; // 状态、温度、压力、速度
plc.WriteShortToDm(STATUS_ADDRESS, productionData[0]);
plc.WriteShortToDm(TEMP_ADDRESS, productionData[1]);
plc.WriteShortToDm(PRESSURE_ADDRESS, productionData[2]);
plc.WriteShortToDm(SPEED_ADDRESS, productionData[3]);
Console.WriteLine("生产数据写入完成");
// 读取并显示生产状态
Console.WriteLine("\n当前生产状态:");
short status;
if (plc.ReadShortFromDm(STATUS_ADDRESS, out status))
{
Console.WriteLine($" 设备状态: {GetStatusDescription(status)}");
}
float temperature;
if (plc.ReadFloatFromDm(TEMP_ADDRESS, out temperature))
{
Console.WriteLine($" 温度: {temperature}°C");
}
float pressure;
if (plc.ReadFloatFromDm(PRESSURE_ADDRESS, out pressure))
{
Console.WriteLine($" 压力: {pressure}kPa");
}
float speed;
if (plc.ReadFloatFromDm(SPEED_ADDRESS, out speed))
{
Console.WriteLine($" 速度: {speed}rpm");
}
}
static void TestStringOperations(OmronFinsTcpCommunicator plc)
{
Console.WriteLine("字符串读写测试...");
// 测试1:写入和读取产品代码
short stringAddress1 = 300;
short stringLength1 = 10;
string productCode = "P-2024-01";
if (plc.WriteStringToDm(stringAddress1, stringLength1, productCode))
{
Console.WriteLine($"✓ 写入产品代码: {productCode}");
string readProductCode;
if (plc.ReadStringFromDm(stringAddress1, stringLength1, out readProductCode))
{
Console.WriteLine($" 读取产品代码: {readProductCode}");
Console.WriteLine($" 验证结果: {(readProductCode == productCode ? "通过" : "失败")}");
}
}
// 测试2:特殊长度字符串处理(4个字长度)
short stringAddress2 = 320;
short stringLength2 = 4; // 4个字 = 8个字符,但会截断为5个字符
string longString = "ABCDEFGH";
if (plc.WriteStringToDm(stringAddress2, stringLength2, longString))
{
Console.WriteLine($"\n✓ 写入长字符串: {longString}");
string readString;
if (plc.ReadStringFromDm(stringAddress2, stringLength2, out readString))
{
Console.WriteLine($" 读取结果: {readString}");
Console.WriteLine($" 注意:4个字长度自动截断为5个字符");
}
}
}
static void TestBatchDataOperations(OmronFinsTcpCommunicator plc)
{
Console.WriteLine("批量数据处理测试...");
// 测试1:批量写入多个数据点
short batchWriteAddress = 400;
short[] batchData = { 100, 200, 300, 400, 500 };
Console.WriteLine("批量写入数据:");
for (int i = 0; i < batchData.Length; i++)
{
if (plc.WriteShortToDm((short)(batchWriteAddress + i), batchData[i]))
{
Console.WriteLine($" DM{batchWriteAddress + i} = {batchData[i]}");
}
}
// 测试2:批量读取数据
short batchReadAddress = 400;
short batchCount = 5;
short[] readBatchData;
if (plc.ReadMultipleShortsFromDm(batchReadAddress, batchCount, out readBatchData))
{
Console.WriteLine("\n批量读取结果:");
for (int i = 0; i < readBatchData.Length; i++)
{
Console.WriteLine($" DM{batchReadAddress + i} = {readBatchData[i]}");
}
// 验证数据一致性
bool allMatch = true;
for (int i = 0; i < Math.Min(batchData.Length, readBatchData.Length); i++)
{
if (batchData[i] != readBatchData[i])
{
allMatch = false;
break;
}
}
Console.WriteLine($"批量数据验证: {(allMatch ? "通过" : "失败")}");
}
// 测试3:批量读取浮点数
short floatBatchAddress = 500;
short floatCount = 3;
float[] floatData;
if (plc.ReadMultipleFloatsFromDm(floatBatchAddress, floatCount, out floatData))
{
Console.WriteLine("\n批量读取浮点数:");
for (int i = 0; i < floatData.Length; i++)
{
Console.WriteLine($" DM{floatBatchAddress + i * 2} = {floatData[i]}");
}
}
}
static void TestRawByteOperations(OmronFinsTcpCommunicator plc)
{
Console.WriteLine("原始字节数据测试...");
// 测试:读取原始字节数据
short rawDataAddress = 600;
short byteLength = 10; // 读取10个字节
byte[] rawData;
if (plc.ReadBytesFromDm(rawDataAddress, byteLength, out rawData))
{
Console.WriteLine($"✓ 成功读取 {rawData.Length} 字节数据");
// 显示字节数据
Console.Write(" 字节数据: ");
for (int i = 0; i < Math.Min(rawData.Length, 16); i++)
{
Console.Write($"{rawData[i]:X2} ");
}
if (rawData.Length > 16) Console.Write("...");
Console.WriteLine();
// 转换为十六进制字符串
string hexString = BitConverter.ToString(rawData).Replace("-", " ");
Console.WriteLine($" 十六进制: {hexString}");
// 尝试将字节数据解释为字符串(ASCII)
string asciiString = System.Text.Encoding.ASCII.GetString(rawData);
Console.WriteLine($" ASCII字符串: {asciiString}");
}
}
static string GetStatusDescription(short status)
{
switch (status)
{
case 0: return "停机";
case 1: return "运行";
case 2: return "报警";
case 3: return "故障";
case 4: return "维护";
default: return $"未知状态({status})";
}
}
}
// 实际应用场景示例:生产线控制器
class ProductionLineController
{
private OmronFinsTcpCommunicator _plc;
// PLC地址常量定义
private const short AUTO_MODE_ADDRESS = 1000; // 自动模式标志
private const short PRODUCTION_COUNT_ADDRESS = 1002; // 生产计数
private const short PRODUCT_CODE_ADDRESS = 1010; // 产品代码地址
private const short PRODUCT_CODE_LENGTH = 20; // 产品代码长度
private const short TEMPERATURE_ADDRESS = 1030; // 温度监控
private const short ALARM_CODE_ADDRESS = 1032; // 报警代码
public ProductionLineController(string plcIp)
{
_plc = new OmronFinsTcpCommunicator();
if (!_plc.ConnectToPlc(plcIp))
{
throw new Exception($"无法连接到PLC: {plcIp}");
}
}
/// <summary>
/// 启动自动生产模式
/// </summary>
public bool StartAutoProduction()
{
return _plc.WriteShortToDm(AUTO_MODE_ADDRESS, 1);
}
/// <summary>
/// 停止自动生产模式
/// </summary>
public bool StopAutoProduction()
{
return _plc.WriteShortToDm(AUTO_MODE_ADDRESS, 0);
}
/// <summary>
/// 获取当前生产计数
/// </summary>
public bool GetProductionCount(out int count)
{
short countShort;
bool success = _plc.ReadShortFromDm(PRODUCTION_COUNT_ADDRESS, out countShort);
count = countShort;
return success;
}
/// <summary>
/// 重置生产计数器
/// </summary>
public bool ResetProductionCounter()
{
return _plc.WriteShortToDm(PRODUCTION_COUNT_ADDRESS, 0);
}
/// <summary>
/// 设置当前生产的产品代码
/// </summary>
public bool SetProductCode(string productCode)
{
return _plc.WriteStringToDm(PRODUCT_CODE_ADDRESS, PRODUCT_CODE_LENGTH, productCode);
}
/// <summary>
/// 获取当前生产的产品代码
/// </summary>
public bool GetProductCode(out string productCode)
{
return _plc.ReadStringFromDm(PRODUCT_CODE_ADDRESS, PRODUCT_CODE_LENGTH, out productCode);
}
/// <summary>
/// 获取设备温度
/// </summary>
public bool GetTemperature(out float temperature)
{
return _plc.ReadFloatFromDm(TEMPERATURE_ADDRESS, out temperature);
}
/// <summary>
/// 检查设备是否有报警
/// </summary>
public bool CheckAlarm(out short alarmCode)
{
return _plc.ReadShortFromDm(ALARM_CODE_ADDRESS, out alarmCode);
}
/// <summary>
/// 获取完整设备状态报告
/// </summary>
public string GetDeviceStatusReport()
{
StringBuilder report = new StringBuilder();
report.AppendLine("=== 设备状态报告 ===");
// 读取自动模式
short autoMode;
if (_plc.ReadShortFromDm(AUTO_MODE_ADDRESS, out autoMode))
{
report.AppendLine($"自动模式: {(autoMode == 1 ? "启用" : "禁用")}");
}
// 读取生产计数
int count;
if (GetProductionCount(out count))
{
report.AppendLine($"生产计数: {count}");
}
// 读取产品代码
string productCode;
if (GetProductCode(out productCode))
{
report.AppendLine($"产品代码: {productCode}");
}
// 读取温度
float temperature;
if (GetTemperature(out temperature))
{
report.AppendLine($"设备温度: {temperature}°C");
}
// 读取报警代码
short alarmCode;
if (CheckAlarm(out alarmCode))
{
if (alarmCode == 0)
report.AppendLine($"报警状态: 正常");
else
report.AppendLine($"报警代码: {alarmCode}");
}
return report.ToString();
}
}
OmronFinsHslUdp 与 OmronFinsHsl 类对比分析
这两个类都是用于欧姆龙PLC通信的,但有以下关键区别:
1. 通信协议不同
| 类 | 通信协议 | 底层实现 | 端口 |
|---|---|---|---|
| OmronFinsHslUdp | FINS/UDP 协议 | OmronFinsUdp 类 |
9600 (UDP) |
| OmronFinsHsl | FINS/TCP 协议 | OmronFinsNet 类 |
9600 (TCP) |
cs
// UDP版本
public class OmronFinsHslUdp
{
private OmronFinsUdp omronFinsNet; // UDP客户端
public bool connect(string ip)
{
omronFinsNet = new OmronFinsUdp(ip, 9600);
return true; // UDP连接是即时的,不需要ConnectServer()
}
}
// TCP版本
public class OmronFinsHsl
{
private OmronFinsNet omronFinsNet; // TCP客户端
public bool connect(string ip)
{
omronFinsNet = new OmronFinsNet(ip, 9600);
OperateResult connect = omronFinsNet.ConnectServer(); // TCP需要显式连接
return connect.IsSuccess;
}
}
2. 性能特性对比
| 特性 | FINS/UDP | FINS/TCP |
|---|---|---|
| 连接开销 | 小(无连接) | 大(需要建立连接) |
| 传输速度 | 快 | 相对较慢 |
| 可靠性 | 低(可能丢包) | 高(确保送达) |
| 数据顺序 | 不保证 | 保证 |
| 适用场景 | 实时控制、状态监测 | 数据传输、参数配置 |
3. 方法差异
OmronFinsHsl 有而 OmronFinsHslUdp 没有的方法:
cs
// 读取原始字节数据 - 只有TCP版本有
public bool read(short address, short length, out byte[] values)
{
var re = omronFinsNet.Read("D" + address, (ushort)length);
// ...
}
OmronFinsHslUdp 有而 OmronFinsHsl 没有的方法:
cs
// 小端序字符串读取 - 只有UDP版本有
public bool readxl(short address, short num, out string value)
{
// 处理小端序字符串...
}