主题
综合例程:串口透传(本地双串口 / 远程 / 网口)
「透传」就是让本设备的串口变成一根透明的线:数据不解析、不加工,从 A 口进来就从 B 口出去。 典型用途是给手上没有接口的那台设备编程 —— 触摸屏、上位机软件、下载线都接不到现场那台仪表, 就借用本机设备的串口把它"搬"过来。 三种透传用的是同一对
set_transparent接口,区别只在两端各是什么,见第一节。
一、三种透传怎么选
| 想要的效果 | 怎么接 | 调什么 |
|---|---|---|
| 一台 485 总线上,触摸屏和 PLC 采集共存 | 串口 1 接从站、串口 2 接触摸屏 | com1:set_transparent(com2)(带参数) |
| 人在外地,用上位机工具给现场设备编程 | 串口接从站,走云 | com1:set_transparent()(不带参数) |
| 现场有网络,远端 PC 直接跟串口设备说话 | 串口接从站 + 一条 TCP 连接 | com1:set_transparent() 并且 tcp:set_transparent() |
核心接口只有两个,都在本手册里已有完整说明:
com.set_transparent(dev, [target]): 传另一个串口对象 → 串口到串口;省略参数 → 把本串口设为云透传口。tcp_client:set_transparent():把这条 TCP 连接登记为透传通道。
透传是「两边登记」的事
除了串口到串口(一个调用就描述了两端),另外两种都需要成对登记: 云透传要靠上位机工具侧发起,网口透传必须 TCP 侧和串口侧各调一次。 只设一边,现象就是"一边通、一边没反应",而且不报任何错。
二、透传一:串口 ↔ 串口(本地共享一条总线)
场景:COM1 上挂着一台 Modbus 仪表,PLC 要周期性读它;现场还有一台触摸屏也要读同一台仪表, 但触摸屏只有 COM2。把 COM2 设为 COM1 的透传口,触摸屏就"仿佛"直接接在仪表上。
完整代码(可直接下载运行):
lua
-- ============================================================
-- 串口 1 正常采集 + 串口 2 透传到串口 1
-- 触摸屏接串口 2,实际访问的是挂在串口 1 上的设备
-- ============================================================
-- ---------- 1. 串口 1 上的正常采集业务 ----------
local modbus_state = data.creat(0) -- 通信状态
local meter = com_modbus.creat(com_modbus.RTU, 2, modbus_state)
meter:set_float_abcd(com_modbus.ABCD) -- 浮点字序按仪表手册
meter:set_time_recv(100) -- 单次应答等 100ms
meter:set_time_error(1000) -- 出错后 1 秒恢复
meter:add_channel(400001, com_modbus.FLOAT, 100, com_modbus.READ) -- 400001 -> D100/D101
local serial_slave = com.setup(1, 9600, com.NONE, 8, 1)
if not serial_slave then
print("串口 1 打开失败")
return
end
serial_slave:add_device(meter)
-- ---------- 2. 串口 2 作为透传口 ----------
local serial_master = com.setup(2, 9600, com.NONE, 8, 1) -- 参数与触摸屏一致
if not serial_master then
print("串口 2 打开失败")
return
end
-- ---------- 3. 建立透传关系后再启动 ----------
serial_slave:set_transparent(serial_master) -- 串口 1 <-> 串口 2
serial_slave:set_time_lunxun(100) -- 采集轮询 100ms 一轮
serial_slave:start()逐段要点:
set_transparent要写在start之前:轮询线程一起来就开始发包, 透传关系晚建一步,触摸屏的头几帧就丢了。- 两个串口的通讯格式必须和挂在总线上的设备一致(波特率、校验、数据位)。 触摸屏是 9600-8-N-1,串口 2 就得填 9600-8-N-1。
- 透传是双向原样搬运,固件不改一个字节,所以触摸屏的协议它不需要懂。
- 轮询间隔要留出总线空隙:
set_time_lunxun太小(比如 1ms)时, 本机采集和触摸屏的请求会挤在同一段总线上冲突,表现为两边都偶发超时。 - 采集业务和透传并存时,串口 1 上不要再用脚本手写
send/recv, 见串口裸报文例程。
验证方法:
- 下载运行,触摸屏上组态读仪表的寄存器,画面数值应正常刷新。
- 同时看设备日志中
modbus_state为 0(本机采集也正常)—— 两边同时通才算透传成功,只有一边通说明参数或顺序有问题。 - 把
set_transparent那行注释掉再下载:触摸屏立刻读不到,本机采集照常 —— 这样能确认透传关系确实是由这一行建立的。
三、透传二:串口 → 云(远程给现场设备编程)
场景:设备装在客户现场,工程师在本地要用 GX Works / 编程软件连它下面的 PLC。 把设备的串口设为云透传口,上位机工具选「远程透传」即可打通。
完整代码(可直接下载运行):
lua
-- ============================================================
-- 云透传:把串口 1 登记为远程透传口
-- 上位机工具与 PLC 需登录同一账户;局域网内也可直接透传
-- ============================================================
local serial_slave = com.setup(1, 9600, com.NONE, 8, 1) -- 参数按现场设备
if not serial_slave then
print("串口打开失败")
return
end
serial_slave:set_transparent() -- 不传参数 = 设为云透传口
serial_slave:set_timeout(1000) -- 远程链路延迟大,接收窗口放宽逐段要点:
- 不带参数的
set_transparent会自动启动轮询线程,不需要再调com.start()。 set_timeout在这里很重要:远程链路的往返比本地慢得多, 默认 100ms 会把对方的应答判成"没收到"。给到 1000ms 起步。- 上位机工具侧的操作(选菜单、挑端口、波特率要对齐)见 远程串口透传; 跟着做一遍的图文流程见 串口透传给第三方设备编程。
- 这台设备的串口在透传期间就交给远程了,本地触摸屏/脚本不要同时抢它。
验证方法:
- 现场设备上电、云服务已连(
D8005.F为 ON,见 特殊软元件详细说明)。 - 本地打开上位机工具 → 远程透传 → 选到这台设备 → 打开本地串口。
- 用厂商编程软件(如 GX Works)通过该串口连现场 PLC,能上线下载即成功。
- 现场侧观察:编程软件每次读写,串口对应指示灯/日志有报文往来。
注意事项:
- 忘了
set_timeout:表现为"连得上、一读写就超时"。 - 上位机工具和 PLC 不是同一账户:找不到设备。
- 现场那一路串口同时还挂着采集脚本:两边抢总线。
四、透传三:串口 ↔ TCP(网口搬到远端)
场景:现场有以太网,远端 PC 上跑一个自己的软件,要直接跟挂在串口上的仪表说话。
完整代码(可直接下载运行):
lua
-- ============================================================
-- 串口 1 <-> TCP 双向透传
-- 关键:TCP 侧和串口侧各登记一次,两边都不能省
-- ============================================================
local serial_slave = com.setup(1, 9600, com.NONE, 8, 1)
if not serial_slave then
print("串口打开失败")
return
end
tcpc = tcp_client.creat("192.168.0.238", 6000, plc.eth_ip()) -- 第 3 参指定走以太网口
tcpc:reg(tcp_client.CONNECTED, function()
print("透传通道已建立")
end)
tcpc:reg(tcp_client.DISCONNECTED, function()
print("透传通道断开,内部会自动重连")
end)
tcpc:start()
tcpc:set_transparent() -- ① TCP 侧登记
serial_slave:set_transparent() -- ② 串口侧登记(不传参数)
-- 可选:把连接状态镜像到 M,给画面当指示灯
timer.start(2000, function()
plc.m(300, tcpc:is_linked() == 1 and 1 or 0)
end)逐段要点:
- 两侧都要
set_transparent,顺序无所谓,缺一个就不通。 串口侧这里不传参数 —— 表示"这个串口参与透传",对端由 TCP 侧那条连接决定。 tcp_client.creat(ip, port, ip_self)的第 3 参plc.eth_ip()用来指定出口网卡。 WiFi + 以太网同时在线的机型上不写这一参,连接可能从 WiFi 出去,走不到您要的网段。- 不要为了"等网口就绪"写一个循环卡在最前面(这是本节要重点纠正的写法,见第五节)。
tcp_client:start()自带自动重连,网口还没起来时它自己会重试, 脚本照常往下走完、进入事件循环即可。 - 一旦登记为透传,不要在脚本里再对同一串口
send/recv,也不用注册RECVDATA, 数据由固件直接搬运。 is_linked()返回整数,判连接必须写== 1。
五、错误写法 vs 正确写法对照
下面这段是真实客户脚本的形态,它不报错,但会把设备卡住:
lua
-- 错误:用阻塞循环等待网口就绪
while (plc.bite(plc.ds(5), 6) == 0) do
system.sleep(1000)
print("正在等待网口就绪")
end
client = tcp_client.creat("192.168.0.238", 6000, plc.eth_ip())
client:set_transparent()| 问题 | 后果 | 正确做法 |
|---|---|---|
脚本顶层的 while + system.sleep | 顶层就是主线程,sleep 在这里是真阻塞、不泵消息队列:循环期间所有回调(串口、MQTT、梯形图交互、其它定时器)全都冻住,只有这一行 print 在动 | 删掉等待循环:tcp_client 的 start 内部会自动重连,不需要您等 |
| 网线没插时这个循环永远出不来 | 设备看起来"在跑",实际整台机器被一个 while 锁死;只能重新下载脚本 | 状态检查放定时器里,当作观测而不是门槛 |
只调了 client:set_transparent() | 只有 TCP 一侧登记了,串口侧不知道,表现为"一边通、一边没反应" | 补上 serial:set_transparent() |
用 plc.ds(5) 却不说它是 D8005 | plc.ds(n) 是 D8000 起的偏移,plc.ds(5) → D8005;写成人看不懂的 5 极容易被后面的人改错 | 加注释写明是 D8005,或直接引用位定义表 |
改成事件驱动,等待这件事就消失了:
lua
-- 正确:不等,直接建对象;网口好不好用定时器去"看"
local serial_slave = com.setup(1, 9600, com.NONE, 8, 1)
if not serial_slave then return end
tcpc = tcp_client.creat("192.168.0.238", 6000, plc.eth_ip())
tcpc:reg(tcp_client.CONNECTED, function() print("透传通道已建立") end)
tcpc:start()
tcpc:set_transparent()
serial_slave:set_transparent()
-- 只做观测:网线没插就在日志里提示一句,不拦任何流程
timer.start(5000, function()
if plc.bite(plc.ds(5), 6) == 0 then -- D8005.6 = 网线已连接
print("提示:D8005.6 未置位,检查网线")
end
end)六、注意事项汇总
set_time_lunxun(0)不会变成 0:小于 1 的值被强制按 1ms 处理。 轮询压到 1ms 会让总线寸步难让,透传对端几乎必然超时 —— 这不是"最快",是"最慢"。- 透传期间同一串口不要混用其它用法:挂了子设备轮询、又手写
send、又开透传, 三者会抢同一条总线,现象是随机丢包,很难查。 - 透传不做任何协议转换:它只搬字节。远端软件必须自己按现场的通讯格式(含波特率、校验)收发。
- 云透传要求云服务在线:
D8005.F(bit F)没置位就先查云连接,不要在串口上找原因。 - 多网卡机型要显式指定出口:
tcp_client.creat的第 3 参不填, 连接可能从另一个网卡出去,到达不了目标网段。 - 参数对不上时不要怀疑透传:串口两侧的设备如果波特率/校验不一致, 透传只会忠实地把乱码搬到对面 —— 先各自单独验证设备通讯正常,再开透传。
- 能免脚本就免脚本:只是要远程编程,用上位机工具的远程透传配置即可, 不必专门下载一段 Lua,见远程串口透传。
七、相关文档
- com — 串口基础:
set_transparent/set_time_lunxun/set_timeout - tcp_client — TCP 客户端:例程 3 就是串口 ↔ TCP 透传
- plc — PLC 数据交互:
plc.ds/plc.bite/plc.eth_ip - 特殊软元件详细说明(D8005)
- 远程串口透传
- 快速入门:串口透传给第三方设备编程
- 综合例程:采集第三方设备