在多设备的串口通信中,用什么方法同时进行多串口的通信(发送AT指令和接收数据),程序能较高的效率运行,请提供方法,最好用什么控件?

解决方案 »

  1.   

    unit TestComUnit;interfaceuses
      Windows, Messages, SysUtils, DateUtils;var
      h_Thread: THandle;       //线程句柄
      ThreadEvent: THandle;    //线程同步事件procedure TestCom(P: Pointer); stdcall;implementation
    uses
      CommonUnit,DmUnit;procedure ChangeLineState(dType: Byte; dNum: WORD; State: Byte); //通知设备状态窗口,通信状态改变
    var
      W: integer;
    begin
      if SsJkHandle>0 then  //如果设备状态显示窗口存在
      begin
        W:=dType;
        W:=W shl 16;
        W:=W or dNum; //W的高16位代表设备类型,低16位代表设备编号
        PostMessage(SsJkHandle,WM_CHANGELINESTATE,W,State); //lParam为1表示通信故障,0表示通信正常
      end;
    end;procedure TestOnLine(p_DkXx: PDkXx); //设备通信测试函数
    var
      Nbw: LongWord;
      SndStr: string;
      Coms: TComStat;
      lpErrors: Cardinal;
      i: integer;
    begin
      if p_DkXx^.hCom>0 then
      begin
        SndStr:=p_DkXx^.TestStr;
        PurgeComm(p_DkXx^.hCom,PURGE_TXABORT+PURGE_RXABORT+PURGE_TXCLEAR+PURGE_RXCLEAR);
        WriteFile(p_DkXx^.hCom,Pointer(SndStr)^,Length(SndStr),Nbw,nil);    for i:=1 to 10 do
        begin
          Sleep(300);
          if WaitForSingleObject(ThreadEvent,10)=WAIT_TIMEOUT then  //说明线程要退出。
            Break;
          ClearCommError(p_DkXx^.hCom,lpErrors,@Coms);
          if Coms.cbInQue>0 then  //说明设备返回了数据,说明通信是正常的。
          begin
            if not p_DkXx^.isOnline then  //原来是通信异常
            begin
              p_DkXx^.isOnline:=True; //把通信状态设为正常
              ChangeLineState(Ord(p_DkXx^.LX),p_DkXx^.BH,0);
            end;
            Break;
          end
          else //如果设备未返回消息
            if (i=10)and(p_DkXx^.isOnline) then  //原来是通信正常
            begin
              p_DkXx^.isOnline:=False; //把通信状态设为异常
              ChangeLineState(Ord(p_DkXx^.LX),p_DkXx^.BH,1);
            end;
        end;
      end
      else //如果没有创建端口,说明通信肯定异常
        if p_DkXx^.isOnline then
        begin
          p_DkXx^.isOnline:=False;
          ChangeLineState(Ord(p_DkXx^.LX),p_DkXx^.BH,1);
        end;
    end;function Parse_CJ_Data(var Buf: array of Byte; var Len: Cardinal; P: Pointer): Boolean;
      procedure Parse_Date(var YY,MM,DD: WORD; P: Pointer); 
      var
        Y: WORD;
        M,D,L: Byte;
        bP: ^Byte;
      begin
        bP:=P;
        Inc(bP);
        Y:=0;
        Y:=(Y+bP^) shl 8;
        Inc(bP);
        Y:=(Y+bP^) shr 1;
        M:=(bP^ and $01);
        M:=M shl 3;
        Inc(bP);
        L:=bP^ and $E0;
        M:=M+L shr 5;
        D:=bP^ and $1F;
        YY:=Y;
        MM:=M;
        DD:=D;
      end;
      
      procedure Parse_Time(var HH,MM,SS: WORD; P: Pointer); 
      var
        H,M,S,L: Byte;
        bP: ^Byte;
      begin
        bP:=P;
        H:=bP^ and $07;
        H:=H shl 2;
        Inc(bP);
        L:=bP^ and $C0;
        L:=L shr 6;
        H:=H+L;
        M:=bP^ and $3F;
        Inc(bP);
        S:=bP^ shr 2;
        HH:=H;
        MM:=M;
        SS:=S;
      end;var
      bP: ^Byte;
      W,Lan,wL,C: WORD;
      i,j,X: WORD;
      dL: DWORD;
      lDT: TDateTime;
      Year,Month,Day,Hour,Minute,Second: WORD;
      lTpoint: pTpoint;
      L: integer;
    begin
      Result:=False;
      try
        L:=-1;
        for i:=0 to Len-1 do
          if (Buf[i]=$5A)and(Buf[i+1]=$31)and((i+672)<=Len)and(ComputeCrc8(@Buf[i],10)=Buf[i+10]) then
          begin
            L:=i;
            Break;
          end;
        if L>-1 then
        begin
          lTpoint:=P;
          C:=0;
          for i:=0 to 5 do 
          begin
            X:=L+i*112;                                                 
            if (Buf[X]=$5A)and(Buf[X+1]=$31)and(ComputeCrc8(@Buf[X+11],$64)=Buf[X+111]) then 
            begin
              bP:=@Buf[X+17];
              Lan:=bP^+1;           Inc(bP); 
              Parse_Date(Year,Month,Day,bP);
              Inc(bP,4); 
              Parse_Time(Hour,Minute,Second,bP);
              lDT:=EncodeDateTime(Year,Month,Day,Hour,Minute,0,0);
              lTpoint^.Time:=IncHour(lDT,8);           Inc(bP,8); 
              if (bP^ and $80)>0 then  
              begin
                if (bP^ or $80)=$80 then
                begin
                  W:=bP^ and $7F;
                  W:=W shl 8;
                  Inc(bP);
                  W:=W or bP^;
                  Inc(bP);
                  lTpoint^.Lane[Lan].AveSpd:=Round(W+(bP^/256)); 
                end
                else  
                begin
                  W:=bP^;
                  W:=W shl 8;
                  Inc(bP);
                  W:=W or bP^;
                  W:=$FFFF xor W;
                  lTpoint^.Lane[Lan].AveSpd:=W+1;
                end;
              end
              else
              begin
                Inc(bP,2);
                lTpoint^.Lane[Lan].AveSpd:=0;
              end;          Inc(bP);
              dL:=bP^;
              dL:=dL shl 16;
              Inc(bP);
              dL:=(dL or bP^) shl 8;
              Inc(bP);
              dL:=dL or bP^;
              lTpoint^.Lane[Lan].Volume:=dL;           Inc(bP); 
              wL:=bP^;
              Inc(bP);
              lTpoint^.Lane[Lan].AveOcy:=wL+bP^/256;           Inc(bP,11); 
              for j:=1 to 5 do
              begin
                Inc(bP);
                dL:=bP^;
                dL:=dL shl 16;
                Inc(bP);
                dL:=(dL or bP^) shl 8;
                Inc(bP);
                dL:=dL or bP^;
                lTpoint^.Lane[Lan].LenBin[j]:=dL; 
              end;
              
              Inc(C);
            end
            else
              Break;
          end;
          if C=6 then
            Result:=True;
        end;
      except
        Result:=False;
      end;
    end;function Get_CJ_Data(p_DkXx: PDkXx; var lSJ: TTPoint; SndStr: string): Boolean;
    var
      j: integer;
      Coms: TComStat;
      Nbw: LongWord;
      lpErrors,cbNum,ReadLen,Len: Cardinal;
      Buf: array[0..1023] of Byte;
      RecvS: array[0..1023] of Byte;
    begin
      Result:=False;  PurgeComm(p_DkXx^.hCom,PURGE_TXABORT+PURGE_RXABORT+PURGE_TXCLEAR+PURGE_RXCLEAR);
      WriteFile(p_DkXx^.hCom,Pointer(SndStr)^,Length(SndStr),Nbw,nil);
      Len:=0;
      for j:=1 to 10 do
      begin
        Sleep(300);
        if WaitForSingleObject(ThreadEvent,10)=WAIT_TIMEOUT then
          Break; //等待超时,说明线程要退出
          
        ClearCommError(p_DkXx^.hCom,lpErrors,@Coms);
        if Coms.cbInQue>0 then
        begin
          cbNum:=Coms.cbInQue;
          if ReadFile(p_DkXx^.hCom,Buf,cbNum,ReadLen,nil) then
          begin
            CopyMemory(@RecvS[Len],@Buf,ReadLen);
            Len:=Len+ReadLen;
          end;
        end;
        if Len>=672 then 
          Break;
      end;  if Len>=672 then
      begin
        ZeroMemory(@lSJ,SizeOf(TTpoint)); //清空临时存放时间点数据的内存
        if Parse_CJ_Data(RecvS,Len,@lSJ) then
          Result:=True;
      end;  if (Len>0)and(not p_DkXx^.isOnline) then //原来是通信异常
      begin
        p_DkXx^.isOnline:=True; //把通信状态设为正常
        ChangeLineState(Ord(p_DkXx^.LX),p_DkXx^.BH,0);
      end
      else
        if (Len=0)and(p_DkXx^.isOnline) then
        begin
          p_DkXx^.isOnline:=False; //把通信状态设为异常
          ChangeLineState(Ord(p_DkXx^.LX),p_DkXx^.BH,1);
        end;
    end;procedure GetData(p_DkXx: PDkXx); //获取数据函数
    var
      lSJ: TTpoint;
      BH: integer;
      L_ane: TLane;
      Y,M,OldD,NewD: WORD;
    begin
      if p_DkXx^.hCom>0 then 
      begin
        case p_DkXx^.LX of
         'C': begin  
                if Get_CJ_Data(p_DkXx,lSJ,p_DkXx^.GetStr) then
                begin
                  lSJ.isFill:=True;
                  BH:=p_DkXx^.BH;
                  p_DkXx^.cTime:=GetTickCount;                if BH=3 then //如果是3号车检,要把车道顺序颠倒
                  begin
                    L_ane:=lSJ.Lane[1];
                    lSJ.Lane[1]:=lSJ.Lane[6];
                    lSJ.Lane[6]:=L_ane;
                    L_ane:=lSJ.Lane[2];
                    lSJ.Lane[2]:=lSJ.Lane[5];
                    lSJ.Lane[5]:=L_ane;
                    L_ane:=lSJ.Lane[3];
                    lSJ.Lane[3]:=lSJ.Lane[4];
                    lSJ.Lane[4]:=L_ane;
                  end;              if DateTimeToStr(lSJ.Time)<>DateTimeToStr(Sensor[BH].Tpoint[CSHOWCOUNT].Time) then  
                  begin
                    DecodeDate(lSJ.Time,Y,M,NewD);
                    DecodeDate(Sensor[BH].Tpoint[CSHOWCOUNT].Time,Y,M,OldD);                MoveMemory(@(Sensor[BH].Tpoint[1]),@(Sensor[BH].Tpoint[2]),SizeOf(TTpoint)*(CSHOWCOUNT-1));
                    CopyMemory(@(Sensor[BH].Tpoint[CSHOWCOUNT]),@lSJ,SizeOf(TTpoint));
                    CJ_CommitDatabase(@lSJ,BH);
                    if SsJkHandle>0 then
                      PostMessage(SsJkHandle,WM_SHOWCJDATA,BH,CSHOWCOUNT); //通知状态窗口显示最后一个元素                SendMnp(Sensor[BH].Tpoint[CSHOWCOUNT],BH); //把新收到的数据发往模拟屏                if OldD<>NewD then 
                      MergeData(DateToStr(EncodeDate(Y,M,OldD)),BH); //合并此车检这一天的数据
                  end;
                end;
              end;
        end;
      end
      else //如果没有创建端口,说明通信肯定异常
        if p_DkXx^.isOnline then
        begin
          p_DkXx^.isOnline:=False; //把通信状态设为异常
          ChangeLineState(Ord(p_DkXx^.LX),p_DkXx^.BH,1);
        end;
    end;procedure TestCom(P: Pointer); stdcall;  //通信测试线程函数
    var
      AID,i: integer;
      ThreadExit: Boolean;
    begin
      AID:=0;
      ThreadExit:=False;
      while not ThreadExit do //通信测试循环
      begin
        EnterCriticalSection(DkXx[AID].Section); //进入临界区
        try
          if (DkXx[AID].LX<>'X')and(DkXx[AID].LX<>'M') then //不是大小情报板
          begin
            if Abs(GetTickCount-DkXx[AID].cTime)>=DkXx[AID].TimeJG then //到设定时间时取数据
              GetData(@DkXx[AID]) //到时间时取数据
            else //未到时间时测试通信情况,不取数据
              TestOnLine(@DkXx[AID]);
          end
          else //如果是大小情报板,则只是测试通信,不获取数据。
            TestOnLine(@DkXx[AID]);
        finally
          LeaveCriticalSection(DkXx[AID].Section); //离开临界区
        end;
                                                     
        Inc(AID);
        if AID>High(DkXx) then
          AID:=0;    for i:=1 to 10 do //延时
          if WaitForSingleObject(ThreadEvent,10)=WAIT_TIMEOUT then //如果超时,则退出线程
          begin
            ThreadExit:=True;
            Break;
          end
          else
            Sleep(50);
      end;  SetEvent(ThreadEvent);     
    end;initialization
      ThreadEvent:=CreateEvent(nil,True,True,'XcGsTxEvt'); //创建线程同步信号finalization
      CloseHandle(ThreadEvent);
      DeleteObject(ThreadEvent);end.
      

  2.   

    多线程处理,如果之前这方面经验欠缺,可直接考虑使用spcomm,使用简单易上手!
      

  3.   

    用CPORT3.1 自己建立收发线程,绝对OK!
      

  4.   

    用CPORT3.1 ,每个串口建立发线程没有问题,那收线程应该怎么处理呢?