由于项目需要,本次通讯使用了modbus协议,用的c++builder的Tcomm串口控件。使用modbus协议时需要添加2个事:
(1)每次发送数据包时需要在包尾部添加CRC16校验码;
(2)处理好每帧数据的帧间隔时间。
上面的(1)很好处理,找个CRC16的接口将算完的校验码附在包尾就行了。主要是(2)的处理,遇到的具体问题和现象是:有时一个完整的数据包需要用多次接收完,而我在接收端一直认为每读一次串口就接收了一个完整的数据包,所以这样肯定会出现问题,表现为接收到了无法识别的数据包。解决这个问题的办法是判断任意两次接收到的数据包的帧间隔时间,如果这个时间小于一个给定值,那么就认为这两个数据包其实是一个协议包的内容,如果帧间隔时间大于这个给定值,就认为接收到的是两个独立的数据协议包。这样处理后就解决了问题。具体的实现见下面:
- //---------------------------------------------------------------------------
-
DWORD dwStart_dwStart=0;
-
int global_len=0;
-
unsigned char global_buff[37];
-
int times=0;
-
void __fastcall TForm1::Comm1ReceiveData(TObject *Sender)
-
{
-
int len;
-
int i;
-
int j;
-
unsigned short int crc;
-
unsigned short int crc_pkt;
-
unsigned char tmp[37];
-
-
if(GetTickCount()-dwStart_dwStart>50)
-
{
-
//已经是完全的一个新帧了
-
//用Next表示这是个新包
-
Label3->Caption="Next";
-
inbuff=Comm1->ReadInputByte();
-
len=inbuff.Length;
-
global_len=inbuff.Length;
-
for(i=0;i<len;i++)
-
{
-
global_buff[i]=inbuff[i];
-
}
-
dwStart_dwStart=GetTickCount();
-
-
}
-
else
-
{
-
//还是接着上次的那个帧数据
-
//用this表示这是个连续的数据包
-
Label3->Caption="This";
-
//读出本次接收到的数据
-
inbuff=Comm1->ReadInputByte();
-
//读出本次接收的数据长度
-
len=inbuff.Length;
-
//将本次接收到的数据追加到上次的数组中去
-
//此时,如果数据仍然没有发送完,就是说还会有
-
//下一帧数据发过来,那么就会重复本部操作,不停的
-
//向上次的数据追加数据,而如果本次追加完没有下一次了
-
//那么需要本次继续向下面运行,怎么才能实现呢
-
for(i=global_len,j=0;j<len;i++,j++)
-
{
-
global_buff[i]=inbuff[j];
-
}
-
global_len=global_len+len;
-
Timer1->Enabled=false;
-
times = times+1;
-
//记录这个数据包被拆分成了几份
-
Label4->Caption=times;
-
}
-
-
Timer1->Enabled=true;
-
-
-
}
- }
-
void __fastcall TForm1::Timer1Timer(TObject *Sender)
-
{
-
Timer1->Enabled=false;
-
int i;
-
-
-
for(i=0;i<global_len;i++)
-
{
-
Memo1->Text = Memo1->Text + " "+IntToHex(global_buff[i],2);
-
}
-
global_len=0;
-
times=0;
-
-
Memo1->Text = Memo1->Text + '\x0d'+'\x0a';
-
}
-
//---------------------------------------------------------------------------
阅读(3698) | 评论(0) | 转发(0) |