這是序列槽程式設計的第三篇, 也是最後一篇.
為客戶開發一個程式, 是個機加工工廠, 他們有個量測儀器, 能将量測值通過序列槽列印機列印出來, 勞工拿着這個紙條, 再加工中心上輸入量測值. 在機床上輸入東西比較麻煩, 也容易出錯, 需要做些改造, 因為量測裝置的作業系統是一個嵌入式系統, 也沒有源碼, 無法直接修改量測軟體. 我給的方案如下:
方案:加一個PC機, 抓取序列槽列印機接收的資料, 提起其中的量測值, 然後将量測值以檔案的形式發送到加工中心上.
現場條件不允許安裝.Net Framework, 是以我選擇使用Delphi開發序列槽程式, 通訊用額是Turbo Power的 TApdComPort 元件,該元件功能非常強大. 但我感覺做為類庫, 在程式設計接口上有些地方反人類, 瑕不掩瑜吧.
=============================
TApdComPort 相關資料
=============================
本文主要參考:
TApdComPort 使用說明,
最重要的資料是源碼, TApdComPort 的核心代碼在 AdPort.pas 中.
官方的Faq 必須要學習, Reference文檔名副其實, 僅做reference用吧.
http://tpapro.sourceforge.net/Faq.html
http://tpapro.sourceforge.net/docs/APRO_ReferenceGuide.pdf
-----------------------------
基本屬性, 必須在序列槽打開之前設定
-----------------------------
**********
1》ComNumber屬性
ComNumber:設定或傳回序列槽号,值為 1、2時分别設定coml、com2。ComNumber并不驗證序列槽号的有效性。當打開序列槽時,Windows驅動程式将決定序列槽号是否有效,如果無效,則出錯。
**********
2》Baud屬性
Baud屬性決定端口使用的波特率。
通常可接受的波特率值包括:300、1200、2400、4800、9600、19200、38400、57600、115200。
當波特率被改變時,如果端口已打開,線路參數立即更新。把Baud屬性傳遞給通信驅動程式之前,Baud不校驗所賦予的值,驅動程式可能拒絕這個值,并将導緻一個異常。異常:ENotSupported.
**********
3》StopBits屬性
決定端口的停止位的個數,可接受的值為1和2。如果DataBits等于5,一個請求2個停止位被解釋為一個請求1.5個停止位。
當改變StopBits屬性時,如果端口已打開,線路參數立即更新。在把StopBit屬性傳遞給通信驅動程式之前,StopBits不校驗所賦予的值, 驅動程式可能拒絕這個值,并将導緻一個異常。異常:EBadArgument、EBadHandle。
**********
4》DataBits屬性
決定端口的資料位的個數。可接受值是:5、6、7、8。
當改變DataBits屬性時,如果端口已打開,線路參數立即更新。把DataBit屬性傳遞給通信驅動程式之前,DataBits不校驗所賦予的值,驅 動程式可能拒絕這個值,并将導緻一個異常。異常:ENotSupported.
**********
5》Parity屬性
決定端口的奇偶校驗模式。
當Parity被改變時,如果端口已打開,線路參數立即更新。把Parity屬性傳遞給通信驅動程式之前,Parity不校驗所賦予的值,驅動程式可能拒 絕這個值,并将導緻一個異常。異常:EBadHandle、ENotSupported.
**********
-----------------------------
其它控制屬性
-----------------------------
1》AutoOpen:決定端口是否按要求自動打開。當然我總是禁掉AutoOpen, 另外PromptForPort也禁掉
**********
2》Open屬性:決定是否打開端口,是否用目前端口的所有屬性初始化該端口。控件發送或接收字元前,Open必須設定為True. 将Open屬性設為True後, 并不表示序列槽就被打開了, 序列槽真正打開後, 會觸發OnOpen事件, 關閉也類似.
**********
3》OutPut屬性:向輸出緩沖區中寫入資料,在設計時無效,運作時隻讀。
**********
4》流控設定, 初始化COM時, 可設定如下流控參數
ApdComPort.HWFlowOptions
ApdComPort.SWFlowOptions
ApdComPort.XOffChar
ApdComPort.XOnChar
設計時和運作時, 可通過設定DTR屬性為True, 表示高電平, DTR為False, 為低電平; 但如要進行切換高低電平, 中間必須要sleep一下. CTS屬性類似.
-----------------------------
捕獲底層的log, 這在抓取序列槽資料時非常有用
-----------------------------
TApdComPort能捕獲到一些底層的資訊, 并可将這些資料自動記錄到對應的log檔案中, 需要作的是開啟Logging功能, 與Logging相關的還有Tracing, 但Tracing抓出的資訊不如Logging全, 是以我僅僅使用Logging功能.
--初始化Logging設定
procedure TDataModule1.InitLogSettings(ApdComPort: TApdComPort);
begin
ApdComPort.LogAllHex:=True;
ApdComPort.LogName:=ExtractFilePath(Application.ExeName)+'_COM.log' ;
ApdComPort.Logging:=tlOn ;
end;
--我寫了個FlushLog(), 看看寫法, 就能體會到 ApdComPort 反人類之處了.
procedure TDataModule1.FlushLog(ApdComPort: TApdComPort);
begin
ApdComPort.Logging:=tlAppend; //save to file then ture off Logging
ApdComPort.Logging:=tlOn; //at last turn on Logging
end;
另外, 可以使用AddStringToLog(), 将任意字元串寫到Log檔案中, 當然序列槽必須先打開.
-----------------------------
發送資料
-----------------------------
PutString()和PutChar(),PutBlock()可以發送, 也可以通過設定OutPut屬性來寫.
-----------------------------
接收資料, 都是以事件的方式接收資料
-----------------------------
1. OnTriggerAvail事件介紹, 我認為這個方法最好用了.
一旦有資料接收到, 就會觸發OnTriggerAvail事件, 代碼一般為,
procedure TForm_Main.ApdComPort_1BTriggerAvail(CP: TObject; Count: Word);
var
I : Word;
begin
for I := 1 to Count do
globalString := globalString + ApdComPort_1B.GetChar;
end;
2.OnTriggerData事件, 有時候需要判斷是否接收到指定的資料, DataTrigger提供了一個簡單的方式
增加 DataTrigger 後, 當TApdComPort接受到指定的字元串後, 即觸發OnTriggerData事件, 我們可以在這個事件中針對不同的dataTriggerHandle做不同的處理.
//建立dataTrigger 的handle(WORD類)
connectDataHandle=ApdComPort_1B.AddDataTrigger('connect server', true)
disconnectDataHandle=ApdComPort_1B.AddDataTrigger('disconnect server', true)
//在OnTriggerData事件, 判斷 TriggerHandle, 是等于 connectDataHandle還是 disconnectDataHandle, 做相應的處理
procedure TForm_Main.ApdComPort_1BTriggerData(CP: TObject;
TriggerHandle: Word);
begin
//比較TriggerHandle和connectDataHandle/disconnectDataHandle值, 做進一步處理
end;
3. DataTrigger是一個簡單的data match trigger, 要實作更複雜的比對條件, 可以使用TApdDataPacket元件, 它可以設定起始字元串, 結束字元串等比對條件, 一旦接受到滿足條件的資料, 會觸發OnPacket事件
-----------------------------
為 TApdComPort 增加 TimerTrigger
-----------------------------
增加 TimerTrigger, 需要兩步, 第一步先擷取handle, 第2步設定timer的interval
//建立timerTrigger 的handle
timerHandle:= ApdComPort_1B.AddTimerTrigger;
ApdComPort_1B.SetTimerTrigger(timerHandle, 100, True); //interval為100,并啟用這個trigger
4. 删除方法RemoveTrigger(), 參數是triggerHandle.
-----------------------------
ApdComport, ApdSLController, ApdStatuslight配合使用
-----------------------------
ApdSLController是Statuslight的管理器, 可以為8個不同的信号事件配置各自的statuslight(顯示紅綠燈). 在将ApdSLController和指定的ApdComport元件綁定, 就可以通過這8個 statuslight來反映ApdComport的狀态.