这是串口编程的第三篇, 也是最后一篇.
为客户开发一个程序, 是个机加工工厂, 他们有个量测仪器, 能将量测值通过串口打印机打印出来, 工人拿着这个纸条, 再加工中心上输入量测值. 在机床上输入东西比较麻烦, 也容易出错, 需要做些改造, 因为量测设备的操作系统是一个嵌入式系统, 也没有源码, 无法直接修改量测软件. 我给的方案如下:
方案:加一个PC机, 抓取串口打印机接收的数据, 提起其中的量测值, 然后将量测值以文件的形式发送到加工中心上.
现场条件不允许安装.Net Framework, 所以我选择使用Delphi开发串口程序, 通讯用额是Turbo Power的 TApdComPort 组件,该组件功能非常强大. 但我感觉做为类库, 在编程接口上有些地方反人类, 瑕不掩瑜吧.
=============================
TApdComPort 相关资料
=============================
本文主要参考:
TApdComPort 使用说明, http://blog.csdn.net/hanxiaoran1022/article/details/3453255
最重要的资料是源码, 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的状态.