适用版本:1.0.27 更新日期:2026-10-09
Lua 可用 uart_send 发送原始字节,并在 on_uart_recv 接收业务数据。自定义协议需要由脚本处理帧头、长度、拆包、粘包和校验;发送字符串 "A5 5A" 得到的是这些字符的编码,不是十六进制字节 A5 5A。
先在工程设置中配置通信协议及波特率、数据位、停止位、校验位,并保持主板参数一致。自由协议示例使用工程的自定义协议模式。
uart_setup(channel, baudrate, databits, stopbit, parity)
新版运行库已实现参数设置和独立第二串口。请更新屏端固件或模拟器后使用;工程配置决定上电初始参数。接口要求 5 个整数参数,正常成功返回 0,失败返回 -1;参数类型或数量不对会抛 Lua 错误。
| 参数 | 说明 |
|---|---|
channel |
0/1 为共享工程通信口;3 为独立第二串口;配置通道 2 不支持 |
baudrate |
波特率,1200~3000000;实际可用范围由设备决定 |
databits |
7 或 8 |
stopbit |
Lua 编码:0=1 位,1=2 位;当前屏端不支持 1.5 位 |
parity |
0=无校验,1=奇校验,2=偶校验 |
uart_setup(0/1, ...) 修改组态协议与 Lua 共用的工程串口,成功后内置协议也使用新参数。工程设置是初始值,脚本生效的设置是当前运行值,不修改工程文件。相同参数重复设置不会重启通信;应在初始化或确需改参时调用。
uart_setup(3, ...) 打开独立 UART3,不改变工程口参数。Lua 通道 0 是工程通信口(UART1),不是硬件 UART0 日志口。独立第二口随脚本关闭释放;串口下载占用期间禁止脚本发包或改参。
function on_init()
local rc = uart_setup(3, 115200, 8, 0, 0) -- 第二口,115200 8N1
print("UART3 setup", rc)
end
function send_second_port()
local rc = uart_send(3, {0xA5, 0x5A, 0x00, 0x09})
print("UART3 send", rc)
end
uart_send(channel, data)
| 参数或返回值 | 说明 |
|---|---|
channel |
0/1 为工程口;3 为独立第二口,2 保留第二口发送别名 |
data 为字符串 |
发送字符串的原始字节,可包含零字节 |
data 为表 |
下标 1 开始的连续整数表,每项 0~255 |
| 数据长度 | 每次 1~255 字节 |
| 返回 0 | 原始字节已成功写入当前串口发送接口 |
| 返回 -1 | 参数不合法、串口不可用、下载占用串口或发送失败 |
uart_send(0/1, data) 使用工程口;uart_send(2/3, data) 使用已通过 uart_setup(3, ...) 打开的第二口。配置第二口不能用 uart_setup(2, ...)。发送成功只表示串口接口接受了数据,不表示对端已接收、校验通过或执行命令;需要设备协议本身的应答确认。
发送 ASCII 文本:
local rc = uart_send(0, "HELLO\r\n")
if rc ~= 0 then
print("UART send failed")
end
发送十六进制字节表或等价二进制字符串:
local rc = uart_send(0, {0xA5, 0x5A, 0x00, 0x09})
if rc ~= 0 then
print("UART send failed")
end
local packet = string.char(0xA5, 0x5A, 0x00, 0x09)
uart_send(0, packet)
运行库按原样发送,不自动增加帧头、长度、CRC 或结束符。较长消息须按自己的协议拆分,单次调用不能超过 255 字节。
在脚本中定义以下函数,运行库收到业务字节后会调用它:
function on_uart_recv(channel, packet, length)
-- packet 是二进制字符串。
end
| 参数 | 说明 |
|---|---|
channel |
0 为工程口,3 为独立第二口;发送别名不改变接收通道号 |
packet |
二进制字符串,保留零字节和 0x80~0xFF 字节 |
length |
本次片段的字节数,与 #packet 一致,最多 512 字节 |
一次回调可能只是部分帧,也可能含多帧,不能直接把一次回调当成一个完整报文。回调返回值不控制内置协议是否继续解析,也不会把串口接收改成独占模式。内置协议同样可监听原始业务片段,但合法下载控制数据不会交给业务脚本;下载占用期间不能发送应用数据。
所有内置协议及自定义协议均支持原始业务接收回调。在模拟器中,主口选择“工程通信”模式才分发工程业务回调;“手动调试”不会向工程脚本分发主口数据。第二口独立收发,两口应各自保存拼帧缓冲。接收回调应简短,及时处理片段,避免阻塞界面。
查看收到的十六进制字节:
function on_uart_recv(channel, packet, length)
local bytes = {}
for i = 1, length do
bytes[i] = string.format("%02X", string.byte(packet, i))
end
print("RX", channel, table.concat(bytes, " "))
end
下面定义一个简单的自定义协议:固定 4 字节,前两字节为 A5 5A,后两字节为高字节在前的 16 位数值。它仅用于演示接收拼帧,不是内置协议的报文格式。
主板发送 A5 5A 00 09 时,脚本将 LW1014 更新为 9;该变量可绑定温度控件。
local LW = 1
local rx = ""
function on_init()
set_run_cycle(100)
end
function on_uart_recv(channel, packet, length)
if channel ~= 0 or length == 0 then
return
end
rx = rx .. packet
while #rx >= 2 do
local first, second = string.byte(rx, 1, 2)
if first ~= 0xA5 or second ~= 0x5A then
rx = string.sub(rx, 2)
elseif #rx < 4 then
break
else
local high, low = string.byte(rx, 3, 4)
local value = high * 256 + low
rx = string.sub(rx, 5)
set_uint16(LW, 0x1014, value)
end
end
end
function on_update(slave, vtype, addr)
if vtype == LW and addr == 0x1014 then
print("received value", get_uint16(LW, addr))
end
end
解析后用寄存器接口写入变量,绑定该变量的控件使用更新后的值。若实际协议还有长度、命令或 CRC 字段,应在全部字段核对通过后再提交变量。
本节公开入口是 uart_setup、uart_send 和脚本回调 on_uart_recv。当前没有注册 uart_recv 同步读取函数,也没有注册 mb_read_coil_01、mb_read_input_02、mb_read_reg_03、mb_read_input_reg_04、mb_write_coil_05、mb_write_reg_06、mb_write_coil_15 或 mb_write_reg_16 自由 Modbus 函数。
0x1234;需拆成 0x12, 0x34。string.char 或字节表构造二进制报文,不把十六进制显示文本直接当报文发送。packet 可能含零字节,使用 #packet、string.byte 和 string.sub 处理。实际项目应按对端协议填写帧结构和串口参数。
主口使用串口副屏选择的 COM。第二口需要在启动模拟器前设置环境变量 STT_SIM_UART3,指定独立 COM,且不能与主口重复。未配置、COM 被占用或硬件不支持时,uart_setup(3, ...) 返回 -1,不会悄悄借用主口。
例如在 Windows 命令提示符中启动(替换为实际模拟器路径;COM13 仅为示例):
set STT_SIM_UART3=COM13
"C:\your-path\TaiSimulator.exe"
Lua print()、脚本加载/执行错误和未被脚本自行处理的回调异常,显示在串口副屏的“运行日志”。筛选选择“运行日志”或“全部日志”,无需连接 COM;日志可复制或导出,不作为串口 TX 发送,也不计入 RX/TX 统计。使用 pcall 捕获的错误,需要脚本自行 print 才会显示。
print("Lua debug", get_uint16(1, 0x1014))
local ok, err = pcall(set_uint16, 1, -1, 7)
if not ok then
print("write failed", err)
end
第二口与工程口的业务回调均在原界面主循环中执行;不要在回调中忙等或阻塞。停止定时脚本见定时器函数;限制本地演示数据自动上传见寄存器操作函数中的 set_notify。