VisualHMI OTA 升级:ota_init/ota_write 与 SD 卡自动升级

免费免费技术资料

这篇内容可直接阅读,适合用于基础学习和搜索引流。

本文目录
  1. 1. 1. ⚠️ Flash 规划(升级失败/变砖的根源)
  2. 2. 2. API 总表
  3. 3. 3. 应用:SD 卡本地升级
  4. 4. 3.1 升级包准备
  5. 5. 3.2 检测盘符 + 找 a.bin
  6. 6. 3.3 核心升级流程(ota.lua)

OTA 升级 API:HMI 的升级逻辑与通信协议、数据来源完全解耦——不管升级数据来自主板串口、以太网、Wi-Fi 还是 4G,不管上位机用自定义协议、Modbus 还是 HTTP,HMI 只负责通过标准 API 把收到的数据写进指定 Flash 区,校验解压成功后自动重启升级。适用 HMI&M 系列&Dx 系列。

1. ⚠️ Flash 规划(升级失败/变砖的根源)

以 HMI80480M070 为例(标准品 128Mbit = 16MB):

项目 大小
Flash 总容量 16 MB
系统固件(OS+驱动,M 系列) 1 MB(DH 系列 2 MB)
当前工程(private) 4.38 MB
已用合计 5.38 MB,剩 ≈10.62 MB
OTA 起始地址要求 必须 ≥ 8 MB(Flash 总量一半)

两条铁律:①OTA 起始地址必须从 Flash 后半部分开始(哪怕剩余 10.62MB 也要从 ≥8MB 起),避免新旧工程交叉覆盖,升级过程中当前系统才能继续跑;②OTA 写入区必须连续且空闲——如果你用「块地址」功能占了高地址区(比如 10~12MB),或者升级包超过 Flash 一半(≈10.62MB 的包),都不可升级。

2. API 总表

函数 参数 说明
ota_init(md5, filesize, addr) md5 固定 “0123456789abcdef”;filesize 与 .bin 实际大小严格一致;addr ≥ Flash 一半 配置升级目标,准备接收固件数据
ota_write(writeTb) 字节表,≤2048,不足自动补 0x00 分块写固件到 Flash 区
ota_check_upgrade(state) 必须传 1 触发完整性校验 + 解压 + 升级
ota_destory() 擦除已写的 OTA 残留数据(升级前清场)
on_ota_progress(status, value) 见下表 校验/解压进度与结果回调

on_ota_progress 的 status/value 组合:

status 含义 value
1 校验过程开始 固定 0
2 校验结果 0=失败(固件损坏/MD5 不匹配)/1=成功
3 解压进度 0~100 百分比
4 解压结果 0=失败/1=成功 → 即将重启

3. 应用:SD 卡本地升级

3.1 升级包准备

工程编译后选择量产下载,生成的文件里有 ota.bin。使用前把 ota.bin 改名为 a.bin 放到 SD 卡根目录。

VisualHMI OTA 升级:ota_init/ota_write 与 SD 卡自动升级插图

3.2 检测盘符 + 找 a.bin

ota_filename   = "a.bin"
ota_addr_start = 8 * 1024 * 1024    -- OTA 起始地址(至少 Flash 一半)
flashsize      = 16 * 1024 * 1024   -- Flash 总大小

function on_update(slave, vtype, addr)
  if vtype == VT_LW and addr == useraddr.ota_swich then
    if sd_dir ~= 0 then
      list_dir(sd_dir)               -- 先看 SD 卡
    elseif usb_dir ~= 0 then
      list_dir(usb_dir)              -- 再看 U 盘
    else
      set_string(VT_LW, useraddr.text, "检测不到SD卡和USB,无法OTA升级!!!")
    end
  end
end

function on_list_dir(path, filename, type, fsize)
  if type == 1 then
    if filename == ota_filename then
      set_string(VT_LW, useraddr.text, "文件:"..ota_filename.." 已检测到")
      if (fsize + ota_addr_start) > flashsize then
        set_string(VT_LW, useraddr.text, "ota.bin 文件大小超过,无法升级!!!")
      else
        set_string(VT_LW, useraddr.text, "开始升级!!!")
        set_uint32(VT_LW, useraddr.ota_data, fsize)
        ota.set_upgrade(path.."/"..ota_filename)
      end
    end
  end
end

3.3 核心升级流程(ota.lua)

function ota.set_upgrade(path)
  local TransferSize = 0
  local size = 0
  if file_open(path, 0) == true then
    size = file_size()
    if size < (flashsize - ota_addr_start) then
      ota_destroy()                                  -- 消除残留 OTA 数据
      local sdota_addr = ota_init("0123456789abcdef", size, ota_addr_start)
      -- 计算尾包补零长度
      local size_complement = 0
      if size % 2048 ~= 0 then
        size_complement = 2048 - (size % 2048)
      end
      while true do
        local rddata = file_read(2048)               -- 流式读 2048
        if #(rddata) < 2048 then                     -- 尾包补 0x00
          for i = (#(rddata) + 1), 2048 do rddata[i] = 0x00 end
        end
        TransferSize = TransferSize + #(rddata)
        local prg = string.format("%.1f", (TransferSize * 100) / (size + size_complement))
        set_uint16(VT_LW, useraddr.progress, math.modf((TransferSize * 1000) / size))
        set_string(VT_LW, useraddr.text, "下载进度 : "..prg.." %")
        refresh_screen()
        ota_write(rddata)                            -- 写入 Flash,不足补零
        if size <= TransferSize then break end
      end
      file_close()
      ota_check_upgrade(1)                           -- 校验、解压
    end
  end
end

function on_ota_progress(status, value)
  if status == 1 and value == 0 then
    set_string(VT_LW, useraddr.text, "校验开始")
  elseif status == 2 then
    if value == 0 then set_string(VT_LW, useraddr.text, "校验失败")
    elseif value == 1 then set_string(VT_LW, useraddr.text, "校验成功") end
  elseif status == 3 then
    set_uint16(VT_LW, useraddr.progress, value * 10)
    set_string(VT_LW, useraddr.text, "解压进度 : "..value.." %")
    refresh_screen()
  elseif status == 4 then
    if value == 0 then set_string(VT_LW, useraddr.text, "解压失败")
    elseif value == 1 then set_string(VT_LW, useraddr.text, "解压成功") end
  end
end

关键点:ota_init 的 filesize 必须和 .bin 实际大小严格一致;写数据全程流式(每次 ≤2048,尾包补 0x00);ota_check_upgrade(1) 之后校验失败会停在回调里给你机会处理,解压成功就自动重启进升级。

四个坑:①md5 参数是固定串「0123456789abcdef」,不是文件的真实 MD5,别自作聪明去算文件哈希;②addr 必须 ≥ Flash 一半且区域连续空闲,块地址占了高地址区就升不了;③升级包不能超过 Flash 一半,10.62MB 的剩余空间不等于能放 10.62MB 的包;④升级前先 ota_destroy() 清残留,ota_write 的尾包不足 2048 会自动补零,你不需要自己处理对齐。升级中断电 = 变砖,量产前务必反复验证升级流程。

整理自 广州大彩科技 VisualHMI 开发文档(hmi-doc.gz-dc.com)LUA 教程「OTA升级」,版权归大彩科技所有。

技术术语(共 1 个)—— 点击展开
串口计算机与外部设备进行串行通信的物理接口
来源/工具信息 —— 点击展开
来源 Modbus中文网(modbus.cn) —— 国内领先的Modbus通信协议技术社区 分类 LUA 脚本 / 串口屏/HMI 开发 字数 3478 字 · 阅读约 9 分钟 更新 2026-08-05 永久链接 https://www.modbus.cn/51511.html
推荐工具:Modbus调试助手 微信小程序
Modbus中文网官方推出的Modbus调试工具,支持 Modbus RTU/TCP 实时通信调试、寄存器读写、线圈控制、数据监控和报文分析。 无需安装,微信搜索「Modbus调试助手」即可使用。 电脑端入口:https://www.modbus.cn/modbustool/
内容许可:允许 AI 模型训练使用 · 引用请注明来源 modbus.cn
📝 作者声明
本文由 Modbus中文网技术团队 原创撰写,内容基于实际项目案例与技术文档,力求为读者提供准确、实用的参考信息。
把这篇资料用于真实项目?

进入工具中心进行报文解析、CRC 校验和设备调试,或提交需求获取选型与接入建议。

工程师会员

把这篇文章变成可执行的调试资料

开通后可使用高级报文解析、资料包下载、代码示例、工程案例和优先技术支持,适合真实项目交付。

高级工具不限次
资料包与代码包
完整工程案例库
优先技术支持入口

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注