C++ builder 多进程串口2 数据的存储和处理。

               数据处理,要保证不重复不漏掉,效率还要高,不做多余的循环。。

              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;
           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,不然通,你发什么指令都没用。。

            至于这个加密,就不过多的赘述了,毕竟不是每个人的串口程序都会涉及到加密。。加密方法是各种各样的。。。

 

你可能感兴趣的:(C++builder,技术文章,串口通讯)