吵吵   2013-12-20  阅读:3,035

刚开始学vb的时候,做的第一个网络聊天程序就是用的activeX控件,就是大名鼎鼎的winsock.ocx控件了。等到用到后面准备搞多线程的时候,才发现vb连多线程都支持不了,后来就自己封装socket类了,也是从那个时候开始,抛弃了vb,用起了delphi。

至于串口的通信类,用mscomm.ocx对于大部分人来讲,是很方便的编程应用了。如上所说的原因,我不喜欢用控件。此外,用这个控件,回头还得注册一下才能用,很伤。于是决定封装一个了。


TSerialPort.pas

wxs这哥们写了个宝贝,挂在csdn上供人下载。我直接下载下来从下午直接弄到晚上,利用虚拟的com连接软件,发送信息是没有问题了,但是依然收不到信息。

等到第二天再打开仔细的看了看他写的接收数据的代码,才发现,这个哥们用调用ReadFile两次,第一次只读取和保存了6个字节的数据,第二次就读全了数据。一开始百思不得其解。后来才想明白,大概是他通讯是有另外一个协议的,第一次读取6byte的数据是数据包头,代表的是整个数据据包的大小。也不知道这是哪门子协议。不管它,反正ASTM还有hl7只有约定每次发送包的最大值,多了就拆,压根就没有限定大小了。我们读出来是啥就是啥。

看看这个类的结构吧,这个哥们写的比较漂亮。

TSerialPort:串口通信的主类,用于创建该类,并且初始化一些连接参数。

TWriteThread:写入数据(发送数据)的类,该类为TThread的多线程类,用于com口发送数据。

TReadThread :读数据类,该类也是TThread的多线程类,用于接受com口的数据。

整个流程如下:

TSerialPort通过open的方法打开com口,然后构造TWriteThread,TReadThread这两个类,这两个类使用while(True)跑一个死循环,各自在自己的线程里面跑着。当调用TSerialPort的WriteData方法发送数据的时候,程序将发送线程消息给TWriteThread,线程循环收到线程消息后将数据发送。TReadThread线程不断的轮询发现com口缓冲区有数据的时候,将会回调一个函数,并将数据返回。

delphi的字符串编码格式

delphi的字符创编码方式从delphi2009后就变的让人很受伤,变成unicode编码了,也就是两个字节编码一个字符。吵吵用的delphi版本是xe2字符串都是宽字符编码的,但是大部分的仪器都是用ascii编码的,所以,把宽字符变成ascii编码再发送就变成了一个纠结的问题。

1、用ansistring和pansistring转化。

网上说ansistring是ascii编码的,因此最简单的方法就是强制转化变量为Ansistring,如果你有这个冲动去定义一个AnsiString的变量来试试,我劝你不用实验了,最后byteslen(’w’)依然是两个字节的。再仔细一想,ansistring和pansistring不过就是一个指针,你原来字符串格式在内存中就是宽字符的,指针指向的自然还是不变的。

2、用bytes来转化。

折腾了半天找到了bytesof这个函数,这个函数能够放回基于ascii编码的字节数组,用它就能转化了:

function StrToBuffer(AStr:string;ABuffer:PAnsiChar):Integer;
var
  i:Integer;
  bytes:TBytes;
begin
  bytes:=BytesOf(AStr);

  for I := 0 to Length(bytes) - 1 do
  begin
    ABuffer[i] :=AnsiChar(bytes[i]);
  end;
  Result:=Length(Bytes);
end;

最后奉上这个多线程的异步串口通讯类,ps:还在继续完善中:

//串口通信类
//吵吵 201312
unit SerialPort;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs;

const
  PWM_COMMWRITE = WM_USER + 101;

type
  TParity = (ptNone, ptOdd, ptEven, ptMark, ptSpace);
  TStopBits = (_1, _1_5, _2);
  TByteBits = (_5, _6, _7, _8);

  TReceiveError = (rverBufferOverflow);

  TReceiveDataEvent = procedure (Sender: TObject; ABuffer: PAnsiChar;
    ABufferLength: DWORD);

  TReceiveErrorEvent = procedure (Sender: TObject; ABuffer: PAnsiChar;
    ABufferLength: DWORD; AReceiveError: TReceiveError);

  TReceiveTimeOutEvent = procedure (Sender: TObject; ABuffer: PAnsiChar;
    ABufferLength: DWORD);

  TRequestHangupEvent = procedure (Sender: TObject; AErrorCode: DWORD);
  
  //读串口线程类
  TReadThread = class(TThread)
  private
    FCommFile: THandle;
    FCloseEvent: THandle;
    FInBufferSize: DWORD;
    FBaudRate: DWORD;
    FIntervalTimeout: DWORD;

    FOnReceiveData: TReceiveDataEvent;
    FOnReceiveError: TReceiveErrorEvent;
    FOnReceiveTimeOut: TReceiveTimeOutEvent;
    FOnRequestHangup: TRequestHangupEvent;

    procedure ReceiveData(ABuffer: PAnsiChar; ABufferLength: DWORD);
    procedure ReceiveError(ABuffer: PAnsiChar; ABufferLength: DWORD;
      AReceiveError: TReceiveError);
    procedure ReceiveTimeOut(ABuffer: PAnsiChar; ABufferLength: DWORD);
    procedure RequestHangup;
  protected
    procedure Execute; override;
    function ReadData(AOverlappedRead: POverlapped; ABuffer: PAnsiChar;
      ANumberOfBytesToRead: DWORD; var ANumberOfBytesRead: DWORD): Boolean;
  end;

  //写串口线程类
  TWriteThread = class(TThread)
  private
    FCommFile: THandle;
    FCloseEvent: THandle;
    FOutBufferSize: DWORD;
    FOnRequestHangup: TRequestHangupEvent;

    procedure RequestHangup;
  protected
    procedure Execute; override;
    function WriteData(AOverlappedWrite: POverlapped;
      ABuffer: PAnsiChar; ANumberToBytesWrite: DWORD): Boolean;
  end;

  //串口类
  TSerialPort = class
  private
    FCommFile: THandle;
    FCloseEvent: THandle;

    FPortOpen: Boolean;
    FCommPort: Byte;

    FCommName: WideString;
    FBaudRate: DWORD;
    FParityCheck: Boolean;
    FParity: TParity;
    FStopBits: TStopBits;
    FByteBits: TByteBits;

    FIntervalTimeout: DWORD; //指定时间间隔内没有收到数据
    FReadIntervalTimeout: DWORD;
    FReadTotalTimeoutMultiplier: DWORD;
    FReadTotalTimeoutConstant: DWORD;
    FWriteTotalTimeoutMultiplier: DWORD;
    FWriteTotalTimeoutConstant: DWORD;

    FInBufferSize: DWORD;
    FOutBufferSize: DWORD;

    FReadThread: TReadThread;
    FWriteThread: TWriteThread;

    FOnReceiveData: TReceiveDataEvent;
    FOnReceiveError: TReceiveErrorEvent;
    FOnReceiveTimeOut: TReceiveTimeOutEvent;
    FOnRequestHangup: TRequestHangupEvent;

    procedure SetCommPort(AValue: Byte);
    procedure SetBaudRate(AValue: DWORD);
    procedure SetParityCheck(AValue: Boolean);
    procedure SetByteBits(AValue: TByteBits);
    procedure SetParity(AValue: TParity);
    procedure SetStopBits(AValue: TStopBits);

    procedure SetReadIntervalTimeout(AValue: DWORD);
    procedure SetReadTotalTimeoutMultiplier(AValue: DWORD);
    procedure SetReadTotalTimeoutConstant(AValue: DWORD);
    procedure SetWriteTotalTimeoutMultiplier(AValue: DWORD);
    procedure SetWriteTotalTimeoutConstant(AValue: DWORD);

    procedure SetCommState;
    procedure SetCommTimeouts;

    procedure CloseReadThread;
    procedure CloseWriteThread;
  public
    property Handle: THandle read FCommFile;

    constructor Create;
    destructor Destroy; override;

    function Open: Boolean;
    procedure Close;

    property IsOpen: Boolean read FPortOpen;

    function GetModemState: DWORD;

    property CommPort: BYTE read FCommPort write SetCommPort default 1;
    property CommName: WideString read FCommName write FCommName;
    property BaudRate: DWORD read FBaudRate write SetBaudRate default 9600;
    property ByteBits: TByteBits read FByteBits write SetByteBits;
    property ParityCheck: Boolean read FParityCheck
      write SetParityCheck default False;
    property Parity: TParity read FParity write SetParity;
    property StopBits: TStopBits read FStopBits write SetStopBits;

    property InBufferSize: DWORD read FInBufferSize write FInBufferSize;
    property OutBufferSize: DWORD read FOutBufferSize write FOutBufferSize;

    property IntervalTimeOut: DWORD read FIntervalTimeout
      write FIntervalTimeout;
    property ReadIntervalTimeout: DWORD read FReadIntervalTimeout
      write SetReadIntervalTimeout;
    property ReadTotalTimeoutMultiplier: DWORD read FReadTotalTimeoutMultiplier
      write SetReadTotalTimeoutMultiplier;
    property ReadTotalTimeoutConstant: DWORD read FReadTotalTimeoutConstant
      write SetReadTotalTimeoutConstant;
    property WriteTotalTimeoutMultiplier: DWORD read FWriteTotalTimeoutMultiplier
      write SetWriteTotalTimeoutMultiplier;
    property WriteTotalTimeoutConstant: DWORD read FWriteTotalTimeoutConstant
      write SetWriteTotalTimeoutConstant;

    function WriteData(ABuffer: PAnsiChar;
      ANumberToBytesToWrite: DWORD): Boolean;
      
    property OnReceiveData: TReceiveDataEvent read FOnReceiveData
      write FOnReceiveData;
    property OnReceiveError: TReceiveErrorEvent read FOnReceiveError
      write FOnReceiveError;
    property OnReceiveTimeOut: TReceiveTimeOutEvent read FOnReceiveTimeOut
      write FOnReceiveTimeOut;
    property OnRequestHangup: TRequestHangupEvent read FOnRequestHangup
      write FOnRequestHangup;
  end;

implementation


//读串口线程类-----------------------------
//2. 按包头、包体分别接收(能避免粘包问题)
//假设包头长度固定为6,包头第5、6字节保存包体数据长度
procedure TReadThread.Execute;
var
  InBuffer: array of AnsiChar;
  dwNumberOfBytesToRead, dwBytesRead, dwNumberOfBytesRead: DWORD;
  dwHandleSignaled, dwLastError: DWORD;
  HandlesToReadFor: array [0 .. 1] of THandle;
  OverlappedRead: TOverlapped;

  procedure EndReadThread;
  begin
    PurgeComm(FCommFile, PURGE_RXABORT + PURGE_RXCLEAR);
    CloseHandle(OverlappedRead.hEvent);
  end;
begin
  SetLength(InBuffer, FInBufferSize);
  FillChar(OverlappedRead, Sizeof(OverlappedRead), 0);

  //ShowMessage(IntToStr(FInBufferSize));

  OverlappedRead.hEvent := CreateEvent(nil, True, True, nil);
  if OverlappedRead.hEvent = 0 then
  begin
    RequestHangup;
    EndReadThread;
    Exit;
  end;          

  HandlesToReadFor[0] := FCloseEvent;
  HandlesToReadFor[1] := OverlappedRead.hEvent;

  //清空输入缓冲区
  PurgeComm(FCommFile, PURGE_RXABORT + PURGE_RXCLEAR);

  while True do
  begin
    //接收包头
    //
    dwNumberOfBytesToRead := FInBufferSize;
    dwNumberOfBytesRead := 0;

    if not ReadFile(FCommFile,
             InBuffer[dwNumberOfBytesRead],
             dwNumberOfBytesToRead,
             dwBytesRead,
             @OverlappedRead) then
    begin
      dwLastError := GetLastError;

      if dwLastError <> ERROR_IO_PENDING then
      begin
        EndReadThread;
        Exit;
      end;
    end;



    dwHandleSignaled := WaitForMultipleObjects(2, @HandlesToReadFor,
                          False, FIntervalTimeout);

    case dwHandleSignaled of
      WAIT_OBJECT_0:
      begin
        EndReadThread;
        Exit;
      end;

      WAIT_OBJECT_0 + 1:
      begin
        if not GetOverlappedResult(FCommFile, OverlappedRead,
                 dwBytesRead, False) then
        begin
          RequestHangup;
          EndReadThread;
          Exit;
        end;


       // ShowMessage(IntToStr(dwBytesRead));


        InBuffer[dwBytesRead] := #0;
        ReceiveData(@InBuffer[0], dwNumberOfBytesRead);
        //FillChar(InBuffer,SizeOf(InBuffer),0);
      end;

      WAIT_TIMEOUT: //超时(指定时间内没有收到数据)
      begin
        PurgeComm(FCommFile, PURGE_RXABORT + PURGE_RXCLEAR);
        ReceiveTimeOut(nil, 0);
      end;
    else
      RequestHangup;
      EndReadThread;
      Exit;
    end;
  end;
end;

function TReadThread.ReadData(AOverlappedRead: POverlapped; ABuffer: PAnsiChar;
  ANumberOfBytesToRead: DWORD; var ANumberOfBytesRead: DWORD): Boolean;
var
  dwBytesRead, dwLastError, dwHandleSignaled, dwMilliseSecond: DWORD;
  HandlesToReadFor: array [0 .. 1] of THandle; 
begin
  Result := False;

  HandlesToReadFor[0] := FCloseEvent;
  HandlesToReadFor[1] := AOverlappedRead.hEvent;

  ANumberOfBytesRead := 0;     

  repeat
    if not ReadFile(FCommFile,
             ABuffer[ANumberOfBytesRead],
             ANumberOfBytesToRead,
             dwBytesRead,
             AOverlappedRead) then
    begin
      dwLastError := GetLastError;

      if dwLastError <> ERROR_IO_PENDING then
        Exit;

      dwMilliseSecond := round(ANumberOfBytesToRead * 8000 / FBaudRate);
      Inc(dwMilliseSecond);
      
      dwHandleSignaled := WaitForMultipleObjects(2,
                            @HandlesToReadFor,
                            False,
                            dwMilliseSecond);

      case dwHandleSignaled of
        WAIT_OBJECT_0:
        begin
          Exit;
        end;

        WAIT_OBJECT_0 + 1:
        begin
          if not GetOverlappedResult(FCommFile,
                   AOverlappedRead^, dwBytesRead, False) then
          begin
            RequestHangup;
            Exit;
          end;
        end;

        WAIT_TIMEOUT:
        begin
          PurgeComm(FCommFile, PURGE_RXABORT + PURGE_RXCLEAR);
          Result := True;
          Exit;
        end;
      else
        RequestHangup;
        Exit;
      end;
    end;

    Dec(ANumberOfBytesToRead, dwBytesRead);
    Inc(ANumberOfBytesRead, dwBytesRead);
  until ANumberOfBytesToRead <= 0;

  Result := True;
end;

procedure TReadThread.ReceiveData(ABuffer: PAnsiChar; ABufferLength: DWORD);
begin
  if Assigned(FOnReceiveData) then
    FOnReceiveData(Self, ABuffer, ABufferLength);


end;

procedure TReadThread.ReceiveError(ABuffer: PAnsiChar; ABufferLength: DWORD;
  AReceiveError: TReceiveError);
begin
  if Assigned(FOnReceiveError) then
    FOnReceiveError(Self, ABuffer, ABufferLength, AReceiveError);
end;

procedure TReadThread.ReceiveTimeOut(ABuffer: PAnsiChar; ABufferLength: DWORD);
begin
  if Assigned(FOnReceiveTimeOut) then
    FOnReceiveTimeOut(Self, ABuffer, ABufferLength);
end;

procedure TReadThread.RequestHangup;
begin
  if Assigned(FOnRequestHangup) then
    FOnRequestHangup(Self, GetLastError);
end;

//写串口线程类-----------------------------
procedure TWriteThread.Execute;
var
  msg: TMsg;
  dwHandleSignaled: DWORD;
  OverlappedWrite: TOverLapped;

  procedure EndWriteThread;
  begin
    PurgeComm(FCommFile, PURGE_TXABORT + PURGE_TXCLEAR);
    CloseHandle(OverlappedWrite.hEvent)
  end;
begin
  FillChar(OverlappedWrite, sizeof(OverlappedWrite), 0);

  OverlappedWrite.hEvent := CreateEvent(nil, True, True, nil);
  if OverlappedWrite.hEvent = 0 then
  begin
    RequestHangup;
    EndWriteThread;
    Exit;
  end;

  while True do
  begin
    if not PeekMessage(msg, 0, 0, 0, PM_REMOVE) then
    begin
      dwHandleSignaled := MsgWaitForMultipleObjects(1,
                            FCloseEvent,
                            False,
                            INFINITE,
                            QS_ALLINPUT);

      case dwHandleSignaled of
        WAIT_OBJECT_0:
        begin
          EndWriteThread;
          Exit;
        end;
        WAIT_OBJECT_0 + 1: 
        begin
          Continue;
        end;
      else
        RequestHangup;
        EndWriteThread;
        Exit;
      end;
    end;

    //确保FCloseEvent没有信号
    if WAIT_TIMEOUT <> WaitForSingleObject(FCloseEvent, 0) then
    begin
      EndWriteThread;
      Exit;
    end;

    if msg.hwnd <> 0 then
    begin
      TranslateMessage(msg);
      DispatchMessage(msg);
      Continue;
    end;

    case msg.message of
      PWM_COMMWRITE:
      begin

        if not WriteData(@OverlappedWrite, PAnsiChar(msg.lParam),
                 DWORD(msg.wParam)) then
        begin
          LocalFree(HLOCAL(msg.lParam));
          EndWriteThread;
          Exit;
        end;
        LocalFree(HLOCAL(msg.lParam));
      end;
    end;
  end;
end;

function TWriteThread.WriteData(AOverlappedWrite: POverlapped;
  ABuffer: PAnsiChar; ANumberToBytesWrite: DWORD): Boolean;
var
  dwLastError, dwNumberOfBytesWritten, dwWhereToStartWriting: DWORD;
  dwHandleSignaled: DWORD;
  HandlesToWaitFor: array [0 .. 1] of THandle;
begin
  Result := False;

  dwNumberOfBytesWritten := 0;
  dwWhereToStartWriting := 0;

  HandlesToWaitFor[0] := FCloseEvent;
  HandlesToWaitFor[1] := AOverlappedWrite^.hEvent;

  repeat
    if not WriteFile(FCommFile,
             ABuffer[dwWhereToStartWriting],
             ANumberToBytesWrite,
             dwNumberOfBytesWritten,
             AOverlappedWrite) then
    begin
      dwLastError := GetLastError;

      if dwLastError <> ERROR_IO_PENDING then
        Exit;

      dwHandleSignaled := WaitForMultipleObjects(2, @HandlesToWaitFor,
                            False, INFINITE);

      case dwHandleSignaled of
        WAIT_OBJECT_0:
        begin
          Exit;
        end;

        WAIT_OBJECT_0 + 1:
        begin
          if not GetOverlappedResult(FCommFile,
                   AOverlappedWrite^,
                   dwNumberOfBytesWritten, True) then
            Exit;
        end;
      else
        Exit;
      end;
    end;

    Dec(ANumberToBytesWrite, dwNumberOfBytesWritten);
    Inc(dwWhereToStartWriting, dwNumberOfBytesWritten);
  until (ANumberToBytesWrite <= 0);  

  Result := True;
end;

procedure TWriteThread.RequestHangup;
begin
  if Assigned(FOnRequestHangup) then
    FOnRequestHangup(Self, GetLastError);
end;

//串口类-------------------------------
constructor TSerialPort.Create;
begin
  FCommFile := 0;
  FCloseEvent := 0;

  FPortOpen := False;
  FCommPort := 1;
  FCommName := 'COM1';
  FBaudRate := 9600;
  FByteBits := _8;
  FParity := ptNone;
  FStopBits := _1;
  FParityCheck := False;

  FInBufferSize := 4096;
  FOutBufferSize := 4096;

  FIntervalTimeout := INFINITE;
  FReadIntervalTimeout := 100;
  FReadTotalTimeoutMultiplier := 0;
  FReadTotalTimeoutConstant := 0;
  FWriteTotalTimeoutMultiplier := 0;
  FWriteTotalTimeoutConstant := 0;

  FOnReceiveData := nil;
  FOnReceiveError := nil;
  FOnReceiveTimeOut := nil;
  FOnRequestHangup := nil;

  FReadThread := nil;
  FWriteThread := nil;
end;

destructor TSerialPort.Destroy;
begin
  if IsOpen then
    Close;
  inherited Destroy;
end;

function TSerialPort.Open: Boolean;
var
  hNewCommFile: THandle;
begin
  Result := False;

  if FCommFile <> 0 then
    Exit;

  hNewCommFile := CreateFile(PWideChar(FCommName),
                    GENERIC_READ or GENERIC_WRITE,
                    0,
                    nil,
                    OPEN_EXISTING,
                    FILE_ATTRIBUTE_NORMAL or FILE_FLAG_OVERLAPPED,
                    0);

  if hNewCommFile = INVALID_HANDLE_VALUE then
    Exit;

  if not SetupComm(hNewCommFile, FInBufferSize, FOutBufferSize) then
  begin
    CloseHandle(hNewCommFile);
    Exit;
  end;

  FCommFile := hNewCommFile;

  PurgeComm(FCommFile,
    PURGE_TXABORT or PURGE_RXABORT or PURGE_TXCLEAR or PURGE_RXCLEAR);

  SetCommTimeouts;

  SetCommState;

  FCloseEvent := CreateEvent(nil, True, False, nil);

  try
    FReadThread := TReadThread.Create(True);
  except
    FReadThread := nil;
    CloseHandle(FCloseEvent);
    CloseHandle(FCommFile);
    FCommFile := 0;
    raise Exception.Create('Unable to create read thread!');
    Exit;
  end;
  FReadThread.FCommFile := FCommFile;
  FReadThread.FCloseEvent := FCloseEvent;
  FReadThread.FBaudRate := FBaudRate;
  FReadThread.FInBufferSize := FInBufferSize;
  FReadThread.FIntervalTimeout := FIntervalTimeout;
  FReadThread.FOnReceiveData := FOnReceiveData;
  FReadThread.FOnReceiveError := FOnReceiveError;
  FReadThread.FOnReceiveTimeOut := FOnReceiveTimeOut;
  FReadThread.FOnRequestHangup := FOnRequestHangup;
  FReadThread.Priority := tpHighest;

  try
    FWriteThread := TWriteThread.Create(True);
  except
    CloseReadThread;
    FWriteThread := nil;
    CloseHandle(FCloseEvent);
    CloseHandle(FCommFile);
    FCommFile := 0;
    raise Exception.Create('Unable to create write thread!');
    Exit;
  end;
  FWriteThread.FCommFile := FCommFile;
  FWriteThread.FCloseEvent := FCloseEvent;
  FWriteThread.FOutBufferSize := FOutBufferSize;
  FWriteThread.FOnRequestHangup := FOnRequestHangup;
  FWriteThread.Priority := tpHigher;

  FReadThread.Resume;
  FWriteThread.Resume;

  FPortOpen := True;

  Result := True;
end;

procedure TSerialPort.Close;
begin
  if FCommFile = 0 then
    Exit;

  CloseReadThread;
  CloseWriteThread;

  CloseHandle(FCloseEvent);

  FPortOpen := False;

  CloseHandle(FCommFile);
  FCommFile := 0
end;

procedure TSerialPort.CloseReadThread;
begin
  if FReadThread <> nil then
  begin
    SetEvent(FCloseEvent);

    PurgeComm(FCommFile, PURGE_RXABORT + PURGE_RXCLEAR);

    if (WaitForSingleObject(FReadThread.Handle, 5000) = WAIT_TIMEOUT) then
      FReadThread.Terminate;

    FreeAndNil(FReadThread);
  end
end;

procedure TSerialPort.CloseWriteThread;
begin
  if FWriteThread <> nil then
  begin
    SetEvent(FCloseEvent);

    PurgeComm(FCommFile, PURGE_TXABORT + PURGE_TXCLEAR);

    if (WaitForSingleObject(FWriteThread.Handle, 5000) = WAIT_TIMEOUT) then
      FWriteThread.Terminate;

    FreeAndNil(FWriteThread);
  end
end;

function TSerialPort.GetModemState: DWORD;
var
  dwModemState: DWORD;
begin
  if GetCommModemStatus(FCommFile, dwModemState) then
    Result := dwModemState
  else
    Result := 0;
end;

procedure TSerialPort.SetCommState;
var
  dcb: TDCB;
begin
  GetCommState(FCommFile, dcb);
  dcb.BaudRate := FBaudRate;
  dcb.Flags := 1; //Enable fBinary
  if FParityCheck then
    dcb.Flags := dcb.Flags or 2; // Enable parity check
  dcb.ByteSize := Ord(FByteBits) + 5;
  dcb.Parity := Ord(FParity);
  dcb.StopBits := Ord(FStopBits);
  Windows.SetCommState(FCommFile, dcb);
end;

procedure TSerialPort.SetCommTimeouts;
var
  CommTimeOuts: TCommTimeouts;
begin
  GetCommTimeouts(FCommFile, CommTimeOuts);
  CommTimeOuts.ReadIntervalTimeout := FReadIntervalTimeout;
  CommTimeOuts.ReadTotalTimeoutMultiplier := FReadTotalTimeoutMultiplier;
  CommTimeOuts.ReadTotalTimeoutConstant := FReadTotalTimeoutConstant;
  CommTimeOuts.WriteTotalTimeoutMultiplier := FWriteTotalTimeoutMultiplier;
  CommTimeOuts.WriteTotalTimeoutConstant := FWriteTotalTimeoutConstant;
  Windows.SetCommTimeouts(FCommFile, CommTimeOuts);
end;

procedure TSerialPort.SetCommPort(AValue: BYTE);
begin
  if (AValue <> 0) and (AValue <> FCommPort) then
  begin
    FCommPort := AValue;
    FCommName := 'COM' + IntToStr(AValue);
  end;
end;

procedure TSerialPort.SetBaudRate(AValue: DWORD);
begin
  if AValue <> FBaudRate then
  begin
    FBaudRate := AValue;
    if FCommFile <> 0 then
      SetCommState;
  end;
end;

procedure TSerialPort.SetParityCheck(AValue: Boolean);
begin
  if AValue <> FParityCheck then
  begin
    FParityCheck := AValue;
    if FCommFile <> 0 then
      SetCommState;
  end;
end;

procedure TSerialPort.SetByteBits(AValue: TByteBits);
begin
  if AValue <> FByteBits then
  begin
    FByteBits := AValue;
    if FCommFile <> 0 then
      SetCommState;
  end;
end;

procedure TSerialPort.SetParity(AValue: TParity);
begin
  if AValue <> FParity then
  begin
    FParity := AValue;
    if FCommFile <> 0 then
      SetCommState;
  end;
end;

procedure TSerialPort.SetStopBits(AValue: TStopBits);
begin
  if AValue <> FStopBits then
  begin
    FStopBits := AValue;
    if FCommFile <> 0 then
      SetCommState;
  end;
end;

procedure TSerialPort.SetReadIntervalTimeout(AValue: DWORD);
begin
  if AValue <> FReadIntervalTimeout then
  begin
    FReadIntervalTimeout := AValue;
    if FCommFile <> 0 then
      SetCommTimeouts;
  end;
end;

procedure TSerialPort.SetReadTotalTimeoutMultiplier(AValue: DWORD);
begin
  if AValue <> FReadTotalTimeoutMultiplier then
  begin
    FReadTotalTimeoutMultiplier := AValue;
    if FCommFile <> 0 then
      SetCommTimeouts;
  end;
end;

procedure TSerialPort.SetReadTotalTimeoutConstant(AValue: DWORD);
begin
  if AValue <> FReadTotalTimeoutConstant then
  begin
    FReadTotalTimeoutConstant := AValue;
    if FCommFile <> 0 then
      SetCommTimeouts;
  end;
end;

procedure TSerialPort.SetWriteTotalTimeoutMultiplier(AValue: DWORD);
begin
  if AValue <> FWriteTotalTimeoutMultiplier then
  begin
    FWriteTotalTimeoutMultiplier := AValue;
    if FCommFile <> 0 then
      SetCommTimeouts;
  end;
end;

procedure TSerialPort.SetWriteTotalTimeoutConstant(AValue: DWORD);
begin
  if AValue <> FWriteTotalTimeoutConstant then
  begin
    FWriteTotalTimeoutConstant := AValue;
    if FCommFile <> 0 then
      SetCommTimeouts;
  end;
end;

function TSerialPort.WriteData(ABuffer: PAnsiChar;
  ANumberToBytesToWrite: DWORD): Boolean;
var
  WriteBuff: Pointer;
begin
  Result := False;
  if (FWriteThread <> nil) and (ANumberToBytesToWrite > 0) then
  begin
    WriteBuff := Pointer(LocalAlloc(LPTR, ANumberToBytesToWrite + 1));
    Move(ABuffer^, WriteBuff^, ANumberToBytesToWrite);
    //ShowMessage(ABuffer[0]);
    Result := PostThreadMessage(FWriteThread.ThreadID,
                PWM_COMMWRITE,
                WPARAM(ANumberToBytesToWrite),
                LPARAM(WriteBuff));
  end;
end;

end.

吵吵微信朋友圈,请付款实名加入:

吵吵 吵吵

一条回应:“多线程串口异步通信类TSerialPort”

  1. 有点深奥,收藏慢慢琢磨琢磨,谢谢楼主!

发表评论

电子邮件地址不会被公开。 必填项已用*标注