Skip to content

com_fx — 串口三菱 FX 协议 ​

模块名:com_fx

通过三菱 FX 系列 PLC 的编程口协议采集数据。和 com_modbus 一样,本模块只描述「要读写哪些软元件」,必须用 com.add_device 挂到一个 com 对象上,由 com.start 的轮询线程驱动。

软元件用字符串指定(如 "D0"、"M100"、"Y0"),不像 Modbus 那样用数字地址。

除 creat 之外的函数在库表和对象元表里都注册了,com_fx.add_channel(dev, ...) 与 dev:add_channel(...) 等价。

函数总览 ​

库级函数 ​

函数作用
com_fx.creat([data_state])创建一个 FX 设备对象

对象方法 ​

方法作用
dev:add_channel增加一条采集/写入通道
dev:set_time_recv设置应答等待超时
dev:set_time_error设置出错后的重试延时

常量 ​

读写属性

常量说明
com_fx.READ只读:FX → 本地
com_fx.READ_WRITE读写双向

数据类型

常量占用说明
com_fx.BITE—位软元件(M/X/Y/S 等)
com_fx.S161 个 D16 位有符号
com_fx.U161 个 D16 位无符号
com_fx.S322 个 D32 位有符号
com_fx.U322 个 D32 位无符号
com_fx.FLOAT2 个 D单精度浮点

字节序(模块里注册了这些常量,供与 com_modbus 保持一致的写法使用)

com_fx.AB、com_fx.BA、com_fx.ABCD、com_fx.CDAB、com_fx.BADC、com_fx.DCBA

模式:com_fx.RTU、com_fx.ASCII(常量存在,creat 不接受模式参数,FX 编程口帧格式固定)


com_fx.creat ​

lua
com_fx.creat([status]) --> device

创建一个 FX 设备对象。

参数

#参数类型必填默认值说明
1statusinteger | data否—通信状态回写位置。数字 = D 寄存器编号,data 对象 = 写到该对象。省略则不回写

返回值

类型说明
userdataFX 设备对象。必须用变量接住

示例

lua
local st = data.creat(0)
local fx = com_fx.creat(st)

说明

  • FX 编程口是点对点协议,没有站号,所以 creat 不需要设备地址参数。
  • 建议传 status,用来判断 PLC 是否在线。

dev:add_channel ​

lua
dev:add_channel(device_name, data_type, target, rw) --> 0 | 1

增加一条通道,把对方 PLC 的一个软元件绑定到本机 D 寄存器或 data 对象。

参数

#参数类型必填默认值说明
1device_namestring是—对方软元件名,如 "D0"、"D100"、"M50"、"Y0"、"X0"
2data_typeinteger是—com_fx.BITE / S16 / U16 / S32 / U32 / FLOAT
3targetinteger | data是—本地落点编号。落点由数据类型决定:BITE 写进 M 区,字类型(S16/U16/S32/U32/FLOAT)写进 D 区;传 data 对象则与 D/M 无关
4rwinteger是—com_fx.READ 或 com_fx.READ_WRITE

返回值

类型说明
integer1 添加成功,0 添加失败(软元件名无法解析等)

示例

lua
-- 把对方 D0 读到本机 D100
fx:add_channel("D0", com_fx.S16, 100, com_fx.READ)

-- 把对方 D10-D11 的浮点读到 data 对象
local temp = data.creat(0)
fx:add_channel("D10", com_fx.FLOAT, temp, com_fx.READ)

-- 双向同步:本机 M200 <-> 对方 M0
fx:add_channel("M0", com_fx.BITE, 200, com_fx.READ_WRITE)

说明

  • 软元件名大小写都能识别,编号按对方 PLC 的编址习惯写(X/Y 按三菱的八进制丝印编号)。
  • BITE 只能用于位软元件(M/X/Y/S、T/C 触点),字类型只能用于 D 等字软元件。
  • 本地落点跟着数据类型走:上面这行把对方 M0 存进本机的 M200(不是 D200), 读取要写 plc.m(200);而 "D0" 那两行落的是 D100,用 plc.d(100) 读。 梯形图侧也照这个规则接:位类通道去取 M,字类通道去取 D。

dev:set_time_recv ​

lua
dev:set_time_recv(ms)

设置本设备的应答等待超时。

参数

#参数类型必填默认值说明
1msinteger是—超时毫秒数

返回值

无返回值。


dev:set_time_error ​

lua
dev:set_time_error(ms)

设置通信出错后,下一次重试前的延时。

参数

#参数类型必填默认值说明
1msinteger是—延时毫秒数

返回值

无返回值。

说明

  • 设大一点可避免对方掉线时反复超时拖慢轮询。

常见用法 ​

把一台 FX3U 的数据搬到本机 D 区,梯形图直接用

lua
local st = data.creat(0)
local fx = com_fx.creat(st)
fx:set_time_recv(500)
fx:set_time_error(2000)

fx:add_channel("D0",   com_fx.S16,   100, com_fx.READ)        -- 对方 D0   → D100
fx:add_channel("D10",  com_fx.FLOAT, 102, com_fx.READ)        -- 对方 D10  → D102-D103
fx:add_channel("M0",   com_fx.BITE,  200, com_fx.READ_WRITE)  -- 对方 M0   <-> M200
fx:add_channel("Y0",   com_fx.BITE,  201, com_fx.READ)        -- 对方 Y0   → M201

local port = com.setup(1, 9600, com.EVEN, 7, 1)   -- FX 编程口常用 9600-7-E-1
port:add_device(fx)
port:set_time_lunxun(500)
port:start()

timer.start(1000, function()
    print("对方 D0 =", plc.d(100), "在线:", st:get_num() == 0)
end)

注意事项 ​

  • FX 编程口的串口参数与 Modbus 不同,常见是 9600、7 数据位、偶校验、1 停止位,接不上先核对这里。
  • FX 编程口是点对点,一条串口上只能接一台 FX PLC,不要挂多个 com_fx 子设备。
  • X/Y 软元件在三菱侧是八进制编号,写通道名时按 PLC 面板上的丝印写。
  • 设备对象和 data 对象都要长期持有,被 GC 回收后采集失效。
  • 需要通过网口而不是串口连三菱 PLC,用 pipe 的 fx 或 mc 协议。

例程 ​

每个例程都是可直接下载运行的完整脚本:com_fx 只描述「要读写哪些软元件」,挂到 com 并 start 后由后台线程轮询,脚本注册完即结束。 API 只用本页已文档化的函数。统一模板「场景 / 完整代码 / 要点 / 验证方法 / 注意事项」。

例程 1:把一台 FX3U 的数据搬到本机 D 区 ​

适用:LP3201 / LP3202 / LP3203 / LP3222 / LP3232 / LP3288 / 软PLC模拟器 | 依赖模块:com_fx com data timer plc | 难度:★☆☆

场景:现场一台三菱 FX3U,要把它的 D0(16 位)、D10(浮点)、M0、Y0 自动搬运到本机 D 区,让梯形图/上位机直接拿来用。

完整代码(可直接下载运行):

lua
local st = data.creat(0)
local fx = com_fx.creat(st)
fx:set_time_recv(500)
fx:set_time_error(2000)

fx:add_channel("D0",  com_fx.S16,   100, com_fx.READ)        -- 对方 D0   → D100
fx:add_channel("D10", com_fx.FLOAT, 102, com_fx.READ)        -- 对方 D10  → D102-D103
fx:add_channel("M0",  com_fx.BITE,  200, com_fx.READ_WRITE)  -- 对方 M0   <-> M200
fx:add_channel("Y0",  com_fx.BITE,  201, com_fx.READ)        -- 对方 Y0   → M201

local port = com.setup(1, 9600, com.EVEN, 7, 1)   -- FX 编程口常用 9600-7-E-1
port:add_device(fx)
port:set_time_lunxun(500)
port:start()

timer.start(1000, function()
    print("对方 D0 =", plc.d(100), "在线:", st:get_num() == 0)
end)

要点:

  • FX 编程口是点对点协议,没有站号,所以 com_fx.creat 不需要设备地址参数。
  • 软元件名用字符串("D0"、"M50"、"Y0"),不是数字地址。
  • 串口参数和 Modbus 不同,常见 9600 / 7 数据位 / 偶校验 / 1 停止位。

验证方法:

  1. 下载重启,D100 出现对方 D0 的值,D102-D103 出现 D10 浮点,st:get_num() = 0(通讯成功)。 通信状态码:0=成功、1=报文异常、2=通信超时, 所以判在线要写 st:get_num() == 0,不是 == 1。
  2. 改变对方 PLC 的 D0,本机 D100 同步变化。

注意事项:

  • X/Y 在三菱侧是八进制编号,写通道名按 PLC 面板丝印(如 Y0、Y10)。
  • 接不上先核对串口参数(9600-7-E-1),这是 FX 编程口最常见的坑。
  • FX 编程口一条串口上只能挂一台 FX PLC,不要建多个 com_fx 子设备。

例程 2:本机写对方 M0(READ_WRITE 双向控制) ​

适用:同上 | 依赖模块:com_fx com data plc | 难度:★☆☆

场景:想用本机 M200 来控制对方 PLC 的 M0(比如远程启动电机)。用 READ_WRITE 通道,本机写 M200 会被自动下发,对方写 M0 也会被自动回读。注意 BITE 通道的落点是 M 区而不是 D 区。

完整代码(可直接下载运行):

lua
-- 本机 M200 置 1 时,轮询线程自动把对方 M0 置 1(READ_WRITE 双向)
local st = data.creat(0)
local fx = com_fx.creat(st)
fx:add_channel("M0", com_fx.BITE, 200, com_fx.READ_WRITE)   -- 本机 M200 <-> 对方 M0

local port = com.setup(1, 9600, com.EVEN, 7, 1)
port:add_device(fx)
port:set_time_lunxun(500)
port:start()
-- 现场要动作:梯形图/上位机把 M200 置 1 即可,无需脚本再写逻辑

要点:

  • com_fx 只有 READ 和 READ_WRITE 两种,没有独立的 WRITE 常量;要下发就选 READ_WRITE。
  • 双向通道既能下发也能回读,不必为「下发」和「上读」各建一条。

验证方法:

  1. 把本机 M200 置 1,用 GX Works 之类看对方 M0 = 1;复位 M200 后 M0 也复位。
  2. 在对方把 M0 手动置 1,本机 M200 应同步变 1(用 plc.m(200) 读,plc.d(200) 永远读不到)。

注意事项:

  • 只配 READ 的话,本机写 M200 不会下发到对方——要下发必须 READ_WRITE。
  • FX 编程口点对点,一条串口一台设备。

例程 3:把本机计算结果写到对方 D 区(下发设定值) ​

适用:同上 | 依赖模块:com_fx com data plc | 难度:★☆☆

场景:本机算好变频器频率给定放在 D300,希望自动下发到对方 D100。

完整代码(可直接下载运行):

lua
-- 本机 D300 = 频率给定,自动下发到对方 D100(双向,也能回读)
local st = data.creat(0)
local fx = com_fx.creat(st)
fx:add_channel("D100", com_fx.S16, 300, com_fx.READ_WRITE)   -- 本机 D300 <-> 对方 D100

local port = com.setup(1, 9600, com.EVEN, 7, 1)
port:add_device(fx)
port:set_time_lunxun(500)
port:start()

要点:

  • 用 READ_WRITE 既能下发(本机 D300 变 → 对方 D100 变)也能回读(对方改 D100 → 本机 D300 同步)。
  • 脚本只需配置一次,下发由轮询线程自动完成。

验证方法:

  1. 把本机 D300 改成 50,用三菱软件读对方 D100 应同步成 50。
  2. 在对方直接改 D100,本机 D300 也跟着变(证明是双向)。

注意事项:

  • com_fx 无独立 WRITE,下发务必用 READ_WRITE。
  • 串口参数错(非 9600-7-E-1)会导致完全通信不上。

例程 4:现场常用脚本 com_fx.lua(原文) ​

适用:同上 | 依赖模块:com_fx com data timer plc | 难度:★☆☆

场景:读对方 FX 的 D0/D1/D2,分别落到本机 D100、数据对象 d1、数据对象 d2, 10 秒打印一次,并把 d1 自增、d2 超 100 时回写 88。这份是三菱编程口最常用的入门脚本 (文件 com_fx.lua),当前固件上可直接运行,原文收录如下。

完整代码(com_fx.lua 原文,可直接下载运行):

lua
fx_state=data.creat(0);
fx_device=com_fx.creat(fx_state);--建立三菱编程口设备
fx_device:add_channel("D0",com_fx.S16,100,com_fx.READ_WRITE)--加入通道将设备D0与本机D100绑定

d1=data.creat(0)
d2=data.creat(0)
fx_device:add_channel("D1",com_fx.S16,d1,com_fx.READ_WRITE)--加入通道将D1与数据对象d1绑定
fx_device:add_channel("D2",com_fx.S16,d2,com_fx.READ_WRITE)--加入通道将D2与数据对象d2绑定
--建立父设备
com1=com.setup(1,9600,com.EVEN,7,1)--打开串口父设备,注意这里要与子设备通讯格式相同,比如ascii设备应该设定为7位数据
com1:add_device(fx_device)--在串口父设备中加入子设备
com1:start()--启动串口父设备

x=timer.start(10000,function()
  --输出读取到的值
  print("D0=".. plc.d(100).."   D1=".. d1:get_num().."   D2=".. d2:get_num().."	state=".. fx_state:get_num())
  --数据改变时会自动写入到设备
  if d2:get_num()>100 then
    d2:set(88)
  end
  d1:set(1+d1:get_num())--自动写入到D1
end)

要点:

  • 一份脚本把三种落点写法都给全了:填数字 100 落本机 D100(用 plc.d(100) 读); 填 data 对象(d1/d2)不占寄存器;com_fx.creat(fx_state) 里的对象用来收通讯状态。
  • 软元件名是字符串("D0"),与本机落点(第 3 个参数)不要弄反。
  • d1:set(...) 写完不用手动下发,轮询线程检测到对象值变化自动写回对方 D1。
  • 串口父设备参数必须是 9600, com.EVEN, 7, 1(编程口格式 7-E-1),写成 8 位数据就完全连不上。

验证方法:对方 PLC 里把 D0 改成 123,日志里 D0=123 跟随;看 D1= 每 10 秒 +1(证明反向写通); 把对方 D2 改成 150,下一轮应变回 88。

注意事项:fx_device 与 d1/d2 都要用全局或长期变量接住,被 GC 回收后对应通道就断了; fx_state:get_num() 一直非 0 说明链路或编程口格式不对;把 100 当成对方软元件号写会采错点。

LPPLC 工业物联网云平台 · 软硬件与云平台全栈自研