C#中如何和欧姆龙进行通信的

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)
{
    // 处理小端序字符串...
}
相关推荐
不绝1912 小时前
C#进阶:委托
开发语言·c#
喜欢喝果茶.2 小时前
跨.cs 文件传值(C#)
开发语言·c#
黑夜中的潜行者10 小时前
构建高性能 WPF 大图浏览器:TiledViewer 技术解密
性能优化·c#·.net·wpf·图形渲染
LongtengGensSupreme11 小时前
C# 中监听 IPv6 回环地址(Loopback Address)----socket和tcp
c#·ipv6 回环地址
就是有点傻11 小时前
C#中如何和西门子通信
开发语言·c#
海底星光11 小时前
c#进阶疗法 -jwt+授权
c#
液态不合群11 小时前
如何提升 C# 应用中的性能
开发语言·算法·c#
多多*12 小时前
计算机网络相关 讲一下rpc与传统http的区别
java·开发语言·网络·jvm·c#
阿蒙Amon13 小时前
C#每日面试题-简述反射
开发语言·面试·c#