五、RTU协议框架
//申明函数
ModbusState BackCheckFunction(uint8_t subcode);
ModbusState ReadEventFunction(void);
//modbus函数框架
ModbusState XL_Modbus_RTU_Frame(uint8_t Addr,uint8_t *pData,uint16_t len)
{
//判断地址是否正确、及数据长度
if(len<3 || Addr != pData[0] )
return MB_NULL;
//通信为低位在前
uint16_t crc = crc16tablefast(pData,len-2);
//判断CRC
if(pData[len-2] != (uint8_t )crc||pData[len-1] != (uint8_t )(crc>>8) )
return MB_NULL;
//对应功能码的函数检查
ModbusState State = LenCheck((FunCode)pData[1],pData,len);
if(State != MB_OK)
{
//返回错误功能码
ErrorSend((FunCode)pData[1],State);
return MB_ERROR;
}
//接收处理计数++
EventCountNum++;
switch(pData[1])
{
case ReadReg: //读取多个寄存器
ReadRegFunction(pData,len);
break;
case ReadInputReg: //读取多个输入寄存器
ReadRegFunction(pData,len);
break;
case WriteSingleReg: //写入单个寄存器
WriteRegFunction(pData,len);
break;
case ReadEventCount: //读取事件计数
ReadEventFunction();
break;
case WriteReg: //写入多个寄存器
WriteRegFunction(pData,len);
break;
default: //异常回复,不存在的功能码
ErrorSend((FunCode)pData[1],UNFUNCODE);
break;
}
return MB_OK;
}
//寄存器映射--MARK()
ModbusState RegMap(uint16_t regaddr,uint16_t *reg,ModbusState code )
{
//先进行地址偏移
/*这部分代码需要自己实现*/
return MB_OK;
}
//读取多个寄存器
ModbusState ReadRegFunction(uint8_t *pData,uint16_t len)
{
//定义发送数组
uint8_t bData[310] = {pData[0],pData[1],2*((pData[4]<<8)+pData[5])};
//定义返回数据长度
uint16_t blen = 2*((pData[4]<<8)+pData[5])+5;
//寄存器开始地址
uint16_t addr = (pData[2]<<8)+pData[3];
//读取寄存器数
uint16_t allnum = (pData[4]<<8)+pData[5];
//遍历寄存器
for(int i = 0 ;i<allnum;i++)
{
uint16_t reg;
RegMap(addr+i,®,MB_READ);
bData[3+i*2] = reg>>8;
bData[3+i*2+1] = reg;
}
//发送数据出去
MBSendCRC(bData,blen);
return MB_OK;
}
//写入寄存器
ModbusState WriteRegFunction(uint8_t *pData,uint16_t len)
{
//寄存器开始地址
uint16_t addr = (pData[2]<<8)+pData[3];
//定义发送数组
uint8_t bData[8] = {pData[0],pData[1],pData[2],pData[3]};
//单个寄存器
if(pData[1] == WriteSingleReg)
{
//填充长度
bData[4] = 0;
bData[5] = 1;
uint16_t preg = (pData[4]<<8)+pData[5];
RegMap(addr,&preg,MB_WRITE);
}
//多个寄存器
if(pData[1] == WriteReg)
{
//填充长度
bData[4] = pData[4];
bData[5] = pData[5];
//读取字节数
uint16_t allnum = pData[6]/2;
//遍历寄存器
for(int i = 0 ;i<allnum;i++)
{
uint16_t preg = (pData[7+i*2]<<8)+pData[7+i*2+1];
RegMap(addr+i,&preg,MB_WRITE);
}
}
//发送数据出去
MBSendCRC(bData,8);
return MB_OK;
}
//modbus的通信状态校验的函数
ModbusState BackCheckFunction(uint8_t subcode)
{
switch(subcode)
{
case 0x00: //返回询问数据
{
uint8_t data[8] = {SlaveAddr,BackCheck,0x00,0x00,0x00,0x01};
MBSendCRC(data,8);
break;
}
default:
ErrorSend(BackCheck,UNFUNCODE);
break;
}
return MB_OK;
}
//modbus的读取事件计数的函数
ModbusState ReadEventFunction(void)
{
uint8_t data[8] = {SlaveAddr,ReadEventCount,0x00,0x00,0x00,EventCountNum};
MBSendCRC(data,8);
return MB_OK;
}
//ModbusRTU的长度检测函数
ModbusState LenCheck(FunCode code,uint8_t *pData,uint16_t len)
{
switch(pData[1])
{
case ReadReg: //读取多个寄存器
if(pData[4]!= 0|| pData[5] > Max_RegNum) //判断读取的最大长度是否超过125寄存器
return LENERROR;
if(len != 8) //数据主机发送的不彻底或字节的数量是错误的
return LENERROR;
return MB_OK; //通过筛选
case ReadInputReg: //读取多个输入寄存器
if(pData[4]!= 0|| pData[5] > Max_RegNum) //判断读取的最大长度是否超过125寄存器
return LENERROR;
if(len != 8) //数据主机发送的不彻底或字节的数量是错误的
return LENERROR;
return MB_OK; //通过筛选
case WriteSingleReg: //写入单个寄存器
if(len != 8) //数据主机发送的不彻底或字节的数量是错误的
return LENERROR;
return MB_OK; //通过筛选
case BackCheck: //回送诊断校验,等待与陈铭讨论
if(len < 8 || len>310)
return LENERROR;
return MB_OK;
case ReadEventCount: //读取事件计数
if(len < 4 || len>310)
return LENERROR;
return MB_OK;
case WriteReg: //写入多个寄存器
if(pData[4]!= 0|| pData[5] > Max_RegNum || len != (pData[6]+9)||(2*((pData[4]<<8)+pData[5]))!=pData[6]) //判断读取的最大长度是否超过125寄存器
return LENERROR;
return MB_OK;
default: //异常回复
return UNFUNCODE;
}
}
/*-----crc校验查表----------------
辅助完成CRC校验,是CRC校验的快速查表法
----------------------------------*/
const uint16_t crctalbeabs[] = {
0x0000, 0xCC01, 0xD801, 0x1400, 0xF001, 0x3C00, 0x2800, 0xE401,
0xA001, 0x6C00, 0x7800, 0xB401, 0x5000, 0x9C01, 0x8801, 0x4400
};
/*-------CRC校验函数----------------
输入为字符指针(ptr)、字符指针长度(len)
//ptr为校验数组的指针,len为校验数组的元素个数
返回CRC校验结果,为16位
根据实际需求进行CRC校验码
----------------------------------*/
uint16_t crc16tablefast(uint8_t *ptr, uint16_t len)
{
uint16_t crc = 0xffff;
uint16_t i;
uint8_t ch;
for (i = 0; i < len; i++)
{
ch = *ptr++;
crc = crctalbeabs[(ch ^ crc) & 15] ^ (crc >> 4);
crc = crctalbeabs[((ch >> 4) ^ crc) & 15] ^ (crc >> 4);
}
return crc;
}
//modbus 发送函数
void MBSend(uint8_t *pData,uint16_t len)
{
//需要自己修改串口发送驱动函数
//XL_Transmit(&hlpuart1,pData,len,Max_SendUart_Time);
//XL_Transmit(&huart3,pData,len,Max_SendUart_Time);
}
//modbus 发送函数
void MBSendCRC(uint8_t *pData,uint16_t len)
{
uint16_t crc = crc16tablefast(pData,len-2);
pData[len-2] = (uint8_t )crc;
pData[len-1] = (uint8_t )(crc>>8);
//需要自己修改串口发送驱动函数
//XL_Transmit(&hlpuart1,pData,len,Max_SendUart_Time);
//XL_Transmit(&huart3,pData,len,Max_SendUart_Time);
}
//异常、错误代码发送
void ErrorSend(FunCode code,ModbusState state)
{
uint8_t data[5] = {SlaveAddr,code+0x80,state};
MBSendCRC(data,5);
}
|