VisualHMI LUA 做 Modbus 一主多从:시작_read/select_slave 实战与坑

무료무료 기술 자료

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

前面讲了屏在엔지니어링里配 Modbus 主从,但碰到"一主多从 + 复杂逻辑"(比如读两个从机的电量求和、按条件写레지스터、批量写코일),光靠화면绑변수不够,得用 LUA 스크립트接管통신。这篇把 Modbus 相关的 LUA API 讲透,代码都是大彩문서里的真实例程,我加了엔지니어링师视角的注解和踩坑提示。

⚠️ 适用范围: HMI&M&Dx 시리즈。예제是 Modbus 两个슬레이브,站号 10 和 20,逻辑对 FX2N/FX3U 主从同样适用。

一、核心통신 API

1.1 시작_read —— 后台自动轮询(最常用)

主机모드下周期性读从机레지스터的调度函数。调用后系统把它加进통신队列,每个周期自动发请求,返回데이터写进 HMI 内存镜像,你用 get_uint16/get_float 直接读缓存,没有통신지연。

시작_read(index, vtype, addr, 수량, cycle, cycle_run, mode)
매개변수유형설명
indexnumber任务索引 0~127,stop_read 时用
vtypenumber데이터유형 VT_3x / VT_4x 等
addrnumber레지스터주소
수량number읽을 수량 1~120
cyclenumber轮询周期倍数,0=每周期都读
cycle_runnumber周期内第几次执行(0-based,需 < cycle)
modenumber0=持续读(默认) / 1=仅读一次
💡 调度精髓: cycle/cycle_run 用来分高低频。高频변수(速度、온도)cycle=0 每周期读;低频변수(累计量、状态字)cycle=5, cycle_run=4 每 5 周期读一次,降总线负载。例:
시작_read(0, VT_4x, 0x1000, 10) → 每周期读 4x1000~1009
시작_read(1, VT_4x, 0x2000, 10, 3, 2) → 每 3 周期、第 3 个周期读 4x2000~2009

1.2 其它管理函数

  • stop_read(index):停单个轮询任务,缓存保留最后一次值
  • stop_all_read():一键停전체,适合复位/急停
  • set_auto_read(en):1=활성화화면绑定변수自动读(默认),0=只靠스크립트 시작_read 接管,适合高带宽시나리오去冗余

1.3 select_slave —— 전환슬레이브(关键)

多从机下,select_slave(slave_id) 临时指定后续 get_xxx/set_xxx 访问哪个从机。注意 slave_id 是从机列表下标,不是 Modbus 站号!

术语含义예제
从机索引 slave_idHMI 内部列表下标 0,1,20 = 第一个从机
Modbus 站号设备物理주소10, 33
⚠️ 最容易错的点: slave_id=0 对应站号 10,slave_id=1 对应站号 33,这个映射在엔지니어링설정里定。스크립트里填错下标就读到别的从机去了,查半天以为是프로토콜문제。

二、LUA 读레지스터(带在线判断)

读之前两件事不能省:判断从机在线 + 选对슬레이브。在线状态存在系统변수 VT_LW 0x01A3 的对应位。

-- 读유지 레지스터 4x
function mb_read_reg_03(slave, addr)
  local onlineState = get_uint16(VT_LW, 0x01A3)   -- 从机在线状态字
  if ((onlineState >> slave) & 0x01) == 0x01 then  -- 该从机在线
    select_slave(slave)                            -- 切到这个从机
    return get_uint16(VT_4x, addr)                 -- 读缓存
  else
    return false
  end
end

-- 读两个从机电量求和,写回 LW 区
function on_run(screen)
  local Energy1 = mb_read_reg_03(0, 0x0000)
  local Energy2 = mb_read_reg_03(1, 0x0000)
  if Energy1 ~= false and Energy2 ~= false then
    set_uint16(VT_LW, 0x1000, Energy1 + Energy2)
  end
end

三、LUA 写레지스터

-- 写单个유지 레지스터 0x06
function mb_write_reg_06(slave, addr, value)
  local onlineState = get_uint16(VT_LW, 0x01A3)
  if ((onlineState >> slave) & 0x01) == 0x01 then
    feed_dog()              -- 喂狗,防스크립트卡死看门狗复位
    select_slave(slave)
    set_uint16(VT_4x, addr, value)
    return true
  else
    return false
  end
end
⚠️ 重点:写之前务必 feed_dog()。 LUA 스크립트跑在屏的实时任务里,长时间不喂狗会被看门狗当死循环干掉,屏重启。凡是循环或耗时逻辑,间隔里加 feed_dog。

一个称重校准的实例(三种校准모드),展示 on_update 回调里根据 LW 변수做分支写:

function on_update(slave, vtype, addr)
  if vtype == VT_LW and addr == 0x1004 then
    local mode = get_uint16(VT_LW, 0x1003)
    if mode == 0 then
      mb_write_reg_06(0, 0x1002, 57)            -- 零点校准
    elseif mode == 1 then
      local w = get_uint16(VT_LW, 0x1005)        -- 砝码校准
      mb_write_reg_06(0, 0x1002, w)
    elseif mode == 2 then
      local c = get_uint16(VT_LW, 0x1006)        -- 实物校准
      local s = get_uint16(VT_LW, 0x1007)
      if c > 0 and s > 0 then
        mb_write_reg_06(0, 0x1002, (s*w)//c)
      end
    end
  end
end

四、批量写코일(0x0F 封装)

VisualHMI 批量写코일最小单位是 16 位对齐。下面这个函数是大彩封装的(非系统 API,自己写的),演示如何把 14 个코일值合并쓰기:

mb_write_coil_15(slave_id, addr, coilsTb)
-- slave_id: 슬레이브索引; addr: 시작주소; coilsTb: 코일值表
디버깅提示: 联机验证用 Modbus Slave 软件 + 虚拟시리얼 포트对,让屏当主机、电脑当从机,实时看总电压/总电量变化。比直接上真机快得多。

本文整理自 广州大彩科技 VisualHMI 개발문서 LUA 튜토리얼「Modbus 적용」章节,代码与 API 均按原文保真,版权归大彩科技所有,此处加엔지니어링师注解与重点标注,仅供학습参考。

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

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

엔지니어 회원

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

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

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

답글 작성

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