1. 程式人生 > >早些時候寫的一個Delphi中的串列埠通讀類.

早些時候寫的一個Delphi中的串列埠通讀類.

這個是早期的版本,後期我做了很大的修動...僅做為學習參考用.

       在做資料採集,及控制系統中,我建議大家自己用API寫通訊類..不要使用SPCOMM,以及MSCOMM...在實際的應用中,自己寫的通訊類在應用上會更加的靈活方便(^^當然寫這個通訊類是比較費時的...)

       在做資料採集時,可以自己很方便的加入CRC或者checksum校驗方式..51以CRC8 /16為主......採用CRC可以使用資料傳輸更加的可靠..

unit MYCOMM;
{
  This unit create by 李金浩
  2004-3-12號23:26修正
  QQ:67260745
  E-Mail:[email protected]

}
interface
  uses
  Forms, SysUtils, Windows, Messages, Dialogs, Controls, Classes, ToolWin, ComCtrls,
  ExtCtrls, StdCtrls, Math;
//----------------
(*串列埠號*)
const
    Com1=1;
    Com2=2;
    Com3=3;
    Com4=4;
    Com5=5;
    Com6=6;
    Com7=7;
    Com8=8;
    Com9=9;
    Com10=10;
  (*StopBit*)
   sbit1=0;
   sbit1_5=1;
   sbit2=2;
  (*modem 事件常量*)
   MY_CTS=1;          //The CTS (clear-to-send) signal is on.
   MY_DSRL=2;         //The DSR (data-set-ready) signal is on.
   MY_RING=4;       //The ring indicator signal is on.
   MY_RLSD=8;       //The RLSD (receive-line-signal-detect) signal is on.
  (*處理訊息*)
   MY_ReadComm=WM_User+507;

Type
  TMyComm=Class
  public
    (*關閉指定串列埠*)
    //********************
    Function CloseComm(Const Com:integer;const CloseAll:boolean=False):boolean;
    (*開啟指定串列埠*)
    function  OpenComm(Const COM:integer;
                       Const My_BandRate:DWORD=4800;
                       Const My_ByteSize:byte=8;
                       Const My_Parity:byte=NoParity;
                       Const My_StopBits:byte=0):Boolean;
    //讀串列埠函式集
    Function ReadComm_string(Const Com:integer;var revcStr:string;const len:DWORD=0):boolean;//讀取串列埠string
    Function ReadComm_ByteArray(const Com:integer;var revcArray:array of byte;const len:DWORD=0):boolean;
    Function ReadComm_Byte(Const Com:integer;var OneByte:byte):boolean;
    //寫串列埠口函式集
    Function WriteComm_String(Const Com:integer;Const SendString:string):boolean;
    Function WriteComm_ByteArray(Const Com:integer;const SendByte:array of byte;Buflong:DWORD):boolean;
    Function WriteComm_Byte(Const Com:integer;const SendByte:byte):boolean;
    //--------------
    Function  GetRXDsize(com:integer):integer; //得到RXD緩衝區資料長度
    Function  GetModemState(com:integer):DWord;//得到狀態口的狀態
    procedure SetReadOFFByte(offByte:byte=$13);//設定接收停止結束符
    Function  IsReadOFFByte(RByte:byte):boolean;//判斷接收的是不是停止結束符
    procedure ClearRXD(com:integer);//清空RXD緩衝區內容
    procedure ClearTXD(com:integer);//清空TXD緩衝區內容
    procedure ClearComBuf(com:integer);//清空所有緩衝區
end;
//---------------------
var
  MComm:TMycomm;//建立TMycomm例項
//  myThread:TThread;
//  Timer1:TTimer;
  bOFFByte:byte;//接收結束byte
  lpDCB:TDCB;
  COMHandle:array[1..10] of Thandle; //檔案控制代碼
  ComOpenFlag:array[1..10] of boolean;//檔案開啟標識
  rCommTimeouts:COMMTIMEOUTS;
  bSuccessFlag:boolean;
  ipError:Dword;
  lpstat:PcomStat;
  abSendBuf,abRecvBuf:array[1..1024] of byte;
  nBytesWrite,nBytesRead:DWORD;//設定已寫/讀的數量
  i:integer;
 //---------
implementation

{***************************************************}
(*開啟檔案控制代碼                                     *)
(*預設格式如:MComm.OpenComm(com1,4800,8,NoParity,0)*)
{***************************************************}
function  TMyComm.OpenComm(const COM:integer; //埠號
                           const My_BandRate:DWORD;//波特率
                           Const My_ByteSize:byte; //資料位
                           Const My_Parity:byte;   //是否有奇偶校驗
                           Const My_StopBits:byte):Boolean;//開啟指定串列埠//開啟指定串列埠
var                //預設設定格式為:4800,8,N,1
  comNum:string;
begin
  //如果ComOpenFlag[COM]=false 表示未開啟。。。則進行操作
 if not ComOpenFlag[COM] then//if ComOpenFlag[COM]=false
 begin
      comNum:=format('Com%d',[com]);
      (*第一。創鍵檔案控制代碼*)
      ComHandle[com]:=Createfile(pAnsiChar(comNum),
                             GENERIC_Read or GENERIC_Write,(*訪問讀寫方式*)
                             0,(*不共享*)
                             nil,(*無安全屬性指標*)
                             open_existing,(*建立方式*)
                             file_attribute_normal,0);

      if ComHandle[com]=invalid_handle_value then
      begin
       // showmessage('com1開啟錯誤!');
        CloseComm(com); //呼叫關閉串列埠
        result:=false;
        exit;
      end
      else begin
        result:=True;
        ComOpenFlag[COM]:=true //表示開啟過
      end; //  if ComHandle[com]=invalid_handle_value then

        (*第二:裝置com輸入輸出緩衝區*)
        bSuccessFlag:=SetupComm(ComHandle[com],4096,4096);
        if not bSuccessFlag then
        begin
           showmessage('裝置com輸入輸出緩衝區錯誤!');
           CloseComm(com);
           result:=false;
           exit;
        end;
        (*第三:取得預設DCB*)
        bSuccessFlag:=GetCommstate(ComHandle[com],lpDcb);
        if not bSuccessFlag then
        begin
         // showmessage('取得預設DCB錯誤!');
          CloseCOMM(ComHandle[com]);
          result:=false;
          exit;
        end;
        (*第四,設定DCB*)
        //4800,8,N,1
        lpDCB.BaudRate:=My_BandRate;
        lpDCB.ByteSize:=My_ByteSize;
        lpDCB.Parity:=My_Parity;//N無奇偶校驗
        lpDCB.StopBits:=My_StopBits;//0,1,2===>1,1.5,2
        bSuccessFlag:=SetCommstate(ComHandle[com],lpDCB);
        if not bSuccessFlag then
        begin
         // showmessage('設定DCB錯誤!');
          CloseCOMM(ComHandle[com]);
          exit;
        end;
       ClearComBuf(Com);//清空所有緩衝區
       ClearCommError(ComHandle[com],iperror,lpstat);

      (*第六 設定TimeOut*)
       rCommTimeouts.ReadIntervalTimeout:=0;
       rCommTimeouts.ReadTotalTimeoutConstant:=250;
       rCommTimeouts.ReadTotalTimeoutMultiplier:=0;
       rCommTimeouts.WriteTotalTimeoutMultiplier:=0;
       rCommTimeouts.WriteTotalTimeoutConstant:=250;
       bSuccessFlag:=SetCommTimeOuts(ComHandle[com],rCommTimeouts);
  //EV_RXCHAR A character was received and placed in the input buffer.
       SetCommMask(comHandle[com],EV_RXCHAR
                               or EV_CTS
                               or EV_DSR
                               or EV_RING
                               or EV_RLSD); //設定接收訊息
  //------------------------------------------
       if not bSuccessFlag then
       begin
          //  showmessage('設定TimeOut出錯!');
            result:=false;
            CloseCOMM(ComHandle[com]);
            exit;
       end;
 end else begin
    result:=false;
 end;
end;


{**************************************************}
(*關閉檔案控制代碼                                    *)
(*CloseAll:boolean預設為false;為True時關閉所有埠*)
{**************************************************}
Function TMyComm.CloseComm(Const Com:integer;const CloseAll:boolean):boolean;
var
  cSucc:boolean;
  i:integer;
begin
 //關閉檔案控制代碼
 if not CloseAll then
 begin
    cSucc:=true;
    if  ComOpenFlag[COM] then //如果處於開啟,就進行關閉處理
    begin
         cSucc:=CloseHandle(ComHandle[com]);
         ComOpenFlag[COM]:=false;//設為false。表示已關閉
    end;
    result:=cSucc;
 end  else
 begin
   //關閉所有埠
    for i:=1 to 10 do
    begin
      CloseHandle(ComHandle[i]);
    end;
    result:=True;;
 end;
 //----------------
end;


{******************************}
(*   讀串列埠 ReadComm_string   *)
(*   讀取string               *)
{******************************}
Function TMyComm.ReadComm_string(Const Com:integer;var revcStr:string;const len:DWORD=0):boolean;
var
  SL:DWORD;
begin
 //在讀取前消空緩衝區
  result:=True;
  SL:=len;
   //如果為len=0 則系統自動獲取緩衝區長度
  if len=0 then  SL:=GetRxDSize(Com);
 revcStr:='';
 bSuccessFlag:=ReadFile(ComHandle[com],Pointer(revcStr)^,SL,nBytesRead,nil);
 if (not bSuccessFlag) or (nBytesRead=0) then result:=false;
end;


{******************************}
(*     讀取byte陣列           *)
{******************************}
Function TMyComm.ReadComm_ByteArray(const Com:integer;
                                    var revcArray:array of byte;
                                    const len:DWORD=0):boolean;
var
  i:integer;
  SL:DWORD;
begin
  result:=True;
  SL:=len;
   //如果為len=0 則系統自動獲取緩衝區長度
  if len=0 then  SL:=GetRXDsize(ComHandle[com]);
  if GetRXDsize(ComHandle[com])>high(revcArray) then//如果接緩衝區的資料大於陣列就出錯
  begin
    ClearRXD(ComHandle[com]);//出錯時清空讀取緩衝區
    result:=false;
    exit;
  end;
  //在讀取前消空緩衝陣列
  for i:=low(revcArray) to high(revcArray) do
  begin  //清空讀寫陣列,防止讀取亂碼
    revcArray[i]:=byte(0);
  end;
  bSuccessFlag:=ReadFile(ComHandle[com],revcArray,SL,nBytesRead,nil);
 if (not bSuccessFlag) or (nBytesRead=0) then result:=false;
end;

{******************************}
(*   讀串列埠 ReadComm_Byte     *)
(*   讀取一個Byte             *)
{******************************}
Function TMyComm.ReadComm_Byte(Const Com:integer;var OneByte:byte):boolean;
begin
  result:=true;
 if GetRXDSize(com)<=0 then
 begin
   result:=false;
   exit;
 end;
  bSuccessFlag:=ReadFile(ComHandle[com],OneByte,1,nBytesRead,nil);
 if (not bSuccessFlag) or (nBytesRead=0)  then  result:=false;
end;


{******************************}
(*   寫串列埠WriteComm_String   *)
{******************************}
Function TMyComm.WriteComm_String(Const Com:integer;Const SendString:string):boolean;
begin
 result:=true;
 PurgeComm(ComHandle[com],4);//清空TXD緩衝區內空
 bSuccessFlag:=writeFile(ComHandle[com],pointer(SendString)^,length(sendString),nBytesWrite,nil);
 if (not bSuccessFlag) or (nBytesWrite=0) then  result:=false;
end;


{***************************}
(*寫串列埠WriteComm_ByteArray*)
(*傳送一個byte 陣列        *)
{***************************}
Function TmyComm.WriteComm_ByteArray(Const Com:integer;const SendByte:array of byte;Buflong:DWORD):boolean;
begin
   result:=true;
  //----------------
 ClearTXD(ComHandle[com]);//清空TXD緩衝區內空
 bSuccessFlag:=writeFile(ComHandle[com],SendByte,Buflong,nBytesWrite,nil);
 if (not bSuccessFlag) or (nBytesWrite=0) then  result:=false;
end;


{***************************}
(*     WriteComm_Byte      *)
(*    寫入一個byte         *)
{***************************}
function TMyComm.WriteComm_Byte(const Com: integer;const SendByte:byte): boolean;
begin
   result:=true;
  //----------------
 ClearTXD(ComHandle[com]);//清空TXD緩衝區內空
 bSuccessFlag:=writeFile(ComHandle[com],SendByte,1,nBytesWrite,nil);
 if (not bSuccessFlag) or (nBytesWrite=0) then  result:=false;
end;

{**************************************}
(*      得到RXD緩衝區的資料長度       *)
{**************************************}
function TMyComm.GetRXDsize(com:integer): integer;
var
 cs:TComstat;
begin
  ClearCommError(ComHandle[com],iperror,@cs);
  result:=cs.cbInQue
end;

{******************}
(*    清空RXD     *)
{******************}
procedure TMyComm.ClearRXD(com: integer);
begin
    PurgeComm(ComHandle[com],8);//清空RXD緩衝區內空
end;

{*************************************}
(*           清空所有緩衝區          *)
{*************************************}
procedure TMyComm.ClearComBuf(com:integer);
begin
     //第五:通過PurgeComm清空指定通訊口的輸入輸出緩衝區的所有字元
    // PURGE_TXABORT = 1;     { Kill the pending/current writes to the comm port. }
   // PURGE_RXABORT = 2;     { Kill the pending/current reads to the comm port. }
   // PURGE_TXCLEAR = 4;     { Kill the transmit queue if there. }
   // PURGE_RXCLEAR = 8;     { Kill the typeahead buffer if there. }
   PurgeComm(ComHandle[com],1 or 2 or 4 or 8);
end;

{******************}
(*     清空TXD    *)
{******************}
procedure TMyComm.ClearTXD(com: integer);
begin
   PurgeComm(ComHandle[com],4);//清空TXD緩衝區內空
end;

{*******************************}
//  埠狀態訊息說明
//    MS_CTS_ON          //The CTS (clear-to-send) signal is on.
//    MS_DSR_ON         //The DSR (data-set-ready) signal is on.
//    MS_RING_ON       //The ring indicator signal is on.
//    MS_RLSD_ON       //The RLSD (receive-line-signal-detect) signal is on.
{*******************************}
function TMyComm.GetModemState(com: integer): DWord;
var
 dwModemState:DWord;
begin
 if GetCommModemStatus(ComHandle[com],dwModemState) then
    result:=dwModemState
 else
    result:=0;//操作失敗返回為0
end;

{************************************************}
{設定接收結束byte--->設定全域性變數offByte         }
{注:這裡的接收結束byte不是DCB裡XoffChar是自定義的}
{************************************************}
procedure TMyComm.SetReadOFFByte(offByte: byte);
begin
   bOFFByte:=offByte
end;

{*****************************************}
{判斷設定的結束byte--->讀取全域性變數offByte}
{*****************************************}
function TMyComm.IsReadOFFByte(RByte: byte): boolean;
begin
   result:=RByte=bOFFByte
end;

initialization
   MComm:= TMycomm.Create;
finalization
   MComm.CloseComm(0,True);//關閉所有埠
   MComm.Free;
end.