程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 更多編程語言 >> Delphi >> Delphi中串行通信的實現

Delphi中串行通信的實現

編輯:Delphi
  隨著現代信息技術的發展以及計算機網絡的廣泛使用,計算機通信技術已經日臻成熟,但串行通信作為一種靈活方 便可靠的通信方式,仍不失為有效的通信手段,被廣泛應用於工業控制中。在工業生產實踐中,用PC機對工程實現實時 監控,通常要求PC機能在用戶界面上具有數據采集、數據處理以及控制信號的產生與傳輸等功能。在這種特定的環境下,PC機要與過程控制的實時信號相聯系,就要求能實現對PC機的串行端口直接操作。Borland公司推出的Delphi是一種功能強大的高級編程語言,其具有的可視化面向對象的特性,特別適於在Windows環境下圖形界面和用戶程序的編制。
  
  基於WIN95/NT的串行通信機制
  
  Windows操作系統的機制禁止應用程序直接訪問計算機硬件,但它為程序員提供了一系列的標准API函數,使得應用程序的編制更加方便並且免除了對有關硬件的調試麻煩。在Windows95/NT中,原來Windows3.X的WM_COMMNOTIFY消息 已被取消,操作系統為每個通信設備開辟了用戶可定義大小的讀/寫緩沖區,數據進出通信口均由操作系統後台完成,應用程序只需對讀/寫緩沖區操作即可。WIN95/NT中幾個常用的串行通信操作函數如下:
  
  CreatFile打開串行口
  CloseHandle關閉串行口
  SetupComm設置通信緩沖區的大小
  ReadFile讀串口操作
  WriteFile寫串口操作
  SetCommState設置通信參數
  GetCommState獲取默認通信參數
  ClearCommError清除串口錯誤並獲取當前狀態

  除上述幾個函數外,還要經常用到一個重要的記錄DCB(設備控制塊)。DCB中記錄有可定義的串行口參數,設置串行口參數時必須先用GetCommState函數將系統默認值填入DCB控制塊,然後才可把用戶想改變的自定義值設定。

  在WIN95/NT中進行串行通信除了解基本的通信操作函數外,還要掌握多線程編程。線程是進程內部執行的路徑,是操作系統分配CPU時間的基本實體。每個進程都由單線程開始完成應用程序的執行。串行通信需要利用多線程技術實 現,其主要的處理邏輯可以表述如下:進程一開始先由主線程做一些必要的初始化工作,然後主線程根據需要在適當時候建立通信監視線程監視通信口,當指定的串行口事件發生時,向主線程發送WM_COMMNOTIFY消息(由於WIN95取消了WM_COMMNOTIFY消息,因此必須自己創建),主線程對其進行處理。若不需要WM_COMMNOTIFY消息,則主線程終止通信監視線程。

  多線程同時執行,將會引起對共享資源的沖突。為避免沖突,就要用同步多線程對共享資源進行訪問。WIN95提供 許多保持線程同步的方法,筆者采用創建事件對象來保持線程同步。通過CraeteEvent()創建事件對象,使用etEvent()或PulseEvent()函數將事件對象設置成信號同步。在應用程序中,利用WaitSingleObject()函數等待同步的觸發,等到指定的事件被其它線程設置為有信號時,才繼續向下執行程序。

Delphi下的具體實現方法
  
  Delphi的強大功能和支持多線程的面向對象編程技術,使得實現串行通信非常簡單方便。它通過調用外部的API函數來實現,主要步驟如下:首先,利用CreateFile函數打開串行口,以確定本應用程序對此串行口的占有權,並封鎖其它應用程序對此串口的操作;其次,通過GetCommState函數填充設備控制塊DCB,再通過調用SetCommState函數配置串行口的波特率、數據位、校驗位和停止位。然後,創建串行口監視線程監視串行口事件。在此基礎上就可以在相應的串口上操作數據的傳輸;最後,用CloseHandle函數關閉串行口。具體的程序如下,本程序用Delphi3.0編制在Win95 環境下調試通過,已投入實際應用中,供廣大讀者參考。

程序:
  unit comdemou;
  interface
  uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs;

const
  Wm_commNotify=Wm_User+12;
  type
  TForm1 = class(TForm)
  procedure FormCreate(Sender: TObject);
  private
  Procedure comminitialize;
  Procedure MsgcommProcess(Var Message:Tmessage); Message Wm_commnotify;
  { Private declarations }
  public
  { Public declarations }
  end;

  //線程聲明
  TComm=Class(TThread)
  protected
  procedure Execute;override;
  end;
  
  
var
  Form1: TForm1;
  hcom,Post_Event:Thandle;
  lpol:Poverlapped;
  implementation

{$R *.DFM}

Procedure TComm.Execute; //線程執行過程
  var
  dwEvtMask:DWord;
  Wait:Boolean;
  Begin
  fillchar(lpol,sizeof(toverlapped),0);
  While True do Begin
  dwEvtMask:=0;
  Wait:=WaitCommEvent(hcom,dwevtmask,lpol); //等待串行口事件;
  if Wait Then Begin
  waitforsingleobject(post_event,infinite); //等待同步事件置位;
  resetevent(post_event); //同步事件復位;
  PostMessage(Form1.Handle,WM_COMMNOTIFY,0,0);//發送消息;
  end;
  end;
  end;

procedure Tform1.comminitialize; //串行口初始化
  var
  lpdcb:Tdcb;
  Begin
  hcom:=createfile('com2',generic_read or generic_write,0,nil,open_existing,
    file_attribute_normal or file_flag_overlapped,0);//打開串行口
  if hcom=invalid_handle_value then
  else
  setupcomm(hcom,4096,4096); //設置輸入,輸出緩沖區皆為4096字節
  getcommstate(hcom,lpdcb); //獲取串行口當前默認設置
  lpdcb.baudrate:=2400;
  lpdcb.StopBits:=1;
  lpdcb.ByteSize:=8;
  lpdcb.Parity:=EvenParity; //偶校驗
  Setcommstate(hcom,lpdcb);
  setcommMask(hcom,ev_rxchar);
  //指定串行口事件為接收到字符;
  end;

Procedure TForm1.MsgcommProcess(Var Message:Tmessage);
  var
  Clear:Boolean;
  Coms:Tcomstat;
  cbNum,ReadNumber,lpErrors:Integer;
  Read_Buffer:array[1..100]of char;
  Begin
  Clear:=Clearcommerror(hcom,lpErrors,@Coms);
  if Clear Then Begin
  cbNum:=Coms.cbInQue;
  ReadFile(hCom,Read_Buffer,cbNum,ReadNumber,lpol);
  //處理接收數據
  SetEvent(Post_Event); //同步事件置位
  end;
  end;

procedure TForm1.FormCreate(Sender: TObject);
  begin
  comminitialize;
  post_event:=CreateEvent(nil,true,true,nil); //創建同步事件;
  Tcomm.Create(False); //創建串行口監視線程;
  end;

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved