一个Modbus-TCP传感器数据传输方案
需求 |
---|
lora接收最多200个节点的传感器数据,每个传感器数据16位。通过modbus-tcp上传至服务器 |
基于需求:提供详细的Modbus-TCP协议方案:
1. 数据包大小分析
总数据量计算:
- 采集时间:4字节 (int32)
- 200个传感器 × (1字节ID + 2字节数据) = 600字节
- 总计:604字节
Modbus-TCP限制:
- Modbus PDU最大长度:253字节
- 功能码03/04单次最大读取寄存器数:125个寄存器(250字节数据)
- 604字节数据必须分包传输
2. 寄存器映射方案
2.1 寄存器分配
地址范围 | 内容 | 长度 | 说明 |
---|---|---|---|
40001-40002 | 采集时间戳 | 2寄存器 | Unix时间戳 |
40003-40004 | 数据包信息 | 2寄存器 | 包序号、总包数等 |
40005-400132 | 传感器数据块1 | 128寄存器 | 第1包数据 |
40101-40128 | 传感器数据块2 | 128寄存器 | 第2包数据 |
40201-40228 | 传感器数据块3 | 128寄存器 | 第3包数据 |
40301-40328 | 传感器数据块4 | 128寄存器 | 第4包数据 |
40401-40420 | 传感器数据块5 | 20寄存器 | 第5包数据 |
2.2 数据包分包方案
共分5包传输:
- 每包:128个寄存器(256字节数据)
- 前4包:各128寄存器
- 第5包:20寄存器
3. 寄存器详细定义
3.1 基本信息寄存器 (40001-40004)
地址 | 内容 | 数据类型 | 说明 |
---|---|---|---|
40001 | 时间戳高16位 | uint16 | 采集时间的高位 |
40002 | 时间戳低16位 | uint16 | 采集时间的低位 |
40003 | 包控制信息 | uint16 | 比特位定义见下表 |
40004 | 传感器总数 | uint16 | 实际传感器数量(1-200) |
包控制信息(40003)比特位定义:
比特15-8: 保留
比特7-4: 总包数 (固定为5)
比特3-0: 当前包序号 (0-4)
3.2 数据包寄存器结构
每包数据格式:
寄存器N+0: [传感器ID1][数据1高8位]
寄存器N+1: [数据1低8位][传感器ID2]
寄存器N+2: [数据2高8位][数据2低8位]
寄存器N+3: [传感器ID3][数据3高8位]
...
数据打包示例:
// 每2个寄存器存储3个传感器数据
寄存器布局:
[ID1][Data1_H] [Data1_L][ID2] [Data2_H][Data2_L] [ID3][Data3_H] ...
4. Modbus-TCP通信协议
4.1 Master请求命令定义
读取基本信息:
事务标识符: 0x0001
协议标识符: 0x0000
长度: 0x0006
单元标识符: 0x01
功能码: 0x03 (读保持寄存器)
起始地址: 0x0000 (40001)
寄存器数量: 0x0004 (4个寄存器)
读取数据包n:
事务标识符: 0x0002
协议标识符: 0x0000
长度: 0x0006
单元标识符: 0x01
功能码: 0x03
起始地址: 0x0004 + (n-1)*128 (对应40005,40101...)
寄存器数量: 0x0080 (128寄存器) 或 0x0014 (20寄存器)
4.2 Slave响应数据定义
基本信息响应:
事务标识符: 0x0001
协议标识符: 0x0000
长度: 0x000B
单元标识符: 0x01
功能码: 0x03
字节数: 0x08
数据: [时间戳高][时间戳低][控制字][传感器数]
数据包响应:
事务标识符: 0x0002
协议标识符: 0x0000
长度: 0x0107 (对于128寄存器)
单元标识符: 0x01
功能码: 0x03
字节数: 0x0100 (256字节)
数据: [传感器数据块...]
5. 通信流程说明
5.1 完整数据读取流程
Master端流程:
1. 建立TCP连接
2. 发送读取基本信息请求(40001-40004)
3. 解析响应,获取时间戳和传感器总数
4. 循环发送5个数据包读取请求
5. 重组并解析所有传感器数据
6. 关闭TCP连接Slave端流程:
1. 监听TCP连接
2. 接收Master请求
3. 根据地址映射返回对应数据
4. 维持连接直到所有数据传送完成
5.2 具体实现示例
Master请求序列:
# 1. 读取基本信息
request1 = "01 03 00 00 00 04" # 40001-40004# 2. 读取5个数据包
request2 = "01 03 00 04 00 80" # 40005-40132 (包1)
request3 = "01 03 01 00 00 80" # 40101-40228 (包2)
request4 = "01 03 02 00 00 80" # 40201-40328 (包3)
request5 = "01 03 03 00 00 80" # 40301-40428 (包4)
request6 = "01 03 04 00 00 14" # 40401-40420 (包5)
6. 数据解析算法
// 数据重组伪代码
struct SensorData {uint8_t id;int16_t value;
};vector<SensorData> parseSensorData(const vector<uint16_t>& allRegisters) {vector<SensorData> result;// 跳过基本信息寄存器(前4个)int regIndex = 4;for(int i = 0; i < 200; i += 3) {// 每3个传感器占用4个寄存器if(regIndex + 3 >= allRegisters.size()) break;// 解析第1个传感器uint8_t id1 = allRegisters[regIndex] >> 8;int16_t value1 = (allRegisters[regIndex] & 0xFF) << 8 | (allRegisters[regIndex+1] >> 8);result.push_back({id1, value1});// 解析第2个传感器 uint8_t id2 = allRegisters[regIndex+1] & 0xFF;int16_t value2 = allRegisters[regIndex+2];result.push_back({id2, value2});// 解析第3个传感器uint8_t id3 = allRegisters[regIndex+3] >> 8;int16_t value3 = (allRegisters[regIndex+3] & 0xFF) << 8 |(allRegisters[regIndex+4] >> 8);result.push_back({id3, value3});regIndex += 4;}return result;
}
7. 注意事项
- 超时处理: 建议设置合理的读写超时(如30秒)
- 错误重试: 实现重试机制,单包失败可重试该包
- 数据一致性: 使用时间戳确保多包数据属于同一采集周期
- 连接管理: 长时间连接建议实现心跳机制
- 性能优化: 可根据网络状况调整包大小和并发请求数
这个方案确保了在Modbus-TCP协议限制内高效可靠地传输所有传感器数据。