VisualHMI 自由串口프로토콜(主动):uart_recv/calc_crc16 与 XGUS 映射

무료무료 기술 자료

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

自由串口프로토콜(主动)是이전 글「被动」的进阶:HMI 不只接收设备主动发的데이터,还能主动向设备发查询帧、读响应,HMI 当总线主。核心 API 是 uart_recv(),配合协程+元表搭一个非阻塞통신框架,对接 XGUS 私有프로토콜。适用 HMI&M 시리즈&Dx 시리즈。

1. 新增 API(相对被动模式)

函数参数说明
uart_rxsize(ch)ch 串口号,通常 0查询接收缓冲区待读바이트数。返回 N 表示有 N 바이트,0 表示无新데이터
uart_recv(ch, size)size 期望读取바이트数,必须 ≥1主动从接收缓冲区读指定数量바이트。返回下标从 1 的바이트表,如 {0xAA,0x55,0x01,0x02}
uart_rxclear(ch)ch 串口号清空接收缓冲区。통신初始化/错误恢复/프로토콜同步时清残留
calc_crc16(데이터)데이터 바이트表,下标从 1Modbus CRC-16 校验计算,返回 0~65535,低바이트在前(符合 Modbus 小端序)

另外 uart_send(ch, packet) 和被动模式一样:向指定串口通道发바이트数组,packet 下标从 1 开始,每元素 0~255。ch=0 主串口,1/2…副串口(依硬件型号)。通道必须处于自由프로토콜模式(未被 Modbus/XGUS 等系统프로토콜占用)。

2. ⚠️ 关键前置:禁用接收回调

主动读串口必须先在工程属性里:串口设置 → 接收回调 → 禁用(신버전软件有这个选项)。不禁用的话,uart_recv() 和 on_uart_recv 回调会抢데이터,帧全乱。

VisualHMI 自由串口协议(主动):uart_recv/calc_crc16 与 XGUS 映射插图

3. 案例:XGUS 프로토콜映射到系统寄存器

目标:把 XGUS 프로토콜中주소 ≥0x1000 的读写,映射到 HMI 系统寄存器 LW1000~LWFFFF。外部设备用 XGUS 帧读写 HMI 内部变量,HMI 也主动给设备发读写请求。

3.1 XGUS 帧格式

字段长度说明
帧头2 바이트0x5AA5
长度1 바이트指令+데이터+校验的바이트数
指令1 바이트0x82 写 / 0x83 读(0x80/0x81 另有用)
데이터最大 249 바이트주소(2바이트) + 데이터内容(n바이트),长度 = n+2
CRC2 바이트(可选)CRC-16 (x16+x15+x2+1)

例:向变量주소 0x1000 写入数值 2(不启用 CRC):5A A5 05 82 10 00 00 02——05 是长度(指令1+주소2+데이터2),按字写入。

3.2 初始化:加载 XGUS.lua

官方提供了基于协程+元表的 XGUS.lua 框架。main.lua 里创建实例:

function on_init()
  dofile("XGUS.lua")
  xgus = XGUS:new(0, 0x55AA, true, true)
  -- 参数:串口号, 帧头, 开启CRC, 开启写应答
end

-- on_run 里跑协程,非阻塞轮询
_EN_SET_데이터_ = false
function on_run(screen)
  _EN_SET_데이터_ = true
  xgus:run()
  _EN_SET_데이터_ = false
end

XGUS:run() 用协程实现:检查串口데이터 → 凑够「帧头+指令+长度+주소」6 바이트 → 解析 → 按长度收剩余데이터 → CRC 검증 → 处理。协程可以打断/恢复任务,不阻塞 on_run 主循环,适合耗时流程。

3.3 指令解析:주소分流

function XGUS:processMsg()
  local func = self.func
  if func == XGUS기능.write then
    -- 写指令
    if self.addr >= 0x1000 then
      -- 用户寄存器区:解析데이터写入 LW
      local 데이터s = {}
      for i = 1, write_count do
        데이터s[i] = self.req[5+i*2]<>8), (self.head&0xFF), 0x03, 0x82, 0x4F, 0x4B})
    end
  elseif func == XGUS기능.read then
    -- 读指令
    if self.addr >= 0x1000 then
      -- 组应答帧:读 LW 值回发
      local 데이터s = {(self.head>>8), (self.head&0xFF), 4+self.req[7]*2,
                     0x83, (self.addr>>8), (self.addr&0xFF), (self.req[7]*2)&0xFF}
      for i = 1, self.req[7] do
        local num = get_uint16(VT_LW, self.addr+(i-1))
        데이터s[6+i*2] = (num>>8) & 0xFF
        데이터s[7+i*2] = num & 0xFF
      end
      self:sendMsg(데이터s)
    else
      on_cmd_resp_xgus(self.addr, self.req[7], func, {})
    end
  end
end

-- 系统寄存器区读写回调(main.lua 里定义)
function on_cmd_resp_xgus(addr, count, wr, 데이터)
  if wr == 0x82 then
    print("write addr num : "..count)
  elseif wr == 0x83 then
    print("read addr num : "..count)
  end
end

3.4 主动发送:XGUS:데이터Send(addr, 데이터)

主动向设备发写指令,데이터 可以是 number 或 table:

-- 写单个值
xgus:데이터Send(0x1000, 1234)
-- 写一组值(table)
xgus:데이터Send(0x2000, {0x12, 0x34, 0x56})

-- 内部 send():开 CRC 时自动补 2 바이트校验再 uart_send
function XGUS:send(resp)
  if self.crc == true then
    resp[3] = resp[3] + 2   -- 长度加 CRC 2 바이트
    local crc_buff = {}
    for i = 4, #resp do crc_buff[i-3] = resp[i] end
    local crc_check = calc_crc16(crc_buff)
    resp[#resp+1] = (crc_check>>0) & 0xFF
    resp[#resp+1] = (crc_check>>8) & 0xFF
  end
  uart_send(self.port, resp)
end
四个坑:①不禁用接收回调就 uart_recv,帧必乱——工程属性→串口设置→接收回调→禁用;②calc_crc16 低바이트在前,组帧时先发低 8 位再发高 8 位;③主动读要防设备无响应——XGUS:wait() 有超时机制(内部 get_tick_count 差值判断),自己写프로토콜务必加超时,不然 on_run 卡死;④주소 ≥0x1000 才走 LW 映射,小于 0x1000 走 on_cmd_resp_xgus 回调自己处理。副串口用之前必须 uart_setup 初始化。

整理自 广州大彩科技 VisualHMI 开发文档(hmi-doc.gz-dc.com)LUA 教程「自由串口프로토콜(主动)」,版权归大彩科技所有。

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

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

엔지니어 회원

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

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

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

发表回复

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