给シリアルポート装上大脑:LLCOM Lua脚本デバッグツール

freeFree Technical Resource

This content is free to read, suitable for basic learning and search traffic.

给シリアルポート装上大脑:LLCOM Lua脚本デバッグツール

Source: Modbus Chinese Network(modbus.cn) —— China leadingModbuscommunication protocol technical community

本記事:LLCOM:给シリアルポート装上 Lua 大脑 —— Modbus デバッグ效率翻倍完全に。ガイド · Author:modbus Technical Team · 发布于 2026-07-01

摘要:LLCOM 是 GitHub 开源的 Windows シリアルポートデバッグ工具(chenxuuu/llcom),基于 .NET 和腾讯 xlua 引擎,让シリアルポートデバッグ不再是手动一条条发十六进制フレーム。其核心杀手锏是在標準シリアルポート工具基础上内嵌了完全的 Lua 5.3 运行环境,サポート合宙 Luat Task 协程框架,可以写脚本自动收发、自动計算 Modbus CRC、自动ポーリング、自动解析レスポンス。本記事从インストール到 API 参照到四个 Modbus 実践脚本,カバー你从下载到跑通自動化测试的每一个步骤。关键词:LLCOM、Lua Serial Port Debugging、Modbus CRC 自动計算、シリアルポート自動化测试、xlua、Luat Task。


debug Modbus RTU デバイス最も一般的な的ワークフローワークフロー是:シリアルポートを開く工具 → 手动入力十六进制フレーム → 点送信 → 等回应 → 肉眼对照バイト → 发现 CRC 算错了 → 重新来。十台デバイス调完,手指痛、眼睛酸、心里碎成渣。

LLCOM 解決的就是这个問題。它不只是一个シリアルアシスタント——它是个能跑脚本的シリアルポートデバッグ引擎。


一、LLCOM What is it

LLCOM 是 GitHub オープンソースプロジェクト(chenxuuu/llcom),用 C# 写、基于 .NET 框架,采用腾讯 xlua 作为脚本引擎。ライセンスは是 Apache 2.0。

ポジショニング一句话:可プログラミング的シリアルポートデバッグ工具。普通的シリアルアシスタント只能「键盘打十六进制→手点送信→肉眼看出十六进制」。LLCOM 可以写 Lua 脚本让データ自动処理、自动送信、自动解析、自动チェック。

核心架构三层:

  • シリアルポート收发层:標準シリアル通信,サポートボーレート、data bit、チェックビット設定,同时集成 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」即可インストール。优势是自动更新,缺点是需要微软账号。

方式二:便携版(免インストール) 从 底部 Download zip 包,解压到任意目录,双击 llcom.exe run。不上登録表、不写系统目录,放到 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 有普通シリアルアシスタント的すべての功能(シリアルポート選択、Baud rate/チェックビット設定、hexadecimal/ASCII 收发、日志表示),然后加了这些:

Function説明Modbus デバッグ场景
Lua 送信前処理入力框内容经过 Lua 脚本処理后才送信自动拼接 CRC、自动加駅からの住所
独立 Lua 脚本区右侧可跑完全的 Lua Script,带タイマータイマー。和协程写一个脚本自动ポーリングすべての駅から。レジスタ
快捷送信栏(10 页×不限条数)保存常用命令,一键送信把读不同レジスタ的フレーム放不同页
シリアルポート监听モニタリング其他程序正在使用的シリアルポートデータ看某トップマシン软件发了什么フレーム
TCP/UDP/SSL クライアント側は和サーバー側。可以通信不可过シリアルポート直接调 TCP测试 Modbus TCP port
MQTT 测试集成 MQTT Published/订阅验证ゲートウェイ的 MQTT 上行
シリアルポート自動再接続。断开后自动恢复连接機器の電源オフと再起動不会断デバッグ
自动日志保存带时间戳的シリアルポート和 Lua 日志调完すべてデバイス,回头看日志复盘
编码互转/乱码恢复GBK/UTF-8/Hex 之间转换中文ストリング·ストリングデバッグ

四、两大核心功能详解

4.1 送信前 Lua 処理

这是 LLCOM 最直接提效的功能。在「送信設定」→「送信処理脚本」里写一段 Lua,每次点送信时,你入力框里的元の文本先传给这段脚本,脚本処理后戻る的ストリング·ストリング才是真正发到シリアルポート的データ。

三个经典用法:

自动加 rn:很多シリアルデバイス要求命令以回车换行结尾——

return uartData .. "rn"

从此不用每次手打 0D 0A,入力命令直接点送信就完事。

十六进制自动转换:在入力框里写十六进制ストリング·ストリング(如 010300000001),脚本自动转成二进制——

return uartData:fromHex()

这是 Modbus RTU デバッグ的标配——你在入力框写 Modbus フレーム的十六进制表示,脚本转成二进制发给デバイス。

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

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

快捷送信栏的每个按钮也同样走这个脚本,所以你可以建 10 页快捷送信,每页放不同的 Modbus Command,然后每次点按钮自动加 CRC 发出去——后面会给出完全な実装。

4.2 独立 Lua 脚本运行区

右边有个「Lua Script」エリア,你可以直接写完全的 Lua 程序并运行。这里的脚本拥有合宙 Luat Task 框架的すべて能力:

  • sys.taskInit() 作成协程任务
  • sys.wait(ms) 延时待機中(不阻塞界面)
  • sys.waitUntil() 待機中メッセージ(事件驱动)
  • sys.timerLoopStart() 循环タイマータイマー。
  • sys.publish() / sys.subscribe() メッセージ发布订阅

基础サンプル:收到シリアルポートデータ后自动回复——

uartReceive = function (data)
    log.info("uartReceive", data)
    sys.publish("UART", data)
end

sys.taskInit(function()
    while true do
        local _, udata = sys.waitUntil("UART")
        log.info("task waitUntil", udata)
        local sendResult = apiSendUartData("ok!")
        log.info("uart send", sendResult)
    end
end)

你甚至可以用 xlua 直接调用 C# 的 System.Net 类库发 HTTP Request——这意味着你可以写一个脚本,シリアルポートデータの受信后自动往クラウド·プラットフォーム推一条メッセージ。


五、核心 API 速查

LLCOM 的 Lua API ドキュメント位于 https://github.com/chenxuuu/llcom/blob/master/LuaApi.md ,这里列出 Modbus デバッグ最もよく使われる部分。

5.1 シリアルポート收发 API

-- 送信データ到シリアルポート(おすすめ新接口)
apiSend("uart", data)

-- 送信データ到シリアルポート(旧接口,后续会削除)
apiSendUartData(data)

-- 订阅シリアルポート受信回调
apiSetCb("uart", function(data)
    log.info("received", data)
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

-- 二进制转十六进制ストリング·ストリング
string.toHex("x01x03")  -- 戻る "0103"

-- 十六进制ストリング·ストリング转二进制
("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(data)
    local crc = 0xFFFF
    for i = 1, #data do
        local b = string.byte(data, i)
        crc = (crc >> 8) ~ crcTable[(crc ~ b) & 0xFF]
    end
    return crc
end

-- 主逻辑:把入力转成二进制,result CRC,拼上去,发给シリアルポート
local raw = uartData:fromHex()  -- 入力框写十六进制,如 010300000001
local crc = modbusCrc16(raw)
local lo = crc & 0xFF
local hi = (crc >> 8) & 0xFF
return raw .. string.char(lo, hi)

现在你在入力框写 010300000001(slave address=01,function code=03,starting address=0000,レジスタの数=0001),点送信后实际发出去的是 01 03 00 00 00 01 84 0A——CRC 自动接在后面。

6.2 Modbus RTU 自动ポーリング脚本

跑在「Lua Script」エリア中,每隔 2 秒读一次スレーブ 01 保持レジスタです。 40001(address 0x0000),自动解析戻るデータ:

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

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

local function parseResponse(data)
    if #data < 5 then
        log.warn("modbus", "レスポンス短すぎる: " .. string.toHex(data))
        return nil
    end
    local slave = string.byte(data, 1)
    local func = string.byte(data, 2)
    if func > 0x80 then
        log.error("modbus", "Exception Code: 0x" .. string.format("%02X", string.byte(data, 3)))
        return nil
    end
    local byteCount = string.byte(data, 3)
    local values = {}
    for i = 0, (byteCount / 2) - 1 do
        local hi = string.byte(data, 4 + i * 2)
        local lo = string.byte(data, 5 + i * 2)
        values[i + 1] = (hi << 8) | lo
    end
    return {slave = slave, values = values}
end

-- 受信処理
apiSetCb("uart", function(data)
    local result = parseResponse(data)
    if result then
        log.info("modbus", string.format("slave%02X Register value: %s",
            result.slave, table.concat(result.values, ", ")))
    end
end)

-- ポーリング任务
sys.taskInit(function()
    while true do
        local frame = buildReadFrame(0x01, 0x0000, 4)
        log.info("modbus", "send: " .. string.toHex(frame))
        apiSend("uart", frame)
        sys.wait(2000)
    end
end)

运行后日志出力类似:modbus send: 0103000000044409modbus slave01 Register value: 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(data)
        if #data >= 5 and string.byte(data, 1) == slaveId
            and string.byte(data, 2) == 0x03 then
            log.info("scan", "slave " .. 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(data)
    if #data < 5 then return end
    local slave = string.byte(data, 1)
    local func = string.byte(data, 2)
    if func >= 0x80 then
        log.error("modbus", string.format("S=%02X Exception Code0x%02X", slave, string.byte(data, 3)))
        return
    end
    local byteCount = string.byte(data, 3)
    local row = {os.date("%H:%M:%S"), slave}
    for i = 0, (byteCount / 2) - 1 do
        local hi = string.byte(data, 4 + i * 2)
        local lo = string.byte(data, 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 open。


七、TCP / MQTT / 监听 —— 其他 Modbus Scenarios

7.1 调 Modbus TCP

LLCOM 可以当 TCP クライアント側は连接 Modbus TCP device(デフォルトポート 502)。open TCP クライアント側は功能,填入デバイス IP ポートと港。 502,接続成功です。后像シリアルポート一样收发—— Modbus TCP フレーム和 RTU フレーム違いはありません只是少了 CRC、多了 MBAP 头(6 byte)。你可以在送信処理脚本里自动补上 MBAP 头:

-- 入力框写 000000000006010300000001
-- 表示:トランザクションID=0000,ProtocolID=0000,Length=0006,ユニットID=01,function code=03,starting address=0000,レジスタの数=0001
return uartData:fromHex()

或者脚本接到シリアルポート收到的 RTU フレーム,去掉 CRC 换成 MBAP 头后経由 TCP 通道发出去。具体见软件自带的 channel-demo.lua 例子。

7.2 MQTT 测试

もしデバッグ Modbus ゲートウェイ(DTU 把シリアルポートデータ转成 MQTT Published),LLCOM 的 MQTT 功能可以直接订阅ゲートウェイ发布的主题,看到ゲートウェイ发上来的データ是否正确。还能往控制主题发布メッセージ测试下行。

7.3 シリアルポート监听

「シリアルポート监听」功能可以抓取其他软件正在使用的シリアル通信——比如你的トップマシン软件在跟デバイス通信,你不想停掉它但想看它发了什么フレーム。LLCOM 可以静默抓取シリアルポートデータ并表示日志,不影响原来的通信。


八、和同类工具的对比

Tools脚本サポートModbus CRC开源Price
LLCOMLua 5.3 + xlua + 协程框架需要自己写(本記事已提供)free
SSCOMサポートなし。free
COMTool有限サポートなし。free
Modbus Poll无(专业 Modbus 固定功能)内置$129
ModScan内置$69

LLCOM ではない「开箱即用」的 Modbus 专用工具,它是「可以变成 Modbus 专用工具的万能工具」。もし你只需要点一个按钮就发 Modbus フレーム,Modbus Poll 更直接。但もし你需要批量自動化测试、自定义解析、データ导出、和 MQTT/TCP 联调——LLCOM 是目前オープンソースツール里最灵活的。


九、common problems

Q: 收到乱码怎么办? チェックボーレート、チェックビット是否和デバイス一致。然后在 LLCOM 的受信区切换 Hex 表示——很多情况下「乱码」是因为デバイス戻る的是二进制データ但表示区按 ASCII 解析了。

Q: CRC 脚本发出去的フレームデバイス没反应? 最初のステップ:Confirm A/B 线没接反。第二のステップ:在受信区看デバイス有ない戻る任何バイト——もし完全ない,可能是デバイスアドレス正しくない。第三のステップ:もしデバイス戻る了データ但是異常コード。(function code + 0x80),看異常コードとは?——0x02 是「Illegal data address」,レジスター·アドレス可能不存在。

Q: 快捷送信栏的按钮能自动跑 CRC 脚本吗? 能。快捷送信栏的内容也会经过「送信処理脚本」——所以你写好了 CRC 自动計算脚本后,快捷送信栏只需要填裸フレーム(如 010300000001),点按钮自动加 CRC。

Q: Lua 脚本运行时报错了? 在脚本エリア最开头加一行 log.info("boot", "script started") 看脚本是否成功启动。主に。エラー是因为变量名拼错或调用了不存在的 API——日志区会表示 Lua エラー信息。


LLCOM 的核心价值ではない多了多少功能,而是把「debug」从重复体力劳动变成了可プログラミング的任务。你在现场花半小时写了三个脚本,接下来三天点几下鼠标データ自己就来了。这就是「给シリアルポート装上大脑」的真正含义——ではない LLCOM 有 AI,是 LLCOM 让你能把自己的デバッグ逻辑写成代码、然后让软件替你跑。

有問題再聊。

Related Tags
Put this resource to use in a real project?

Go to the Tool Center for message parsing, CRC verification and device debugging, or submit your requirements for selection and integration advice.

Engineer Membership

Turn this article into actionable debugging resources

After activation, you can use advanced message parsing, resource pack downloads, code examples, engineering cases and priority technical support, suitable for real project delivery.

Unlimited Advanced Tools
Resource & Code Packs
Complete Engineering Case Library
Priority Technical Support

Leave a Reply

Your email address will not be published. Required fields are marked *.