简介:这份资源是面向欧姆龙PLC与Modbus TCP/IP通信场景的实例源码,适合刚接触工业通信的新手以及需要快速验证方案的开发人员,用于解决上位机与欧姆龙系列PLC建立连接、完成数据收发的问题。压缩包共47个文件,约199KB,以vb源码为主体,配合exe可执行程序、xml配置、resx资源、dll库及sln解决方案等,构成一套可直接打开调试的Visual Studio工程。内容围绕OmronComm主程序展开,涉及串口通信、HostLink协议、FINS指令以及Keyence通信等模块,便于读者理解Modbus TCP/IP与欧姆龙PLC交互的代码组织方式。目前已有2772人学习下载,说明该实例在同类资料中具备一定参考价值。读者可从中获得完整的通信工程结构、协议封装思路与调试入口,适合作为学习工业通信编程的起步样例。
1. 欧姆龙 PLC 走 Modbus TCP/IP:为什么老设备偏偏要啃这块硬骨头
车间里一台跑了七八年的欧姆龙 CP 系列 PLC,上位机想读它的 DM 区数据,现场没有 OPC 服务器,也没有组态软件授权,只有一根网线和一台装了 IIS 的 Windows 机器。这种场景下,Modbus TCP/IP 几乎是唯一不需要额外花钱、不需要停产改造就能打通的路径。欧姆龙部分机型原生支持 Modbus TCP 从站(服务器)功能,通过以太网口直接暴露寄存器;而 ASP 作为服务端脚本,可以在 IIS 上快速搭一个读写页面,把 PLC 的 DM 区数据拉到浏览器里。这套组合听起来老派,但在设备联网改造、SCADA 与 PLC 连接、毕业设计这类需求里,它落地快、依赖少、调试直观。适合手里有欧姆龙 PLC、需要快速做数据采集或远程监控、又不想引入重型中间件的工程师。
2. 先搞清楚欧姆龙侧到底怎么把 Modbus TCP/IP 跑起来
2.1 欧姆龙 PLC 做 Modbus TCP 从站的两种常见路径
欧姆龙 PLC 要对外提供 Modbus TCP 服务,常见做法有两种。第一种是 CPU 自带以太网口且固件支持 Modbus TCP 服务器功能,比如 CP2E 部分型号、NJ/NX 系列配合内置 EtherNet/IP 口,通过参数设置把端口 502 打开,映射 DM 区或 CIO 区到 Modbus 寄存器地址。第二种是加装通信模块,比如 PRM21 这类通信板/模块,由模块独立处理 Modbus TCP 协议栈,CPU 只负责和模块交换数据区。两条路径的差别在于:原生支持的方式地址映射固定、配置简单;模块方式灵活但需要额外组态,且模块说明书里的寄存器映射表必须逐条核对。
我一般优先确认 CPU 型号和固件版本是否带 Modbus TCP 服务器功能。如果带,直接在 Sysmac Studio 或 CX-Programmer 里勾选设置,不用写一行通信代码。如果不带,再考虑 PRM21 或第三方网关。这里有个容易翻车的点:CP2E 的下载程序口和以太网口是分开的,下载程序走 USB 或串口,Modbus TCP 走以太网,两者互不干扰,但 IP 地址必须在同一网段。
2.2 用 CX-Programmer 配置 Modbus TCP 从站的最小步骤
以 CP2E 原生支持为例,配置流程如下。第一步,用 USB 线连接 PLC,打开 CX-Programmer,在线工作后进入 PLC 设置。第二步,找到「内置以太网」或「通信设置」里的 Modbus TCP 服务器选项,启用并设置端口号,默认 502。第三步,设置 IP 地址、子网掩码,确保和上位机同网段。第四步,定义寄存器映射,通常 DM 区对应 Modbus 保持寄存器 4xxxx,CIO 区对应线圈或离散输入。第五步,下载设置并断电重启,让以太网参数生效。
# 用 modbus 调试工具验证 PLC 从站是否在线 # 假设 PLC IP 为 192.168.1.10,读取保持寄存器起始地址 0,数量 10 modbus read --tcp 192.168.1.10:502 --slave 1 --function 3 --address 0 --quantity 10这段命令的含义是:以 TCP 方式连接 192.168.1.10 的 502 端口,从站地址 1,功能码 03(读保持寄存器),起始地址 0,读 10 个寄存器。如果返回一串数值,说明 PLC 侧 Modbus TCP 从站已经跑通。如果超时,先 ping 通再查端口,最后查从站地址和功能码是否匹配。参数说明:--slave对应 PLC 的单元号,欧姆龙默认常为 1;--address是 Modbus 逻辑地址,不是 DM 编号,DM0 通常对应地址 0,但不同机型偏移可能不同,必须查手册。
2.3 寄存器地址映射:DM 区、CIO 区和 Modbus 地址的对应关系
欧姆龙 PLC 的 DM 区是数据存储区,CIO 区是 I/O 刷新区。Modbus 协议里,保持寄存器(4xxxx)通常映射到 DM 区,线圈(0xxxx)映射到 CIO 区。以 CP2E 为例,DM0 对应 Modbus 地址 0,DM100 对应地址 100,但有些模块会把地址偏移加 1,变成 DM0 对应地址 1。这个偏移量是血泪经验:不查手册直接写代码,读出来的数据永远差一位。建议先用调试工具从地址 0 开始读 20 个寄存器,和 PLC 里 DM0 到 DM19 的当前值逐一比对,确认偏移规则后再写 ASP 代码。
3. ASP 侧怎么把 Modbus TCP 数据读到浏览器里
3.1 ASP 环境准备:IIS 配置与 Modbus 组件选择
ASP 跑在 IIS 上,Windows 11 配置 IIS 时记得勾选「ASP」和「ISAPI 扩展」两项,否则 .asp 文件直接下载而不是执行。Modbus TCP 通信在 ASP 里没有原生支持,常见做法是两种:一是用第三方 COM 组件,比如 Modbus ActiveX 控件,注册后用Server.CreateObject调用;二是用 ASP 调用外部 exe 或脚本,把 Modbus 读写结果写到临时文件再读回来。第一种性能好但组件要授权,第二种零依赖但并发差。我一般用第二种做原型验证,稳定后再换组件。
<% ' 创建 Modbus TCP 客户端对象(以某常见 ActiveX 组件为例) Dim mbClient Set mbClient = Server.CreateObject("ModbusTCP.Client") mbClient.Connect "192.168.1.10", 502 mbClient.SlaveID = 1 Dim values values = mbClient.ReadHoldingRegisters(0, 10) If IsArray(values) Then For i = 0 To UBound(values) Response.Write "DM" & i & " = " & values(i) & "<br>" Next Else Response.Write "读取失败,检查 PLC 连接" End If mbClient.Disconnect Set mbClient = Nothing %>这段 ASP 代码的逻辑是:创建 Modbus TCP 客户端,连接 PLC 的 IP 和端口,设置从站号,读取起始地址 0 的 10 个保持寄存器,然后遍历输出。参数说明:Connect的第一个参数是 PLC IP,第二个是端口;SlaveID必须和 PLC 设置一致;ReadHoldingRegisters的第一个参数是起始地址,第二个是数量。如果返回空数组,先确认组件是否注册成功,再确认 PLC 是否允许该 IP 连接。注意 ASP 默认超时时间较短,网络抖动时容易误报失败,可以在组件属性里把超时调到 3000 毫秒。
3.2 用 ASP 写一个读写 DM 区的完整页面
一个完整的读写页面需要包含连接、读、写、断开四个动作。读操作上面已经演示,写操作调用WriteHoldingRegisters方法,传入起始地址和数值数组。下面是一个带表单的完整示例,用户输入 DM 地址和值,提交后写入 PLC 并回读确认。
<% Dim mbClient, addr, val, result addr = Request.Form("addr") val = Request.Form("val") If addr <> "" And val <> "" Then Set mbClient = Server.CreateObject("ModbusTCP.Client") mbClient.Connect "192.168.1.10", 502 mbClient.SlaveID = 1 result = mbClient.WriteHoldingRegisters(CInt(addr), Array(CInt(val))) If result Then Response.Write "写入成功,回读值:" & mbClient.ReadHoldingRegisters(CInt(addr), 1)(0) Else Response.Write "写入失败" End If mbClient.Disconnect Set mbClient = Nothing End If %> <form method="post"> 地址:<input type="text" name="addr"><br> 数值:<input type="text" name="val"><br> <input type="submit" value="写入"> </form>逻辑说明:先判断表单是否提交,有数据则连接 PLC,调用写保持寄存器方法,写入成功后立即回读同一个地址确认。参数说明:CInt(addr)把表单字符串转成整数,地址范围必须在 PLC 支持的 DM 区内;Array(CInt(val))构造写入数组,Modbus 写单个寄存器用功能码 06,写多个用 16,组件内部自动处理。注意写入前确认 PLC 处于允许写入状态,有些机型在 RUN 模式下禁止写 DM 区,需要切到 MONITOR 或 PROGRAM 模式。
3.3 数据刷新频率与页面性能的平衡
ASP 页面每次请求都新建连接、读写、断开,如果做实时刷新,浏览器端用 meta 刷新或 JavaScript 定时请求,频率高了 PLC 连接数会爆。欧姆龙 PLC 的 Modbus TCP 从站通常支持 4 到 8 个并发连接,ASP 每次请求占一个,刷新间隔低于 1 秒就容易出现连接拒绝。我一般把刷新间隔设在 2 到 5 秒,页面只读不写,写操作单独放一个提交页面。如果确实需要高频采集,建议改用后台服务或定时任务把数据缓存到数据库,ASP 只读数据库,不直接碰 PLC。
4. 避坑与排查:欧姆龙 Modbus TCP 联调中最容易翻车的五个点
4.1 现象:调试工具能读,ASP 读不到
原因:ASP 进程运行在 IIS 的应用池身份下,默认账户可能没有权限访问网络或调用 COM 组件。解决:把 IIS 应用池身份改成管理员账户,或者在组件配置里允许 IIS 用户访问。另外检查 Windows 防火墙是否放行了 ASP 进程的出站 502 端口。
4.2 现象:读出来的数值全是 0 或乱码
原因:寄存器地址偏移不对,或者数据类型不匹配。Modbus 寄存器是 16 位无符号整数,欧姆龙 DM 区也是 16 位,但如果 PLC 里存的是 32 位浮点数,需要读两个寄存器再合并。解决:先用调试工具读原始值,和 PLC 监控界面对比,确认偏移和数据类型。浮点数合并时注意高低字顺序,欧姆龙通常低字在前。
4.3 现象:连接几秒后自动断开
原因:Modbus TCP 从站有连接空闲超时,ASP 页面执行慢或网络延迟高时,PLC 主动断开。解决:在 ASP 里缩短连接持有时间,读完立即断开;或者用连接池组件保持长连接。另外检查 PLC 设置里的「保持连接时间」参数,适当调大。
4.4 现象:写入成功但 PLC 不动作
原因:写的是 DM 区,但程序里用的是 CIO 区,或者写入后没有触发刷新。解决:确认程序里实际引用的地址,写完后给一个触发位或重新下载程序。有些欧姆龙机型 DM 区写入后需要断电重启才生效,这个坑在 CP 系列上遇到过。
4.5 现象:IIS 上 ASP 页面报 500 错误
原因:组件未注册、权限不足、或者 ASP 父路径未启用。解决:用regsvr32注册组件,在 IIS 里启用「ASP 父路径」,检查应用程序池的 32 位/64 位设置是否和组件匹配。Windows 11 上 IIS 默认不装 ASP,记得在「启用或关闭 Windows 功能」里勾选。
5. 进阶:把 Modbus TCP 读写封装成可复用的 ASP 函数库
5.1 封装连接与重试逻辑
直接在页面里写连接代码,改一个 IP 要翻十个文件。我习惯把 Modbus 操作封装成独立函数,放在一个modbus_lib.asp里,用<!--#include file="modbus_lib.asp"-->引入。函数内部处理连接、重试、断开,页面只调ReadDM(addr, count)和WriteDM(addr, value)。
<% Function ReadDM(startAddr, count) Dim mb, vals, retry retry = 0 Do While retry < 3 Set mb = Server.CreateObject("ModbusTCP.Client") If mb.Connect("192.168.1.10", 502) Then mb.SlaveID = 1 vals = mb.ReadHoldingRegisters(startAddr, count) mb.Disconnect Set mb = Nothing If IsArray(vals) Then ReadDM = vals Exit Function End If End If retry = retry + 1 Loop ReadDM = Array() End Function %>逻辑说明:重试三次,每次新建连接,成功读到数组就返回,失败返回空数组。参数说明:startAddr是 Modbus 起始地址,count是寄存器数量。重试间隔可以用Server.ScriptTimeout控制,但 ASP 里没有 sleep,只能靠循环空转,实际项目中建议用组件自带的重试属性。
5.2 用表格对比原生 Modbus TCP 和网关方案的取舍
| 对比项 | 原生 Modbus TCP | 第三方网关 |
|---|---|---|
| 硬件成本 | 零,CPU 自带 | 网关模块费用 |
| 配置复杂度 | 低,软件设置 | 中,需组态映射 |
| 寄存器映射 | 固定,查手册 | 灵活,可自定义 |
| 并发连接数 | 4 到 8 | 通常更多 |
| 适用场景 | 单机采集、毕业设计 | 多设备汇聚、SCADA |
选型建议:如果只是读一台欧姆龙 PLC 的 DM 区,原生方案足够;如果要接多台不同品牌 PLC 或需要协议转换,网关更省心。原生方案的天花板在并发和地址映射灵活性,网关的天花板在成本和配置工作量。
5.3 一个验证读写一致性的小技巧
写完 PLC 后,不要只信 ASP 页面的回读值,用调试工具再读一遍同一个地址,两边一致才算真正写入。我遇到过组件缓存导致回读值正确但 PLC 实际没变的情况,后来养成习惯:ASP 写完后,用独立调试工具二次确认。这个习惯帮我省了很多后悔药。另外,PLC 的 DM 区掉电不保持,如果做数据记录,记得在 PLC 程序里把关键数据写到保持寄存器或 EEPROM。
这套方案我前后在三个现场用过,最深的教训是:不要假设地址映射是连续的,也不要假设 ASP 组件的超时和 PLC 的超时能对上。每次联调,先用调试工具把 PLC 侧跑通,再写 ASP,顺序反了就是给自己找麻烦。希望帮到你。
本文还有配套的精品资源,点击获取