主题
9.1 常用解决方案
为快速熟练使用而编写本节,具体应用请参考对应的应用指令说明。
本节涉及两个硬件平台,请先对号入座
- STM32 版(旧称 ARM 版):LP2252MT / LP2252MR / LP2222MT 等 LP22xx 系列。串口多、运行稳定,不支持 Lua 脚本。
- ESP32 / RDA8910 版:LP3202 / LP3203 / LP3222 / LP3232 / LP8910 等。支持 Lua 脚本与云组态。
下文凡是两个平台行为不同的地方,都会用 【STM32 版】、【ESP32 / RDA8910 版】 明确标注;没有标注的内容表示两个平台通用。
9.1.1 程序保护
程序保护有 2 种方法,两种加密方法可以同时使用。
方法一:编程软件密码加密
| 加密级别 | 说明 | 安全性 |
|---|---|---|
| 1 级密码 | 可通过软件解密(LPPLC 1 级密码也可解密) | 较低 |
| 2 级密码 | 三菱 PLC 可硬件解密;LPPLC 硬件不同于三菱,2 级密码不可解密 | 较高 |
推荐使用 2 级加密
2 级密码在 LPPLC 上不可解密,安全性远高于 1 级密码,推荐使用。
批量二级加密
正常二级加密需在编程软件中逐台设定密码,对批量操作来说费时且易遗漏。LPPLC 支持在程序里直接设定二级密码,一共三条途径,效果完全相同(都是同一套算法、同样置保护标志、同样掉电保持):
途径一:梯形图 ADPRW(D8126 = 9999 模式)
先把 D8126 设为 9999,再执行一次 ADPRW。密码取 ADPRW 的前 4 个操作数,每个 16 位,从左到右拼成 64 位(16 位十六进制)密码:
LD M8002 ; 只需上电执行一次
MOV K9999 D8126 ; 切到「加密码模式」
ADPRW H1234 H5678 H9ABC HDEF0 K0
; 密码 = 1234 5678 9ABC DEF0- 第 5 个操作数当前未使用,填
K0即可 - 指令只在上升沿执行一次,所以用
M8002(初始脉冲)驱动最合适
只有 ADPRW 能这样设密码,EXTR 不行
D8126 = 9999 的「用操作数设定密码」模式只在 ADPRW 上实现。
两个平台的 EXTR 都没有这个模式:STM32 版的 EXTR 遇到 D8126 = 9999 会直接报错(当前模式不存在);ESP32 / RDA8910 版只会置上保护标志,不会从操作数取密码。请一律用 ADPRW,或用下面的 Lua / config 途径。
实用例程
LD M8000
MOV D8031 D0
MOV D8032 D2
END把上面的地址、主题、引脚替换成你项目里的即可。
途径二:Lua 一行搞定(推荐,仅 ESP32 / RDA8910 版)
lua
plc.plc_password("123456789ABCDEF0") -- 16 位十六进制,与上面 ADPRW 等价比拼梯形图操作数直观得多。不足 16 位会自动在前面补 0。
顺便还能给 Lua 脚本本身上锁
lua
plc.lua_password("你的密码") -- 保护 Lua 脚本,防止被读走这是 PLC 密码之外的另一把锁:plc_password 保护梯形图程序,lua_password 保护 Lua 脚本,两者独立。
途径三:config 批量下发(真正的批量部署首选,仅 ESP32 / RDA8910 版)
lua
plc.AI({ cmd = "config", data = {
plc_password = "123456789ABCDEF0",
lua_password = "xxxxxx",
-- 还可一并下发云服务器地址、账号、设备名等
}})这条通道可以通过云端或 config.lua 对成批设备统一下发,密码和其它出厂参数一次配完,配置更简单。
设定后的效果
| 项目 | 结果 |
|---|---|
| 保护等级 | 自动置为 D8169 = 0x0011(关键字保护 + 禁止读出和写入) |
| 生效时间 | 立即生效,不需要重启 |
| 掉电保持 | 是,重启后保护依然有效 |
| 解除方式 | 用编程软件或上位机输入正确关键字解除;见 上位机的关键字保护 |
加密后程序无法读回,需先备份
D8169 = 0x0011 表示禁止读出,加密之后无法再从这台 PLC 上载程序。批量烧写前应在电脑上保存好工程源文件。
密码本身也需记录归档:LPPLC 的二级密码在硬件上不可解密,遗忘后只能通过「清除 PLC」把程序和数据一并清除后重做。
不要在正常运行的程序里保留这段加密逻辑
加密指令只需执行一次。批量烧写完成后,建议把这几行从量产程序里去掉,或确保它只由 M8002 驱动,避免误改密码。
方法二:程序区虚拟法【仅 STM32 版】
平台差异
程序区虚拟法是 STM32 版(LP22xx)的机制。ESP32 / RDA8910 版没有这个功能,同等的「禁止读出」效果由方法一的关键字保护实现(设定二级密码后自动置 D8169 = 0x0011)。
保护原理:程序区既要供 PLC 运行时执行程序,也要供通讯接口(编程软件读写)。程序区虚拟法把用户程序区只接给 PLC 运行时,在其它需要访问程序区的模块(包括通讯模块)上虚拟出一个空程序区,程序就无法再被通讯接口读出。
实际效果是:编程软件请求读程序时,读回的不是错误提示,而是一个空工程,其中没有任何内容,看不到真正的程序。
虚拟后的限制:
| 操作 | 是否可用 | 说明 |
|---|---|---|
| 监视(有原程序时) | 可用 | 监视是编程软件与数据区的连接,不依赖程序区 |
| 在线写入 | 不可用 | 编程软件读取的是虚拟空程序区,在线写入无效 |
| 写入程序 | 无效 | 写入目标为虚拟程序区,实际程序区不受影响 |
| 取消虚拟 | 清除存储器 | 常规途径是清除 PLC 存储器 |
取消虚拟程序区
常规途径只能通过清除 PLC 存储器实现,清除后所有程序和数据将丢失。因此加密前应在电脑上保存好工程源文件。
9.1.2 掉电数据保持
PLC 提供多种掉电保持机制,适用于不同场景:
| 保持方式 | 保持范围 | 适用场景 | 推荐度 |
|---|---|---|---|
| 参数区设定保持 | D0-D511, M0-M1023, S0-S999, C0-C255(不含 T) | 频繁读写场合,不建议作为用户参数配置 | 一般 |
| R0-R39 电池保持 | R0-R39【仅 STM32 版】 | 普通断电保持 | 推荐(用户工程配置参数) |
| R0-R32767 FLASH 保持 | R0-R32767【仅 ESP32 / RDA8910 版】 | 用户工程配置参数 | 推荐 |
| 文件寄存器 | D1000-D7999(最大 7000 点) | 需通过 BMOV 指令写入 | 特定场景 |
| ER0-ER32767 扩展寄存器 | ER0-ER32767 | 历史数据记录,FLASH 保持 | 推荐(历史数据) |
ESP32 / RDA8910 版说明
在 ESP32 版和 RDA8910 版中,R 和 ER 是同一片存储,R0-R32767 掉电保持,推荐作为用户工程的配置参数。STM32 版的 R0-R39 由电池供电保持,两者机制不同。
参数区可设定的掉电保持
工作原理:PLC 掉电时将设定保持范围的软元件写入 FLASH 区保存,上电时从 FLASH 恢复数据到对应软元件。
R0-R39 电池保持【仅 STM32 版】
工作原理:STM32 版 PLC 的 R0-R39 由电池供电保持数据,掉电后数据不丢失。ESP32 / RDA8910 版没有备份电池,R 区整体走 FLASH 保持,见上面的说明。
文件寄存器
- 保持范围:D1000-D7999,由参数中文件寄存器容量设定
- 工作原理:STOP→RUN 过程会将文件寄存器 FLASH 区数据传送到 D 区
- 写入方法:使用
BMOV指令写入,具体参考 BMOV 指令和文件寄存器说明
ER0-ER32767 扩展寄存器
- 工作原理:FLASH 保持,掉电后数据不丢失
- 写入注意【仅 STM32 版】:需注意扇区初始化,初始化后寄存器值为 -1,只有在值为 -1 时才可写入新值;若值不为 -1,需先使用
INITR或INITER指令初始化为 -1 后再写入
; 写入扩展寄存器流程(STM32 版)
; 1. 检查 R 值是否为 -1
; 2. 若非 -1,先初始化
INITER R0 R10 ; 把 R0-R10 这一段初始化为 -1
MOV K100 R0 ; 3. 写入数据
END指令表里写 R0,不要写 ER0
文档和界面里常把这片区域叫「扩展寄存器 ER」,但指令表的操作数只认 R 前缀(R0~R32767)。 写成 ER0 会在编译时报 E 浮点常数格式非法: ER0 —— 因为 E 开头被当成浮点常数前缀去解析了。
ESP32 / RDA8910 版不需要「先写 -1」
ESP32 / RDA8910 版的 ER(= R)区可以直接覆盖写入,不存在扇区初始化的限制。INITR / INITER 在这些平台上写了也不起作用,为兼容旧程序保留,新程序不用写。
历史数据记录建议
推荐使用 LOGR 指令记录历史数据,该指令将根据需要自动进行格式化并写入,无需手动管理扇区初始化。(LOGRP 是它的上升沿脉冲形式。)
9.1.3 通讯数据交换
PLC 之间的数据交换有三种主要方式:
通过 MODBUS 基础协议交换
| 项目 | 说明 |
|---|---|
| 数据范围 | Y, M, S, T, C, D(详见 MODBUS 地址表) |
| 工作原理 | 一台 PLC 设为 MODBUS TCP SERVER,其它设为 CLIENT,通过 ADPRW 指令交换数据 |
| 优点 | 使用通用 MODBUS 指令,兼容性好 |
| 缺点 | 需自行规划主从与地址映射,多机通讯结构相对复杂 |
MODBUS TCP SERVER 能带几个客户端
- 【ESP32 / RDA8910 版】可建立的 MODBUS TCP SERVER 数量不受限制,真正的限制是每个 Server 允许的同时在线客户端数(默认 1~2 路,建立 Server 时可以指定)。多机组网时按需要把这个值调大即可。
- 【STM32 版】内置的 MODBUS TCP SERVER 是 1 路(502 端口,同时 1 个客户端)。另外还可以把 com7 / com8 / com9 也配置成 MODBUS TCP SERVER,合计最多 4 路。
通过专用多机通讯指令交换
多机通讯是 LPPLC 自带的一套 PLC 之间交换 D 区数据的私有协议,走 UDP(端口 25388)。STM32 版和 ESP32 版都支持,区别只在「怎么发起」:STM32 版用梯形图指令,ESP32 版用 Lua 函数。被读写的那一方(数据源)两个平台都是开机常开、不用做任何设定。
这里是速查版。完整的实战教程(含多机轮询示例、心跳判断在线、排查顺序)见 9.6 多机通讯。
| 项目 | 说明 |
|---|---|
| 数据范围 | D 区。STM32 版一次最多 512 点;ESP32 版一次最多 255 点 |
| 工作原理 | 基于 UDP 通讯,任一 PLC 无需设定即可作为数据源,不限制连接数 |
| 优点 | 传输速度快,使用简单,数据源端零配置,连接数无限制 |
| 缺点 | 需在同一局域网内(UDP 单播穿不了 NAT),跨网段/跨地区需使用云服务 |
25388 端口没有认证
局域网内任何一方都能直接读写本机 D0-D7999,固件不校验身份。不要把这个端口映射到公网;需要跨地区交换数据请走云服务。
STM32 版:梯形图 DFROM / DTO
操作数含义(DFROM / DTO 都是 32 位指令):
| 操作数 | 含义 |
|---|---|
| 第 1 个 | 对方 IP,必须是打包成 32 位整数的值 |
| 第 2 个 | 对方的 D 地址 |
| 第 3 个 | 本机的 D 地址 |
| 第 4 个 | 传送点数,最大 512,且本机「D 地址 + 点数」不得超过 D7999 |
用之前还要先用 D8126 选择走哪个网络通道:8887 = com7,8888 = com8,8889 = com9。
LD M8000
MOV K8888 D8126 ; 选择 com8 作为 UDP 通道
; 读取 192.168.0.10 的 D100 到本机 D0,1 点(192.168.0.10 = C0A8000A)
DFROM HC0A8000A K100 D0 K1
; 把本机 D100 写到 192.168.0.11 的 D200,1 点(192.168.0.11 = C0A8000B)
DTO HC0A8000B K200 D100 K1IP 要写成打包后的 32 位值
第 1 个操作数不能用「192.168.0.10」这样的点分写法。固件是把它按 4 个字节逐字节解析成 IP 的,所以要传打包后的 32 位值,用十六进制写最直观:
- 192.168.0.10 →
HC0A8000A - 192.168.1.100 →
HC0A80164
换算方法:每段各转成两位十六进制再拼起来。192=C0、168=A8、0=00、10=0A → HC0A8000A。
也不要写成 K192168000010 这种去掉点的十进制数,它超出 32 位有符号整数上限(2147483647),无法输入。
ESP32 / RDA8910 版:Lua 的 plc.get / plc.put
选型提醒:DFROM / DTO 在两个平台语义不同
在 ESP32 版上,DFROM / DTO 是扩展模块寄存器读写指令,第一个操作数是扩展模块的单元号(0~7),不是 IP 地址。把 IP 当成单元号传进去会直接报参数错误(出错代码 6708)。
发起端改用 Lua,两个函数的参数顺序一样:
lua
plc.get(对方IP, 对方D起始, 本机D起始, 点数) -- 读:把对方的 D 读到本机
plc.put(对方IP, 对方D起始, 本机D起始, 点数) -- 写:把本机的 D 写到对方lua
timer.start(100, function() -- 100ms 一轮
plc.get("192.168.2.136", 1, 2, 2) -- 读对方 D1-D2 → 本机 D2-D3
plc.put("192.168.2.136", 3, 2, 1) -- 本机 D2 → 对方 D3
print("D2=", plc.d(2))
end)不用选通道,也不用在设备参数里开什么开关,网口 / WiFi 通了就能用。函数说明见 plc.get / plc.put。
四个要注意的地方
- 一次最多 255 点:点数在协议里只占 1 个字节,填超过 255 会被截断(填 300 实际只传 44 点),固件不报错。
- 异步、没有回执:两个函数都是发出去就返回,没有返回值、没有超时、没有错误码。
plc.put对方也不回执,要确认写进去了,只能过一会用plc.get读回来核对。 - 只能同局域网:UDP 单播,穿不了 NAT。跨网段跨地区请用下面的云服务数据交换。
- 【Linux / RDA8910 版】
plc.get读不回数据:这个平台不支持plc.get,发出的读取请求收不到回应。所以它可以被别的 PLC 读写,自己发plc.get却拿不到数据;该平台上只有plc.put可用。
通过云服务交换
| 项目 | 说明 |
|---|---|
| 数据范围 | 不限 |
| 工作原理 | 数据源 PLC 将数据发布到云服务,需要数据的 PLC 订阅,数据变化时自动下发 |
| 优点 | 可跨地区数据交换,数据点可在客户端可视化管理 |
| 缺点 | 要求 PLC 接入互联网,有云服务器使用费(现阶段免费,未来可能收费) |