数据处理,要保证不重复不漏掉,效率还要高,不做多余的循环。。
1. 首先设置你的MSComm1控件的 RThreShold=1,属性值就好,这一条是保证只要串口缓存有数据就会触发,你的串口线程接收数据,不然你总是进不了接收事件。。
2 。数据处理的过程
2.1因为从串口接收来的数据,是不可预见的类型,所以用到 OleVariant 数据类型,
2.2在C++中字符串口,String 型,char型都有一个问题,你可能不一定会碰到,但是会蛋疼,数据遇到0就结束,这个在C++里面是一个约定,字符型的结束符号就是 \0 .所以存储数据的时候要换一种数据类型来接受,,这里我用到了队列类数据类型vector,至于他的用法C++ /C++builder的用法都是一样的,你可以去查。。
2.3 ,按照自己拿到的通讯协议解析数据,我的数据类型大概是这样, Head +length +data1+data2+。。。。+dataN +checksum.
所有我的任务就是下面的
2.3.1 找头0x0B ,一次从串口缓存接收的数据数组,判断第一个是不是0X0B,如果是然后接下来存储这去处理,如果不是就只是把这个头扔掉
void __fastcall TForm1::Comm_DataReceived(TObject *Sender)
{
Sleep(20); //不急于处理
OleVariant s ;
int frameLength; //记录有效值长度BufferLength=frameLength
int BufferLength=MSComm1->InBufferCount ;//收到数据的长度
MSComm1->InputLen=0; //讀取整個接收緩沖區。
MSComm1->InputMode=1; //將Input模式設為二進制。
s=MSComm1->Input;
String str;
for(int i=0;i
int a=s.GetElement(i);
str+=IntToHex(a,2)+" "; //转换成16进制
//GetBuffer[i]=s.GetElement(i);//动态数组不能接受有00的值。。
//buffer1.push_back(GetBuffer[i]);
buffer1.push_back(s.GetElement(i));
}
Memo1->Lines->Add(str);
//数据的队列判断存储
while(buffer1.size()!=0) //这样就遇0x0B存一次 不行的
{
byte data1=buffer1.at(0);
byte data2=buffer1[0];
int len1=buffer1.size();
if(buffer1[0]==0x0B&&buffer1[1]!=0x00)
{
//在这里校验CheckSum() 通过就存入数组中,不通过 删除头,
for(int j=0;j
GetBuffer[j]=buffer1[j]; //把正确的一组存进来
}
//重复校验的问题
DealData(BufferLength);
//删除这一帧数据
buffer1.erase(&buffer1[0],&buffer1[buffer1[1]+3]); //正确与否都要删除头部
}
else
{
if(buffer1.size()>=1)
buffer1.erase(&buffer1[0]); //下次开始依旧从第一个元素开始
}
}
}
2.3.2,找到一组对的上通讯协议的的数据,就开始正式的处理,
2.3.2.1 校验(我的通讯协议是 和校验方式所有有效数据之和)
if(checkSum==CheckSum(GetBuffer,frameLength))
2.3.2.2 校验通过后的数据处理。。(就是一个数据一个数据的处理了。。)
void __fastcall TForm1::DealData(int BufferLength)
{
int flag=0;
Byte frameLength;
while(BufferLength>=5&&flag==0)
{
if(GetBuffer[0]==0x0B&&BufferLength>0)
{
frameLength=GetBuffer[1]+3;
int a=StrToInt(frameLength);
if(a<50)
{
if(BufferLength>=frameLength)
{
Byte checkSum=GetBuffer[frameLength-1]; //取校验值
if(checkSum==CheckSum(GetBuffer,frameLength))
{
Byte dataType=GetBuffer[2];
int user=0; //废话 但是没他不能在switch里定义变量
switch(dataType)
{ //BCB的swicth case语句不能独自定义变量
case 0x00: //PC开机界面应答指令
if(user==0)
{
Byte data1 = GetBuffer[3]; //应答指令类型
Byte data2 = GetBuffer[4]; //是否成功应答
if (data1 == 0x00 && data2 == 0xFF) //PC开机应答
{
isReceive = true;
isSend = true;
//
Byte sourceByte[13];
for (int i = 5; i
sourceByte[i-5] = GetBuffer[i];
}
DynamicArray
encryptionByte = dataEncryption(sourceByte);
Byte cmdByte[17]= { 0x0A, 0x0E, 0x00, 0x02, encryptionByte[0], encryptionByte[1], encryptionByte[2], encryptionByte[3], encryptionByte[4], encryptionByte[5], encryptionByte[6], encryptionByte[7], encryptionByte[8], encryptionByte[9], encryptionByte[10], encryptionByte[11], 0x00 };
Byte checkNumber = CheckSum(cmdByte); //自己校验
cmdByte[16] = checkNumber;
Memo1->Lines->Add("发出校验 等回复");
}
}
break;
default:
break;
}
}
我的程序用到的通讯协议,是比较复杂的,有个开机校验,就是你发出开机指令后他会给你一组加密的数据你必须解析出来,然后发给ARM,不然通,你发什么指令都没用。。
至于这个加密,就不过多的赘述了,毕竟不是每个人的串口程序都会涉及到加密。。加密方法是各种各样的。。。