Cport 詳細解釋和應用



轉載:http://www.cnblogs.com/Bung/archive/2011/05/20/2051636.html

通過comport獲取計算機中的所有串口號:


procedure TForm1.FormCreate(Sender: TObject);  //獲取計算機中的串口號

var

  Cnumber:TStrings;

  i:Integer;

begin

  cbb2.Items.Clear;

  Cnumber:=TStringList.Create;

  EnumComPorts(Cnumber);  //獲取串口號函數:EnumComPorts

  for i:=0 to Cnumber.Count-1 do

  begin

  cbb2.Items.Add(Cnumber.Strings[i])

  end;

  cbb2.ItemIndex:=0;

  Cnumber.Free;

end;

 

procedure TForm1.btn7Click(Sender: TObject);  //打開串口

begin

  ComPort1.Port:=cbb2.Text;

  if ComPort1.Connected then

  begin

    ComPort1.Close;

    ComPort1.Open;

  end

  else

  ComPort1.Open;

end;


我開始用comport時發現它每次14個字符觸發一次接收事件,而我要接收的一幀完整數據是82個字符,因此我在每幀的前後個加了開始碼和結束碼,共84個字符,當Count值大於84我才處理,程序片斷如下:


procedure TFCOMM.ComPortRxChar(Sender: TObject; Count: Integer);

var

  ReceiveData:TDateRec;

  p:Pbyte;

  Block : array[0..85] of Char;

begin

  if (not Ready)  then

    begin

      ComPort.Read(p,1);   //開始碼爲$7FFE,接收時先收的是$FE

      move(p, SecondByte,1);

      if SecondByte = $FE then        //如果收到的字節是$FE,那就看看下一個是不是$7F

        begin

          FirstByte := SecondByte;

          ComPort.Read(p,1);;

          move(p, SecondByte,1);

        end;

    end;

 

  if (FirstByte = $FE) and (SecondByte = $7F) then

    Ready := True;

 

  if Ready and (count>=84) then

    begin

      。。。。

    end;

end;


Spcomm有的是定時查詢的方式讀COM口;而ComPort用Overlapped機制進行COM讀寫,只要COM有數據接收到,ComPort就能夠從Event響應,並通知應用程序接收,所以,某種ComPort的實時性更好。但是,Overlapped的Event被觸發,並不是COM接入一段完整的信息才觸發,是Windows自己決定的,我在多個計算機和不同的Windows版本上試過,其觸發後接收到的字符數並不一樣。因此,需要自己建一個緩衝區來處理數據。


procedure TCustomComPort.CreateHandle;

begin

  FHandle := CreateFile(

    PChar('\\.\' + FPort),

    GENERIC_READ or GENERIC_WRITE,

    0,

    nil,

    OPEN_EXISTING,

    FILE_FLAG_OVERLAPPED,  // 以Overlapped方式打開COM口

    0);

 

  if FHandle = INVALID_HANDLE_VALUE then

    raise EComPort.Create(CError_OpenFailed, GetLastError);

end;

 

procedure TComThread.Execute;

var

  EventHandles: array[0..1] of THandle;

  Overlapped: TOverlapped;

  Signaled, BytesTrans, Mask: DWORD;

begin

  FillChar(Overlapped, SizeOf(Overlapped), 0);

  Overlapped.hEvent := CreateEvent(nil, True, True, nil);

  EventHandles[0] := FStopEvent;

  EventHandles[1] := Overlapped.hEvent; // COM口上的Overlapped事件

  repeat

    // 等待COM上的事件

    // wait for event to occur on serial port

    WaitCommEvent(FComPort.Handle, Mask, @Overlapped);

    Signaled := WaitForMultipleObjects(2, @EventHandles, False, INFINITE);

    // if event occurs, dispatch it

    if (Signaled = WAIT_OBJECT_0 + 1)

      and GetOverlappedResult(FComPort.Handle, Overlapped, BytesTrans, False)

    then

    begin

      // 通知應用程序接收數據

      FEvents := IntToEvents(Mask);

      DispatchComMsg;

    end;

  until Signaled <> (WAIT_OBJECT_0 + 1);

  // clear buffers

  SetCommMask(FComPort.Handle, 0);

  PurgeComm(FComPort.Handle, PURGE_TXCLEAR or PURGE_RXCLEAR);

  CloseHandle(Overlapped.hEvent);

  CloseHandle(FStopEvent);

end; 
Cport - 應用集合



通過comport獲取計算機中的所有串口號:


procedure TForm1.FormCreate(Sender: TObject);  //獲取計算機中的串口號

var

  Cnumber:TStrings;

  i:Integer;

begin

  cbb2.Items.Clear;

  Cnumber:=TStringList.Create;

  EnumComPorts(Cnumber);  //獲取串口號函數:EnumComPorts

  for i:=0 to Cnumber.Count-1 do

  begin

  cbb2.Items.Add(Cnumber.Strings[i])

  end;

  cbb2.ItemIndex:=0;

  Cnumber.Free;

end;

 

procedure TForm1.btn7Click(Sender: TObject);  //打開串口

begin

  ComPort1.Port:=cbb2.Text;

  if ComPort1.Connected then

  begin

    ComPort1.Close;

    ComPort1.Open;

  end

  else

  ComPort1.Open;

end;


我開始用comport時發現它每次14個字符觸發一次接收事件,而我要接收的一幀完整數據是82個字符,因此我在每幀的前後個加了開始碼和結束碼,共84個字符,當Count值大於84我才處理,程序片斷如下:


procedure TFCOMM.ComPortRxChar(Sender: TObject; Count: Integer);

var

  ReceiveData:TDateRec;

  p:Pbyte;

  Block : array[0..85] of Char;

begin

  if (not Ready)  then

    begin

      ComPort.Read(p,1);   //開始碼爲$7FFE,接收時先收的是$FE

      move(p, SecondByte,1);

      if SecondByte = $FE then        //如果收到的字節是$FE,那就看看下一個是不是$7F

        begin

          FirstByte := SecondByte;

          ComPort.Read(p,1);;

          move(p, SecondByte,1);

        end;

    end;

 

  if (FirstByte = $FE) and (SecondByte = $7F) then

    Ready := True;

 

  if Ready and (count>=84) then

    begin

      。。。。

    end;

end;


Spcomm有的是定時查詢的方式讀COM口;而ComPort用Overlapped機制進行COM讀寫,只要COM有數據接收到,ComPort就能夠從Event響應,並通知應用程序接收,所以,某種ComPort的實時性更好。但是,Overlapped的Event被觸發,並不是COM接入一段完整的信息才觸發,是Windows自己決定的,我在多個計算機和不同的Windows版本上試過,其觸發後接收到的字符數並不一樣。因此,需要自己建一個緩衝區來處理數據。



procedure TCustomComPort.CreateHandle;

begin

  FHandle := CreateFile(

    PChar('\\.\' + FPort),

    GENERIC_READ or GENERIC_WRITE,

    0,

    nil,

    OPEN_EXISTING,

    FILE_FLAG_OVERLAPPED,  // 以Overlapped方式打開COM口

    0);

 

  if FHandle = INVALID_HANDLE_VALUE then

    raise EComPort.Create(CError_OpenFailed, GetLastError);

end;

 

procedure TComThread.Execute;

var

  EventHandles: array[0..1] of THandle;

  Overlapped: TOverlapped;

  Signaled, BytesTrans, Mask: DWORD;

begin

  FillChar(Overlapped, SizeOf(Overlapped), 0);

  Overlapped.hEvent := CreateEvent(nil, True, True, nil);

  EventHandles[0] := FStopEvent;

  EventHandles[1] := Overlapped.hEvent; // COM口上的Overlapped事件

  repeat

    // 等待COM上的事件

    // wait for event to occur on serial port

    WaitCommEvent(FComPort.Handle, Mask, @Overlapped);

    Signaled := WaitForMultipleObjects(2, @EventHandles, False, INFINITE);

    // if event occurs, dispatch it

    if (Signaled = WAIT_OBJECT_0 + 1)

      and GetOverlappedResult(FComPort.Handle, Overlapped, BytesTrans, False)

    then

    begin

      // 通知應用程序接收數據

      FEvents := IntToEvents(Mask);

      DispatchComMsg;

    end;

  until Signaled <> (WAIT_OBJECT_0 + 1);

  // clear buffers

  SetCommMask(FComPort.Handle, 0);

  PurgeComm(FComPort.Handle, PURGE_TXCLEAR or PURGE_RXCLEAR);

  CloseHandle(Overlapped.hEvent);

  CloseHandle(FStopEvent);

end; 

發佈了58 篇原創文章 · 獲贊 22 · 訪問量 16萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章