STM32从零到量产开发:四路继电器工业控制模块开发--- Modbus RTU 通讯协议设计
文档版本:v1.0.0(对应固件 v1.0.0 / 设备类型码 0x0002)
适用产品:
P02_Relay_Controller_4Channels Relay Industrial Control Module本文档面向主站/网关开发工程师,描述设备的 Modbus RTU 从站协议。所有示例帧的 CRC16 均已用脚本实算(多项式 0x8005,初值 0xFFFF,小端)。
1. 物理层与链路层
| 项目 | 说明 |
|---|---|
| 物理接口 | RS485(A/B 差分),半双工 |
| 默认波特率 | 9600 bps(见 §6 波特率索引表) |
| 数据位 / 停止位 / 校验 | 8 / 1 / 无(8N1) |
| 从站地址范围 | 1 ~ 247(0 为广播地址,用于写指令,不回响应) |
| 帧间隔(T3.5) | 3.5 个字符时间(9600bps 下约 3.6ms,建议 ≥ 5ms 余量) |
| 字节超时 | 1.5 个字符时间(约 1.5ms @9600) |
接线:RS485_A 接总线 A,RS485_B 接总线 B;总线两端需加 120Ω 终端电阻。设备由外部提供隔离电源。
2. 帧格式(Modbus RTU)
[ 从站地址 ][ 功能码 ][ 数据域 ][ CRC 低字节 ][ CRC 高字节 ]
1 字节 1 字节 N 字节 1 字节 1 字节
- 字节序 :地址、数据域中的多字节数值(寄存器值、寄存器地址、数量)均为大端(MSB 在前)。
- CRC :Modbus CRC16(多项式 0x8005,初值 0xFFFF,小端,即低字节先发)。
- 广播:地址=0 时设备执行写操作但不回任何响应;读操作不支持广播。
3. 支持的功能码
| 功能码 | 名称 | 访问对象 | 说明 |
|---|---|---|---|
| 0x01 | 读线圈 | 继电器 | 读取 RELAY1~4 状态 |
| 0x02 | 读离散输入 | DI | 读取 DI1~4 状态 |
| 0x03 | 读保持寄存器 | 通信参数 | 读从站地址/波特率/故障安全配置等 |
| 0x04 | 读输入寄存器 | 诊断/运行信息 | 运行时间、计数、固件版本、设备类型、SN 等 |
| 0x05 | 写单个线圈 | 继电器 | 单个继电器开/断 |
| 0x06 | 写单个保持寄存器 | 通信参数 | 改地址/波特率/故障安全 |
| 0x0F | 写多个线圈 | 继电器 | 批量控制 4 路继电器 |
| 0x10 | 写多个保持寄存器 | 通信参数 | 批量写配置(本设备常用单寄存器,0x06 即可覆盖) |
| 0x11 | 上报从站标识(Report Slave ID) | 设备信息 | 返回固件版本、设备类型码、运行状态 |
4. 异常码
| 异常码 | 含义 | 触发场景 |
|---|---|---|
| 0x01 | 非法功能码 | 收到本设备不支持的功能码 |
| 0x02 | 非法数据地址 | 寄存器地址/范围越界 |
| 0x03 | 非法数据值 | 数值非法(如从站地址=0、波特率索引越界、故障安全秒=0 且使能=1 等) |
| 0x06 | 设备忙 | 正在处理上一条请求(极少触发) |
异常响应格式:[地址][功能码 | 0x80][异常码][CRC低][CRC高]
5. 寄存器映射总览
| 对象 | 地址范围 | 读写 | 内容 |
|---|---|---|---|
| 线圈 Coils | 0x0000 ~ 0x0003 | 读/写 | RELAY1~4(0=断开, 1=吸合) |
| 离散输入 Discrete Inputs | 0x0000 ~ 0x0003 | 只读 | DI1~4(0=断开, 1=闭合) |
| 输入寄存器 Input Registers | 0x0000 ~ 0x000F | 只读 | 运行秒/复位/帧/CRC/异常/运行小时/寿命/固件/类型/SN/故障安全 |
| 保持寄存器 Holding Registers | 0x0000 ~ 0x0004 | 读/写 | 从站地址/波特率/通信使能/故障安全使能/超时秒 |
说明:线圈、离散输入、输入寄存器、保持寄存器是 Modbus 的四个独立地址空间,各自从 0x0000 编号,互不相干。
6. 通信参数(保持寄存器 0x0000~0x0004)
| 地址 | 名称 | 读写 | 范围/取值 | 说明 |
|---|---|---|---|---|
| 0x0000 | 从站地址 SlaveAddr | 读/写 | 1~247 | 掉电保存,重启后/下次回复后生效 |
| 0x0001 | 波特率索引 BaudIndex | 读/写 | 0~4 | 见下表,掉电保存,回复后切换波特率 |
| 0x0002 | 通信使能 LinkEnable | 读/写 | 0 / 1 | 0=静默模式(不回复任何帧);1=正常回复 |
| 0x0003 | 故障安全使能 FailSafeEn | 读/写 | 0 / 1 | 1=开启通信故障安全(默认 1) |
| 0x0004 | 故障安全超时 FailSafeSec | 读/写 | 0~255 | 秒;0 表示禁用(需配合 FailSafeEn=0) |
波特率索引表(P02 专用):
| 索引 | 波特率 |
|---|---|
| 0 | 9600(出厂默认) |
| 1 | 19200 |
| 2 | 38400 |
| 3 | 57600 |
| 4 | 115200 |
⚠️ 系列差异提醒:同系列 P03 模块的波特率索引表不同(额外支持 4800,且 9600 在索引 1)。若网关需同时接入 P02/P03,请按本表各自区分(详见 §13)。
出厂默认值:SlaveAddr=1,BaudIndex=0(9600),LinkEnable=1,FailSafeEn=1,FailSafeSec=10。
7. 线圈 --- 继电器(0x0000~0x0003)
| 线圈地址 | 位 | 名称 | 写值含义 |
|---|---|---|---|
| 0x0000 | bit0 | RELAY1 | 0xFF00=吸合,0x0000=断开 |
| 0x0001 | bit1 | RELAY2 | 同上 |
| 0x0002 | bit2 | RELAY3 | 同上 |
| 0x0003 | bit3 | RELAY4 | 同上 |
- 继电器为低电平有效驱动,线圈写 1(吸合)= 输出闭合。
- 写保持寄存器 FailSafeSec 触发故障安全时,所有继电器强制断开(安全态)。
8. 离散输入 --- DI(0x0000~0x0003,只读)
| 离散地址 | 位 | 名称 | 含义 |
|---|---|---|---|
| 0x0000 | bit0 | DI1 | 外部接点闭合=1,断开=0 |
| 0x0001 | bit1 | DI2 | 同上 |
| 0x0002 | bit2 | DI3 | 同上 |
| 0x0003 | bit3 | DI4 | 同上 |
读响应中首字节的低 4 位为 DI1~DI4 状态。
9. 输入寄存器(0x0000~0x000F,只读)
| 地址 | 名称 | 位宽 | 含义 |
|---|---|---|---|
| 0x0000 | 运行秒数 Uptime | 16 | 累计运行秒(16 位回绕) |
| 0x0001 | 复位次数 ResetCount | 16 | 累计上电复位次数 |
| 0x0002 | 有效帧计数 FrameCount | 16 | 收到合法 Modbus 帧数 |
| 0x0003 | CRC 错误计数 CrcErrCount | 16 | CRC 校验失败计数 |
| 0x0004 | 异常响应计数 ExcepCount | 16 | 回复异常帧累计次数(通信质量评估) |
| 0x0005 | 运行小时 RunHours | 16 | 累计运行小时 |
| 0x0006 | 继电器1 动作次数 | 16 | 寿命计数(翻转时 +1) |
| 0x0007 | 继电器2 动作次数 | 16 | 同上 |
| 0x0008 | 继电器3 动作次数 | 16 | 同上 |
| 0x0009 | 继电器4 动作次数 | 16 | 同上 |
| 0x000A | 寿命告警位图 LifeAlarm | 16 | bit0~3 对应 RELAY1~4 寿命越限(默认阈值 100000 次) |
| 0x000B | 固件版本 FwVer | 16 | 0xMMmm,如 0x0100 = v1.0 |
| 0x000C | 设备类型码 DevType | 16 | 0x0002(P02 标识) |
| 0x000D | 序列号低16位 SN_Low | 16 | 取自芯片 UID(全球唯一) |
| 0x000E | 序列号高16位 SN_High | 16 | 取自芯片 UID |
| 0x000F | 故障安全态 FailSafe | 16 | bit0=使能,bit8=当前是否触发(1=已切安全态) |
10. 故障安全机制(#1 量产增强)
- 设备默认开启通信故障安全(FailSafeEn=1,超时 10s)。
- 主站连续
FailSafeSec秒未发来任何有效 Modbus 帧 → 设备自动把所有继电器切到安全态(断开),防止主站死机导致失控。 - 任意一帧合法 Modbus 帧到达 → 立即清除故障安全态,恢复由主站控制。
- 由主站重新下发控制指令即可恢复继电器状态;无需人工复位。
设计原则:心跳/保活必须用只读帧(如 FC01 读线圈、FC03 读保持、FC04 读输入),绝不能拿控制帧(如 FC0F 全开)当心跳------控制帧只改变状态,不能做保活。
11. 心跳 / 保活 SOP(双视角)
主站视角: 以小于 FailSafeSec(默认 10s)的周期,周期性发送只读轮询帧(推荐 FC04 读输入寄存器,或 FC01 读线圈)维持链路活跃。例如每 5s 读一次 0x0000 运行秒数。
设备视角: 收到任意合法帧即清零故障安全计时器;若计时超过阈值则进入安全态并置位 0x000F 的 bit8。
12. 设备识别(FC17 Report Slave ID)
主站发送 01 11 即可获取设备标识。P02 响应含固件版本与设备类型码 0x0002。
示例(见 §14)可验证设备类型码,主站据此加载对应的寄存器字典。
13. 系列关系说明
P02 与 P03 属于同一产品系列 :同芯片(STM32F103RCT6)、同 Modbus 协议框架(9 功能码、异常码 01/02/03/06、大端数据+小端 CRC、故障安全默认开)。两者通信参数保持寄存器 0x0000~0x0004 含义完全对齐,主站"设地址/设波特率/开关故障安全"的帧格式一致。
差异(主站须注意):
| 项目 | P02(本文档) | P03(模拟量模块) |
|---|---|---|
| 设备类型码 | 0x0002 | 0x0003 |
| 波特率索引表 | 0=9600...4=115200 | 0=4800,1=9600...5=115200 |
| 业务寄存器 | 继电器/DI 相关 | ADC/DAC/校准/报警相关 |
| LinkEnable | 可写(0=静默) | 只读(恒为 1,无静默模式) |
接入网关时,建议先用 FC17 读取设备类型码,再按产品加载寄存器字典。
14. 通信示例(CRC 已实算)
以下主站地址均为 1(0x01)。CRC 以「低字节 高字节」给出。
14.1 读线圈(FC01)--- 读 4 路继电器状态
请求: 01 01 00 00 00 04 3D C9
响应: 01 01 01 00 51 88 (00 = 4 路全断)
14.2 写单线圈(FC05)--- 继电器1 吸合
请求: 01 05 00 00 FF 00 8C 3A
响应: 01 05 00 00 FF 00 8C 3A (原样回显)
14.3 写多线圈(FC0F)--- 4 路全开
请求: 01 0F 00 00 00 04 01 0F 7E 92
响应: 01 0F 00 00 00 04 (原样回显起始/数量)
14.4 读保持寄存器(FC03)--- 读从站地址
请求: 01 03 00 00 00 01 84 0A
响应: 01 03 02 00 01 79 84 (00 01 = 地址 1)
14.5 写保持寄存器(FC06)--- 改波特率为 115200(索引 4)
请求: 01 06 00 01 00 04 D9 C9
响应: 01 06 00 01 00 04 D9 C9 (原样回显,之后设备切换 115200)
14.6 读离散输入(FC02)--- 读 4 路 DI
请求: 01 02 00 00 00 04 79 C9
响应: 01 02 01 00 A1 88 (00 = 无 DI 闭合)
14.7 读输入寄存器(FC04)--- 读运行小时
请求: 01 04 00 05 00 01 21 CB
响应: 01 04 02 00 05 79 33 (00 05 = 5 小时)
14.8 上报从站标识(FC17)
请求: 01 11 C0 2C
响应: 含设备类型码 0x0002 + 运行状态(详见固件实现;可用 FC04 单独读 0x000B/0x000C 获取版本与类型)
14.9 异常响应示例(FC01 非法功能码)
请求: 01 08 ... (假设主站发了一个不支持的功能码 0x08)
响应: 01 81 01 81 90 (功能码|0x80=0x81, 异常码 0x01=非法功能)
15. 出厂默认参数速查
| 参数 | 值 |
|---|---|
| 从站地址 | 1 |
| 波特率 | 9600(索引 0) |
| 通信使能 | 1(正常回复) |
| 故障安全 | 开启,超时 10s |
| 继电器上电态 | 全断(安全态) |
| 设备类型码 | 0x0002 |
| 固件版本 | v1.0.0(0x0100) |
本文档依据 P02 工程源码(modbus_rtu.c / flash_param.c / bsp_rs485.c)核对编写,示例帧 CRC 经脚本验证。