3. ADS 端口与符号寻址
在 TwinCAT ADS 通信中,真正决定“能不能读到、读到什么”的,往往不是 IP 地址,而是端口号(Port)与符号寻址(Symbol Addressing)这两层机制。前者决定你与哪个 ADS 服务器对话,后者决定你访问的是 PLC 运行时中的哪一个变量。理解这两层,才能把“通信成功”与“数据正确”区分开。
一、端口号:ADS 服务器的逻辑地址
ADS 端口号是一个 16 位无符号整数,用于标识目标设备上的某个 ADS 服务器实例。它不随网卡或 IP 变化,而是由设备内部的服务注册决定。常见端口分配如下:
| 端口号 | 服务对象 | 典型用途 |
|---|---|---|
| 851 | TwinCAT 3 PLC 运行时(默认实例) | 读写 PLC 变量、调用 PLC 方法 |
| 852 | TwinCAT 3 PLC 运行时(第二实例) | 多 PLC 项目并行时的第二个运行时 |
| 10000 | TwinCAT 系统服务(System Service) | 系统状态、路由、事件通知 |
| 10001 | TwinCAT 实时服务器(Real-Time) | 实时任务、CPU 负载信息 |
| 500 | 本地 ADS 路由器(Router) | 本机内部通信、路由转发 |
端口号不是“随便填”的。若目标设备上运行的是 TwinCAT 3 PLC,默认端口就是 851;若项目配置了多个 PLC 实例,则第二个实例通常为 852,依此类推。在 ADS 客户端代码中,端口号与 AMS Net ID 一起构成目标地址:AMS Net ID + Port。例如,本机 PLC 的地址可写作 5.1.2.3.1.1:851,其中冒号前是 AMS Net ID,冒号后是端口号。
0x20(ADSERR_DEVICE_NOTFOUND),优先检查端口号是否与目标设备上实际运行的 ADS 服务器一致,而不是先怀疑网络。二、符号名称解析:从变量名到运行时地址
PLC 变量在源代码中有一个人类可读的符号名,例如 MAIN.nSpeed、MAIN.bStart、MAIN.stAxis.fPos。但 ADS 读写并不直接使用这个字符串,而是使用一个由运行时分配的句柄(Handle)。符号名称解析就是“把符号名翻译成句柄”的过程。
解析由目标设备上的 ADS 符号服务器完成。客户端发送符号名,服务器在已下载的 PLC 符号表中查找,若找到则返回一个 32 位句柄。这个句柄在本次连接会话内有效,后续读写都通过句柄进行,不再重复解析字符串。这样做的好处是:读写路径短、效率高,且符号名变化不会影响已获取句柄的读写操作。
符号名的书写必须与 PLC 项目中的声明一致,包括大小写和层级分隔符。例如,全局变量 MAIN.nSpeed 中,MAIN 是程序实例名,nSpeed 是变量名,中间用点号连接。结构体成员则继续用点号展开,如 MAIN.stAxis.fPos。数组元素可用 MAIN.aData[3] 形式访问。
三、句柄获取与释放:成对出现的资源管理
句柄是一种有限资源。每次调用 AdsSyncReadWriteReq 或 AdsSyncReadReq 之前,通常需要先通过 AdsSyncReadWriteReq 向端口 0xF003(ADS 符号服务器)发送符号名,获取句柄。获取成功后,句柄值通常是一个大于 0 的整数;若返回 0 或错误码,说明符号名不存在或符号服务器未就绪。
释放句柄通过向同一端口发送释放请求完成。释放后,该句柄不再可用,继续使用会导致读写失败。因此,句柄的获取与释放必须成对出现,尤其是在长时间运行的客户端程序中,避免句柄泄漏。一个典型的生命周期是:连接建立 → 获取句柄 → 多次读写 → 释放句柄 → 断开连接。
// 示例:获取句柄(伪代码,参数为示意值)
nPort = 851;
szSym = "MAIN.nSpeed";
nHandle = AdsSyncReadWriteReq(port=0xF003, ...);
// 若 nHandle > 0,则获取成功
// 使用句柄读取变量
AdsSyncReadReq(port=851, handle=nHandle, ...);
// 释放句柄
AdsSyncReadWriteReq(port=0xF003, release, handle=nHandle);
四、变量读写基本流程
一次完整的 ADS 变量读写,可以拆成四个阶段:连接、解析、传输、释放。连接阶段确定 AMS Net ID 与端口号;解析阶段获取符号句柄;传输阶段按句柄读写数据;释放阶段归还句柄。下图展示了这一流程中客户端与 ADS 服务器之间的交互关系。
在读写阶段,客户端需要指定数据长度和数据类型。例如,读取 MAIN.nSpeed(DINT,4 字节)时,请求长度应为 4;读取 MAIN.bStart(BOOL,1 字节)时,长度为 1。若长度不匹配,服务器可能返回数据截断或错误码。写入时同样需要保证长度与变量类型一致,否则可能写入错误字节或触发异常。
0x700(ADSERR_INVALID_HANDLE)通常表示句柄已失效。五、实践中的判断依据
在实际调试中,可以按以下顺序判断问题出在哪一层:
- 连接失败:检查 AMS Net ID、端口号、路由是否可达。错误码
0x20指向设备未找到,0x21指向端口未监听。 - 句柄获取失败:检查符号名拼写、大小写、层级路径是否与 PLC 项目一致;确认 PLC 已运行且符号已下载。
- 读写失败:检查句柄是否有效、数据长度是否匹配、变量是否被优化或映射到非 ADS 可访问区域。
- 数据异常:检查字节序、数据类型对齐、数组索引是否越界。