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

freeFree Technical Resource

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

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)见下表check/解压进度与结果回调

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_시작 = 8 * 1024 * 1024    -- OTA 시작ing 주소(至少 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_시작) > flashsize then
        set_string(VT_LW, useraddr.text, "ota.bin 文件大小超过,无法升级!!!")
      else
        set_string(VT_LW, useraddr.text, "开始升级!!!")
        set_uint32(VT_LW, useraddr.ota_데이터, 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_열기(path, 0) == true then
    size = file_size()
    if size < (flashsize - ota_addr_시작) then
      ota_destroy()                                  -- 消除残留 OTA 데이터
      local sdota_addr = ota_init("0123456789abcdef", size, ota_addr_시작)
      -- 计算尾包补零长度
      local size_complement = 0
      if size % 2048 ~= 0 then
        size_complement = 2048 - (size % 2048)
      end
      while true do
        local rd데이터 = file_read(2048)               -- 流式读 2048
        if #(rd데이터) < 2048 then                     -- 尾包补 0x00
          for i = (#(rd데이터) + 1), 2048 do rd데이터[i] = 0x00 end
        end
        TransferSize = TransferSize + #(rd데이터)
        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(rd데이터)                            -- 写入 Flash,不足补零
        if size <= TransferSize then break end
      end
      file_close()
      ota_check_upgrade(1)                           -- check、解压
    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 Tutorial「OTA升级」,版权归大彩科技所有。

Put this resource to use in a real project?

Go to the Tool Center for message parsing, CRC 검증 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 주소 will not be published. Required fields are marked *.