Delphi中串行通信的實(shí)現(xiàn)
隨著現(xiàn)代信息技術(shù)的發(fā)展以及計(jì)算機(jī)網(wǎng)絡(luò)的廣泛使用,計(jì)算機(jī)通信技術(shù)已經(jīng)日臻成熟,但串行通信作為一種靈活方 便可靠的通信方式,仍不失為有效的通信手段,被廣泛應(yīng)用于工業(yè)控制中。在工業(yè)生產(chǎn)實(shí)踐中,用PC機(jī)對(duì)工程實(shí)現(xiàn)實(shí)時(shí) 監(jiān)控,通常要求PC機(jī)能在用戶界面上具有數(shù)據(jù)采集、數(shù)據(jù)處理以及控制信號(hào)的產(chǎn)生與傳輸?shù)裙δ?。在這種特定的環(huán)境下,PC機(jī)要與過程控制的實(shí)時(shí)信號(hào)相聯(lián)系,就要求能實(shí)現(xiàn)對(duì)PC機(jī)的串行端口直接操作。Borland公司推出的Delphi是一種功能強(qiáng)大的高級(jí)編程語言,其具有的可視化面向?qū)ο蟮奶匦?,特別適于在Windows環(huán)境下圖形界面和用戶程序的編制。
基于WIN95/NT的串行通信機(jī)制
Windows操作系統(tǒng)的機(jī)制禁止應(yīng)用程序直接訪問計(jì)算機(jī)硬件,但它為程序員提供了一系列的標(biāo)準(zhǔn)API函數(shù),使得應(yīng)用程序的編制更加方便并且免除了對(duì)有關(guān)硬件的調(diào)試麻煩。在Windows95/NT中,原來Windows3.X的WM_COMMNOTIFY消息 已被取消,操作系統(tǒng)為每個(gè)通信設(shè)備開辟了用戶可定義大小的讀/寫緩沖區(qū),數(shù)據(jù)進(jìn)出通信口均由操作系統(tǒng)后臺(tái)完成,應(yīng)用程序只需對(duì)讀/寫緩沖區(qū)操作即可。WIN95/NT中幾個(gè)常用的串行通信操作函數(shù)如下:
CreatFile打開串行口 CloseHandle關(guān)閉串行口 SetupComm設(shè)置通信緩沖區(qū)的大小 ReadFile讀串口操作 WriteFile寫串口操作 SetCommState設(shè)置通信參數(shù) GetCommState獲取默認(rèn)通信參數(shù) ClearCommError清除串口錯(cuò)誤并獲取當(dāng)前狀態(tài)
除上述幾個(gè)函數(shù)外,還要經(jīng)常用到一個(gè)重要的記錄DCB(設(shè)備控制塊)。DCB中記錄有可定義的串行口參數(shù),設(shè)置串行口參數(shù)時(shí)必須先用GetCommState函數(shù)將系統(tǒng)默認(rèn)值填入DCB控制塊,然后才可把用戶想改變的自定義值設(shè)定。 在WIN95/NT中進(jìn)行串行通信除了解基本的通信操作函數(shù)外,還要掌握多線程編程。線程是進(jìn)程內(nèi)部執(zhí)行的路徑,是操作系統(tǒng)分配CPU時(shí)間的基本實(shí)體。每個(gè)進(jìn)程都由單線程開始完成應(yīng)用程序的執(zhí)行。串行通信需要利用多線程技術(shù)實(shí) 現(xiàn),其主要的處理邏輯可以表述如下:進(jìn)程一開始先由主線程做一些必要的初始化工作,然后主線程根據(jù)需要在適當(dāng)時(shí)候建立通信監(jiān)視線程監(jiān)視通信口,當(dāng)指定的串行口事件發(fā)生時(shí),向主線程發(fā)送WM_COMMNOTIFY消息(由于WIN95取消了WM_COMMNOTIFY消息,因此必須自己創(chuàng)建),主線程對(duì)其進(jìn)行處理。若不需要WM_COMMNOTIFY消息,則主線程終止通信監(jiān)視線程。 多線程同時(shí)執(zhí)行,將會(huì)引起對(duì)共享資源的沖突。為避免沖突,就要用同步多線程對(duì)共享資源進(jìn)行訪問。WIN95提供 許多保持線程同步的方法,筆者采用創(chuàng)建事件對(duì)象來保持線程同步。通過CraeteEvent()創(chuàng)建事件對(duì)象,使用etEvent()或PulseEvent()函數(shù)將事件對(duì)象設(shè)置成信號(hào)同步。在應(yīng)用程序中,利用WaitSingleObject()函數(shù)等待同步的觸發(fā),等到指定的事件被其它線程設(shè)置為有信號(hào)時(shí),才繼續(xù)向下執(zhí)行程序。 Delphi下的具體實(shí)現(xiàn)方法
Delphi的強(qiáng)大功能和支持多線程的面向?qū)ο缶幊碳夹g(shù),使得實(shí)現(xiàn)串行通信非常簡(jiǎn)單方便。它通過調(diào)用外部的API函數(shù)來實(shí)現(xiàn),主要步驟如下:首先,利用CreateFile函數(shù)打開串行口,以確定本應(yīng)用程序?qū)Υ舜锌诘恼加袡?quán),并封鎖其它應(yīng)用程序?qū)Υ舜诘牟僮?;其次,通過GetCommState函數(shù)填充設(shè)備控制塊DCB,再通過調(diào)用SetCommState函數(shù)配置串行口的波特率、數(shù)據(jù)位、校驗(yàn)位和停止位。然后,創(chuàng)建串行口監(jiān)視線程監(jiān)視串行口事件。在此基礎(chǔ)上就可以在相應(yīng)的串口上操作數(shù)據(jù)的傳輸;最后,用CloseHandle函數(shù)關(guān)閉串行口。具體的程序如下,本程序用Delphi3.0編制在Win95 環(huán)境下調(diào)試通過,已投入實(shí)際應(yīng)用中,供廣大讀者參考。 程序: 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; //線程執(zhí)行過程 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); //同步事件復(fù)位; PostMessage(Form1.Handle,WM_COMMNOTIFY,0,0);//發(fā)送消息; 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); //設(shè)置輸入,輸出緩沖區(qū)皆為4096字節(jié) getcommstate(hcom,lpdcb); //獲取串行口當(dāng)前默認(rèn)設(shè)置 lpdcb.baudrate:=2400; lpdcb.StopBits:=1; lpdcb.ByteSize:=8; lpdcb.Parity:=EvenParity; //偶校驗(yàn) 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); //處理接收數(shù)據(jù) SetEvent(Post_Event); //同步事件置位 end; end; procedure TForm1.FormCreate(Sender: TObject); begin comminitialize; post_event:=CreateEvent(nil,true,true,nil); //創(chuàng)建同步事件; Tcomm.Create(False); //創(chuàng)建串行口監(jiān)視線程; end; end. 作者會(huì)員名:ruan_bangqiu |