(1).CRC16算法:
INT16U CRC16(INT8U *puchMsg, INT16U usDataLen)
{
INT8U uchCRCHi = 0xFF; /*高CRC字节初始化*/
INT8U uchCRCLo = 0xFF; /*低CRC字节初始化*/
INT8U uIndex; /* CRC循环中的索引*/
while (usDataLen--) /*传输消息缓冲区*/
{
uIndex = uchCRCHi ^*puchMsg++; /*计算CRC */
uchCRCHi = uchCRCLo ^auchCRCHi[uIndex];
uchCRCLo = auchCRCLo[uIndex];
}
return (uchCRCHi << 8 |uchCRCLo);
}
(2)发送命令程序
本例程以Mag64为核心CPU
void Read_InPut(INT8U Addr,INT16UStart,INT16U Len)
{
INT16U CRC;
SendBuffer_485[0]=Addr; //设备地址
SendBuffer_485[1]=0x04; //modbus功能码
SendBuffer_485[2]=Start/256; //Start为寄存器地址
SendBuffer_485[3]=Start%256;
SendBuffer_485[4]=Len/256; //Len为读取寄存器长度
SendBuffer_485[5]=Len%256;
CRC=CRC16(SendBuffer_485,6);
SendBuffer_485[6]=CRC/256; //CRC校验高位
SendBuffer_485[7]=CRC%256; //CRC校验低位
R485_OUT; //使能RS485发送
SendLen_485=8;
SendNum_485=0;
CloseINT0(); //关闭串口接受中断
UCSR0B |= BIT(UDRIE0); //打开串口发送中断
}
(3)返回数据解析
数据接收使用串口中断,ReceivedBuffer_485为接收数据组,ReceivedNum_485为接收到数据长度,ReceivedFlag_485接收到数据标志。函数float
Datasum(INT8UBYTE1, INT8U BYTE2, INT8U BYTE3, INT8U
BYTE4)把浮点数的4个字节转换为1个浮点数。
float Datasum(INT8U FloatByte1, INT8U FloatByte2,INT8U FloatByte3, INT8U FloatByte4)
{
float aa;
union IntTOFP
{
FP32 F32;
INT8U T8[4];
};
union IntTOFPaa;
aa.T8[0] = FloatByte1;
aa.T8[1] = FloatByte2;
aa.T8[2] = FloatByte3;
aa.T8[3] = FloatByte4;
return aa;
}
void Read_Lmag(INT8U Ad)
{
INT8U i,j;
INT8U Num1[10],BIT;
INT16UCRC1,CRC2;
FP32 Flow; //aaa为瞬时流量数值
ReceivedFlag_485=1;
Open_Time1_Ms5(20);
Read_InPut(Ad,0x1010,2); //发送设备地址、寄存器地址、寄存器长度
while(ReceivedFlag_485); //等待接收结束
if((ReceivedNum_485==9)&&(ReceivedBuffer_485[0]==Ad)) //判断数据是否正确
{
CRC1=CRC16(ReceivedBuffer_485,7);
CRC2=ReceivedBuffer_485[7]*256+ReceivedBuffer_485[8];
if(CRC1==CRC2)
{//转换数据为浮点数
Flow= Datasum(ReceivedBuffer_485[6], ReceivedBuffer_485[5], ReceivedBuffer_485[4] ,ReceivedBuffer_485[3]);
}
}
}