主题
❓ 常见问题
LPPLC Lua 开发中常见问题与解决方案
基础问题
Q: 脚本下载后没有执行?
检查以下几点:
- 是否点击了"运行"按钮
- 脚本是否有语法错误(查看日志输出)
- 是否下载到了正确的设备
Q: 脚本执行一次就停了?
Lua 脚本默认执行到文件末尾就结束。如果需要持续运行,使用以下方式:
lua
-- 方式一:使用定时器(推荐)
timer.start(1000, function()
-- 每秒执行
end)
-- 方式二:要一直跑、中间还要等 —— 用任务
task.start(function()
while true do
do_work()
system.sleep(1000) -- 任务内:让出一拍,不阻塞
end
end)
-- 方式三:几件事同时进行、要写顺 —— 用协程
coroutine.wrap(function()
while true do
do_work()
system.sleep(1000) -- 协程内:挂起,不阻塞
end
end)()
> ⚠️ **主线程里绝不能用 `sleep` / `system.sleep` 写 `while true` 循环**:它只停住线程、不推进消息泵,
> 期间定时器与 MQTT/TCP/串口回调**全部失效**,设备像死机。`sleep` 只在**协程内**或**任务内**才不阻塞。
> 脚本侧的 `system.recv` 已于 2026-10-22 删除(泵在固件 C 侧),注册完定时器/任务让脚本自然结束即可。Q: 定时器回调不触发?
先查三件事:① 脚本里是不是有 while true do ... system.sleep(n) ... end 这类自写主循环(它会堵死消息泵)—— 删掉它,让脚本自然结束;② 定时器是不是写在 if 分支里没执行到;③ 是不是重复下载了旧版本脚本。 要"一直跑、中间还要等"用 task.start,见并发模型概述。
Q: 修改脚本后行为没变化?
修改代码后需要重新点击"下载"按钮,仅保存编辑器内容不会更新设备上的脚本。
PLC 数据交互
Q: 读取 D 寄存器返回的值不对?
- 确认使用正确的数据类型函数:
plc.d()(16位)、plc.dd()(32位)、plc.df()(浮点) - 16 位 D 寄存器范围 -32768~32767,超出范围会溢出
- 32 位寄存器占用两个连续 D 地址,注意地址不要重叠
Q: plc.x/plc.y 返回什么类型?
返回整数 0 或 1,不是布尔值。判断时必须写 == 1 或 == 0:
lua
-- 正确
if plc.x(0) == 1 then end
-- 错误:Lua 里只有 nil 和 false 为假,0 也是真,这个条件永远成立
if plc.x(0) then endQ: 远程 plc.get/put 没有数据?
- 确认对方设备在线且 IP 正确,且两台在同一局域网(UDP 单播穿不了 NAT)
- 远程通信使用 UDP 协议,端口 25388,不要把该端口映射到公网
- 一次最多 255 点,填超过会被静默截断
- 请求是异步的,没有返回值;
plc.get要等对方回包后数据才落到本地 D 区,丢包时本轮不更新 - 【Linux / RDA8910 版】该平台
plc.get收不回数据(固件未处理读回应),只能用plc.put
完整排查顺序见 9.6 多机通讯。
网络通信
Q: MQTT 连接不上?
- 检查 Broker 地址和端口是否正确
- 检查网络是否连通:
net.ping("broker.emqx.io") - Client ID 是否与其他设备冲突
- 用户名密码是否正确(无需认证时传空字符串
"")
Q: HTTP 请求超时?
- 同步请求会阻塞,检查网络连通性
- 检查 URL 是否正确(注意 http/https)
- 尝试使用异步模式
get_asy/post_asy - 多网卡环境需指定出口 IP
Q: TCP 通信数据不完整?
- TCP 是流式协议,需要自己处理消息边界
- 使用
net.recv(sock, "*l")按行读取 - 或在协议中定义长度字段,按长度读取
Q: 如何读取 WiFi 信号强度(RSSI)?
使用 plc.AI 接口获取当前 WiFi 连接的信号强度:
lua
local result = plc.AI({
cmd = "ShowMe",
data = "WIFI,RSSI"
})
-- result.data 返回 RSSI 值(单位 dBm,负数,如 -50 ~ -90)
-- result.errno == 0 表示成功
-- result.errno == -4 表示 WiFi 未连接RSSI 参考范围:
- -30 ~ -50 dBm:信号极强(紧挨路由器)
- -50 ~ -70 dBm:信号良好
- -70 ~ -85 dBm:信号较弱,可能偶有延迟
- 低于 -85 dBm:信号很差,容易断连
注意:此功能仅 ESP32 版本支持,且设备需通过 WiFi STA 方式连接路由器后才可读取。
想在上位机或网页里持续看信号强度? 设备不会自动上报 RSSI,用 Lua 定时把它写进一个 D 寄存器,再用现有手段读这个寄存器即可:
lua
-- 周期任务用 timer.start,别用 while true + sleep 当主循环(那会堵死消息泵)
timer.start(1000, function()
local r = plc.AI({ cmd = "ShowMe", data = "WIFI,RSSI" })
plc.d(500, (r and r.errno == 0) and r.data or 0) -- 0 = 读不到(多为未连上 WiFi)
end)之后用上位机「命令控制台」执行 plc read --type D --start 500 --count 1,或在云平台的数据点/组态画面里显示 D500。读回 0 就说明当前没连上 WiFi(而不是信号为 0)。
Q: 多网卡环境如何选择出口?
指定本地 IP 地址作为出口:
lua
-- HTTP 指定以太网出口
local client = http.creat("http://api.example.com", plc.eth_ip())
-- MQTT 使用 WiFi 出口
-- 当前系统自动选择,如需指定请使用对应模块的 IP 参数系统与内存
Q: 系统运行一段时间后变慢或崩溃?
- 避免在循环或定时器回调中不断创建新对象(闭包、大字符串)
- 使用
local变量代替全局变量 - 检查是否有不断增长的 table(如缓冲区没有清理)
Q: 可用内存有多少?
ESP32 Lua 堆内存约 40-80KB,可通过以下方式查看:
lua
-- 查看文件系统空间
local total, used, free = system.fs_info()
print("Flash 剩余:", free, "字节")Q: system.sleep 在主线程会怎样?
会阻塞整个 Lua 运行时。消息泵推不动,所以这期间定时器回调、MQTT/TCP/UDP/串口回调、BACnet 的 on_change 和 reg() 回调一个都不会触发。
所以不要自己写 while true do ... system.sleep(n) end 当主循环。周期任务交给 timer.start(ms, fn),脚本 return 后固件自动接管消息泵;要"一直跑、中间还要等"用 task.start 起任务。协程里可以放心用 sleep,那里的 sleep 是挂起而不是阻塞,不影响主循环。脚本侧的 system.recv 已于 2026-10-22 删除。
文件系统
Q: 文件写入失败?
- SPIFFS 是扁平文件系统,不支持创建目录
- Flash 有擦写次数限制,避免频繁写入
- 检查存储空间是否充足:
system.fs_info()
Q: 如何持久化存储少量数据?
使用 plc.kv_set/kv_get 或 fdb.kv_set/kv_get:
lua
-- 方式一:plc 模块(简单键值)
plc.kv_set("calibration", "1.025")
local val = plc.kv_get("calibration")
-- 方式二:fdb 模块(支持更多类型)
fdb.kv_set("config", {ip = "192.168.1.1", port = 502})
local config = fdb.kv_get("config")调试技巧
Q: 如何调试 Lua 脚本?
- 使用
print()输出到串口/日志 - 使用
string.format()格式化复杂数据 - 用
type()检查变量类型 - 用
pcall()捕获运行时错误
lua
-- pcall 错误捕获
local ok, err = pcall(function()
-- 可能出错的代码
local val = plc.d(99999) -- 越界访问
end)
if not ok then
print("错误:", err)
endQ: 如何查看 PLC 寄存器状态?
lua
-- 批量打印 D0-D9
for i = 0, 9 do
print(string.format("D%d = %d", i, plc.d(i)))
end
-- 打印所有输入 X0-X7
for i = 0, 7 do
print(string.format("X%d = %d", i, plc.x(i)))
end相关例程
想直接抄可运行的脚本,去 例程总览 B-0:按模块分组列出了每个页面里的 3 个完整例程(场景 / 代码 / 要点 / 验证 / 注意事项)。
- 通信:com 串口 · tcp_server · mqtt · pipe 概述 · net
- 云与数据:cloud · json · data · fdb
- 综合工程:Modbus 采集 + MQTT 上报 + 云端下发
写例程的硬规矩(禁止阻塞主循环、API 不编造等)见 B-0 的「写例程时的硬性约定」。
最后更新: 2026-05-05