精华区 [关闭][返回]

当前位置:网易精华区>>讨论区精华>>编程开发>>● Delphi>>Windows API函数>>对串口的简单读取

主题:对串口的简单读取
发信人: 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版 版副发贴印 
               

[关闭][返回]