DELPHI 如何实现串口通讯

DAOMUZI 2007-01-12 10:19:27
如和用COMM 控件实现上位机和单片机之间的数据发送与接收;
主要是在XP系统下;
...全文
1181 10 打赏 收藏 转发到动态 举报
写回复
用AI写文章
10 条回复
切换为时间正序
请发表友善的回复…
发表回复
constantine 2007-01-25
  • 打赏
  • 举报
回复
星多就可以连续发
我只用过mscomm32控件
jpyc 2007-01-25
  • 打赏
  • 举报
回复

下边的测试工具,我以前编的,大家反映也都不错.

http://bbs.e-0631.cn/down.aspx

[精品源码]delphi串口通讯控制程序
[精品控件]tubropower通讯控件
yqdragon 2007-01-14
  • 打赏
  • 举报
回复
直接用API好了,用好那几个函数就好了,思路理好,先打开COM端口,开一个线程一直接收下位机数据,接到后处理,数据正确,发送合格指令给下位机,并将数据存入数据库即可。数据不正确,发送不合格指令给下位机。注意线程同步
zhangl_cn 2007-01-13
  • 打赏
  • 举报
回复
找本电子书看:
http://www.2ccc.com/article.asp?articleid=3676
wudi_1982 2007-01-12
  • 打赏
  • 举报
回复
靠,现在居然可以连续发.
wudi_1982 2007-01-12
  • 打赏
  • 举报
回复
wudi_1982 2007-01-12
  • 打赏
  • 举报
回复



//指定传输速度
procedure TComm.SetBaudRate( Rate : TBaudRate );
begin
if Rate = FBaudRate then
Exit;
FBaudRate := Rate;
if hComm <> 0 then
_SetCommState
end;

//硬件流量控制
procedure TComm.SetHwHandShaking( c: THwHandShaking);
begin
if c = FHwHandShaking then
Exit;
FHwHandShaking := c;
if hComm <> 0 then
_SetCommState
end;

//软件交握指定
procedure TComm.SetSwHandShaking( c : TSwHandShaking );
begin
if c = FSwHandShaking then
Exit;
FSwHandShaking := c;
if hComm <> 0 then
_SetCommState
end;

//设置数据位数
procedure TComm.SetDataBits( Size : TDataBits );
begin
if Size = FDataBits then
Exit;
FDataBits := Size;
if hComm <> 0 then
_SetCommState
end;

//设置极性检查方式
procedure TComm.SetParity( p : TParity );
begin
if p = FParity then
Exit;
FParity := p;
if hComm <> 0 then
_SetCommState
end;

//设置停止位
procedure TComm.SetStopBits( Bits : TStopBits );
begin
if Bits = FStopBits then
Exit;
FStopBits := Bits;
if hComm <> 0 then
_SetCommState
end;

//读取CD状态
function TComm.ReadCDHolding():Boolean;
begin
Result:=FCDHolding;
end;

//读取DSR状态
function TComm.ReadDSRHolding():Boolean;
begin
Result:=FDSRHolding;
end;

//读取RI状态
function TComm.ReadRIHolding():Boolean;
begin
Result:=FRIHolding;
end;

//读取CTS状态
function TComm.ReadCTSHolding():Boolean;
begin
Result:=FCTSHolding;
end;

//设置DTR状态
procedure TComm.SetDTRStatus(b:Boolean);
begin
if hComm=0 then exit ;
FDTR:=b;
if b then
EscapeCommFunction(hComm,SETDTR) //将DTR升至高电压
else
EscapeCommFunction(hComm,CLRDTR);//将DTR降至低电压
end;

//设置RTS状态
procedure TComm.SetRTSStatus(b:Boolean);
begin
if hComm=0 then
begin
ECommError.Create('COM Port is not opened yet!');
exit ;
end;
FRTS:=b;
if b then
EscapeCommFunction(hComm,SETRTS) //将RTS升至高电压
else
EscapeCommFunction(hComm,CLRRTS); //将RTS降至低电压
end;

//返回数据
function TComm.ReadInputData():String;
begin
if hComm=0 then
begin
ECommError.Create('COM Port is not opened yet!');
end;
//决定每一次的指令要返回多少的字符(以Byte为单位)
ReadProcess;
Result:=FInputData;
end;

//返回数据
function TComm.ReadInputByte(var AP:PByte):DWORD;
begin
if hComm=0 then
begin
ECommError.Create('COM Port is not opened yet!');
end;
ReadProcess;//执行读取函数
AP:= @FInputByteData[0];//取得数据地址
Result:=High(FInputByteData);//取得数据数组的最高索引值
end;


//读取数据的字节数
function TComm.ReadInDataCount():DWORD;
var
CS: TCOMSTAT;
dwCommError:DWORD;
begin
ClearCommError(hComm,dwCommError,@CS); //取得状态
Result:=CS.cbInQue;
end;

//清空数据缓冲区
procedure TComm.SetInDataCount(StrNO:DWORD);
begin
if StrNo<>0 then exit ;
PurgeComm(hComm, PURGE_RXCLEAR) // 清除COM 数据
end;

//线路状态的数值
function TComm.ReadCommEvent():DWORD;
begin
Result:=FCommEvent;
end;

//错误状态值的读取
function TComm.ReadCommError():DWORD;
begin
Result:=FCommError;
end;


//设置引发接收事件的阀值
procedure TComm.SetRThreshold(RTNo:DWORD);
begin
FRThreshold:=RTNo;
end;

//以下是实际的读取动作
Procedure TComm.ReadProcess;
var
nBytesRead: DWORD;
dwCommError: DWORD;
CS: TCOMSTAT;
i,ReadLen: DWORD;
begin
//使用ClearCommError得知有多少的数据在缓冲区中
//并得知错误种类
ClearCommError(hComm,dwCommError,@CS); //取得状态
FCommError:=dwCommError; //错误数值
if cs.cbInQue <>0 then //若缓冲区有数据,则读取
begin
if InputLen=0 then //指定读取的数据数
ReadLen:=cs.cbInQue
else
ReadLen:=InputLen;
if cs.cbInQue > sizeof(szInputBuffer) then
PurgeComm(hComm, PURGE_RXCLEAR) // 清除COM 数据
else
begin
//读取数据
if ReadFile(hComm, szInputBuffer,ReadLen,nBytesRead,nil) then // 接收COM 的数据
begin
//取出数据
FInputData:=Copy(szInputBuffer,1,ReadLen);
//设置字节数组长度
SetLength(FInputByteData,ReadLen);
//将数据搬到数组中
for i:=0 to ReadLen-1 do
FInputByteData[i]:=ord(szInputBuffer[i]);
end; //ReadFile Loop
end;//else Loop
end; //cs.binQue Loop
end;

//取得线路的状态
procedure TComm.GetModemState;
var
dwModemState : DWORD;
begin
if hComm=0 then
begin
raise ECommError.Create('COM Port is not opened yet!');
end;
//取得线路状态
FCommEvent:=0;
if GetCommModemStatus( hComm, dwModemState ) then
begin
//判断CD状态
if (dwModemState and MS_RLSD_ON)=MS_RLSD_ON then
begin
if not FCDHolding then FCommEvent:= EV_RLSD;
FCDHolding:=True;
end
else
begin
if FCDHolding then FCommEvent:= EV_RLSD;
FCDHolding:=False;
end;
//判断DSR状态
if (dwModemState and MS_DSR_ON)=MS_DSR_ON then
begin
if not FDSRHolding then FCommEvent:=FCommEvent + EV_DSR;
FDSRHolding:=True;
end
else
begin
if FDSRHolding then FCommEvent:=FCommEvent + EV_DSR;
FDSRHolding:=False;
end;
//判断RI状态
if (dwModemState and MS_RING_ON)=MS_RING_ON then
begin
if not FRIHolding then FCommEvent:=FCommEvent + EV_RING;
FRIHolding:=True;
end
else
begin
if FRIHolding then FCommEvent:=FCommEvent + EV_RING;
FRIHolding:=False;
end;
//判断CTS状态
if (dwModemState and MS_CTS_ON)=MS_CTS_ON then
begin
if not FCTSHolding then FCommEvent:=FCommEvent + EV_CTS;
FCTSHolding:=True;
end
else
begin
if FCTSHolding then FCommEvent:=FCommEvent + EV_CTS;
FCTSHolding:=False;
end;
end;
end;


procedure Register;
begin
RegisterComponents('UserVcl', [TComm])
end;
//组件的定时器程序,在此会决定事件是否被触发
procedure TComm.ProcTimer(Sender: TObject);
var
tmpValue: DWORD;
dwCommError:DWORD;
CS: TCOMSTAT;
begin
if hComm=0 then exit;
//若设置读取的字符数,检查并触发事件
ClearCommError(hComm,dwCommError,@CS); //取得状态
FCommError:=dwCommError; //错误数值
if FRThreshold>0 then
begin
if cs.cbInQue >=FRthreshold then
ReceiveData();
end;
GetModemState;
Application.ProcessMessages; //看有无其它的指令需执行,以免锁住
//检查线路状态是否发生改变,若改变则触发事件
tmpValue:=ReadCommEvent;
if tmpValue<>0 then ModemStateChange(tmpValue);
Application.ProcessMessages; //看有无其它的指令需执行,以免锁住
//若发生错误,则引发错误
tmpValue:=ReadCommError;
if tmpValue<>0 then ReceiveError(tmpValue);
Application.ProcessMessages; //看有无其它的指令需执行,以免锁住
end;

end.
wudi_1982 2007-01-12
  • 打赏
  • 举报
回复
implementation

(******************************************************************************)
// TComm PUBLIC METHODS
(******************************************************************************)

constructor TComm.Create( AOwner: TComponent );
begin
inherited Create( AOwner );
CommTimer:=TTimer.Create(Self);
CommTimer.Interval:=100;
CommTimer.OnTimer:=ProcTimer;
hComm := 0; //通信端口Handle先清空
FPortOpen:=False;
FCommPort := pnCOM2; //默认COM2
FBaudRate := br9600; //9600bps
FHwHandShaking := hhNone; //不激活硬件流量控制
FSwHandShaking := shNone; //不激活软件流量控制
FDataBits := DB8; //数据位数=8
FParity := None; //不作同位检查
FStopBits := SB1; //停止位数=1
FInputLen:=0; //默认是一次执行全部读取
CommTimer.Enabled:=True;

end;

destructor TComm.Destroy;
begin
CommTimer.Interval:=0;
CommTimer.Enabled:=False;
inherited Destroy;
end;

//打开通信端口
procedure TComm.OpenComm;
var
hNewCommFile: THandle;
ComStr:String;
begin
ComStr:='COM' + IntToStr(1+ord(FCommPort));
hNewCommFile := CreateFile( PChar(ComStr),
GENERIC_READ or GENERIC_WRITE,
0, {not shared}
nil, {no security ??}
OPEN_EXISTING,
0,{No Overlapped}
0 {template} );

if hNewCommFile = INVALID_HANDLE_VALUE then
raise ECommError.Create( 'Error opening serial port' );

if not SetupComm( hNewCommFile, INPUTBUFFERSIZE, INPUTBUFFERSIZE ) then
begin
CloseHandle( hComm );
raise ECommError.Create( 'Cannot setup comm buffer' );
end;
// It is ok to continue.
hComm := hNewCommFile;
// 清除湲冲区
PurgeComm( hComm, PURGE_TXABORT or PURGE_RXABORT or
PURGE_TXCLEAR or PURGE_RXCLEAR ) ;
// 通信端口组态
_SetCommState;

{ // 设置事件屏蔽
if not SetCommMask(hComm, EV_CTS or EV_DSR or EV_RLSD or EV_RING ) then
begin
MessageDlg('Set Comm Mask Error!', mtError, [mbOK], 0);
exit ;
end;}
FPortOpen:=True;

end; {TComm.OpenComm}

//关闭通信端口
procedure TComm.CloseComm;
begin
// No need to continue if we're not communicating.
if hComm = 0 then
Exit;
// 实际关闭通信端口
CloseHandle( hComm );
FPortOpen:=False;
hComm := 0
end;

//由通信端口送出字符串数据
function TComm.OutputString(DataToWrite: String ): Boolean;
var
lrc: LongWord;
tmpChar: PChar;
begin

if hComm=0 then
begin
MessageDlg('COM Port is not opened yet!', mtError, [mbOK], 0);
Result := False;
exit;
end;
// 送出数据
tmpChar:=PChar(DataToWrite);
if WriteFile(hComm,tmpChar^,Length(DataToWrite), lrc, nil) then
begin
Result:=True;
exit;
end;
Result:=False;
end; {TComm.OutputString}

//传送二进制的数据
function TComm.OutputByte(const ByteData: array of Byte ): Boolean;
var
lrc: LongWord;
i: Integer;
begin
if hComm=0 then
begin
MessageDlg('COM Port is not opened yet!', mtError, [mbOK], 0);
Result := False;
exit;
end;
// 送出数据
for i:=Low(ByteData) to High(ByteData) do
WriteFile(hComm,ByteData[i],1,lrc, nil);
Result := True;
end; {TComm.OutputByte}


//数据到达时的事件触发
procedure TComm.ReceiveData();
begin
if Assigned(FOnReceiveData) then
FOnReceiveData(self)
end;

//接收错误时的事件触发
procedure TComm.ReceiveError( EvtMask : DWORD );
begin
if Assigned(FOnReceiveError) then
FOnReceiveError( self, EvtMask )
end;

//线路状态改变时的事件触发
procedure TComm.ModemStateChange( ModemEvent : DWORD );
begin
if Assigned(FOnModemStateChange) then
FOnModemStateChange( self, ModemEvent )
end;

(******************************************************************************)
// TComm PRIVATE 方法
(******************************************************************************)

//以下是通信参数的设置
procedure TComm._SetCommState;
var
dcb: Tdcb;
tmpValue: DWORD;
begin
//取得串行端口设置
GetCommState( hComm, dcb );
//变更传输速率
case FBaudRate of
br110 : tmpValue := 110;
br300 : tmpValue := 300;
br600 : tmpValue := 600;
br1200 : tmpValue := 1200;
br2400 : tmpValue := 2400;
br4800 : tmpValue := 4800;
br9600 : tmpValue := 9600;
br14400 : tmpValue := 14400;
br19200 : tmpValue := 19200;
br38400 : tmpValue := 38400;
br56000 : tmpValue := 56000;
br57600 : tmpValue := 57600;
else
{br115200 :} tmpValue := 115200;
end;
//指定新值
dcb.BaudRate := tmpValue;
dcb.Flags := 1; //必须指定为1
dcb.Parity := Ord( FParity );//Parity的指定
FParityCheck:=False;
if Ord(FParity)<>0 then FParityCheck:=True;
if FParityCheck then
dcb.Flags := dcb.Flags or dcb_ParityCheck; // Enable parity check
// 设置硬件流量控制
Case FHwHandShaking of
hhNone:;
hhNoneRTSON:
dcb.Flags := dcb.Flags or dcb_RTSControlEnable;
hhRTSCTS:
dcb.Flags := dcb.Flags or dcb_RTSControlHandShake or dcb_OutxCtsFlow;
end;
//设置软件流量控制
Case FSwHandShaking of
shNone:;
shXonXoff:
dcb.Flags := dcb.Flags or dcb_OutX or dcb_InX;
end;
//设置数据位数
dcb.ByteSize := Ord( FDataBits ) + 5;
//设置停止位数
dcb.StopBits := Ord( FStopBits );
//将设置写入
SetCommState( hComm, dcb )
end;

procedure TComm.SetPortOpen(b:Boolean);
begin
if b then //若指定打开通信端口,则…
begin
if FPortOpen then
begin
MessageDlg('COM Port has been opened!', mtError, [mbOK], 0);
exit;
end; //FportOpen loop
OpenComm; //打开通信端口
exit;
end; //b loop
CloseComm;
end;

还有,可惜只能连续回复3次,发不了了.
wudi_1982 2007-01-12
  • 打赏
  • 举报
回复
给你个例子:
如果简单需求,你可以直接用这个控件,如果需要了解的深入一点,把代码里边的那些win api在MSDN上搜索一下,看看究竟是干了什么.


unit TComm1;
// 这是一个串行端口通信组件
// 简单传输. 此组件调用 Win32 API 来达成所需功能
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
extctrls,Dialogs,syncobjs;
type
//类型定义
TBaudRate = ( br110, br300, br600, br1200, br2400, br4800,
br9600, br14400, br19200, br38400, br56000,
br57600, br115200 );
TComPortNumber = ( pnCOM1, pnCOM2, pnCOM3, pnCOM4, pnCOM5, pnCOM6, pnCOM7,
pnCOM8, pnCOM9, pnCOM10, pnCOM11, pnCOM12, pnCOM13,
pnCOM14, pnCOM15, pnCOM16 );
TParity = ( None, Odd, Even, Mark, Space );
TStopBits = ( SB1, SB1_5, SB2 );
TDataBits = ( DB5, DB6, DB7, DB8 );
THWHandShaking=(hhNone,hhNoneRTSON,hhRTSCTS);
TSWHandShaking=(shNone,shXonXoff);
//例外声明
ECommError = class( Exception );
//事件函数定位器声明
TReceiveDataEvent = procedure(Sender: TObject) of object;
TReceiveErrorEvent = procedure(Sender: TObject; EventMask : DWORD) of object;
TModemStateChangeEvent = procedure(Sender: TObject; ModemEvent : DWORD) of object;
const
// 输入缓冲区的默认大小
INPUTBUFFERSIZE = 4096;
// Line Status位定义
ME_CTS = 1;
ME_DSR = 2;
ME_RING = 4;
ME_RLSD = 8;
//DCB 位定义
dcb_Binary = $00000001;
dcb_ParityCheck = $00000002;
dcb_OutxCtsFlow = $00000004;
dcb_OutxDsrFlow = $00000008;
dcb_DtrControlMask = $00000030;
dcb_DtrControlDisable = $00000000;
dcb_DtrControlEnable = $00000010;
dcb_DtrControlHandshake = $00000020;
dcb_DsrSensivity = $00000040;
dcb_TXContinueOnXoff = $00000080;
dcb_OutX = $00000100;
dcb_InX = $00000200;
dcb_ErrorChar = $00000400;
dcb_NullStrip = $00000800;
dcb_RtsControlMask = $00003000;
dcb_RtsControlDisable = $00000000;
dcb_RtsControlEnable = $00001000;
dcb_RtsControlHandshake = $00002000;
dcb_RtsControlToggle = $00003000;
dcb_AbortOnError = $00004000;
dcb_Reserveds = $FFFF8000;
type

TComm = class( TComponent )
private
{ Private declarations }
CommTimer: TTimer; //组件用的定时器
szInputBuffer: array[0..INPUTBUFFERSIZE-1] of Char;
hComm: THandle;
FCommPort: TComPortNumber;
FPortOpen: Boolean;
FBaudRate: TBaudRate;
FParityCheck: Boolean;
FHwHandShaking: THwHandShaking;
FSwHandShaking: TSwHandShaking;
FDataBits: TDataBits;
FParity: TParity;
FStopBits: TStopBits;
FInputLen: DWORD; //每次执行Input时所读取的字符串长度
FRThreshold: DWORD;//设置引发接收事件的阀值
FDTR: Boolean;
FRTS: Boolean;
FInputData: String;
// FByteNo: DWORD; //已读取的字节数
FInputByteData: array of Byte;
FCommEvent: DWORD;
FCommError: DWORD;
FCDHolding: Boolean;
FCTSHolding: Boolean;
FDSRHolding: Boolean;
FRIHolding: Boolean;

//事件
FOnReceiveData: TReceiveDataEvent;
FOnReceiveError: TReceiveErrorEvent;
FOnModemStateChange:TModemStateChangeEvent;

//设置函数
procedure SetBaudRate( Rate : TBaudRate ); //设置速率
procedure SetHwHandShaking( c : THwHandShaking);//硬件交握
procedure SetSwHandShaking( c : TSwHandShaking);//软件交握
procedure SetDataBits( Size : TDataBits );//数据位数
procedure SetParity( p : TParity );//极性检查
procedure SetStopBits( Bits : TStopBits );//停止位
procedure SetInDataCount(StrNo:DWORD);//设成0表示清除FInputData
procedure SetRThreshold(RTNo:DWORD); //接收阀值
procedure SetPortOpen(b:Boolean);//打开通信端口
procedure _SetCommState;//设置通信参数
procedure SetDTRStatus(b:Boolean);//DTR 状态
procedure SetRTSStatus(b:Boolean);//RTS状态
Procedure ReadProcess;//读取数据函数
Procedure GetModemState;//线路状态检测函数
procedure OpenComm;//打开通信端口函数
procedure CloseComm;//开关通信端口函数
function ReadCommEvent():DWORD; //硬件线路状态值读取
function ReadCommError():DWORD; //错误状态值的读取
function ReadInputData():String;//返回收到的数据
function ReadInDataCount():DWORD;//读取有多少数据
function ReadCDHolding:Boolean; //取得CD线路状态
function ReadDSRHolding:Boolean;//取得DSR线路状态
function ReadRIHolding:Boolean;//取得RI线路状态
function ReadCTSHolding:Boolean;//取得CTS线路状态

protected
//给子类继承用
procedure ProcTimer(Sender:TObject);
procedure ReceiveData();
procedure ReceiveError( EvtMask : DWORD );
procedure ModemStateChange( ModemEvent : DWORD );
public
//给应用程序调用用
property Handle: THandle read hComm;
constructor Create( AOwner: TComponent ); override;
destructor Destroy; override;
function OutputString(DataToWrite: String): Boolean;
function OutputByte(const ByteData:array of Byte):Boolean;
function ReadInputByte(var AP:PByte):DWORD;
published
//属性列表用
property CommPort: TComPortNumber read FCommPort write FCommPort;
property PortOpen:Boolean read FPortOpen write SetPortOpen;
property BaudRate: TBaudRate read FBaudRate write SetBaudRate;
property HwHandShaking: THwHandShaking read FHwHandShaking write SetHwHandShaking;
property SwHandShaking: TSwHandShaking read FSwHandShaking write SetSwHandShaking;
property DataBits: TDataBits read FDataBits write SetDataBits;
property Parity: TParity read FParity write SetParity;
property StopBits: TStopBits read FStopBits write SetStopBits;
property CommEvent:DWORD read ReadCommEvent;
property CommError:DWORD read ReadCommError;
property Input:string read ReadInputData;
property InputLen:DWORD read FInputLen write FInputLen;
property RThreshold:DWORD read FRThreshold write SetRThreshold;
property CDHolding:Boolean read ReadCDHolding;
property DSRHolding:Boolean read ReadDSRHolding;
property RIHolding:Boolean read ReadRIHolding;
property CTSHolding:Boolean read ReadCTSHolding;
property DTREnabled:Boolean read FDTR write SetDTRStatus;
property RTSEnabled:Boolean read FRTS write SetRTSStatus;
property DataCount:DWORD read ReadInDataCount write SetInDataCount;

property OnReceiveData: TReceiveDataEvent
read FOnReceiveData write FOnReceiveData;
property OnReceiveError: TReceiveErrorEvent
read FOnReceiveError write FOnReceiveError;
property OnModemStateChange: TModemStateChangeEvent
read FOnModemStateChange write FOnModemStateChange;
end;

procedure Register;
wudi_1982 2007-01-12
  • 打赏
  • 举报
回复
简单的方法:用控件 例如MSCOMM,SPCOM等

如果有兴趣,用WIN API做,其实常用的就那么几个

1,593

社区成员

发帖
与我相关
我的任务
社区描述
Delphi 网络通信/分布式开发
社区管理员
  • 网络通信/分布式开发社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧