Skip to content

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 提供多种掉电保持机制,适用于不同场景:

掉电不丢数据该用哪个区:R 区首选,及参数区/文件寄存器/ER 区的分工与平台差异

保持方式保持范围适用场景推荐度
参数区设定保持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 多机通讯。

多机通讯:两台 LPPLC 直接交换 D 区数据

项目说明
数据范围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 K1

IP 要写成打包后的 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。

四个要注意的地方

  1. 一次最多 255 点:点数在协议里只占 1 个字节,填超过 255 会被截断(填 300 实际只传 44 点),固件不报错。
  2. 异步、没有回执:两个函数都是发出去就返回,没有返回值、没有超时、没有错误码。plc.put 对方也不回执,要确认写进去了,只能过一会用 plc.get 读回来核对。
  3. 只能同局域网:UDP 单播,穿不了 NAT。跨网段跨地区请用下面的云服务数据交换。
  4. 【Linux / RDA8910 版】plc.get 读不回数据:这个平台不支持 plc.get,发出的读取请求收不到回应。所以它可以被别的 PLC 读写,自己发 plc.get 却拿不到数据;该平台上只有 plc.put 可用。

通过云服务交换 ​

项目说明
数据范围不限
工作原理数据源 PLC 将数据发布到云服务,需要数据的 PLC 订阅,数据变化时自动下发
优点可跨地区数据交换,数据点可在客户端可视化管理
缺点要求 PLC 接入互联网,有云服务器使用费(现阶段免费,未来可能收费)

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