# RS485 SDK 控制 本章供上位机、工站及第三方 SDK 的集成人员使用,说明如何通过设备的 SDK RS485 接口查询状态、下发操作并接收结果。日常操作员不需要使用本接口;现场集成和维护时, 应先用无副作用的状态查询完成通信验证,再接入检测、参数或标定操作。 ```{important} 本章属于授权集成附录,不是用户操作说明。设备用户应在触摸屏完成检测、维护、标定、 设置和升级;集成测试不得改变触摸屏当前选择,也不得与现场操作同时进行。 ``` ```{important} 本章所述“SDK RS485 接口”是设备与外部上位机通信的 Modbus RTU 接口,不是 “进水拓展板”页面中的“RS485 开关”。后者用于控制拓展板所连接的外部设备, 不能用来配置或通断本章的 SDK 通信。 ``` ## 适用范围与安全边界 SDK 可以用于: - 查询设备和检测状态; - 启动、暂停、恢复或停止检测; - 读取、修改并保存允许开放的设备参数; - 启动经过授权的维护、清洗或标定流程; - 接收命令进度、最终响应、日志文本、参数数据和健康故障信息。 SDK 不应绕过设备屏幕上的安全提示,也不应在有人拆机、管路断开、试剂不足或设备 处于其他维护流程时强制启动动作。远程执行泵、阀、排水、标定等操作前,现场必须有 人员确认设备周围无泄漏风险。 ## 接线 断电后完成接线,再依次给设备和上位机适配器上电。 | 设备端 | 上位机/转换器端 | 要求 | | --- | --- | --- | | `RS485 A` | `A`、`D+` 或 `485+` | 同名端连接;不同厂商标注可能相反 | | `RS485 B` | `B`、`D-` 或 `485-` | 同名端连接;通信失败时核对适配器说明书 | | `GND` | 信号地 | 建议连接,避免两端参考电位差过大 | - 使用双绞线连接 A、B,屏蔽层按现场接地规范单点接地。 - 总线采用手拉手连接,不要星形分叉;较长线路在总线两端使用匹配终端电阻。 - 同一总线上的从站地址必须唯一。 - 不要带电插拔裸线,不要将 RS485 端子接到市电、网口或普通 TTL 串口。 - USB 转 RS485 适配器必须支持半双工 Modbus RTU,并正确控制收发方向。 若 A/B 标识不统一,先查看转换器说明书。只有在断电状态下才能交换 A、B 试验。 ## 默认通信参数 | 项目 | 默认值 | | --- | --- | | 协议 | Modbus RTU | | 波特率 | `115200` | | 数据位 | `8` | | 校验 | 无 | | 停止位 | `1` | | 流控 | 无 | | 设备角色 | Modbus 从站 | | 从站地址 | `1` | | 合法从站地址 | `1..247` | 修改设备角色或从站地址后必须重启设备才会生效。常规 SDK 集成应保留设备的默认从站 角色,由 SDK 作为 Modbus 主站。除非项目明确要求多节点反向轮询,否则不要切换设备为 主站模式。 ## 通信模型 RS485 线路上传输的是标准 Modbus RTU 帧。设备控制命令位于 Modbus Holding Register 邮箱中,不能把设备命令字节直接写到串口。 ```text SDK 生成设备命令 -> 打包到下行邮箱 -> 0x10 写多个保持寄存器 -> 设备受理并执行 -> 设备把响应放入上行邮箱 -> SDK 用 0x03 读取保持寄存器 -> 解包并判断业务响应码 ``` | 方向 | 起始寄存器 | 数量 | Modbus 功能码 | | --- | ---: | ---: | --- | | SDK -> 设备 | `0` | 按实际载荷计算,最多 123 | `0x10` 写多个保持寄存器 | | 设备 -> SDK | `128` | 固定读取 123 | `0x03` 读保持寄存器 | ```{warning} Modbus 写入成功仅表示命令已送入通信邮箱,不表示检测、清洗、标定等业务已经完成。 SDK 必须继续读取响应邮箱,直到收到该命令的最终业务响应。 ``` ## 邮箱格式 | 相对偏移 | 内容 | 说明 | | ---: | --- | --- | | `0` | `payload_length` | 有效字节数,范围 `1..242`;`0` 表示没有消息 | | `1` | `sequence` | 16 位消息序号 | | `2..122` | `payload` | 每个寄存器先放高字节、再放低字节 | 一次写入所需的寄存器数: ```text register_count = 2 + ceil(payload_length / 2) ``` 载荷为奇数字节时,最后一个寄存器的低字节补 `0x00`,但补位不计入 `payload_length`。单条载荷最大为 242 字节,一条完整设备命令不得拆到两个邮箱序号中。 ### 序号规则 - 每条新消息的序号必须与上一条已发送消息不同。 - SDK 可从 `1` 开始递增,达到 `65535` 后自然回绕。 - 相同序号的重复消息会被设备忽略,用于避免重发造成重复动作。 - 不要只更新序号而保留旧长度和旧载荷,否则旧命令可能被再次执行。 - SDK 也必须按上行序号去重,避免重复处理同一响应。 - 重连后先读取一次上行邮箱并记录当前序号,再发送新的下行序号。 ## 第一次联调:查询检测状态 检测状态查询无副作用,适合作为首次联调命令。设备命令载荷为: ```text AA BB 21 ``` 假设下行序号为 `1`,SDK 应从寄存器 `0` 写入以下 4 个寄存器: | 寄存器 | 值 | 说明 | | ---: | ---: | --- | | `0` | `0x0003` | 载荷长度为 3 | | `1` | `0x0001` | 序号为 1 | | `2` | `0xAABB` | 帧头 | | `3` | `0x2100` | 命令 `0x21`,低字节补零 | 推荐联调步骤: 1. 设置串口为 `115200/8/N/1`,从站地址设为 `1`。 2. 用功能码 `0x10` 从地址 `0` 写入上述 4 个寄存器。 3. 确认收到正常 Modbus 写响应。 4. 每隔约 `100 ms` 用功能码 `0x03` 从地址 `128` 读取 123 个寄存器。 5. 当长度为 `1..242` 且序号变化时,按长度解包响应。 6. 解析响应正文,并依据业务响应码判断是否结束。 若第 3 步成功但始终没有业务响应,优先检查轮询的从站地址、起始寄存器和上行序号 去重逻辑,不要连续重发控制命令。 ## SDK 打包与解包示例 以下伪代码用于说明外部 SDK 的行为,不限定具体编程语言或 Modbus 库。 ```python MAX_PAYLOAD = 242 UPLINK_START = 128 UPLINK_REGISTERS = 123 def pack_mailbox(payload, sequence): assert 1 <= len(payload) <= MAX_PAYLOAD registers = [len(payload), sequence & 0xffff] for offset in range(0, len(payload), 2): high = payload[offset] low = payload[offset + 1] if offset + 1 < len(payload) else 0 registers.append((high << 8) | low) return registers def unpack_mailbox(registers): length = registers[0] sequence = registers[1] if length == 0: return None if length > MAX_PAYLOAD: raise ProtocolError("invalid mailbox length") payload = bytearray() for value in registers[2:]: payload.append((value >> 8) & 0xff) payload.append(value & 0xff) return sequence, bytes(payload[:length]) def send_command(modbus, slave_id, command_payload, sequence): registers = pack_mailbox(command_payload, sequence) modbus.write_multiple_registers(slave_id, 0, registers) def poll_new_response(modbus, slave_id, last_sequence): registers = modbus.read_holding_registers( slave_id, UPLINK_START, UPLINK_REGISTERS) message = unpack_mailbox(registers) if message is None or message[0] == last_sequence: return None return message ``` 生产 SDK 还应加入串口互斥、CRC/Modbus 异常处理、超时、断线重连、响应分类、日志 脱敏和操作审计。对于泵、阀、检测、标定等非幂等动作,超时后应先查询设备状态, 不得直接以新序号盲目重发。 ## 命令响应处理 设备可能返回 UTF-8/ASCII 状态文本,也可能返回二进制参数 BSON。文本状态通常包含: ```text Status code: Result: ``` 并可能附带 `Action`、`Parameters` 或 `Info`。SDK 应按字段解析,不要依赖某一种语言的 完整提示句。 | 响应码 | SDK 处理 | | ---: | --- | | `102` | 正在处理或输出分段内容;继续收取,不结束事务 | | `202` | 命令已受理;记录事务并继续等待最终响应 | | `200` | 成功终态;完成事务并更新界面 | | `400` | 请求或参数错误;停止重试并提示修正输入 | | `409` | 设备忙或流程冲突;查询状态,等待当前流程结束 | | `499` | 操作已取消;完成事务并显示取消结果 | | `500` | 执行失败;记录原始响应并进入故障处理 | 完整解释和操作建议见[指令响应码](command-response-codes.md)。 ### 异步命令 检测、维护和标定通常是异步命令。正确生命周期为: ```text 发送命令 -> 收到该命令的 202 -> 设备执行 -> 收到该命令的最终状态 ``` 最终状态只能是 `200/400/409/499/500`。SDK 不得把以下情况当作完成: - 收到 Modbus `0x10` 正常响应; - 收到 `102` 或 `202`; - 收到一段日志或过程文本; - 收到其他操作产生的状态事件; - 上行邮箱序号发生变化但正文不属于当前事务。 同一连接上一次只发起一个会改变设备状态的流程最稳妥。需要并行处理查询时,SDK 应按 命令类型、响应正文和本地事务状态做关联,并保留完整时间线。 ### 长文本和分段结果 日志、参数列表等长内容可能被拆成多条消息。SDK 应按照消息中的 `stream_id`、 `chunk_index`、`chunk_count`、`offset` 和 `total_length` 重组,校验段号无缺失后再交给 用户。分段内容不是命令终态,重组完成后仍要等待最终响应码。 参数数据可能以 `AA BB 60` 开头,后接 BSON 文档。应使用成熟 BSON 库并依据 BSON 自身长度解析,不能通过查找 `0x00` 判断文档结束。 ## 常用控制工作流 ### 查询状态 使用 `AA BB 21` 查询检测状态。SDK 应在以下时机主动查询: - 建立连接后; - 控制命令超时后; - 收到 `409` 后; - 通信中断并恢复后; - 操作员准备启动检测、维护或标定前。 ### 检测控制 | 操作 | 设备命令 | SDK 前置检查 | | --- | --- | --- | | 启动检测 | `0x4F`,后接稀释与 7 个项目开关 | 设备空闲、试剂和废液状态正常、检测项目合法 | | 暂停检测 | `AA BB 04` | 当前有可暂停的检测流程 | | 恢复检测 | `AA BB 05` | 当前处于暂停状态 | | 停止/取消 | `AA BB 06` | 提示用户流程将终止,并等待 `499` 或其他终态 | | 查询状态 | `AA BB 21` | 无副作用,可随时用于确认状态 | 启动检测载荷为: ```text AA BB 4F ``` 项目开关使用 `0` 或 `1`。稀释倍率和项目组合应来自受控配置,不应让用户输入任意 字节。收到 `202` 后锁定重复启动按钮,最终响应到达后再恢复。 ### 参数读写 - `0x33`:按参数 ID 读取,参数 ID 为 16 位小端。 - `0x34`:按参数 ID 写入数值或 UTF-8 字符串。 - `0x1C`:将已修改参数保存到设备。 - `0x0B`:恢复默认参数,属于高风险操作,必须二次确认。 参数写入成功不一定等于已永久保存。推荐流程为“读取旧值 -> 校验新值 -> 写入 -> 读取 回验 -> 保存 -> 再次读取”。通信角色或从站地址等启动参数保存后还需要重启设备。 ### 日志和数据 通过 SDK 获取日志或文件时,应先确认设备未处于 USB 大容量存储占用状态。长结果按分段 消息重组,并记录设备返回的实际文件名、时间范围和字节数。日常查看、下载和导出方法见 [日志查看与数据下载](logs-and-data-export.md)。 ### 标定和维护 SDK 可调用已授权的标定、清洗和维护命令,但必须复用手册中的现场前置条件:标液正确、 管路连接正确、废液容量足够、现场有人值守。SDK 界面应明确显示当前标定对象、阶段、 已用标液及最终结果。具体步骤见[设备标定流程](calibration-procedures.md)和 [维护指令参考](maintenance-page-reference.md)。 不要在 SDK 中向普通操作员暴露原始泵号、阀位、掩码或底层调试操作。需要底层执行器 测试时,应进入受控的工厂/工程模式,由授权人员按维修规程操作。 ## 健康故障处理 命令响应码和健康故障码是两套独立信息:响应码说明本次命令是否受理或完成;健康故障码 说明设备当前或近期检测到的异常。一次命令返回 `200`,不代表设备不存在其他健康告警。 SDK 收到健康故障时应保存: - 故障码和原始文本; - 首次出现、最近出现和恢复时间; - 当时正在执行的命令及响应码; - 设备状态、连接状态和操作员; - 同一时间段的相关日志。 界面应按[健康管理故障码](fault-code-reference.md)显示“现象、可能原因、设备行为和处理 方法”,并允许维护人员标记已检查项目。严重故障、漏液、异常发热或电气异味必须提示 现场立即停机断电,不能提供“一键忽略并继续运行”。 ## 超时、重试与重连 建议将通信超时和业务超时分开配置: - 通信超时:等待一次 Modbus 请求响应的时间;可有限次数重试同一 Modbus 事务。 - 受理超时:写入成功后等待 `202` 或同步终态的时间。 - 业务超时:从 `202` 到最终状态的时间;按检测、排水、标定等流程分别设置。 对查询类命令,可以在确认无响应后使用新序号重发。对启动检测、加液、排水、清洗、 标定、参数恢复和重启等有副作用的命令,业务响应超时后应: 1. 停止自动重发。 2. 恢复读取上行邮箱并检查是否漏收响应。 3. 查询设备当前状态。 4. 根据状态决定继续等待、显示已执行、允许取消或转人工处理。 5. 将原命令序号、时间和所有响应写入 SDK 审计日志。 断线重连后,不应假设设备回到空闲。先读取并去重当前邮箱,再执行状态查询;若设备仍在 运行原流程,SDK 应恢复监控,而不是再次启动。 ## 多设备接入 一条 RS485 总线可以连接多个设备,但每台设备必须有唯一地址 `1..247`。主站依次轮询, 不得并发向总线发送多个请求。设备数量、线长和轮询频率增加时,应适当延长完整轮询周期, 并保证每台设备的上行邮箱被及时读取。 设备默认从站模式只有一个上行邮箱。若 SDK 长时间不读取,新消息可能覆盖等待中的旧消息。 因此应持续轮询,命令执行期间优先读取正在操作的设备。周期遥测在 RS485 上默认关闭; 如项目开启遥测,还应评估 242 字节邮箱限制和额外总线负载。 设备也支持特定项目使用的 Modbus 主站模式,但该模式没有广播发现,最多跟踪 8 个节点, 且外部节点必须实现从站邮箱。普通上位机 SDK 不应使用此模式。 ## SDK 验收清单 - [ ] A/B/GND 接线、屏蔽和终端匹配符合现场规范。 - [ ] 串口参数为 `115200/8/N/1`,从站地址正确。 - [ ] 支持 Modbus `0x03` 和 `0x10`,CRC 由可靠协议库处理。 - [ ] 能正确处理奇数、偶数和最大 242 字节载荷。 - [ ] 下行序号递增,上行序号去重,回绕后仍能工作。 - [ ] `AA BB 21` 状态查询可以稳定重复执行。 - [ ] 能区分 Modbus 成功、`202` 受理和最终响应。 - [ ] 能处理 `102/200/202/400/409/499/500`。 - [ ] 能重组长文本,并使用 BSON 库解析参数响应。 - [ ] 有副作用命令超时后先查状态,不自动重复执行。 - [ ] 断线重连后能恢复当前流程监控。 - [ ] 能记录响应码、故障码、原始响应和操作审计信息。 - [ ] 多设备地址唯一,轮询不会造成总线冲突。 ## 常见问题排查 | 现象 | 可能原因 | 处理方法 | | --- | --- | --- | | 完全没有 Modbus 响应 | A/B 接反、串口参数或地址错误、转换器方向控制异常 | 断电核对接线;确认 `115200/8/N/1` 和地址 `1`;用标准 Modbus 工具验证 | | 出现 CRC 或帧错误 | 干扰、接地不良、支线过长、终端不当或多个主站同时发送 | 检查双绞线、屏蔽、共地和终端;确保总线只有一个主站 | | `0x10` 写成功但没有操作结果 | 只检查了 Modbus 响应,未轮询上行邮箱 | 从寄存器 `128` 固定读取 123 个寄存器并解析业务响应 | | 状态查询只执行一次 | 后续仍使用相同下行序号 | 每条新消息使用不同序号,并同时更新完整载荷 | | 同一操作执行两次 | 超时后用新序号盲目重发有副作用命令 | 停止重发,先查询设备状态并检查是否漏收最终响应 | | 反复读到同一结果 | SDK 未按上行序号去重 | 保存最后处理的上行序号,相同序号不重复通知用户 | | 收到 `409` | 设备正忙、当前流程不允许该操作 | 查询状态,等待或先按规程停止冲突流程 | | 收到 `400` | 命令长度、字段、范围或项目组合不合法 | 检查设备命令和小端字段;不要修改序号后重复旧载荷 | | 收到 `500` | 执行、硬件、存储或内部异常 | 保存完整响应和日志;结合健康故障码按排故章节处理 | | 参数值乱码或无法解析 | 把 BSON 当文本、用零字节截断数据 | 识别 `AA BB 60`,使用 BSON 内部长度和成熟解析库 | | 长日志缺段 | 轮询太慢或未按分段元数据重组 | 提高轮询频率;按流 ID 和段号校验,缺段时重新发起查询 | | RS485 遥测一直没有数据 | RS485 周期遥测默认关闭 | 这不是连接故障;先用 `AA BB 21` 验证命令链路 | | 进水拓展板开关无效 | 混淆了两个 RS485 概念 | SDK 连接使用本章接口;拓展板开关仅按拓展板章节操作 | 仍无法恢复时,保留 SDK 原始 Modbus 请求/响应、邮箱序号、设备响应正文、故障码、设备 时间和接线照片,按[联系支持](support.md)中的清单提交。不要只提供“通信失败”截图。