Modbus协议的通信流程遵循**“主机请求-从机响应”的主从式闭环逻辑,核心是帧的传输、校验、解析与执行**。不同传输模式(RTU/ASCII/TCP)的流程框架一致,仅在帧格式、分隔方式、校验手段上有差异。本文以嵌入式场景最常用的Modbus RTU为例,从单帧通信的完整流程、多从机轮询流程、异常处理流程三个维度,详细拆解通信的每一个步骤,结合实战案例让流程更易理解。
一、通信流程的核心前提(必须明确的基础规则)
在讲解具体流程前,先明确Modbus主从通信的3条核心规则,这是流程的基础:
- 角色权限唯一:同一总线中,只有1台主机能主动发起请求;多台从机(地址1-247)只能被动接收指令、执行操作并返回响应。
- 帧是通信的基本单位:主机和从机的所有数据交互,都以“一帧”为单位;帧的完整性由校验字段(如RTU的CRC16)保证。
- 请求-响应一一对应:主机发送一帧请求,只有目标从机返回一帧响应;无响应则主机判定超时,触发重发机制。
二、单帧完整通信流程(以RTU模式读取保持寄存器为例)
选取嵌入式开发中最典型的场景——主机读取从机保持寄存器(功能码0x03),详细拆解从“主机构建请求帧”到“主机解析响应帧”的6个步骤。
场景定义
| 设备角色 | 地址/配置 | 通信需求 | 串口参数(RTU默认) |
|---|---|---|---|
| 主机 | 无固定地址(仅发起请求) | 读取从机0x01的保持寄存器地址0x0001~0x0002(存储温度、湿度数据) | 波特率9600bps、数据位8、停止位1、无校验 |
| 从机 | 地址0x01(STM32嵌入式设备) | 接收主机指令,返回寄存器数据;若指令错误,返回异常响应 | 同主机(参数必须完全一致) |
步骤1:主机构建Modbus RTU请求帧
请求帧是主机向从机下达的“操作指令”,Modbus RTU请求帧的结构为:从机地址 + 功能码 + 数据域 + CRC16校验。
针对本场景,请求帧的具体字节如下(字节序为大端序):
| 字段 | 字节值 | 功能说明 |
|---|---|---|
| 从机地址 | 0x01 | 指定通信目标为地址0x01的从机 |
| 功能码 | 0x03 | 告知从机执行“读取保持寄存器”操作 |
| 数据域-起始地址高位 | 0x00 | 要读取的寄存器起始地址:0x0001 |
| 数据域-起始地址低位 | 0x01 | |
| 数据域-寄存器数量高位 | 0x00 | 要读取的寄存器数量:2个 |
| 数据域-寄存器数量低位 | 0x02 | |
| CRC16校验低字节 | 0x85 | 对前6个字节(地址+功能码+数据域)计算CRC16,低字节在前 |
| CRC16校验高字节 | 0x39 | CRC16结果为0x3985,高字节在后 |
关键计算:CRC16校验值是保证帧完整性的核心,需严格按照Modbus标准算法计算,低字节存于前,高字节存于后。
步骤2:主机发送请求帧(控制RS485收发状态)
Modbus RTU基于RS485总线传输,RS485是半双工通信,需通过DE/RE引脚切换“发送/接收”状态,这是嵌入式开发的关键步骤:
- 切换为发送状态:主机将RS485模块的
DE/RE引脚置高(高电平=发送); - 发送帧数据:通过串口将请求帧的8个字节按顺序发送到RS485总线;
- 延迟切换回接收状态:发送完成后,延迟1~2ms(确保总线数据传输完毕,避免提前切换导致数据丢失),将
DE/RE引脚置低(低电平=接收); - 启动超时计时器:主机设置超时时间(通常500~1000ms),等待从机响应。
代码参考(STM32主机):
// 切换为发送状态HAL_GPIO_WritePin(GPIOA,GPIO_PIN_8,GPIO_PIN_SET);// 发送请求帧(buf为请求帧字节数组,len=8)HAL_UART_Transmit(&huart1,buf,len,100);// 延迟2ms,确保数据发送完成HAL_Delay(2);// 切换为接收状态,等待响应HAL_GPIO_WritePin(GPIOA,GPIO_PIN_8,GPIO_PIN_RESET);// 启动1秒超时计时器uint32_ttimeout=HAL_GetTick()+1000;
步骤3:从机接收并校验请求帧
从机(如STM32)通过串口接收中断实时监听RS485总线,接收到数据后需完成“帧完整性校验”,这是避免干扰导致错误的关键:
- 逐字节接收并缓存:从机每收到1个字节,就存入接收缓冲区,并记录当前字节的接收时间戳;
- 检测帧边界(核心!):Modbus RTU无帧头帧尾,靠>3.5个字符时间的间隔区分帧。
- 字符时间计算:波特率9600bps → 1个字符(10位:1起始+8数据+1停止)的传输时间≈1.04ms → 帧间隔阈值≈3.64ms(取4ms作为软件判断阈值);
- 若两次接收字节的时间差>4ms,则判定一帧接收完成,触发帧解析流程;
- 三层校验(过滤错误帧):
校验类型 校验逻辑 处理结果 地址校验 检查帧首字节是否等于本机地址( 0x01)或广播地址(0x00)不匹配 → 清空缓冲区,不处理 CRC16校验 计算接收帧前 len-2字节的CRC值,与帧尾2个字节对比不匹配 → 清空缓冲区,不处理 功能码校验 检查功能码( 0x03)是否为本机支持的功能不支持 → 准备异常响应
步骤4:从机执行指令并构建响应帧
校验通过后,从机根据功能码执行对应的操作,并构建响应帧:
- 解析请求参数:从数据域提取“起始地址
0x0001”和“寄存器数量0x0002”; - 读取寄存器数据:从机从保持寄存器数组中取出地址1和2的值,假设为:
- 寄存器1(温度):
0x012C→ 十进制300 → 对应实际温度30.0℃; - 寄存器2(湿度):
0x0064→ 十进制100 → 对应实际湿度10.0%RH;
- 寄存器1(温度):
- 构建正常响应帧:Modbus RTU响应帧结构为从机地址 + 功能码 + 数据域 + CRC16校验,本场景响应帧字节如下:
字段 字节值 功能说明 从机地址 0x01标识响应来自地址 0x01的从机功能码 0x03与请求功能码一致,表示正常响应 数据域-数据长度 0x04返回的数据字节数(2个寄存器×2字节=4字节) 数据域-寄存器1高位 0x01温度数据 0x012C(高位在前)数据域-寄存器1低位 0x2C数据域-寄存器2高位 0x00湿度数据 0x0064(高位在前)数据域-寄存器2低位 0x64CRC16校验低字节 0x70前8字节的CRC16结果,低字节在前 CRC16校验高字节 0x48CRC16结果为 0x4870,高字节在后
异常响应处理:若请求参数错误(如寄存器地址越界),从机构建异常响应帧——从机地址 + 功能码|0x80 + 异常码 + CRC16。
示例:非法寄存器地址 → 功能码变为0x83,异常码0x02。
步骤5:从机发送响应帧
从机发送响应帧的流程与主机发送请求帧一致,核心是控制RS485收发状态:
- 置高
DE/RE引脚,切换为发送状态; - 将响应帧的10个字节发送到RS485总线;
- 延迟2ms后,置低
DE/RE引脚,切换回接收状态,等待下一次请求。
步骤6:主机接收并解析响应帧
主机在超时时间内接收到响应帧后,重复步骤3的三层校验,校验通过后解析数据:
- 校验响应合法性:
- 地址校验:响应帧首字节必须为
0x01(目标从机地址); - 功能码校验:响应帧功能码必须为
0x03(与请求一致); - CRC16校验:确保帧未被干扰;
- 地址校验:响应帧首字节必须为
- 解析数据域:
- 数据长度:
0x04→ 对应2个寄存器; - 提取寄存器值:
- 寄存器1:
0x01(高位) +0x2C(低位) =0x012C→ 十进制300 → 转换为实际温度300 ÷ 10 = 30.0℃; - 寄存器2:
0x00+0x64=0x0064→ 十进制100 → 转换为实际湿度100 ÷ 10 = 10.0%RH;
- 寄存器1:
- 数据长度:
- 完成通信闭环:主机更新传感器数据,清空接收缓冲区,准备下一次请求。
单帧通信流程总结图
主机侧流程:构建请求帧 → 切换发送→发帧→切回接收→等待响应→解析响应 ↓ ↑ RS485总线:---------------请求帧传输---------------响应帧传输--------------- ↑ ↓ 从机侧流程:监听总线→接收帧→帧边界检测→三层校验→执行指令→构建响应帧→发帧三、多从机轮询通信流程(工业现场常用)
工业现场通常有多个从机(如传感器、执行器),主机需通过轮询机制逐个通信,避免总线冲突,流程如下:
- 主机轮询初始化:定义从机地址列表(如
[0x01, 0x02, 0x03]),设置轮询间隔(≥50ms,避免总线拥堵); - 逐个发起请求:
- 主机向
0x01从机发送请求帧 → 等待响应 → 解析数据 → 记录结果; - 延迟50ms后,向
0x02从机发送请求帧 → 重复上述流程; - 所有从机轮询一遍后,等待1秒,开始下一轮轮询;
- 主机向
- 超时与重发处理:
- 若某从机超时无响应,主机最多重发3次;
- 3次重发失败 → 标记该从机“离线”,跳过该从机,继续轮询下一个;
- 广播指令特殊处理:主机发送地址为
0x00的广播指令(如批量设置从机参数),所有从机执行指令,但无需返回响应,主机发送后直接进入下一轮轮询。
轮询优势:避免多从机同时发送数据导致总线冲突,是工业现场Modbus通信的标准流程。
四、异常通信流程与处理方案
通信过程中会因干扰、参数错误等出现异常,需针对性处理,常见异常及解决方案如下:
| 异常类型 | 产生原因 | 主机处理方案 | 从机处理方案 |
|---|---|---|---|
| 从机无响应 | 1. 从机离线/接线错误;2. 请求帧CRC错误;3. 地址不匹配 | 1. 重发3次;2. 失败则标记从机离线;3. 检查总线接线 | 无(未收到有效请求) |
| 功能码不支持 | 主机发送的功能码从机未实现 | 1. 解析异常响应帧(功能码 | 0x80 + 异常码0x01);2. 更换支持的功能码 |
| 寄存器地址越界 | 请求的寄存器地址超出从机有效范围 | 1. 解析异常码0x02;2. 检查寄存器地址配置 | 1. 构建异常响应帧;2. 拒绝执行读写操作 |
| 数据值非法 | 主机写入的数据超出从机参数范围 | 1. 解析异常码0x03;2. 调整写入值 | 1. 构建异常响应帧;2. 不修改寄存器值 |
五、不同传输模式的通信流程差异
Modbus RTU/ASCII/TCP的核心流程都是“请求-响应”,差异主要在帧格式、分隔方式、传输介质,对比如下:
| 流程环节 | Modbus RTU | Modbus ASCII | Modbus TCP |
|---|---|---|---|
| 帧分隔方式 | >3.5字符时间间隔 | 帧头:+ 帧尾\r\n | TCP报文长度字段 |
| 校验方式 | CRC16(2字节) | LRC(1字节) | 依赖TCP/IP校验,无额外校验 |
| 发送流程 | 串口+RS485,需切换收发状态 | 同RTU | 以太网TCP连接,全双工无需切换 |
| 响应超时 | 500~1000ms | 同RTU | 基于TCP超时机制(通常2000ms) |