给시리얼 포트装上大脑:LLCOM Lua스크립트디버깅 도구

무료무료 기술 자료

이 글은 바로 읽을 수 있으며 기초 학습과 검색 유입에 적합합니다.

给串口装上大脑:LLCOM Lua脚本调试工具

출처: Modbus 중국 네트워크(modbus.cn) —— 중국 최고의 Modbus 통신 프로토콜 기술 커뮤니티

本文:LLCOM:给시리얼 포트装上 Lua 大脑 —— Modbus 디버깅效率翻倍的完整指南 · 作者:modbus기술팀 · 发布于 2026-07-01

요약:LLCOM 是 GitHub 오픈소스的 Windows 시리얼 포트디버깅 도구(chenxuuu/llcom),基于 .NET 和腾讯 xlua 引擎,让시리얼 통신 디버깅不再是手动一条条发16진수帧。其核心杀手锏是在표준시리얼 포트도구基础上内嵌了完整的 Lua 5.3 运行환경,支持合宙 Luat Task 协程框架,可以写스크립트自动收发、自动계산 Modbus CRC、自动轮询、自动분석响应。本文从安装到 API 参考到四个 Modbus 实战스크립트,覆盖你从下载到跑通自动化测试的每一个步骤。关键词:LLCOM、Lua 시리얼 통신 디버깅、Modbus CRC 自动계산、시리얼 포트自动化测试、xlua、Luat Task。


디버깅 Modbus RTU 设备最常见的工作流是:시리얼 포트 열기도구 → 手动16진수 입력帧 → 点보내기 → 等回应 → 肉眼对照바이트 → 发现 CRC 算错了 → 重新来。十台设备调完,手指痛、眼睛酸、心里碎成渣。

LLCOM 解决的就是这个문제。它不只是一个시리얼 포트助手——它是个能跑스크립트的시리얼 통신 디버깅引擎。


一、LLCOM 是什么

LLCOM 是 GitHub 오픈소스项目(chenxuuu/llcom),用 C# 写、基于 .NET 框架,采用腾讯 xlua 作为스크립트引擎。许可证是 Apache 2.0。

定位一句话:可编程的시리얼 포트디버깅 도구。普通的시리얼 포트助手只能「键盘打16진수→手点보내기→肉眼看出16진수」。LLCOM 可以写 Lua 스크립트让데이터自动处理、自动보내기、自动분석、自动체크섬。

核心架构三层:

  • 시리얼 포트收发层:표준시리얼 포트통신,支持통신 속도、데이터 비트、패리티설정,同时통합 TCP/UDP/MQTT 클라이언트和服务器功能,还能监听其他程序使用的시리얼 포트
  • Lua 스크립트引擎层:Lua 5.3 환경 + 合宙 Luat Task 协程框架(sys.wait、sys.taskInit、sys.timerLoopStart 等전체移植)
  • 보내기前处理层:用户在보내기框中입력的데이터,可以经过一段 Lua 스크립트处理后再发出去——自动换行、自动转 Hex、自动组装 JSON,什么都能干

오픈소스주소:https://github.com/chenxuuu/llcom


二、安装与下载

三个官方渠道,选一个:

방식一:微软商店 在 Windows 自带的 Microsoft Store 中검색「LLCOM」即可安装。优势是自动更新,缺点是需要微软账号。

방식二:便携版(免安装) 从 底部 下载 zip 包,解压到任意目录,双击 llcom.exe 运行。不上회원가입表、不写系统目录,放到 U 盘里到处带着跑。

방식三:GitHub Releases 从 https://github.com/chenxuuu/llcom/releases/latest 下载最新稳定版。适合需要特定버전的디버깅시나리오。

系统要求:Windows 10 及以上,64 位。需要 .NET Runtime(Windows 10/11 通常已内置;如果提示缺少 .NET Runtime,从微软官网下载 .NET Desktop Runtime 8.0 即可)。


三、功能清单:比普通시리얼 포트助手多了什么

LLCOM 有普通시리얼 포트助手的所有功能(시리얼 포트选择、통신 속도/패리티설정、16진수/ASCII 收发、로그显示),然后加了这些:

功能설명Modbus 디버깅시나리오
Lua 보내기前处理입력框콘텐츠经过 Lua 스크립트处理后才보내기自动拼接 CRC、自动加슬레이브 주소
独立 Lua 스크립트区右侧可跑完整的 Lua 스크립트,带定时器和协程写一个스크립트自动轮询所有슬레이브레지스터
快捷보내기栏(10 页×不限条数)저장常用命令,一键보내기把读不同레지스터的帧放不同页
시리얼 포트监听监控其他程序正在使用的시리얼 포트데이터看某上位机软件发了什么帧
TCP/UDP/SSL 클라이언트和服务端可以不通过시리얼 포트直接调 TCP测试 Modbus TCP 포트
MQTT 测试통합 MQTT 发布/订阅验证게이트웨이的 MQTT 上行
시리얼 포트自动重连断开后自动恢复연결设备断电重启不会断디버깅
自动로그저장带时间戳的시리얼 포트和 Lua 로그调完전체设备,回头看로그复盘
编码互转/乱码恢复GBK/UTF-8/Hex 之间转换중국어문자串디버깅

四、两大核心功能详解

4.1 보내기前 Lua 处理

这是 LLCOM 最直接提效的功能。在「보내기设置」→「보내기处理스크립트」里写一段 Lua,每次点보내기时,你입력框里的原始文本先传给这段스크립트,스크립트处理后返回的문자串才是真正发到시리얼 포트的데이터。

三个经典用法:

自动加 rn:很多시리얼 포트设备要求命令以줄바꿈(CRLF)结尾——

return uart데이터 .. "rn"

从此不用每次手打 0D 0A,명령 입력直接点보내기就完事。

16진수自动转换:在입력框里写16진수문자串(如 010300000001),스크립트自动转成2진수——

return uart데이터:fromHex()

这是 Modbus RTU 디버깅的标配——你在입력框写 Modbus 帧的16진수表示,스크립트转成2진수发给设备。

JSON 自动组装:입력 a,b,c,发出去的是 JSON——

json = require("JSON")
t = uart데이터:split(",")
return json:encode({
    key1 = t[1],
    key2 = t[2],
    key3 = t[3],
})

快捷보내기栏的每个버튼也同样走这个스크립트,所以你可以建 10 页快捷보내기,每页放不同的 Modbus 命令,然后每次点버튼自动加 CRC 发出去——后面会给出完整实现。

4.2 独立 Lua 스크립트运行区

右边有个「Lua 스크립트」区域,你可以直接写完整的 Lua 程序并运行。这里的스크립트拥有合宙 Luat Task 框架的전체能力:

  • sys.taskInit() 创建协程任务
  • sys.wait(ms) 延时대기(不阻塞界面)
  • sys.waitUntil() 대기消息(事件驱动)
  • sys.timerLoopStart() 循环定时器
  • sys.publish() / sys.subscribe() 消息发布订阅

基础예제:收到시리얼 포트데이터后自动回复——

uartReceive = function (데이터)
    log.info("uartReceive", 데이터)
    sys.publish("UART", 데이터)
end

sys.taskInit(function()
    while true do
        local _, u데이터 = sys.waitUntil("UART")
        log.info("task waitUntil", u데이터)
        local sendResult = apiSendUart데이터("ok!")
        log.info("uart send", sendResult)
    end
end)

你甚至可以用 xlua 直接调用 C# 的 System.Net 类库发 HTTP 请求——这意味着你可以写一个스크립트,시리얼 포트收到데이터后自动往클라우드 플랫폼推一条消息。


五、核心 API 速查

LLCOM 的 Lua API 문서位于 https://github.com/chenxuuu/llcom/blob/master/LuaApi.md ,这里列出 Modbus 디버깅最常用的部分。

5.1 시리얼 포트收发 API

-- 보내기데이터到시리얼 포트(推荐新인터페이스)
apiSend("uart", 데이터)

-- 보내기데이터到시리얼 포트(旧인터페이스,后续会제거)
apiSendUart데이터(데이터)

-- 订阅시리얼 포트수신回调
apiSetCb("uart", function(데이터)
    log.info("received", 데이터)
end)

-- 취소订阅
apiUnsetCb("uart", callback)

5.2 定时器与协程 API

-- 创建任务
sys.taskInit(function()
    while true do
        -- 你的逻辑
        sys.wait(1000)  -- 等 1000ms
    end
end)

-- 循环定时器
sys.timerLoopStart(function()
    log.info("tick", os.time())
end, 1000)  -- 每 1000ms 触发一次

-- 정지定时器
sys.timerStop(timerId)

5.3 문자串处理 API

-- 2진수转16진수문자串
string.toHex("x01x03")  -- 返回 "0103"

-- 16진수문자串转2진수
("010300000001"):fromHex()

-- 分割문자串
("a,b,c"):split(",")  -- 返回 {"a","b","c"}

5.4 로그 API

log.info("tag", "message")
log.warn("tag", "warning")
log.error("tag", "error")

所有로그自动저장到软件目录,并附带时间戳。


六、Modbus RTU 实战스크립트

以下스크립트可以直接복사到 LLCOM 里运行。每个都是完整可用的。

6.1 智能보내기:自动계산 Modbus CRC 并보내기

Tired of 手动算 CRC?这是 LLCOM 在 Modbus 디버깅中最经典的적용。

在「보내기处理스크립트」中粘贴:

-- Modbus CRC16 查表法(多项式 0xA001)
local crcTable = {}
for i = 0, 255 do
    local crc = i
    for _ = 1, 8 do
        if (crc & 1) ~= 0 then
            crc = (crc >> 1) ~ 0xA001
        else
            crc = crc >> 1
        end
    end
    crcTable[i] = crc
end

local function modbusCrc16(데이터)
    local crc = 0xFFFF
    for i = 1, #데이터 do
        local b = string.byte(데이터, i)
        crc = (crc >> 8) ~ crcTable[(crc ~ b) & 0xFF]
    end
    return crc
end

-- 主逻辑:把입력转成2진수,계산 CRC,拼上去,发给시리얼 포트
local raw = uart데이터:fromHex()  -- 입력框写16진수,如 010300000001
local crc = modbusCrc16(raw)
local lo = crc & 0xFF
local hi = (crc >> 8) & 0xFF
return raw .. string.char(lo, hi)

现在你在입력框写 010300000001(슬레이브 주소=01,기능 코드=03,시작주소=0000,레지스터数=0001),点보내기后实际发出去的是 01 03 00 00 00 01 84 0A——CRC 自动接在后面。

6.2 Modbus RTU 自动轮询스크립트

跑在「Lua 스크립트」区域中,每隔 2 秒读一次슬레이브 01 的유지 레지스터 40001(주소 0x0000),自动분석返回데이터:

-- CRC 表(同上,这里省略,需要放在스크립트最前面)
-- ...(和 6.1 的 crcTable 和 modbusCrc16 函数一样)

local function buildReadFrame(slave, 시작Addr, regCount)
    local frame = string.char(slave, 0x03,
        (시작Addr >> 8) & 0xFF, 시작Addr & 0xFF,
        (regCount >> 8) & 0xFF, regCount & 0xFF)
    local crc = modbusCrc16(frame)
    return frame .. string.char(crc & 0xFF, (crc >> 8) & 0xFF)
end

local function parseResponse(데이터)
    if #데이터 < 5 then
        log.warn("modbus", "响应太短: " .. string.toHex(데이터))
        return nil
    end
    local slave = string.byte(데이터, 1)
    local func = string.byte(데이터, 2)
    if func > 0x80 then
        log.error("modbus", "异常码: 0x" .. string.format("%02X", string.byte(데이터, 3)))
        return nil
    end
    local byteCount = string.byte(데이터, 3)
    local values = {}
    for i = 0, (byteCount / 2) - 1 do
        local hi = string.byte(데이터, 4 + i * 2)
        local lo = string.byte(데이터, 5 + i * 2)
        values[i + 1] = (hi << 8) | lo
    end
    return {slave = slave, values = values}
end

-- 수신处理
apiSetCb("uart", function(데이터)
    local result = parseResponse(데이터)
    if result then
        log.info("modbus", string.format("슬레이브%02X 레지스터 값: %s",
            result.slave, table.concat(result.values, ", ")))
    end
end)

-- 轮询任务
sys.taskInit(function()
    while true do
        local frame = buildReadFrame(0x01, 0x0000, 4)
        log.info("modbus", "보내기: " .. string.toHex(frame))
        apiSend("uart", frame)
        sys.wait(2000)
    end
end)

运行后로그출력类似:modbus 보내기: 0103000000044409 → modbus 슬레이브01 레지스터 값: 168, 2234, 0, 512。不需要人工干预,스크립트自动轮询、自动분석、自动打로그。

6.3 多슬레이브扫描器

自动扫描总线上有哪些슬레이브在线。挨个发읽기命令,有响应的就是在线:

-- CRC 函数同上,省略

local function scanSlave(slaveId)
    local frame = string.char(slaveId, 0x03, 0x00, 0x00, 0x00, 0x01)
    local crc = modbusCrc16(frame)
    frame = frame .. string.char(crc & 0xFF, (crc >> 8) & 0xFF)

    apiSetCb("uart", function(데이터)
        if #데이터 >= 5 and string.byte(데이터, 1) == slaveId
            and string.byte(데이터, 2) == 0x03 then
            log.info("scan", "슬레이브 " .. slaveId .. " 在线✓")
        end
    end)

    apiSend("uart", frame)
    log.info("scan", "扫描슬레이브 " .. slaveId .. " ...")
end

sys.taskInit(function()
    for slaveId = 1, 247 do
        scanSlave(slaveId)
        sys.wait(150)  -- 等 150ms 给슬레이브响应时间
    end
    log.info("scan", "扫描完成")
end)

스크립트跑完,로그里列出所有在线的슬레이브 주소。大型项目中第一次上电后跑一遍这个,省去挨个看설명书的功夫。

6.4 响应帧自动분석 + 데이터导出

收到 Modbus 响应后,自动분석并형식化为 CSV 行,方便복사到 Excel 做趋势分析:

local results = {}

apiSetCb("uart", function(데이터)
    if #데이터 < 5 then return end
    local slave = string.byte(데이터, 1)
    local func = string.byte(데이터, 2)
    if func >= 0x80 then
        log.error("modbus", string.format("S=%02X 异常码0x%02X", slave, string.byte(데이터, 3)))
        return
    end
    local byteCount = string.byte(데이터, 3)
    local row = {os.date("%H:%M:%S"), slave}
    for i = 0, (byteCount / 2) - 1 do
        local hi = string.byte(데이터, 4 + i * 2)
        local lo = string.byte(데이터, 5 + i * 2)
        table.insert(row, (hi << 8) | lo)
    end
    table.insert(results, table.concat(row, ","))
    log.info("csv", table.concat(row, ","))
end)

-- 轮询任务(每 5 秒采集一次,共采集 60 次 = 5 分钟)
sys.taskInit(function()
    for i = 1, 60 do
        local frame = string.char(0x01, 0x03, 0x00, 0x00, 0x00, 0x04)
        local crc = modbusCrc16(frame)
        apiSend("uart", frame .. string.char(crc & 0xFF, (crc >> 8) & 0xFF))
        sys.wait(5000)
    end
    log.info("export", "采集完成,共 " .. #results .. " 行")
end)

로그출력的每一行都可以直接복사粘贴到 CSV 文件里用 Excel 열기。


七、TCP / MQTT / 监听 —— 其他 Modbus 시나리오

7.1 调 Modbus TCP

LLCOM 可以当 TCP 클라이언트연결 Modbus TCP 设备(默认포트 502)。열기 TCP 클라이언트功能,填入设备 IP 和포트 502,연결成功后像시리얼 포트一样收发—— Modbus TCP 帧和 RTU 帧的区别只是少了 CRC、多了 MBAP 头(6 바이트)。你可以在보내기处理스크립트里自动补上 MBAP 头:

-- 입력框写 000000000006010300000001
-- 表示:事务ID=0000,프로토콜ID=0000,길이=0006,单元ID=01,기능 코드=03,시작주소=0000,레지스터数=0001
return uart데이터:fromHex()

或者스크립트接到시리얼 포트收到的 RTU 帧,去掉 CRC 换成 MBAP 头后通过 TCP 通道发出去。具体见软件自带的 channel-demo.lua 例子。

7.2 MQTT 测试

如果디버깅 Modbus 게이트웨이(DTU 把시리얼 포트데이터转成 MQTT 发布),LLCOM 的 MQTT 功能可以直接订阅게이트웨이发布的主题,看到게이트웨이发上来的데이터是否正确。还能往控制主题发布消息测试下行。

7.3 시리얼 포트监听

「시리얼 포트监听」功能可以抓取其他软件正在使用的시리얼 포트통신——比如你的上位机软件在跟设备통신,你不想停掉它但想看它发了什么帧。LLCOM 可以静默抓取시리얼 포트데이터并显示로그,不影响原来的통신。


八、和同类도구的对比

도구스크립트支持Modbus CRC오픈소스价格
LLCOMLua 5.3 + xlua + 协程框架需要自己写(本文已提供)是무료
SSCOM无不支持否무료
COMTool有限不支持是무료
Modbus Poll无(专业 Modbus 固定功能)内置否$129
ModScan无内置否$69

LLCOM 不是「开箱即用」的 Modbus 专用도구,它是「可以变成 Modbus 专用도구的万能도구」。如果你只需要点一个버튼就发 Modbus 帧,Modbus Poll 更直接。但如果你需要批量自动化测试、自定义분석、데이터导出、和 MQTT/TCP 联调——LLCOM 是目前오픈소스도구里最灵活的。


九、常见문제

Q: 收到乱码怎么办? 检查통신 속도、패리티是否和设备一致。然后在 LLCOM 的수신区전환 Hex 显示——很多情况下「乱码」是因为设备返回的是2진수데이터但显示区按 ASCII 분석了。

Q: CRC 스크립트发出去的帧设备没反应? 第一步:确认 A/B 线没接反。第二步:在수신区看设备有没有返回任何바이트——如果完全没有,可能是设备주소不对。第三步:如果设备返回了데이터但是异常码(기능 코드 + 0x80),看异常码是什么——0x02 是「非法데이터주소」,레지스터주소可能不存在。

Q: 快捷보내기栏的버튼能自动跑 CRC 스크립트吗? 能。快捷보내기栏的콘텐츠也会经过「보내기处理스크립트」——所以你写好了 CRC 自动계산스크립트后,快捷보내기栏只需要填裸帧(如 010300000001),点버튼自动加 CRC。

Q: Lua 스크립트运行时报错了? 在스크립트区域最开头加一行 log.info("boot", "script 시작ed") 看스크립트是否成功启动。大部分错误是因为변수名拼错或调用了不存在的 API——로그区会显示 Lua 错误信息。


LLCOM 的核心价值不是多了多少功能,而是把「디버깅」从重复体力劳动变成了可编程的任务。你在现场花半小时写了三个스크립트,接下来三天点几下鼠标데이터自己就来了。这就是「给시리얼 포트装上大脑」的真正含义——不是 LLCOM 有 AI,是 LLCOM 让你能把自己的디버깅逻辑写成代码、然后让软件替你跑。

有문제再聊。

실제 프로젝트에 이 자료를 활용하시겠습니까?

도구 센터에서 프레임 분석, CRC 검증, 장비 디버깅을 진행하거나 요청을 제출하여 선정 및 연동 제안을 받아보세요.

엔지니어 회원

이 글을 실행 가능한 디버깅 자료로 활용하세요

가입하면 고급 프레임 분석, 자료 패키지 다운로드, 코드 예제, 엔지니어링 사례, 우선 기술 지원을 이용할 수 있어 실제 프로젝트 납품에 적합합니다.

고급 도구 무제한 이용
자료 패키지와 코드 패키지
완전한 엔지니어링 사례 라이브러리
우선 기술 지원 채널

답글 작성

이메일 주소는 공개되지 않습니다. 必填项已用 * 标注