各位大牛,你们在串口开发时,选用的是哪种组件,哪种最稳定?最好用?
理由是什么?
1. Cport
2. CnRS232
3. MScom
4. SPCOM
5. 其他组件
理由是什么?
1. Cport
2. CnRS232
3. MScom
4. SPCOM
5. 其他组件
解决方案 »
- 关于delphi7访问SQL同义词的怪异现象!在线等!
- delphi如何进行对象序列化和反序列化?
- 菜鸟求助[Fatal Error] Unit1.pas(6): File not found: 'MessageBox.dcu'的问题!
- fastreport2.5怎么修改预览值?
- 如何运用Delphi编写Windows NT中服务程序并调试?100分相送。
- 有谁有第一届 borland竞赛的源码吗?
- 又一个dxDBGrid 的 问题?
- 把文件写入sql server 字段里?
- spcomm控件接收数据出现乱码有哪些可能的原因
- 怎样把一个由PARADOX建立的表的内容变成TEXT文件,由EMAIL传送
- 春节散分,顺祝战友们全家身体健康,兔年吉祥如意
- 请问:如何用TRMReport控件打印TImage控件中的图片?TRMReport控件如何和TImage控件相关联呢?
我说是我啊
稳定,用了5年。
// 王昌雨
// 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;
//////////////////////////////////
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;
spcomm,有个问题,就是接收缓冲满了才返回,响应速度跟不上,稳定性也可以
mscomm,需要用变体才能正确发送如果实时性要求不高,用spcomm,
如果响应速度高一点,用comport3
spcomm,和comport3,接收部分,几乎不用改代码就可以套用