发信人: showskyws(示天) 
整理人: teleme(2001-05-08 12:36:34), 站内信件
 | 
 
 
对串口的简单读取 
 
 /////////////// 
 // 
 //    (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; 
 }
 
  ---- 我每天都在努力,因为每天都要进步!
 沉迷网络,程序人生,这就是我!
 欢迎光临我的个人主页:示天工作室 
 
 网易北京社区 DELPHI版 版副发贴印                 | 
 
 
 |