9.2.1 分析 Write File Record 功能(保姆级讲解)

你好!我们继续学习"综合实现"课程中的产品框架 部分。之前我们了解了硬件、软件和界面,现在要深入一个具体的技术点:Modbus 协议中的 Write File Record 功能。为什么需要它?因为我们的上位机需要把"映射关系表"(即哪些传感器对应哪些寄存器)下发给中控,还需要给中控升级固件(传输整个文件)。这些数据往往比较大,不能用一个简单的Modbus读写命令一次性完成,所以需要分块传输。Write File Record 正是Modbus协议里专门用来传输文件的功能。

下面我将用最通俗的语言,一步一步拆解这个功能。请对照我提到的图片进行理解。


一、为什么要用 Write File Record?

想象你要给朋友寄一本很厚的书(比如几百页)。你不能把整本书塞进一个信封里,因为信封太小。所以你只能把书拆成一叠一叠的页,每叠用一个小信封寄出。每个信封上要注明:

  • 这是哪本书(文件编号

  • 这是第几叠(记录编号

  • 这一叠有多少页(记录长度

  • 这一叠的内容是什么(记录数据

Write File Record 就是Modbus协议里的"寄书方法"。它允许我们把大文件分成多个"记录"(Record),每个记录最大可以放约250字节的数据,然后通过多个Modbus报文依次发送。接收方(中控)收到后,再按照信封上的信息把数据重新拼成完整的文件。

在我们的产品中,这个功能用来:

  1. 下发映射表:用户在上位机配置好所有"点"后,生成一个配置文件(比如JSON格式),通过Write File Record发送给中控,中控解析后保存在Flash里。

  2. 升级固件:中控的应用程序(APP)需要升级时,上位机把新的固件文件分块发送,中控的Bootloader负责接收并写入Flash,完成升级。


二、Write File Record 报文格式详解

这张图展示了Write File Record请求报文的完整结构。我们从左到右,从上到下逐一解释。图中标注了一些数字,我们结合这些数字来理解。

1. 报文整体结构

一个Modbus报文通常包含:地址码 + 功能码 + 数据 + CRC校验 。但Write File Record有点特殊,它属于Modbus的扩展功能码,数据部分比较复杂。

  • 功能码(Function code):图中第一行写着"1 Byte 0x15"。0x15(十进制21)就是Write File Record的功能码。Modbus规定,功能码0x15表示"写文件记录"。

  • 请求数据长度(Request data length):功能码后面紧接着一个字节,表示后面所有数据的字节数(不包括这个长度字节本身)。图中标注"1 Byte 0x09 to 0xEB",意思是这个长度可以从0x09(9)到0xEB(235)。为什么有这个范围?因为后面要携带多个子请求,每个子请求有固定长度,所以总数据长度必须合理。

2. 子请求结构(Sub-Request)

Write File Record允许在一个报文中包含多个子请求(即同时操作多个文件记录)。每个子请求的格式相同。图中用"Sub-Req. x, ..."表示第一个子请求,然后"Sub-Req. x+1, ..."表示第二个,以此类推。每个子请求包含以下字段:

  • Reference Type(引用类型):2字节,图中标注"2 Bytes / 0x0001 to 0xFFFF"。这个字段通常固定为0x0006,表示"文件记录"。具体值由Modbus规范定义,我们不必深究,记住它是6即可。

  • File Number(文件编号):2字节,范围0x0001~0xFFFF。这就是我们之前说的"哪本书"。上位机在发送文件时,会给每个文件分配一个唯一的编号。比如映射表文件用1,固件文件用2。这样中控就能区分不同的文件。

  • Record Number(记录编号):2字节,范围0x0000~0x270F(0~9999)。这是当前数据块在整个文件中的序号。比如第一个数据块的Record Number是0,第二个是1,以此类推。中控根据这个编号将数据按顺序组装。

  • Record Length(记录长度):2字节,表示这个子请求中携带的数据有多少个字节。注意:图中标注"N x 2 Bytes"?实际上Record Length是指后面Record data的字节数。但图中可能画得不准确。标准定义中,Record Length后面紧跟着的就是Record data,数据长度就是Record Length的值。

  • Record Data(记录数据):长度由Record Length决定。这里就是实际的文件内容片段。

3. 报文总长度限制

图中右下角标注了长度计算:

  • "255 - 1 - 2 = 253" 等。这涉及到Modbus RTU模式下报文最大长度为256字节(包括地址和CRC)。我们来推导一下:

    • 标准Modbus RTU报文最大长度为256字节。

    • 减去1字节地址码,减去2字节CRC校验,剩下253字节可用于功能码+数据。

    • 功能码占1字节,所以数据部分最多252字节(253-1=252)。但图中又有"1 Byte 0x15"和"1 Byte 长度",所以数据部分还要减去长度字节本身?实际上我们需要仔细看。

图中第一行有"1 Byte 0x15"和"1 Byte 0x09 to 0xEB",这表示:功能码1字节,后面跟着1字节的"请求数据长度"(即后面所有子请求的总字节数)。然后才是子请求。所以数据部分的总长度(不包括功能码和长度字节)最大是253-1=252?但长度字节本身是1,所以子请求总长度最大是251?图中计算"255 - 1 - 1 = 251 = 0xFB",这个255可能是指整个报文最大255?实际上常见Modbus RTU最大256,地址1+功能码1+数据+CRC2=256,所以数据最大252。但这里他们可能用了另一种习惯。无论如何,我们知道有限制即可。

关键限制:每个子请求中,Record Data的最大长度受到限制。图中底部标注:"最大Record 长度: 24byte"和"最大 Record 长度: 2byte"?这有点矛盾。实际上,Modbus协议规定,在一个报文中,所有子请求的数据总和不能超过某个值,且每个子请求的数据长度也有上限。通常,为了简单,我们往往每个报文只发送一个子请求,这样Record Data最大可以接近250字节。图中可能是在推导具体数值,比如总数据长度为251,减去每个子请求固定开销(Reference Type 2 + File Number 2 + Record Number 2 + Record Length 2 = 8字节),那么数据最多243字节。但不同资料可能有不同说法。我们只需知道:每个报文能携带的数据量有限,所以大文件必须分块。


三、如何用Write File Record发送文件

现在我们来模拟一下上位机发送一个固件文件的过程。假设固件文件大小为10KB,我们需要把它分成多个记录(Record)发送。

  1. 初始化:上位机决定文件编号为2(因为1可能已经用于映射表)。

  2. 分块:将文件按每块240字节(留点余量)分割,得到多个数据块。每个块对应一个记录。

  3. 发送第一个记录:构造报文,功能码0x15,请求数据长度 = 1个子请求的固定8字节 + 数据块长度240 = 248字节。子请求中:Reference Type=6,File Number=2,Record Number=0,Record Length=240,Record Data=第一块数据。

  4. 发送第二个记录:Record Number=1,以此类推,直到最后一个记录(可能不足240字节)。

  5. 结束:所有记录发送完成后,中控根据收到的Record Number顺序组合成完整文件。

注意:中控需要知道文件传输何时结束。通常有两种方式:

  • 上位机先发送一个文件头,包含文件总大小、块数等信息。

  • 或者在最后一个记录中,Record Length小于块大小,表示结束。

在我们的产品中,可能通过约定好的协议(比如JSON封装)来管理文件传输过程,但底层都依赖Write File Record来实际传输数据。


4、在我们的产品框架中如何应用

回顾之前的内容:

  • 硬件框架:上位机通过串口连接中控,中控通过通道连接传感器。

  • 设计思路:上位机把映射关系(5个参数)通过Write File Record发送给中控,中控保存后建立映射表。

  • 软件框架:中控的Bootloader和APP都支持接收Write File Record,APP收到映射表后存入Flash,Bootloader收到固件后升级。

所以,Write File Record是连接上位机和下位机(中控)的"数据管道",让大文件传输成为可能。


总结

通过今天的讲解,你应该明白了:

  • 为什么需要Write File Record(传输大文件,如映射表和固件)。

  • 它的报文结构:功能码0x15,包含一个或多个子请求,每个子请求有文件号、记录号、记录长度和记录数据。

  • 如何分块发送文件。

  • 图片中的标注和要点对应哪些字段。

相关推荐
橙露1 小时前
Python 异步爬虫进阶:协程 + 代理池高效爬取实战
开发语言·爬虫·python
阿在在1 小时前
Spring 系列(三):Spring PostProcessor 顶级扩展接口全解析
java·后端·spring
天荒地老笑话么2 小时前
Bridged 与虚拟机扫描:合规边界与自测范围说明
网络·网络安全
kylezhao20192 小时前
C#异步和并发在IO密集场景的典型应用 async/await
开发语言·数据库·c#
m0_531237172 小时前
C语言-函数练习2
c语言·开发语言
kyrie学java2 小时前
使用SpringBoot框架搭建简易的项目
java·spring boot·spring
锅包一切2 小时前
在蓝桥杯边练边学Rust:2.原生类型
开发语言·学习·蓝桥杯·rust
lightqjx2 小时前
【C++】C++11 常见特性
开发语言·c++·c++11
TechubNews2 小时前
燦谷(Cango Inc)入局AI 資本重組彰顯決心
大数据·网络·人工智能·区块链