1. 目标与原理
IoT2050(OPC UA 客户端,open62541) ──opc.tcp://<PLC_IP>:4840──▶ S7-1200(OPC UA 服务器)
IoT2050 作为边缘网关,通过 OPC UA 采集 PLC 数据块中的变量。
2. 前置条件(缺一不可,先核对)
| 条件 | 要求 | 说明 |
|---|---|---|
| CPU 固件 | 经典款 ≥ V4.4 / G2 ≥ V4.1 | S7-1200 经典款从 FW V4.4 起内置 OPC UA 服务器;S7-1200 G2 从 V4.1 起 |
| 组态软件 | TIA Portal ≥ V16(G2 需 V21) | V16 起才能组态 V4.4 的 S7-1200 |
| 运行许可证 | SIMATIC OPC UA S7-1200 Basic(订货号 6ES7823-0BA00-2BA0 纸质 / 6ES7823-0BE00-2BA0 下载版) |
一个 PLC 一个授权。没有授权 OPC UA 服务器不工作(或使用与 CPU 关联的 Basic 许可证) |
| 网络 | IoT2050 与 PLC 同网段、可互相 ping 通 | 客户端地址固定格式 opc.tcp://<PLC_IP>:4840 |
3. TIA Portal 侧配置(关键步骤)
3.1 激活 OPC UA 服务器
设备视图 → 选中 CPU → 属性 → OPC UA → 服务器 → 勾选 "激活 OPC UA 服务器"。
激活后服务器地址固定为:opc.tcp://<PLC的IP>:4840。
⚠️ 如果项目树里看不到"OPC UA 通信"目录:先确认是否激活了 OPC UA 服务器(有些版本激活并编译后才出现),再确认固件版本达标。
3.2 建模"服务器接口"(S7-1200 特有,必做!)
S7-1200 与 S7-1500 的关键区别:
| S7-1500 | S7-1200(本文场景) | |
|---|---|---|
| 勾选 DB"允许 OPC UA 访问" | ✅ 下载后变量自动出现 | ❌ 不够! |
| 服务器接口(Server Interface) | 可选 | 必须手动建模! |
S7-1200 不支持标准 SIMATIC 服务器接口,光勾选 DB 的"允许 OPC UA 访问"属性没用,必须手动建模接口并把变量拖进去,编译下载后才对客户端可见——这是新手最常踩的坑。
创建服务器接口(TIA 不同版本入口不同):
-
方式 A(TIA V16~V20 通用):项目树 → 展开 CPU →
OPC UA 通信 > 服务器接口→ 双击 "添加新服务器接口" -
方式 B(TIA V21,可能):项目树 → CPU → "程序块" → 双击"添加新块" → 对象类型选 "OPC UA 服务器接口"
命名并确认后,在接口表格的 "新增" 行,从左侧拖入要暴露的 DB 或单个变量。
⚠️ 数组注意:S7-1200 OPC UA 每个数组元素算一个变量,上限 2000 个。如果 DB 里有两个
Array[0..999]共 2000 个元素会顶到上限,建议新建一个小的优化访问 DB 放几个变量用于测试,或只拖入数组的前几个元素。⚠️ 非优化 DB 兼容性:OPC UA 仅支持符号访问。非优化寻址的 DB(如 snap7 用的)只要有符号名,同样可以拖入服务器接口;但稳妥起见,验证阶段建议用优化访问的小 DB。
3.3 安全策略 + 运行许可证 + 下载
-
安全策略:调试期 CPU 属性 →
OPC UA → 安全,勾选 "无安全设置"(None) 最省事;生产环境务必用Basic256Sha256+ 证书,并禁用其它策略。 -
运行许可证:CPU 属性 →
运行系统许可证 → OPC UA→ 设置购买的许可证类型(SIMATIC OPC UA S7-1200 Basic)。 -
可信客户端(可选):调试期可勾选"运行时自动接受客户端证书",免去手动配置可信列表。
-
编译项目 → 下载到 PLC(硬件和软件都下载)。
4. IoT2050 侧验证(open62541 客户端)
4.1 第一步:浏览地址空间,确认变量已暴露
用 open62541 写一个 C 客户端,递归浏览地址空间(跳过 Server 系统子树,只看 DeviceSet 下的 PLC 数据):
cat > /tmp/ua_client_test.c <<'EOF'
#include <open62541/client.h>
#include <open62541/client_highlevel.h>
#include <open62541/client_config_default.h>
#include <stdio.h>
static UA_Boolean isInstance(UA_NodeClass nc) {
return nc == UA_NODECLASS_OBJECT || nc == UA_NODECLASS_VARIABLE;
}
static void browseRecursive(UA_Client *client, UA_NodeId node, int depth) {
if (depth > 6) return;
UA_BrowseRequest bReq; UA_BrowseRequest_init(&bReq);
bReq.requestedMaxReferencesPerNode = 100;
bReq.nodesToBrowse = UA_BrowseDescription_new();
bReq.nodesToBr


934

被折叠的 条评论
为什么被折叠?



