首页  编辑  

对串口的简单读取

Tags: /超级猛料/Hardware.硬件相关/其它硬件/   Date Created:

]、。·ˉˇ¨〃々—~‖…’”〕〉》」』〗】∶!"'),.:;?]` ///////////////

//

//    (P) Eagle.Yin

//    Serial port communication unit based on timers

//

//    1999/10/02  Mainframe was finished

//    1999/10/03  Add routine 'Get_Port_Config' for debug

//                Add Input-Time-Out processing code

//    1999/10/07  Add error checking when read and write serial port

//                Add routine 'Set_Port_TimeOut' and delete 'tmOut' parameters in 'Open_Port'

//                Add routine 'Port_Error_Str' to get text description of port error

//

{---$define debugall}

{---$define debug}

unit SerialPort;

interface

uses

  Windows, ExtCtrls;

const

  tmInterval  = 50; // timer interval is 50ms

const

E_NO_ERROR = 0; // port error codes

  E_OPEN = 1;

  E_GET_STATE = 2;

  E_SET_STATE = 3;

  E_GET_TMO = 4;

  E_SET_TMO = 5;

  E_TIMEOUT   = 6;

  E_READ      = 7;

  E_WRITE     = 8;

 

const

  InBufferSize= 1024; // size of input buffer

type

  TInBuffer=  array[0..InBufferSize-1] of byte; // input buffer

 

type

TReader = procedure( len:integer; var buf:TInBuffer ) of object; // data reader procedure

  TWatcher = procedure( erCode:integer ) of object; // port exception watcher

type

  TSerialPort = class( TObject )

  private

     hReader  : TReader; // handle of data reader

     hWatcher : TWatcher; // handle of watcher

     tmReader : TTimer; // port monitor

     tmOutCnt,

     tmOutVal : integer; // time out value, tmOut = TIME_OUT(ms)/tmInterval(ms)

     DataInFlag: boolean; // data flow in flag

     procedure   Monitor( Sender:TObject );

  protected

     hPort    : THandle; // handle of serial port

  public

     procedure   Set_Port_TimeOut( tmOut:integer );

     function    Open_Port( PortName:string; BaudRate, ByteSize, StopBits, Parity:integer ):integer;

     procedure   Close_Port;

     function    WriteData( num:integer; var buf ):integer;

     function    Get_Port_Config( var BaudRate, ByteSize, StopBits, Parity:integer ):boolean;

     constructor Create( dReader:TReader; dWatcher:TWatcher );

     destructor  Destroy; override;

  end;// TSerialPort

  function    Port_Error_Str( eCode:integer ):string;

implementation

uses

  SysUtils, Dialogs;

//-----------------------------------------------------------------------------------

var

  Err_Table   : array[0..8] of string = ( // port error message table

     '', // no error

     '打开串行口失败',

     '获取串行口状态失败',

     '设置串行口状态失败',

     '获取串行口超时失败',

     '设置串行口超时失败',

     '串行口无数据输入',

     '读串行口错误',

     '写串行口错误'

  ); // Error string table

function    Port_Error_Str( eCode:integer ):string;

//

// This function return text description for port errors

//    eCode : Port error code

//    result: Text description for port error

//

begin

  if ( eCode>=0 ) and ( eCode<=8 ) then

     result := Err_Table[eCode] + '(' + inttostr( eCode ) + ')'

  else

     result := '未知串行口错误(' + inttostr( eCode ) + ')';

end;

//-----------------------------------------------------------------------------------

var

  buf      : TInBuffer; // input buffer for monitor

procedure   TSerialPort.Monitor( Sender:TObject );

//

// This procedure is the 'OnTimer' event handler of 'tmReader', it reads data from serial port and

// call 'hReader' if necessary, it also counts timeouts, if timeout occured, it will call the error

// handler 'hWatcher'

//

var

  eCode    : dword;

  cStat    : COMSTAT;

  numRead  : dword;

begin

  // manipulate serial port

  eCode := 0;

  ClearCommError( hPort, eCode, @cStat );

  repeat

     numRead :=0;

     if not ReadFile( hPort, buf, sizeof( buf ), numRead, nil ) then

     begin

        if Assigned( hWatcher ) then // call read-error handler

           hWatcher( E_READ );

        exit;

     end;{ if }

     // count timeout counter

     DataInFlag := numRead >0; // set data flow in flag

     if DataInFlag then // reset time out counter if data in

        tmOutCnt := 0;

     inc( tmOutCnt );

     if tmOutCnt>=tmOutVal then // timeout occured

     begin

        tmOutCnt := 0; // reset time out counter

        if Assigned( hWatcher ) then

           hWatcher( E_TIMEOUT );

     end;{ if }

     // pass data to reader

     if Assigned( hReader ) then

        hReader( numRead, buf );

  until ( numReadend;

//--------------------------------------------------------------------------------------------------

procedure   TSerialPort.Set_Port_TimeOut( tmOut:integer );

//

// This procedure set port timeout value and reset the timeout counter

//    tmOut : Port timeout value, in milliseconds

//

begin

  tmOutVal := tmOut div tmInterval;

  tmOutCnt := 0;

end;

function    TSerialPort.Open_Port( PortName:string; BaudRate, ByteSize, StopBits, Parity:integer ):integer;

//

// Open and config serial port and activate the monitor timer

//

function OpenPort:integer;

  begin

   hPort := INVALID_HANDLE_VALUE; // init port handle

     hPort := CreateFile(  pchar( PortName ), // port name

       GENERIC_READ or GENERIC_WRITE, // access mode

                           0, // share mode

                           nil, // security attributes

                           OPEN_EXISTING, // how to create

                           0, // file attributes

                           0 ); // template file

     if hPort = INVALID_HANDLE_VALUE then

      result := E_OPEN

     else

      result := E_NO_ERROR;

     {$ifdef debug}

        if result<>E_NO_ERROR then

         ShowMessage( 'Can not open port:' + PortName );

     {$endif}

  end;

  function ConfigPort:integer;

  var

   commDCB : DCB;

     commTMO : TCOMMTIMEOUTS;

  begin

   if not GetCommState( hPort, CommDCB ) then // can't get port state

     begin

      result := E_GET_STATE;

        CloseHandle( hPort );

        hPort := INVALID_HANDLE_VALUE;

     {$ifdef debug}

       ShowMessage( 'Can not get port state:' + PortName );

      {$endif}

        exit;

     end;{ if }

     commDCB.BaudRate := BaudRate; // setup port device control block

     commDCB.ByteSize := ByteSize;

     commDCB.StopBits := StopBits;

     commDCB.Parity := Parity;

     if not SetCommState( hPort, commDCB ) then // can't set port state

     begin

      result := E_SET_STATE;

        CloseHandle( hPort );

        hPort := INVALID_HANDLE_VALUE;

     {$ifdef debug}

       ShowMessage( 'Can not set port state:' + PortName );

      {$endif}

        exit;

     end;{ if }

     if not GetCommTimeOuts( hPort, commTMO ) then // can't get port time outs

     begin

      result := E_GET_TMO;

        CloseHandle( hPort );

        hPort := INVALID_HANDLE_VALUE;

     {$ifdef debug}

       ShowMessage( 'Can not get port timeouts:' + PortName );

      {$endif}

        exit;

     end;{ if }

     with commTMO do // setup port time outs

     begin

   ReadIntervalTimeOut:=MAXDWORD;

      ReadTotalTimeOutMultiplier:=0;

      ReadTotalTimeOutConstant:=0;

     end;{ with }

     if not SetCommTimeOuts( hPort, commTMO ) then // can't set port time outs

     begin

      result := E_SET_TMO;

        CloseHandle( hPort );

        hPort := INVALID_HANDLE_VALUE;

     {$ifdef debug}

       ShowMessage( 'Can not set port timeouts:' + PortName );

      {$endif}

        exit;

     end;{ if }

     result := E_NO_ERROR; // default result

  end;

begin

result := OpenPort; // open port

  if result<>E_NO_ERROR then

     exit;

  result := ConfigPort; // config port

  if result<>E_NO_ERROR then

     exit;

  PurgeComm( hPort, PURGE_TXABORT + PURGE_RXABORT + PURGE_TXCLEAR + PURGE_RXCLEAR );

  tmReader.Enabled := True; // init monitor timer

end;

procedure   TSerialPort.Close_Port;

//

// Close port and deactivate the monitor timer

//

begin

  if hPort<>INVALID_HANDLE_VALUE then

  begin

     tmReader.Enabled := False; // disable monitor timer

     

     PurgeComm( hPort, PURGE_TXABORT + PURGE_RXABORT + PURGE_TXCLEAR + PURGE_RXCLEAR );

     CloseHandle( hPort ); // close port

     hPort := INVALID_HANDLE_VALUE;

  end;{ if }

end;

function    TSerialPort.WriteData( num:integer; var buf ):integer;

var

  eCode : dword;

  cStat : COMSTAT;

begin

  eCode := 0;

  ClearCommError( hPort, eCode, @cStat );

  result := 0;

  if not WriteFile( hPort, buf,num, dword( result ), nil ) then

  begin

     if Assigned( hWatcher ) then // call write error handler

        hWatcher( E_WRITE );

  end;{ if }

end;

function    TSerialPort.Get_Port_Config( var BaudRate, ByteSize, StopBits, Parity:integer ):boolean;

//

// Get current port configuration

//

var

  commDCB  : DCB;

begin

  result := ( hPort<>INVALID_HANDLE_VALUE );

  if result then

  begin

     result := GetCommState( hPort, commDCB );

     if result then

     begin

        BaudRate := commDCB.BaudRate;

        ByteSize := commDCB.ByteSize;

        StopBits := commDCB.StopBits;

        Parity := commDCB.Parity;

     end;{ if }

  end;{ if }

end;

//-----------------------------------------------------------------------------------

constructor TSerialPort.Create( dReader:TReader; dWatcher:TWatcher );

begin

inherited Create;

  hPort := INVALID_HANDLE_VALUE; // init port handle

  hReader := dReader; // init event handler

  hWatcher := dWatcher; // init watcher handler

  tmOutVal := 5*1000; // default time out value is 5s

  DataInFlag := True;

  tmReader := TTimer.Create( nil ); // init timer

  with tmReader do

  begin

   Enabled := False;

     Interval := tmInterval;

     OnTimer := Monitor;

  end;{ with }

end;

destructor  TSerialPort.Destroy;

begin

hWatcher := nil; // disable event handler

hReader := nil;

  Close_Port; // close serial port

  tmReader.Destroy; // destroy monitor reader

inherited;

end;

end.

========================================================

1.用M$的MSComm控件

2.用CreateFile打开串口,ReadFile来读,这里有一段我用C Builder写的程序中的一段函数,你看看

bool ReceiveByteFromComDev(double TimeReceiveDelay, unsigned char* ByteBuf, HANDLE hCom)

{

    unsigned long dwNumRead ;

    unsigned long dwNumtoRead ;

    unsigned char TempCommRead[3];

    GetCommTimeouts(hCom,&MyCommTimeouts);

    MyCommTimeouts.ReadIntervalTimeout = TimeReceiveDelay;

    MyCommTimeouts.ReadTotalTimeoutMultiplier = 1;

    MyCommTimeouts.ReadTotalTimeoutConstant = TimeReceiveDelay;

    SetCommTimeouts(hCom ,&MyCommTimeouts );

    dwNumtoRead = 1 ;

    BOOL Fcom=ReadFile(hCom,&TempCommRead,dwNumtoRead ,&dwNumRead,NULL);

    if (Fcom &&  dwNumRead!= 0) {*ByteBuf = TempCommRead[0] ;return true;}

    else return false;

}