{*****************************************************************************
 *本单元说明:串口通信封装类
 ****************************************************************************}
unit COMDevIO;
 
interface
 
uses
  SysUtils, Forms, CPort;
  
type
  TOnDataReceived = procedure(const AStr: string) of object;
 
type
  TCOMDevIO = class
  private
    //串口通信对象
    fPort: TComPort;
    //串口通信接收对象
    fPortDataPacket: TComDataPacket;
    //数据接收回调函数
    fOnDataReceived: TOnDataReceived;
  private
    //数据接收处理
    procedure PortDataPacketPacket(Sender: TObject; const Str: String);
  public
    //创建
    constructor Create(ACOM: Byte);
    //设置通信参数
    procedure setParameters(ACOM: Byte; ABaudRate: TBaudRate = br9600;
      ADataBits: TDataBits = dbSeven; AParityBit: TParityBits = prOdd;
      AParityCheck: Boolean = True; AStopBit: TStopBits = sbTwoStopBits);
    //设置通信超时
    procedure setWriteTotal(t: Integer);
    //打开串口
    function openCOM(ACOM: Byte): Boolean;
    //关闭串口
    procedure close;
    //发送数据
    function sendData(const AStr: string): Boolean;
    //设置数据接收函数
    procedure setOnDataReceived(AOnDataReceived: TOnDataReceived);
  end;
 
 
implementation
 
uses
  LogUnit;
 
{ TCOMDevIO }
 
constructor TCOMDevIO.Create(ACOM: Byte);
begin
  fPort := TComPort.Create(Application.MainForm);
  if ACOM > 0 then
  begin
    fPort.Port := 'COM' + IntToStr(ACOM);
  end;
  fPort.BaudRate := br9600;
  fPort.DataBits := dbSeven;
  fPort.StopBits := sbTwoStopBits;
  fPort.Parity.Bits := prOdd;
  fPort.Parity.Check := TRUE;
  fPort.DiscardNull := FALSE ;
  fPort.EventChar := #13;
  fPort.Events := [evRxChar];
  fPort.Timeouts.ReadInterval := -1;
  fPort.Timeouts.ReadTotalMultiplier := 0;
  fPort.Timeouts.ReadTotalConstant := 0;
  fPort.Timeouts.WriteTotalConstant := 1000;
  fPort.Timeouts.WriteTotalMultiplier := 100;
  fPortDataPacket := TComDataPacket.Create(fPort);
  fPortDataPacket.OnPacket := PortDataPacketPacket;
  fPortDataPacket.ComPort := fPort;
  fPortDataPacket.MaxBufferSize := 1024;
  fPortDataPacket.CaseInsensitive := False;
  fPortDataPacket.IncludeStrings := False;
  fPort.SyncMethod := smThreadSync;
end;
 
procedure TCOMDevIO.setParameters(ACOM: Byte; ABaudRate: TBaudRate = br9600;
  ADataBits: TDataBits = dbSeven; AParityBit: TParityBits = prOdd;
  AParityCheck: Boolean = True; AStopBit: TStopBits = sbTwoStopBits);
begin
  // note: 尽量不要在已打开串口的情况下修改参数
  fPort.BaudRate := ABaudRate;
  fPort.DataBits := ADataBits;
  fPort.Parity.Bits := AParityBit;
  fPort.Parity.Check := AParityCheck;
  fPort.StopBits := AStopBit;
end;
 
procedure TCOMDevIO.setWriteTotal(t: Integer);
begin
  fPort.Timeouts.WriteTotalConstant := t;
end;
 
function TCOMDevIO.openCOM(ACOM: Byte): Boolean;
var
  Port: TPort;
begin
  Result := False;
  Port := 'COM' + IntToStr(ACOM);
  fPort.Close;
  if fPort.Port <> Port then
  begin
    // note: 如果以前串口已经打开,执行下面的语句会更换串口号后打开串口
    fPort.Port := Port;
  end;
  try
    fPort.Open;
    Result := fPort.Connected;
  except
    On E: Exception do
    begin
      WriteLog(Format('无法打开串口:%d, %s', [ACOM, E.Message]));
    end;
  end;
end;
 
procedure TCOMDevIO.close;
begin
  fPort.Close;
end;
 
procedure TCOMDevIO.PortDataPacketPacket(Sender: TObject;
  const Str: String);
begin
  if Assigned(fOnDataReceived) then
  begin
    fOnDataReceived(Str);
  end;
end;
 
function TCOMDevIO.sendData(const AStr: string): Boolean;
begin
  Result := False;
  try
    if not fPort.Connected then
    begin
      Exit;
    end;
    fPort.WriteStr(AStr);
    // ErrorLog('TCOMDevIO.SendData:'+TransHexStr(AStr));
    Result := True;
  except
    On E: Exception do
    begin
      WriteLog('向串口发送数据出现异常: '+E.Message);
    end;
  end;
end;
 
procedure TCOMDevIO.setOnDataReceived(AOnDataReceived: TOnDataReceived);
begin
  fOnDataReceived := AOnDataReceived;
end;
 
end.

解决方案 »

  1.   

    TOnDataReceived = procedure(const AStr: string) of object;  //这是一个方法指针吧procedure TCOMDevIO.setOnDataReceived(AOnDataReceived: TOnDataReceived);
    begin
      fOnDataReceived := AOnDataReceived;
    end;这里面没有处理啊?如何调用这个来处理从COM接收到的数据
      

  2.   

    这不就是个操作串口的吗,有什么好解释的,而且注释也能看明白TOnDataReceived 是个方法类型,用作事件,没有执行,是因为这个事件时有外部关联的,当外部对这个事件做了定以后,就会触发,就行button的OnClick
      

  3.   

    在这里是一个回调函数,是封装在另外的地方,比如在dll中当setOnDataReceived这个方法触发时,就会执行dll中对应的这个函数
    即procedure xx(const AStr: string);
      

  4.   

    就是要把串口操作封装到DLL中,只公开几个接口,比如打开串口,关闭串口,发送数据,接收数据等。
    打开关闭发送都好说,接收的话如何做呢?这个回调函数会在什么情况下发生,接收到数据后,我如何通知调用者呢,谢谢
      

  5.   

    首先,你要理解,串口对象是用来做什么事情的.比如打印的接口,一些硬件的驱动等. 
    然后,要使用某对象,最简单的思路就是:对象的创建(Create)->对象的初始化设置参数(setParameters)->对象的应用(此为串口,如果打开就返回此串口,如果没打开,就重新注册生成新的串口,这相当与设计模式中的单例模式,一个类(此处是串口)只能有一个该类的实例(串口对象))->对象的销毁.按照这个思路再重新理解你的代码.