基于freemodbus的传感器数据传输方案
·
前面文章里,我们需要实现通过modbus tcp传输传感器数据:
一个Modbus-TCP传感器数据传输方案
这里有基于freemodbus的详细实现:
代码功能分析
1. 函数参数和变量
eMBException eMBFuncReadHoldingRegister(UCHAR *pucFrame, USHORT *usLen)
pucFrame: 指向接收到的Modbus请求帧的指针usLen: 指向帧长度的指针,函数会更新它为响应帧长度- 返回值:
eMBException异常状态码
2. 请求帧长度验证
if(*usLen == (MB_PDU_FUNC_READ_SIZE + MB_PDU_SIZE_MIN))
- 检查请求帧长度是否正确
MB_PDU_FUNC_READ_SIZE = 4(地址2字节 + 寄存器数量2字节)MB_PDU_SIZE_MIN是最小PDU长度
3. 解析请求参数
usRegAddress = (USHORT)(pucFrame[MB_PDU_FUNC_READ_ADDR_OFF] << 8);
usRegAddress |= (USHORT)(pucFrame[MB_PDU_FUNC_READ_ADDR_OFF + 1]);
usRegAddress++;
usRegCount = (USHORT)(pucFrame[MB_PDU_FUNC_READ_REGCNT_OFF] << 8);
usRegCount |= (USHORT)(pucFrame[MB_PDU_FUNC_READ_REGCNT_OFF + 1]);
解析过程:
-
寄存器地址解析:
- 从请求帧中读取2字节的起始地址(大端格式)
usRegAddress++:Modbus协议中地址从1开始,转换为从0开始的内部地址
-
寄存器数量解析:
- 从请求帧中读取2字节的要读取的寄存器数量
4. 寄存器数量验证
if((usRegCount >= 1) && (usRegCount <= MB_PDU_FUNC_READ_REGCNT_MAX))
MB_PDU_FUNC_READ_REGCNT_MAX = 0x007D(125个寄存器)- 检查请求的寄存器数量是否在有效范围内(1-125)
5. 构建响应帧
pucFrameCur = &pucFrame[MB_PDU_FUNC_OFF];
*usLen = MB_PDU_FUNC_OFF;
*pucFrameCur++ = MB_FUNC_READ_HOLDING_REGISTER; // 功能码03
*usLen += 1;
*pucFrameCur++ = (UCHAR)(usRegCount * 2); // 数据字节数
*usLen += 1;
响应帧结构:
[功能码(1B)] [字节数(1B)] [数据(n×2B)]
6. 调用回调函数获取数据
eRegStatus = eMBRegHoldingCB(pucFrameCur, usRegAddress, usRegCount, MB_REG_READ);
回调函数参数:
pucFrameCur: 响应数据缓冲区指针usRegAddress: 起始寄存器地址usRegCount: 寄存器数量MB_REG_READ: 操作模式(读取)
7. 错误处理和长度更新
if(eRegStatus != MB_ENOERR) {
eStatus = prveMBError2Exception(eRegStatus);
} else {
*usLen += usRegCount * 2; // 更新总响应长度
}
对于LoRa网关项目的具体应用
请求示例分析
假设主站请求读取40005开始的10个寄存器:
请求帧: 01 03 00 04 00 0A XX XX
解析结果:
- 起始地址: 0x0004 → 40005 (Modbus地址)
- 内部地址: 0x0004 → 需要转换为您的寄存器映射
- 寄存器数量: 0x000A → 10个寄存器
在您的项目中需要实现的关键部分
1. 寄存器地址映射转换:
// 在eMBRegHoldingCB回调函数中需要实现地址转换
USHORT internal_address = ConvertModbusToInternal(usAddress);
2. 数据打包逻辑:
eMBErrorCode eMBRegHoldingCB(UCHAR *pucRegBuffer,
USHORT usAddress,
USHORT usNRegs,
eMBRegisterMode eMode)
{
// 根据请求的地址范围返回对应的传感器数据
if(usAddress >= REG_DATA_START && usAddress < REG_DATA_START + 516) {
// 返回传感器数据
for(int i = 0; i < usNRegs; i++) {
USHORT reg_value = GetSensorRegisterValue(usAddress + i);
pucRegBuffer[i*2] = (reg_value >> 8) & 0xFF;
pucRegBuffer[i*2+1] = reg_value & 0xFF;
}
return MB_ENOERR;
}
return MB_ENOREG;
}
3. 分包处理:
由于最大只能读取125个寄存器(250字节),您的604字节数据需要分5次读取:
- 包1: 40005-40129 (125寄存器)
- 包2: 40130-40254 (125寄存器)
- 包3: 40255-40379 (125寄存器)
- 包4: 40380-40504 (125寄存器)
- 包5: 40505-40520 (16寄存器)
这个函数是Modbus从站的核心处理逻辑,负责解析主站请求并返回对应的保持寄存器数据。
更多推荐
所有评论(0)