各位大牛,你们在串口开发时,选用的是哪种组件,哪种最稳定?最好用? 
理由是什么?
1. Cport
2. CnRS232
3. MScom
4. SPCOM 
5. 其他组件

解决方案 »

  1.   

    因为就用过spcom,呵呵
    我说是我啊
      

  2.   

    comport3使用简单,有完整的例子。
    稳定,用了5年。
      

  3.   

    第4个最好。用过后你就知道。纯API的封装,开源,不需要额外文件来支持。
      

  4.   

    //串口对象
    // 王昌雨 
    // 2007.05
    // [email protected]
    //
    unit ComPortU;interfaceuses Windows, SysUtils, Classes;const
      COM_BLOCK=1024;type
      TBaudRate = (brCustom, br110, br300, br600, br1200, br2400, br4800, br9600, br14400,
        br19200, br38400, br56000, br57600, br115200, br128000, br256000);
      TDataBits = (dbFive, dbSix, dbSeven, dbEight);
      TStopBits= (sb1,sb15,sb2);
      TParityBits = (prNone, prOdd, prEven, prMark, prSpace);
      TDTRFlowControl = (dtrDisable, dtrEnable, dtrHandshake);
      TRTSFlowControl = (rtsDisable, rtsEnable, rtsHandshake, rtsToggle);type
      TComEvent = (evRxChar, evTxEmpty, evRxFlag, evRing, evBreak, evCTS, evDSR,
        evError, evRLSD, evRx80Full);
      TComEvents = set of TComEvent;  type
      TRxCharEvent=procedure(Sender:TObject; Count:Integer) of Object;  
       
    type
       TComPort=Class;
       TComThread=Class(TThread)
       private
          fComPort: TComPort;
          FStopEvent: THandle;
          FEvents:  DWord;
          procedure DoEvents;
          procedure DispatchComMsg;
        protected
          procedure Execute; override;
        public
          constructor Create(AComPort: TComPort);
          destructor Destroy; override;
       end;   TComParity = class(TPersistent)
       private
         FComPort: TComPort;
         FBits: TParityBits;
         FCheck: Boolean;
         FReplace: Boolean;
         FReplaceChar: Char;
         procedure SetComPort(const AComPort: TComPort);
         procedure SetBits(const Value: TParityBits);
         procedure SetCheck(const Value: Boolean);
         procedure SetReplace(const Value: Boolean);
         procedure SetReplaceChar(const Value: Char);
       protected
         procedure AssignTo(Dest: TPersistent); override;
       public
         constructor Create;
         property ComPort: TComPort read FComPort;
       published
         property Bits: TParityBits read FBits write SetBits;
         property Check: Boolean read FCheck write SetCheck default False;
         property Replace: Boolean read FReplace write SetReplace default False;
         property ReplaceChar: Char read FReplaceChar write SetReplaceChar default #0;
       end;     TComPort=Class
       private
         fConnected: Boolean;
         fHandle:THandle;
         fPort: String;
         fTag: Integer;
         FParity: TComParity;
         fStopBits: TStopBits;
         fDataBits: TDataBits;
         fBaudRate: TBaudRate;
         fThrdCreated:Boolean; //创建线程
         fOverlapped:TOverlapped;
         fComThread: TComThread;
         //FControlDTR: TDTRFlowControl;
         //FControlRTS: TRTSFlowControl;
         fRxEvent:  TRxCharEvent;
         procedure  SetComDataBits(AValue: TDataBits);
         procedure  SetComStopBits(AValue: TStopBits);
         procedure  SetParityBits(AValue: TComParity);
         procedure  SetBaudRate(AValue: TBaudRate);
         function   WaitForComData(Read_not_Write:Boolean):Integer;
         Function   SetCommPortTimeout:Boolean;
         Function   SetComPortParas:Boolean;        //设置参数
         procedure  CallComRxCharEvent;  //串口事件
         function   ReciveLength:Integer;  //接受的数据长度
       public
         constructor  Create;
         destructor   Destroy; override;
         function   Open:Boolean;
         procedure  Close;
         function   ReadData(const Len: Integer ;var Buf ):Integer;
         function   WriteData(const Len: Integer; const Data):Integer;
         function   WriteStr(Str:String):Integer;
         function   ReadStr(Len:Integer; var Str:String):Integer;   ///     property  Handle : THandle read fHandle;
         property  Port: String read fPort write fPort;
         property  Tag: Integer read fTag write fTag;
         property  Connected:Boolean read fConnected;  //串口是否已打开
         property  RecLen: Integer read ReciveLength;  //接收数据长度 
         property  DataBits:  TDataBits read fDataBits write SetComDataBits;
         property  StopBits:  TStopBits read fStopBits write SetComStopBits;
         property  Parity: TComParity  read FParity write SetParityBits;
         property  BaudRate:   TBaudRate read fBaudRate write SetBaudRate;
         property  RxCharEvent: TRxCharEvent read fRxEvent write fRxEvent;
         //property  ControlDTR: TDTRFlowControl read FControlDTR write SetControlDTR;
         //property  ControlRTS: TRTSFlowControl read FControlRTS write SetControlRTS;   end;
      function BaudRateToStr(BaudRate: TBaudRate): string;
      function StopBitsToStr(StopBits: TStopBits): string;
      function DataBitsToStr(DataBits: TDataBits): string;
      function StrToBaudRate(Str: string): TBaudRate;
      function StrToStopBits(Str: string): TStopBits;
      function StrToDataBits(Str: string): TDataBits;   implementationfunction BaudRateToStr(BaudRate: TBaudRate): string;
    const
      BaudRateStrings: array[TBaudRate] of string = ('Custom', '110', '300', '600',
        '1200', '2400', '4800', '9600', '14400', '19200', '38400', '56000', '57600',
        '115200', '128000', '256000');
    begin
      Result := BaudRateStrings[BaudRate];
    end;// stop bits to string
    function StopBitsToStr(StopBits: TStopBits): string;
    const
      StopBitsStrings: array[TStopBits] of string = ('1', '1.5', '2');
    begin
      Result := StopBitsStrings[StopBits];
    end;// data bits to string
    function DataBitsToStr(DataBits: TDataBits): string;
    const
      DataBitsStrings: array[TDataBits] of string = ('5', '6', '7', '8');
    begin
      Result := DataBitsStrings[DataBits];
    end;// string to baud rate
    function StrToBaudRate(Str: string): TBaudRate;
    var
      I: TBaudRate;
    begin
      I := Low(TBaudRate);
      while (I <= High(TBaudRate)) do  begin
        if UpperCase(Str) = UpperCase(BaudRateToStr(TBaudRate(I))) then  Break;
        I := Succ(I);
      end;
      if I > High(TBaudRate) then Result := br9600 else  Result := I;
    end;// string to stop bits
    function StrToStopBits(Str: string): TStopBits;
    var
      I: TStopBits;
    begin
      I := Low(TStopBits);
      while (I <= High(TStopBits)) do begin
        if UpperCase(Str) = UpperCase(StopBitsToStr(TStopBits(I))) then Break;
        I := Succ(I);
      end;
      if I > High(TStopBits) then Result := sb1 else Result := I;
    end;// string to data bits
    function StrToDataBits(Str: string): TDataBits;
    var
      I: TDataBits;
    begin
      I := Low(TDataBits);
      while (I <= High(TDataBits)) do  begin
        if UpperCase(Str) = UpperCase(DataBitsToStr(I)) then  Break;
        I := Succ(I);
      end;
      if I > High(TDataBits) then    Result := dbEight  else  Result := I;
    end;
    ///////////////////////////TComThread
    constructor TComThread.Create(AComPort: TComPort);
    begin
      inherited Create(True);
      FStopEvent := CreateEvent(nil, True, False, nil);
      FComPort := AComPort;
      SetCommMask(FComPort.Handle, EV_RXCHAR);  //仅关心 EV_RXCHAR 事件
      Resume;  //执行
    end;destructor TComThread.Destroy;
    begin
      SetEvent(FStopEvent);
      Sleep(0);  
      inherited Destroy;
    end;
    procedure TComThread.DispatchComMsg;
    begin
      Synchronize(DoEvents);
    end;procedure TComThread.DoEvents;
    begin
      if (FEvents and EV_RXCHAR)<>0 then fComPort.CallComRxCharEvent;
    end;procedure TComThread.Execute;
    var
      EventHandles: array[0..1] of THandle;
      Overlapped: TOverlapped;
      Signaled, BytesTrans, Mask: DWORD;
    begin
      FillChar(Overlapped, SizeOf(Overlapped), 0);
      Overlapped.hEvent := CreateEvent(nil, True, True, nil);
      EventHandles[0] := FStopEvent;
      EventHandles[1] := Overlapped.hEvent;
      repeat
        // wait for event to occur on serial port
        WaitCommEvent(FComPort.Handle, Mask, @Overlapped);
        Signaled := WaitForMultipleObjects(2, @EventHandles, False, INFINITE);
        // if event occurs, dispatch it
        if (Signaled = WAIT_OBJECT_0 + 1)
            and GetOverlappedResult(FComPort.Handle, Overlapped, BytesTrans, False)
            then begin
          FEvents := Mask;
          DispatchComMsg;
        end;
      until Signaled <> (WAIT_OBJECT_0 + 1);
      // clear buffers
      SetCommMask(FComPort.Handle, 0);
      PurgeComm(FComPort.Handle, PURGE_TXCLEAR or PURGE_RXCLEAR);
      CloseHandle(Overlapped.hEvent);
      CloseHandle(FStopEvent);
    end;
    { TComParity }constructor TComParity.Create;
    begin
      inherited Create;
      FBits := prNone;
    end;// copy properties to other class
    procedure TComParity.AssignTo(Dest: TPersistent);
    begin
      if Dest is TComParity then  begin
        with TComParity(Dest) do    begin
          FBits        := Self.Bits;
          FCheck       := Self.Check;
          FReplace     := Self.Replace;
          FReplaceChar := Self.ReplaceChar;
        end
      end else  inherited AssignTo(Dest);
    end;// select TCustomComPort to own this class
    procedure TComParity.SetComPort(const AComPort: TComPort);
    begin
      FComPort := AComPort;
    end;// set parity bits
    procedure TComParity.SetBits(const Value: TParityBits);
    begin
      if Value <> FBits then begin
        FBits := Value;
        if FComPort <> nil then FComPort.SetComPortParas;
      end;
    end;// set check parity
    procedure TComParity.SetCheck(const Value: Boolean);
    begin
      if Value <> FCheck then begin
        FCheck := Value;
        if FComPort <> nil  then FComPort.SetComPortParas;
      end;
    end;// set replace on parity error
    procedure TComParity.SetReplace(const Value: Boolean);
    begin
      if Value <> FReplace then begin
        FReplace := Value;
        if FComPort <> nil then FComPort.SetComPortParas;
      end;
    end;// set replace char
    procedure TComParity.SetReplaceChar(const Value: Char);
    begin
      if Value <> FReplaceChar then begin
        FReplaceChar := Value;
        if FComPort <> nil then FComPort.SetComPortParas;
      end;
    end;
    //////////////////////////////////
      

  5.   

    constructor TComPort.Create;
    begin
      inherited Create;
      fHandle:=INVALID_HANDLE_VALUE;
      fTag:=0;
      fConnected:=False;
      fPort:='COM1';
      fBaudRate:=br9600;
      fDataBits:=dbEight;
      fStopBits:=sb1;
      fThrdCreated:=False;
      FParity := TComParity.Create;
      FParity.SetComPort(Self);
    end;destructor  TComPort.Destroy;
    begin
      Self.Close;
      FParity.Free;
      inherited Destroy;
    end;procedure TComPort.CallComRxCharEvent;  //串口事件
    var
      Len:Integer;
    begin
      Len:=ReciveLength;
      if (Len>0) and Assigned(fRxEvent) then fRxEvent(Self,Len); 
    end;function TComPort.Open: Boolean;
    begin
      if not fConnected then begin  // if already connected, do nothing
        // open port
        FHandle := CreateFile(PChar('\\.\' + FPort),
                              GENERIC_READ or GENERIC_WRITE,
                              0,
                              nil,
                              OPEN_EXISTING,
                              FILE_FLAG_OVERLAPPED,
                              0);
        Result:=FHandle<>INVALID_HANDLE_VALUE;
        if Result then Result:=GetFileType( FHandle )=FILE_TYPE_CHAR;
        if not Result then begin
          CloseHandle(FHandle);
          Exit;  //raise Exception.Create( 'File handle is not a comm handle ' );
        end;
        Result:=SetupComm( FHandle, COM_BLOCK, COM_BLOCK );
        if not Result then begin
          CloseHandle( FHandle );
          Exit; //raise Exception.Create( 'Cannot setup comm buffer' );
        end;
        Result:=PurgeComm( FHandle, PURGE_TXABORT or PURGE_RXABORT or PURGE_TXCLEAR or PURGE_RXCLEAR );
        if not Result then begin
          CloseHandle( FHandle );
          Exit; //raise Exception.Create( 'Cannot clear comm buffer' );
        end;
        Result:=SetCommPortTimeout;
        if not Result then begin
          CloseHandle( FHandle );
          Exit; //raise Exception.Create( 'Setup COM TimeOut Error' );
        end;
        Result:=SetComPortParas;
        if not Result then begin
          CloseHandle( FHandle );
          Exit; //raise Exception.Create( 'Setup COM Dcb Paramstrs Error' );
        end;
        FConnected := True;
        // if at least one event is set, create special thread to monitor port
        fComThread := TComThread.Create(Self);
        fThrdCreated := True;
      end else Result:=True;
    end;Function TComport.SetCommPortTimeout:Boolean;
    var
      ctout:   TCommTimeouts;
    begin
      ctout.ReadIntervalTimeout:=MAXDWORD;
      ctout.ReadTotalTimeoutMultiplier:=0;
      ctout.ReadTotalTimeoutConstant:=0;
      ctout.WriteTotalTimeoutMultiplier:=0;
      ctout.WriteTotalTimeoutConstant:=0;
      Result:=SetCommTimeouts(fHandle, ctout);
    end;procedure TComPort.Close;
    begin
      // if already closed, do nothing
      if FConnected  then begin
        PurgeComm(FHandle, PURGE_TXABORT or PURGE_RXABORT);
        // stop monitoring for events
        if fThrdCreated then  begin
          fComThread.Free;
          fThrdCreated:= False;
        end;
        // close port
        if FHandle <> INVALID_HANDLE_VALUE then CloseHandle(FHandle);
        FConnected := False;
      end;
    end;function TComPort.ReadData( const Len: Integer ; var Buf ): Integer;
    var
      wok: Boolean;
      BytesTrans: DWORD;
    begin
      FillChar(fOverlapped, SizeOf(TOverlapped), 0);
      fOverlapped.hEvent:=CreateEvent( nil, True, False, nil );
      wok := ReadFile(fHandle, Buf, Len, BytesTrans, @fOverlapped) or
             (GetLastError = ERROR_IO_PENDING);
      if not wok then begin
        CloseHandle(fOverlapped.hEvent);
        Raise Exception.Create('read data from ComPort Error ');
      end;
      Result:=WaitForComData(True);
      CloseHandle(fOverlapped.hEvent);
    end;function TComPort.ReadStr(Len: Integer; var Str: String): Integer;
    var
      i1:Integer;
      fc:Array[0..COM_BLOCK-1] of Char;
    begin
      Str:='';
      if Len>0 then begin
        Result:=ReadData(Len,fc[0]);
        for i1:=1 to Result do Str:=Str+fc[i1-1];
      end else Result:=0;
    end;function TComPort.WriteData(const Len: Integer ;const Data): Integer;
    var
      Wok: Boolean;
      BytesTrans: DWORD;
    begin
      FillChar(fOverlapped, SizeOf(TOverlapped), 0);
      fOverlapped.hEvent:=CreateEvent( nil, True, False, nil );
      Wok :=WriteFile(fHandle, Data, Len, BytesTrans, @fOverlapped) or
            (GetLastError = ERROR_IO_PENDING);
      if not wok then begin
        CloseHandle(fOverlapped.hEvent);
        Raise Exception.Create('Write Data To ComPort Error ');
      end;
      Result:=WaitForComData(False);
      CloseHandle(fOverlapped.hEvent);
    end;function TComPort.WriteStr(Str: String): Integer;
    var
      sl:Integer;
    begin
      sl:=Length(Str);
      if sl>0 then Result:=WriteData(sl,Str[1]) else Result:=0;
    end;function TComPort.ReciveLength: Integer;
    var
      Errors: DWORD;
      ComStat: TComStat;
    begin
      if not ClearCommError(fHandle, Errors, @ComStat) then
          raise Exception.Create('clear commerror error ');
      Result := ComStat.cbInQue;
    end;function TComPort.SetComPortParas: Boolean;
    const
      CBaudRate: array[TBaudRate] of Integer =
        (0, CBR_110, CBR_300, CBR_600, CBR_1200, CBR_2400, CBR_4800, CBR_9600,
         CBR_14400, CBR_19200, CBR_38400, CBR_56000, CBR_57600, CBR_115200,
         CBR_128000, CBR_256000);
      CStopBits: array[TStopBits] of Integer =
        (ONESTOPBIT, ONE5STOPBITS, TWOSTOPBITS);
      CDataBits: array[TDataBits] of Integer = (5, 6, 7, 8);
      CControlRTS: array[TRTSFlowControl] of Integer =
        (RTS_CONTROL_DISABLE shl 12,
         RTS_CONTROL_ENABLE shl 12,
         RTS_CONTROL_HANDSHAKE shl 12,
         RTS_CONTROL_TOGGLE shl 12);
      CControlDTR: array[TDTRFlowControl] of Integer =
        (DTR_CONTROL_DISABLE shl 4,
         DTR_CONTROL_ENABLE shl 4,
         DTR_CONTROL_HANDSHAKE shl 4);
      CParityBits: array[TParityBits] of Integer =
        (NOPARITY, ODDPARITY, EVENPARITY, MARKPARITY, SPACEPARITY);
    var
       dcb:            Tdcb;
       commprop:       TCommProp;
       fdwEvtMask:     DWORD;
    begin
      Result:=GetCommState( fHandle, dcb );
      if Result then Result:=GetCommProperties( fHandle, commprop );
      if Result then Result:=GetCommMask( fHandle, fdwEvtMask );
      if Result then begin
        dcb.DCBlength:=SizeOf(dcb);
        DCB.XonChar:=#17;
        Dcb.XoffChar:=#19;
        DCB.XonLim := COM_BLOCK;
        DCB.XoffLim := DCB.XonLim;
        DCB.EvtChar := #0;
        Dcb.ErrorChar:=#0;
        DCB.Flags := 1;
        //if FOutx_CtsFlow then    dcb.Flags := dcb.Flags or 4;
        //if FOutx_DsrFlow then    dcb.Flags := dcb.Flags or 8;
        //if FDsrSensitivity then  dcb.Flags := dcb.Flags or $40;
        //if FTxContinueOnXoff then  dcb.Flags := dcb.Flags or $80;
        //if fXonXoffOut then DCB.Flags := DCB.Flags or $100;
        //if fXonXoffIn then  DCB.Flags := DCB.Flags or $200;
        //if FReplaceWhenParityError then dcb.Flags := dcb.Flags or $400;
        //if FDisCardNull then  dcb.Flags := dcb.Flags or $800;
        DCB.Flags := DCB.Flags or CControlDTR[dtrEnable] or CControlRTS[rtsEnable];
        //custom set
        Dcb.ByteSize:=CDataBits[fDataBits];
        dcb.StopBits:=CStopBits[fStopBits];
        dcb.BaudRate:=CBaudRate[fBaudRate];
        DCB.Parity := CParityBits[FParity.Bits];
        if FParity.Check then begin
          DCB.Flags := DCB.Flags or $02;
          if FParity.Replace then begin
            DCB.Flags := DCB.Flags or $0400;
            DCB.ErrorChar := Char(FParity.ReplaceChar);
          end;
        end;
        Result:=SetCommState(fHandle,dcb);
      end;
    end;function TComPort.WaitForComData(Read_not_Write: Boolean): Integer;
    var
      Wok: Boolean;
      BytesTrans,Signaled: DWORD;
    begin
      Signaled:=WaitForSingleObject(fOverlapped.hEvent,INFINITE);
      wok:=(Signaled = WAIT_OBJECT_0) and
           (GetOverlappedResult(fHandle, fOverlapped, BytesTrans, False));
      if not wok then begin
        if Read_not_Write then begin
          Raise Exception.Create('Read Data Form '+fPort+' Error ');
        end else begin
          Raise Exception.Create('Write Data To '+fPort+' Error ');
        end;
      end;
      Result := BytesTrans;
    end;
    procedure TComPort.SetBaudRate(AValue: TBaudRate);
    begin
      if fBaudRate<>AValue then begin
        fBaudRate:=AValue;
        if fConnected then begin
          if not SetComPortParas then raise Exception.Create( 'Setup COM Dcb Paramstrs Error' );
        end;
      end;
    end;procedure TComPort.SetComDataBits(AValue: TDataBits);
    begin
      if fDataBits<>AValue then begin
        fDataBits:=AValue;
        if fConnected then begin
          if not SetComPortParas then raise Exception.Create( 'Setup COM Dcb Paramstrs Error' );
        end;
      end;
    end;procedure TComPort.SetComStopBits(AValue: TStopBits);
    begin
      if fStopBits<>AValue then begin
        fStopBits:=AValue;
        if fConnected then begin
          if not SetComPortParas then raise Exception.Create( 'Setup COM Dcb Paramstrs Error' );
        end;
      end;
    end;procedure TComPort.SetParityBits(AValue: TComParity);
    begin
      FParity.Assign(AValue);
      if fConnected then begin
        if not SetComPortParas then raise Exception.Create( 'Setup COM Dcb Paramstrs Error' );
      end;
    end;end.//使用
      fComPort:=TComPort.Create;
      fComPort.RxCharEvent:=SysComDataEvent;SysComDataEvent(Sender:TObject; Count:Integer);
    var
      s:String;
    begin
      TComPort(Sender).ReadStr(Count,s);
    end;
      

  6.   

    comport3 相对稳定点,响应速度也快
    spcomm,有个问题,就是接收缓冲满了才返回,响应速度跟不上,稳定性也可以
    mscomm,需要用变体才能正确发送如果实时性要求不高,用spcomm,
    如果响应速度高一点,用comport3
    spcomm,和comport3,接收部分,几乎不用改代码就可以套用
      

  7.   

    用api方式最稳定,但是spcom很不错。
      

  8.   

    用过CPort 3, 挺稳定,速度也可以。 
      

  9.   

    PComm.dll这个动态链接库可以,提供了很多接口函数,功能比SPCOMM全面,但就是复杂一些!
      

  10.   

    我偏向于使用MSComm控件和API函数