Proteus仿真二,通过51单片机来实现虚拟串口通信,基于MODBUS_RTU协议(2)
接着上一章的内容来讲,本次主要实现的是功能码0x03的功能。前面说过了它的主要功能是读取多个寄存器。先看报文:
我在下位机的寄存器1和寄存器2给予了1,2的值,上位机同时读取到了下位机的值。
报文如下,
Tx:175-01 03 00 00 00 02 C4 0B
Rx:176-01 03 04 00 01 00 02 2A 32
TX表示发送,即上文机往下位机发送的报文。01 为从机地址,03为功能码,00 00表示寄存器,00 02表示寄存器的数量,C4 0B为校验码。
下位机接收到这报文后先需要做的是检验发送过来的报文的校验码是否正确,然后在进行对功能码的分析。
RX表示的是下位机发送给上位机的报文。01为从机地址,03为功能码,04为数据的个数,因为上位机是要读取2个寄存器的值,一个寄存器的值有2个字节,所以2*2=4。所以数据个数为4。00 01为寄存器0的值,00 02为寄存器1的值,2A 32为下位机的校验码。
分析完后就可以对上一章所接受到的1帧报文进行分析了。
先分析报文的校验码,从站地址和功能码。
void DisposeEvent(void)
{
unsigned int CRCCheck;
unsigned int ReCRC;
if(Modbus.ReFlag!=1)
{
return;
}
CRCCheck=crc16(&Modbus.ReBuff[0],6);
ReCRC=Modbus.ReBuff[6]<<8|Modbus.ReBuff[7];
if(CRCCheck==ReCRC)
{
if(Modbus.ReBuff[0]==Modbus.SlaveID)
{
switch(Modbus.ReBuff[1])
{
case 0x03:Func_0x03();break;
case 0x06:Func_0x06();break;
case 0x10:Func_0x10();break;
}
}
}
Modbus.Cnt=0;
Modbus.ReFlag=0;
}
然后则是对功能码的处理
void Func_0x03(void)
{
unsigned char i=0;
unsigned char j=0;
unsigned int cnt=0;
unsigned int add=0;
unsigned int CRCCheck=0;
Modbus.SendBuff[i++]=Modbus.SlaveID;
Modbus.SendBuff[i++]=0x03;
cnt=(Modbus.ReBuff[4]<<8|Modbus.ReBuff[5])*2;
Modbus.SendBuff[i++]=cnt;
add=Modbus.ReBuff[2]<<8|Modbus.ReBuff[3];
for(j=0;j<cnt/2;j++)
{
Modbus.SendBuff[i++]=regs[add+j]/256;
Modbus.SendBuff[i++]=regs[add+j]%256;
}
CRCCheck=crc16(Modbus.SendBuff,i);
Modbus.SendBuff[i++]=CRCCheck/256;
Modbus.SendBuff[i++]=CRCCheck%256;
for(j=0;j<i;j++)
{
SBUF=Modbus.SendBuff[j];
while(TI==0);
TI=0;
}
}
最后则可以通过Modbus调试助手来进行检验。打开调试精灵,
选择COM为1,波特率为9600(改了波特率),然后读取寄存器1的值
读取寄存器2
从寄存器1读取3个寄存器
验证成功!