- 打卡等级:常住居民III
- 打卡总天数:153
- 最近打卡:2026-03-30 19:54:03
已绑定手机
论坛元老
- 积分
- 3422
|
发表于 2026-2-11 21:27:19
|
显示全部楼层
重点还是ModBus 协议的解析函数:
/********************* modbus协议 *************************/
/***************************************************************************
写多寄存器
数据: 地址 功能码 寄存地址 寄存器个数 写入字节数 写入数据 CRC16
偏移: 0 1 2 3 4 5 6 7~ 最后2字节
字节: 1 byte 1 byte 2 byte 2 byte 1byte 2*n byte 2 byte
addr 0x10 xxxx xxxx xx xx....xx xxxx
返回
数据: 地址 功能码 寄存地址 寄存器个数 CRC16
偏移: 0 1 2 3 4 5 6 7
字节: 1 byte 1 byte 2 byte 2 byte 2 byte
addr 0x10 xxxx xxxx xxxx
读多寄存器
数据:站号(地址) 功能码 寄存地址 寄存器个数 CRC16
偏移: 0 1 2 3 4 5 6 7
字节: 1 byte 1 byte 2 byte 2 byte 2 byte
addr 0x03 xxxx xxxx xxxx
返回
数据:站号(地址) 功能码 读出字节数 读出数据 CRC16
偏移: 0 1 2 3~ 最后2字节
字节: 1 byte 1 byte 1byte 2*n byte 2 byte
addr 0x03 xx xx....xx xxxx
返回错误代码
数据:站号(地址) 错误码 CRC16
偏移: 0 1 最后2字节
字节: 1 byte 1 byte 2 byte
addr 0x93 xxxx
***************************************************************************/
u8 MODBUS_RTU(void)
{
u8 i,j,k;
u16 reg_addr; //寄存器地址
u8 reg_len; //写入寄存器个数
u16 crc;
if(RX1_Buffer[1] == 0x10) //写多寄存器
{
if(RX1_cnt < 9) return 0x91; //命令长度错误
if((RX1_Buffer[4] != 0) || ((RX1_Buffer[5] *2) != RX1_Buffer[6])) return 0x92; //写入寄存器个数与字节数错误
if((RX1_Buffer[5]==0) || (RX1_Buffer[5] > REG_LENGTH)) return 0x92; //写入寄存器个数错误
reg_addr = ((u16)RX1_Buffer[2] << 8) + RX1_Buffer[3]; //寄存器地址
reg_len = RX1_Buffer[5]; //写入寄存器个数
if((reg_addr+(u16)RX1_Buffer[5]) > (REG_ADDRESS+REG_LENGTH)) return 0x93; //寄存器地址错误
if(reg_addr < REG_ADDRESS) return 0x93; //寄存器地址错误
if((reg_len*2+7) != RX1_cnt) return 0x91; //命令长度错误
j = reg_addr - REG_ADDRESS; //寄存器数据下标
for(k=7, i=0; i<reg_len; i++,j++)
{
modbus_reg[j] = ((u16)RX1_Buffer[k] << 8) + RX1_Buffer[k+1]; //写入数据, 大端模式
k += 2;
}
if(RX1_Buffer[0] != 0) //非广播地址则应答
{
for(i=0; i<6; i++) TX1_Buffer[i] = RX1_Buffer[i]; //要返回的应答
crc = MODBUS_CRC16(TX1_Buffer, 6);
TX1_Buffer[6] = (u8)crc; //CRC是小端模式, 先发低字节,后发高字节。
TX1_Buffer[7] = (u8)(crc>>8);
B_TX1_Busy = 1; //标志发送忙
TX1_cnt = 0; //发送字节计数
TX1_number = 8; //要发送的字节数
TI = 1; //启动发送
}
}
else if(RX1_Buffer[1] == 0x03) //读多寄存器
{
if(RX1_Buffer[0] != 0) //非广播地址则应答
{
if(RX1_cnt != 6) return 0x91; //命令长度错误
if(RX1_Buffer[4] != 0) return 0x92; //读出寄存器个数错误
if((RX1_Buffer[5]==0) || (RX1_Buffer[5] > REG_LENGTH)) return 0x92; //读出寄存器个数错误
reg_addr = ((u16)RX1_Buffer[2] << 8) + RX1_Buffer[3]; //寄存器地址
reg_len = RX1_Buffer[5]; //读出寄存器个数
if((reg_addr+(u16)RX1_Buffer[5]) > (REG_ADDRESS+REG_LENGTH)) return 0x93; //寄存器地址错误
if(reg_addr < REG_ADDRESS) return 0x93; //寄存器地址错误
j = reg_addr - REG_ADDRESS; //寄存器数据下标
TX1_Buffer[0] = SL_ADDR; //站号地址
TX1_Buffer[1] = 0x03; //读功能码
TX1_Buffer[2] = reg_len*2; //返回字节数
for(k=3, i=0; i<reg_len; i++,j++)
{
TX1_Buffer[k++] = (u8)(modbus_reg[j] >> 8); //数据为大端模式
TX1_Buffer[k++] = (u8)modbus_reg[j];
}
crc = MODBUS_CRC16(TX1_Buffer, k);
TX1_Buffer[k++] = (u8)crc; //CRC是小端模式, 先发低字节,后发高字节。
TX1_Buffer[k++] = (u8)(crc>>8);
B_TX1_Busy = 1; //标志发送忙
TX1_cnt = 0; //发送字节计数
TX1_number = k; //要发送的字节数
TI = 1; //启动发送
}
}
else return 0x90; //功能码错误
return 0; //解析正确
}
|
|