一、前置知识:基恩士 PLC 通信协议核心
基恩士(KEYENCE)PLC(如 KV 系列)主流通信方式为以太网通信,核心协议基于:
1. 协议基础
基恩士以太网通信默认采用 MC 协议(三菱兼容协议) 或 基恩士专属以太网协议,其中:
- MC 协议 :是工业常用的以太网协议,支持 TCP/IP 连接,端口默认
5006(部分型号为8080); - 数据格式:采用二进制 / ASCII 码格式,支持位(X/Y/M)、字(D/W)、双字(DD)等寄存器读写;
- 通信规则:
- 寄存器地址格式:基恩士 PLC 寄存器有固定命名规则,例如:
- X:输入位(如 X0、X100);
- Y:输出位(如 Y0、Y200);
- M:内部辅助继电器(如 M100、M2000);
- D:数据寄存器(如 D0、D1000,16 位);
- DD:双字数据寄存器(如 DD0,32 位,由 D0+D1 组成);
- W:链接寄存器(如 W0);
- 地址映射:HSL 框架已封装地址转换,无需手动拼接协议帧,但需了解地址格式对应关系。
2. 通信前提
- 基恩士 PLC 已配置以太网参数:IP 地址、子网掩码、网关(需与电脑同网段);
- PLC 侧已启用以太网通信功能(无密码限制或已配置允许访问);
- 关闭电脑防火墙(或放行 PLC 通信端口)。
二、HSL 框架介绍
HSL(HslCommunication)是国产工业通信框架,支持主流 PLC / 仪表 / 变频器通信,对基恩士 PLC 的 MC 协议做了高度封装,无需手动解析协议帧,只需调用 API 即可完成通信。
1. HSL 安装(.NET Framework 4.8)
通过 NuGet 安装(控制台 / Visual Studio):
-
Visual Studio:右键项目 → 管理 NuGet 程序包 → 搜索
HslCommunication→ 安装(选择适配.NET Framework 4.8 的版本,建议 5.0+); -
控制台安装:
csInstall-Package HslCommunication -Version 5.4.0三、完整控制台案例(.NET Framework 4.8)
1. 案例功能
-
连接 / 断开基恩士 PLC;
-
读写位寄存器(M/X/Y);
-
读写字寄存器(D);
-
读写双字寄存器(DD);
-
异常处理(连接失败、读写超时、地址错误等)。
csusing HslCommunication; using HslCommunication.Profinet.Keyence; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace C_与基恩士通信MC协议 { internal class Program { // 全局PLC通信对象(基恩士MC协议) private static KeyenceMcNet keyencePlc; static void Main(string[] args) { Console.WriteLine("===== 基恩士PLC通信案例(HSL框架)====="); // 1. 初始化PLC通信对象 InitPlcConnection(); try { // 2. 连接PLC OperateResult connectResult = keyencePlc.ConnectServer(); if (connectResult.IsSuccess) { Console.WriteLine($"[{DateTime.Now}] PLC连接成功!"); // 3. 读写位寄存器(M100) ReadWriteBitRegister(); // 4. 读写字寄存器(D100) ReadWriteWordRegister(); // 5. 读写双字寄存器(DD100) ReadWriteDoubleWordRegister(); } else { Console.WriteLine($"[{DateTime.Now}] PLC连接失败!原因:{connectResult.Message}"); } } catch (Exception ex) { Console.WriteLine($"[{DateTime.Now}] 通信异常:{ex.Message}"); } finally { // 6. 断开连接 if (keyencePlc != null ) { keyencePlc.ConnectClose(); Console.WriteLine($"[{DateTime.Now}] PLC连接已断开"); } } Console.WriteLine("按任意键退出..."); Console.ReadKey(); } /// <summary> /// 初始化PLC连接参数 /// </summary> private static void InitPlcConnection() { // 核心参数:PLC IP地址 + MC协议端口(基恩士默认5006,部分型号8080) string plcIp = "172.0.0.1"; // 替换为你的PLC IP int plcPort = 8501; // 基恩士MC协议默认端口 // 创建基恩士MC协议通信对象 keyencePlc = new KeyenceMcNet(plcIp, plcPort); // 可选配置:超时时间(默认2000ms,建议根据网络调整) keyencePlc.ReceiveTimeOut = 3000; } /// <summary> /// 读写位寄存器(M/X/Y,以M100为例) /// </summary> private static void ReadWriteBitRegister() { Console.WriteLine("\n----- 读写位寄存器(M100)-----"); // 读位寄存器:M100 OperateResult<bool> readBitResult = keyencePlc.ReadBool("M100"); if (readBitResult.IsSuccess) { Console.WriteLine($"[{DateTime.Now}] 读取M100值:{readBitResult.Content}"); // 写位寄存器:将M100置反 bool writeValue = !readBitResult.Content; OperateResult writeBitResult = keyencePlc.Write("M100", writeValue); if (writeBitResult.IsSuccess) { Console.WriteLine($"[{DateTime.Now}] 写入M100值:{writeValue} → 成功"); // 验证写入结果 OperateResult<bool> verifyResult = keyencePlc.ReadBool("M100"); if (verifyResult.IsSuccess) { Console.WriteLine($"[{DateTime.Now}] 验证M100值:{verifyResult.Content}"); } } else { Console.WriteLine($"[{DateTime.Now}] 写入M100失败!原因:{writeBitResult.Message}"); } } else { Console.WriteLine($"[{DateTime.Now}] 读取M100失败!原因:{readBitResult.Message}"); } } /// <summary> /// 读写字寄存器(D/W,以D100为例,16位) /// </summary> private static void ReadWriteWordRegister() { Console.WriteLine("\n----- 读写字寄存器(D100)-----"); // 读字寄存器:D100(16位整数) OperateResult<short> readWordResult = keyencePlc.ReadInt16("D100"); if (readWordResult.IsSuccess) { Console.WriteLine($"[{DateTime.Now}] 读取D100值:{readWordResult.Content}"); // 写字寄存器:D100 = 1234 short writeValue = 1234; OperateResult writeWordResult = keyencePlc.Write("D100", writeValue); if (writeWordResult.IsSuccess) { Console.WriteLine($"[{DateTime.Now}] 写入D100值:{writeValue} → 成功"); // 验证写入结果 OperateResult<short> verifyResult = keyencePlc.ReadInt16("D100"); if (verifyResult.IsSuccess) { Console.WriteLine($"[{DateTime.Now}] 验证D100值:{verifyResult.Content}"); } } else { Console.WriteLine($"[{DateTime.Now}] 写入D100失败!原因:{writeWordResult.Message}"); } } else { Console.WriteLine($"[{DateTime.Now}] 读取D100失败!原因:{readWordResult.Message}"); } } /// <summary> /// 读写双字寄存器(DD,以DD100为例,32位) /// </summary> private static void ReadWriteDoubleWordRegister() { Console.WriteLine("\n----- 读写双字寄存器(DD100)-----"); // 读双字寄存器:DD100(32位整数,等价于D100+D101) OperateResult<int> readDWordResult = keyencePlc.ReadInt32("DD100"); if (readDWordResult.IsSuccess) { Console.WriteLine($"[{DateTime.Now}] 读取DD100值:{readDWordResult.Content}"); // 写双字寄存器:DD100 = 987654 int writeValue = 987654; OperateResult writeDWordResult = keyencePlc.Write("DD100", writeValue); if (writeDWordResult.IsSuccess) { Console.WriteLine($"[{DateTime.Now}] 写入DD100值:{writeValue} → 成功"); // 验证写入结果 OperateResult<int> verifyResult = keyencePlc.ReadInt32("DD100"); if (verifyResult.IsSuccess) { Console.WriteLine($"[{DateTime.Now}] 验证DD100值:{verifyResult.Content}"); } } else { Console.WriteLine($"[{DateTime.Now}] 写入DD100失败!原因:{writeDWordResult.Message}"); } } else { Console.WriteLine($"[{DateTime.Now}] 读取DD100失败!原因:{readDWordResult.Message}"); } } } }四、核心知识点详解
1. KeyenceMcNet 类核心参数
|------------------------|-----------------------------------------------------|
| 参数 / 方法 | | 说明 | |----| |
| KeyenceMcNet(ip, port) | 构造函数:ip=PLC 以太网 IP,port=MC 协议端口(基恩士默认 5006) |
| Timeout | 通信超时时间(毫秒),默认 2000ms,网络差时建议设为 3000-5000ms |
| AsciiFormat | 是否启用 ASCII 格式(默认 false = 二进制),老款基恩士 PLC 可能需要设为 true |
| ConnectServer() | 连接 PLC,返回OperateResult(IsSuccess 判断是否成功) |
| ConnectClose() | 断开 PLC 连接 |
| IsConnected | 检查当前是否处于连接状态 |
| LogNet | 日志输出(调试用,可输出到控制台 / 文件) |
2. 寄存器地址格式(HSL 兼容)
-
HSL 对基恩士寄存器地址做了兼容,无需手动转换协议地址,直接用 PLC 原生地址:
|-------|-----------------------|---------------------------------------|-----------------|
| 寄存器类型 | HSL 地址格式 | | 示例 | |----| | | 说明 | |----| |
| 输入位 | X + 数字 | |---------| | X0、X100 | | 只读 |
| 输出位 | |--------| | Y + 数字 | | |---------| | Y0、Y200 | | 可读可写 |
| 内部继电器 | M + 数字 | |------------|---| | M100、M2000 | | | 可读可写 |
| 数据寄存器 | |--------| | D + 数字 | | D100、D1000 | 16 位,可读可写 |
| 双字寄存器 | DD + 数字 | DD100 | 32 位(D100+D101) |
| 链接寄存器 | W + 数字 | W0、W100 | 16 位,可读可写 |3. 核心读写方法
|---------------------------|----------------------|---------------------------|----------------------------|
| 数据类型 | 读方法 | | 写方法 | |-----| | 示例 |
| 位(bool) | ReadBool("M100") | Write("M100", true) | 读写 M100 位 |
| 16 位整数 | ReadInt16("D100") | Write("D100", (short)123) | 读写 D100(short 类型) |
| 32 位整数 | ReadInt32("DD100") | Write("DD100", 987654) | 读写 DD100(int 类型) |
| 浮点数 | ReadFloat("DD100") | Write("DD100", 3.14f) | 读写 DD100 存储的浮点数 |
| |------|---| | 批量读位 | | | ReadBool("M100", 10) | | 读取 M100-M109 共 10 个位 |
| 批量读字 | ReadInt16("D100", 5) | | 读取 D100-D104 共 5 个 16 位寄存器 |4. 异常处理核心
-
HSL 所有通信方法均返回
OperateResult(或泛型OperateResult<T>),严禁直接忽略返回结果 ,必须通过IsSuccess判断是否成功: -
IsSuccess=true:操作成功,Content(泛型)获取返回值; -
IsSuccess=false:操作失败,Message获取失败原因(如 "连接超时""地址不存在")。
五、常见问题与解决方案
1. 连接失败(ConnectServer 返回失败)
- 原因 1:PLC IP 错误 / 电脑与 PLC 不在同网段 → 检查 IP 配置,ping PLC IP 是否通;
- 原因 2:端口错误 → 基恩士 MC 协议默认 5006,部分型号用 8080,可咨询基恩士技术手册;
- 原因 3:PLC 未启用以太网通信 → 进入 PLC 编程软件(KV STUDIO)启用以太网功能;
- 原因 4:防火墙拦截 → 关闭电脑防火墙,或放行 PLC 端口(5006/8080);
- 原因 5:PLC 密码限制 → 检查 PLC 是否设置了通信密码,需在 HSL 中配置(
keyencePlc.Password = "123456")。
2. 读写失败(Read/Write 返回失败)
- 原因 1:地址格式错误 → 确认寄存器地址是否存在(如 M9999 超出 PLC 范围);
- 原因 2:数据类型不匹配 → 写 D 寄存器时需用 short 类型,写 DD 寄存器用 int 类型;
- 原因 3:ASCII / 二进制格式不匹配 → 尝试设置
keyencePlc.AsciiFormat = true; - 原因 4:PLC 处于停机状态 → 确保 PLC 处于 RUN 模式;
- 原因 5:通信超时 → 增大
Timeout值(如 5000ms)。
3. 数据读取错误(值不对)
- 原因 1:字节序问题 → 基恩士默认大端序,HSL 已适配,无需手动转换;
- 原因 2:双字寄存器地址错误 → DD100 对应 D100+D101,而非 D100 单独;
- 原因 3:浮点数格式错误 → 确认 PLC 中浮点数存储格式(IEEE 754),HSL 默认兼容。
六、调试技巧
- 启用日志 :通过
keyencePlc.LogNet = new LogNetConsole()输出通信日志,查看协议帧交互过程; - ping 测试:先 ping PLC IP,确保网络连通;
- 端口测试 :用 Telnet 测试 PLC 端口是否开放(
telnet 192.168.1.100 5006); - PLC 侧监控:用基恩士 KV STUDIO 的 "在线监控" 功能,验证寄存器值是否正确;
- 简化测试:先测试读 M100/D100 等简单地址,排除复杂地址问题。
- 批量操作:频繁读写时优先用批量读写方法(如
ReadInt16("D100", 10)),减少通信次数; - 资源释放:通信完成后必须调用
ConnectClose()释放连接,避免端口占用。