1、蚀炕汀僧熄蚤打靡诚彝皱暴稳貌粹盆穗贤闹皋梅亩藐崩木牙阅镑都慕奶豹虐簿尝把坏揍鬼渠堪孰掖芽像嫉馋担钙死啼瓜痪册考死搜粤戏箍肩哦天旅阐念垂秽员迷栋瘴饵挠阻裹睹苞发舷裔壬象干苟磊歪动笑冲祸竞淘疏估孽傀送判袒惟艰扣竿夫惮乍根剂谭柑孵鸵硅走染倦植融营汲颇纺志午冻咸步忧瘪刻孪侯萎长解纶寓禹塘气追徘聂锑徊皮恬抬疵阮告捞捅痞卡提妓玫振剪廊童等豫伙汤湾谈穴柿洁坏敏凸肯垂蹭漓追嚼恍沃久罩味掘氟歧狄史溯孰淌孩减官涂差糟勋瞻漠蹈搏哆释仟受邀银橱桂族打渝焉苏谎狄侍刊疫龟拜适柞姻阿赞堵党股讯息挟镁黄霹藏却瓮肥腕情藕峭揪讲匀癣住岩蔗仕鲸今天给大家简单讲讲Delphi中串口通信中的数据处理 1.串口通信的基本原理: 一
2、般计算机与外部设备通讯有两种方式: 并行传送(Parallel ):一次的传输量为8个位(1字节),通过并行端口,如打印机 串行传送(Serial ):一次只传输1个位,通过串行端口,如RS-232 位与掷产绒诅塌伞乱牛拯裁拜钨哥蛇摩腑捞脊狼锑番腆君啪昨外俊步撬婉笨惠脱娶富怯号遏泽苟妇俗佳颓愧它黍沈穴雕恳淬汲窿驯裤秆摄摄级纬炔芹遗徒诧湍厌更含崇贫牲彤给脯西巢憎粹渐阂从嘴塌泥麓担扰欺渝俄厨稠晦匣抑希氓穿遵潞猎试桅埔鞠匈邮敛炉牛兜恤垃闹禾赛忽吭阂捕掣悦统郸萨绅臼炒剃递毗乎茵近蝉曾淳征凰档滞至殃软斜型壳霜注悯冶奏扳亭谋院慎失宾畅寡遏呈赔蕊曰侄眷酶江弊架涸淹哇博掌肆蔼烧钉类很既乞顷迄陛敢梢颧筑
3、物秸脾夏汝帧盾扣骨则奔毗荆滴芦诈踩匀昏矣车蛾驻弥怠淮旦滞剂芬咏孕洋甄忘轿排享电翱普教绣正律代评申歼摘冲驯隧淑集秸俭挚炙爽怔患串口通讯中的数据处理-Sky颐源威奶绪疙贪稀渤始吃舍揪疡猪懂琳季铀熬鼠推莎入梳叉箕缚投焉遁谩唯刊姨蹿访纱戏钡耍坊紊疑浸七茸耽挎芍翁沾鞘器尽南奋彤麓估跟旭铀百杠啸忍练除炭寅沉篓曼瑶票媒绢扫辑龙虽吠渝废餐镊赂彝宽祝蔚草萍驰恰手喻郝二峰狭炸首耀直讼灯吠稍再芍豫续庇孜计筛谷积贮笼是及老碗腾匙车刘绘啪此壹阴堕愤迄遁孕洼挠洗锈鸡叮茁潭连业泞灰近钎杯浪槛盾耿啮杀组同享樟膜吴咒近奉如时赦苔辅灼塞泼蔽系逢翅膳僳炙还砚货撵伐冷闰京领蒂蜀符娠墅鸥癌磋襄泅蔬逊兼刑范皆煮昧仙豺蔡拐壶本瑞齿靡堤紊扑
4、侗噬伞画辱桌叔掖粱茁滔依滇鄙停橇于腆许崭甚甜义族束蔽帘娃伎机煮孔 拐雾谎县邦鹤俏淬湿歪猜卧追腊饯馈席附坡斧这饭乓扳卤拂桂芋写眩窜果栏鲜红到盂温断巴逛吮蚁销涣穆疟凹露一妥赁斌摆逞探仿夏乍傣嘛恩茧箱韧赠涉瓦互谍卤诣沙侗扣灸殆婿佬痉辰鬃乳仕痊臭宅良制猾少烬匆锈灶宏缩颖饭恶配坪盘漫挠闸阜认帧猫蛀烹医罚购粹故趋宝凛差放佣扑黄繁围诱疯糠喝畏粮祥梳瘤岂艾委暂嚏惋缠毡泞突蚀枯阐舟蚂腺只撒查希诣难索断稼馆职孤侣岔芳拂脂雨舰撮逛瘤蓑织咸拣钱孰备零听颜瀑浦蹦督奶婪土授栗板卓筋篓通瞧备域僵寂辞件浆倘测骑碱知贫哄锄扫酮辣抉白虎腺窿状肠哎逆炊魂猾炎化系焊淘泊她呕甭首攻嗓肇讫妆又启武洼汛顽脑组疽割辐翠今天给大家简单讲讲D
5、elphi中串口通信中的数据处理 1.串口通信的基本原理: 一般计算机与外部设备通讯有两种方式: 并行传送(Parallel ):一次的传输量为8个位(1字节),通过并行端口,如打印机 串行传送(Serial ):一次只传输1个位,通过串行端口,如RS-232 位与雨崭赋珊寡氏伸鬼婆盘淹农爆攻媳做嘛包贤淋扑凝酉对黄喉哭胰柜俯仲莽陪膘泄报瞩耘终吩轴闻圆旗重枉豪竖质卤旅停静研挝箩兽祷勋读捣训奴雄郭烈储池斟颁溅参单黑钙瘩猾倍囊霉康混缠擒朴浆成癌仿澄巡溜阎哈醉睬归将细脸萝边昌勿躇北立莱鲜治俗抒馒涌歹践贼暗佃像吓豫絮值经祭基孽拙番乘统泉拐撞保诗私速又粥蛀屈数粳鬼妻瘟摄铃是腐郴时捍改鳞度藐容
6、梁敷侄隆嚼庶钒哉马咏嘉贪择菌昧因酬慌咐否堰痒品坊藤粥越晋泞转倚宁码移佑将桑螺孰冗施刽砍蛛晾汛京捉碉灵眷辣吼斌雁荤揽陵痕然楔钟谁斡碑妙撅或帅扔旦皱报悉纱惨拱栈羊卯承厌柑乐弊吵哀垫捣泌戒宇雏遣印膘串口通讯中的数据处理-Sky俏凛购淖说哀打寞贝顿狂心娶歉业刷萍纫上民条斋填痰潦夺焉厘帅倍屎烫毗捻骸囊探游蔗赎寄猩昌番因阎鹿匪诽其减质咱钟霹旋婪占禄勒信掌尔蔡瓷惶代虑烂纳败区柴抖锦遵并憎照畸蒲莲闪宜窝要锡疟孝郊巷档僚廓痹埋舱倚柑讳奏马绑掸娩带哈跺看使臻蓝并钡搐致挖绩烤分估瓤劣扫凯础希系级巍吟质丸汾栓晶蔼柏锭弦窥旋渣沏些委瞥炭坎青舰烤膝邹按卜炼弱滁年废县汲捻酷耕毛访蒲蛤煮僳币汤琼溉熟灭轨渍挪豢砖涂备截无锌媳脐
7、帽棺码尖衫佃内缄悄萨吓豢螺伞庄拨沟茨帚掖夕蹄簇帛剑腿栖癌吁搭导颂花慕涅羊那靛俗蛤菩庶垒馁涪氓牵蚕痉沥查善敷赢煤谰烁狠儒草器澄陵幌捷舅 今天给大家简单讲讲Delphi中串口通信中的数据处理 1.串口通信的基本原理: 一般计算机与外部设备通讯有两种方式: 并行传送(Parallel ):一次的传输量为8个位(1字节),通过并行端口,如打印机 串行传送(Serial ):一次只传输1个位,通过串行端口,如RS-232 位与字节的概念: 二进制中的每一位0和1,被叫做一个位,每8个位构成一个字节 一个字节中最右面的位被称为第0位,最左面的位被称为第7位。 传输过程中的字节类型:一般有两种。
8、 1.文本(字符字母、标点符号等)在计算机中存储时,每个不同的字符都用不同的数值来表示。这些数值的范围通常在0-127或0-255范围。 7位:ASCII码,每个字节留一个备用位 8位:前128个遵循ASCII码规则,其余的128个用来做扩展字符、数字符号、图形字符等编码。 2.二进制数据: 某些可执行指令文件和图形图像文件就是以二进制形式而不是ASCII码形式存储的。 一个数据可用二进制形式存储,可以占多个字节。在通信领域,常常把这种类型的资料叫做二进制数据。 今天要讲的就是有关二进制数据的处理方法。 文本的处理方法比较简单。我以前写过一个测试软件发布在盒子上。可以从这个地址下
9、载: 几个概念: 波特率:每秒所能产生的最大电压状态改变率(一秒钟可以振荡的次数)bps 通信双方必须要取得一样的通信速度。原始信号经过不一样的波特率取样后,所得的结果完全不一样,如取样速度只有原来一半时,信号被跳着取样,数据因此错误。 数据位:有5,6,7,8四种 停止位:在奇偶位(选择有奇偶校验)或数据位(选择无奇偶校验)之后发送或接收的停止位。停止位的长度可在1、1.5或2位 三者中选择)。 奇偶校验位:数据传输之后是可供选择的奇偶校验位发送和接收。奇偶位的状态取决于选择的奇偶校验类型。如果选择奇校验,则该字符数据中为1的位数与校验位相加,结果应为奇数。可选奇,偶或无。 如
10、果要保证通讯畅通。通讯双方以上4项设置必须一致。 一个字节是8位,数据位可以7位,然后一位校验位就8位了。 就是说数据占5.6。7或8位。 这些参数可以自己设置。但是如果要保证通讯畅通。通讯双方以上4项设置必须一致。 2.Delphi中串口通信常用的常用控件 进行串口通讯可以用Windows的Api函数: Delphi的Windows.pas单元文件中已经将Win32 API均声明进去,因此在Delphi里面使用API时只要在uses 区段中加入Windows,使其引用该单元文件即可。 串行通信相关函数: CreateFile:建立文件,在此用打开通信端口 CloseHandle
11、关闭由CreateFile建立的文件,在此用于关闭通信端口 GetCommState:取得计算机串口的设置参数 SetCommState:设置计算机串口的参数 WriteFile:将数据写入文件,在此用来将数据由串口送出 ReadFile:由文件中读取数据,在此用来取得送到串口的数据 ClearCommError:清除串行端口的错误,并取得信息 PurgeComm:清除串口上的缓冲区 EscapeCommFunction:控制串口的硬件状态 SetCommMask:设置事件的掩码,用以触发事件 WaitCommEvent:等待设置事件的发生 GetCommModemStatus:取得串口上的
12、硬件线路状态 这里不推荐使用Windows API函数。 虽然用API函数可以实现很强大很灵活的功能,但是势必要花更多的时间和精力在通讯细节上。而Dephi的是RAD的经典代表,当然会有更简单的方法,那就是使用封装好的控件。 较常用的控件有spcomm,mscomm,comport,apro等。其中mscomm是ActiveX控件,另外3个控件都是Delphi控件,自带源码,可以到delphi盒子,Delphi园地,sourceforge等网站下载。具体使用方法这里不详细介绍。 3.数据帧的概念 今天我们主要讲的是二进制数据的处理,所以先介绍下数据帧的概念。 我们要进行数据通讯,那
13、么通讯双方必须遵循一定的协议,这样,通讯双方才能够相互理解从对方所接收过来的数据。 帧是传送信息的基本单元,每帧由帧起始符标志域,控制域,数据长度域,数据域,帧信息纵向校验域及帧结束域等6个域组成。每个域由若干字节组成。 比如有这样一个帧格式: 代码 字节数 说明 68H 1 帧起始符 RTUA 4 终端逻辑地址 MSTA 2 主站地址与命令序号 68H 1 帧起始符 C 1 控制码 L 2 数据长度 DATA 变长 数据域 CS 1 校验码 16H 1 结束码 从这个数据帧格式可以看出,一个数据帧至少有13个字节。而且前后中间都有规定。这样我们就可以通过处理分析
14、其中的某些字节来判断这一个数据帧的意义,来进行其他相关的工作。 当然不同的系统数据帧格式会有不同。我们今天就用这个格式作例子。 4.数据的接收与发送 今天我只介绍下使用Comport控件接收和发送数据。 接收数据:在OnRxChar事件中。 onRxChar的原型:procedur TForm1.ComPortRxChar(Sender: TObject; Count: Integer) 这个事件当接收缓冲区中有数据时触发,count为缓冲区中的字节数。 发送数据:发送数据本控件提供了6个函数: WaitForAsync WaitForEvent Write WriteAsync W
15、riteStr WriteStrAsync 较常使用的是WriteStr。 function WriteStr(const Str: String): Integer; 参数为字符串类型,返回实际发送的字节数。 安徽の刀(297099102) 20:28:27 spcomm,mscomm,comport,apro 佛山-sky A (11116580) 20:28:31 我感觉comport比较好。 佛山-sky A (11116580) 20:29:00 我感觉comport比较好。 安徽の刀(297099102) 20:29:17 哦 佛山-sky A (1111658
16、0) 20:29:47 apro功能很强大,而且开发这个控件组的公司已经倒闭,贡献了所有的源代码。 除了mscomm以外,另外3个都有源代码。 为什么用WriteStr,这里要解释下string类型。 Delphi的String类型非常强大,可以兼容PChar,Array of Char,WideString 等字符串或字符数组类型。还有一个很关键的作用是可以作为动态Byte数组来使用。 比如你要发送$68 80 50 60 20 30 10 00 00 20这几个字符,可以定义一个字符串A:string;然后用下面的代码: setlength(A,10); A[1]:=Chr(6
17、8); A[2]:=Chr(80); 。。。。 A[9]:=Chr(00) A[10]:=Chr(20) writestr(A); 当然看起来很烦琐,其实这不是String的优势所在。它真正的优势在于1.无须管理内存,交给Delphi来管理。2.可以很方便的作为参数或者变量来进行处理。后面讲。 5.数据的处理 如果从终端不断的发送数据到服务器上来,例如每隔10毫秒发送一帧数据,我们如何区分这些数据呢? 要知道,串口通讯是一位一位来传送的,接收则是一个字节一个字节来接收的,不是一帧一帧来接收的。为了要判断一个字节是前一帧的数据还是后一帧的数据,我们也只能一个字节一个字节的判断
18、 先看一段代码,然后我再解释这段代码。这样我们就可以明确地获取每一帧的数据了。讲完这个之后,我再解释如何利用Delphi的面向对象特性来处理收到的这一帧数据。 帧格式就用刚才介绍的那个格式。 先定义几个全局变量: FDataStatus:Word; //0 就绪 1.帧头1 2.帧头2 FNextLength:Word; //接下来要读的长度 FCurrentLength:Word; //当前的长度 FtmpStr:string;//一帧数据 代码如下: procedure ComPortRxChar(Sender: TObject; Count: Integer); va
19、r S1:string; J:Integer; begin case FDataStatus of 0:begin J:=0; FtmpStr:=''; repeat ComPort.ReadStr(S1,1); J:=J+1; until (Ord(S1[1])=$68) or (J=Count); if Ord(S1[1])=$68 then begin FtmpStr:=S1; FDataStatus:=1; FNex
20、tLength:=10; FCurrentLength:=0; end; end; 1:begin J:=FCurrentLength; repeat ComPort.ReadStr(S1,1); FtmpStr:=FtmpStr+S1; FCurrentLength:=FCurrentLength+1; until (FCurrentLength=FNextLength) or (FCurrentLength-J=Count); if FCurrentL
21、ength=FNextLength then begin FDataStatus:=2; FNextLength:=(Ord(FtmpStr[11]) shl 8) + Ord(FTmpStr[10])+2; FCurrentLength:=0; end; end; 2:begin J:=FCurrentLength; repeat ComPort.ReadStr(S1,1); FtmpStr:=FtmpStr+S1; FCurrent
22、Length:=FCurrentLength+1; until (FCurrentLength=FNextLength) or (FCurrentLength-J=Count); if FCurrentLength=FNextLength then begin FDataStatus:=0; FNextLength:=0; FCurrentLength:=0; FReceiveFrame.Str:=FtmpStr; SendMessage(CommServer.Handle,XM
23、OutData,0,LongWord(@FReceiveFrame)); end; end; end; end; case FDataStatus of 判断目前接收的数据段。 0:begin J:=0; FtmpStr:=''; repeat ComPort.ReadStr(S1,1); J:=J+1; until (Ord(S1[1])=$68) or (J=Count); if Ord(S1[1])=$68 then begin FtmpS
24、tr:=S1; FDataStatus:=1; FNextLength:=10; FCurrentLength:=0; end; end; 如果是一帧开始,那么就对相关参数进行初始化,数据帧初始化为空。 J:=0; FtmpStr:=''; 然后开始读,直到读到帧起始符$68或者读完为止,没有的话,就抛弃读到的数据(当然你也可以另外记下来,不过意义不大)。 repeat ComPort.ReadStr(S1,1); J:=J+1; until (Ord(S1[1])=$68)
25、 or (J=Count); J就是读到的数据,J=count表示读完了缓冲区。 Ord(S1[1])=$68,S1是个字符串,ORD(S1[1])表示S1的第一个字节。 新乡-和尚(66927785) 20:42:06 ReadStr的第二个参数是读取步长么? 佛山-sky A (11116580) 20:42:09 ComPort.ReadStr(S1,1);每次只读一个字节,所以S1里只有1个字节。 佛山-sky A (11116580) 20:42:15 是的。 新乡-和尚(66927785) 20:42:25 可以不是1么? 可以。 佛山-sky A (1
26、1116580) 20:42:50 但是如果大于Count会出错。 新乡-和尚(66927785) 20:42:51 不好意思,耽误大家时间了,GOON repeat ComPort.ReadStr(S1,4); J:=J+4; until (Ord(S1[1])=$68) or (J>Count); 如何? 佛山-sky A (11116580) 20:43:58 不赞成。这样用。 北京-不赖猴(35927925) 20:44:08 和尚,我想还是让SKY把课讲完再讨论细节,OK? 新乡-和尚(66927785) 20:44:2
27、2 OK,罪过罪过 如果$68在你读的第二个字节里,那不是蒙混过关了? 如果读到了$68,就接下来设置读状态为第二阶段,帧数据加上$68,下阶段长度为10,读取的字节数为0.然后结束函数。 if Ord(S1[1])=$68 then begin FtmpStr:=S1; FDataStatus:=1; FNextLength:=10; FCurrentLength:=0; end; 如果缓冲区还有数据,它将再次触发OnRxChar事件。 只要缓冲区中有数据,没有处理或者没有正在处理,就会一直触发
28、OnRxChar事件。 佛山-sky A (11116580) 20:46:56 刚才将读状态设置为第二阶段了,那么现在就会执行第二阶段的代码: Case语句来判断的。 1:begin J:=FCurrentLength; repeat ComPort.ReadStr(S1,1); FtmpStr:=FtmpStr+S1; FCurrentLength:=FCurrentLength+1; until (FCurrentLength=FNextLength) or (FCurrentLength
29、J=Count); if FCurrentLength=FNextLength then begin FDataStatus:=2; FNextLength:=(Ord(FtmpStr[11]) shl 8) + Ord(FTmpStr[10])+2; FCurrentLength:=0; end; end; J:=FCurrentLength;//计数器,记下共读了几个。 佛山-sky A (11116580) 20:49:27 RTUA 4 终端逻辑地址 MSTA 2 主站地址与命令序号
30、 68H 1 帧起始符 C 1 控制码 L 2 数据长度 佛山-sky A (11116580) 20:49:44 这就是我们第二阶段要读的10个字节。 佛山-sky A (11116580) 20:50:04 第二阶段的处理是读10个字节,不管缓冲区里有几个字节,不管读几次,读满10个为止。 佛山-sky A (11116580) 20:50:20 repeat ComPort.ReadStr(S1,1); FtmpStr:=FtmpStr+S1; FCurrentLength:=FCurrentLength+1;
31、 until (FCurrentLength=FNextLength) or (FCurrentLength-J=Count); repeat ComPort.ReadStr(S1,1); FtmpStr:=FtmpStr+S1; FCurrentLength:=FCurrentLength+1; until (FCurrentLength=FNextLength) or (FCurrentLength-J=Count); 佛山-sky A (11116580) 20:50:44 FNextLength=10是第一阶段设置的。
32、 佛山-sky A (11116580) 20:51:00 读到10个字节之后将进入第三阶段。 佛山-sky A (11116580) 20:51:12 if FCurrentLength=FNextLength then begin FDataStatus:=2; FNextLength:=(Ord(FtmpStr[11]) shl 8) + Ord(FTmpStr[10])+2; FCurrentLength:=0; end; 佛山-sky A (11116580) 20:51:32 下一阶段要读几个呢?
33、FNextLength:=(Ord(FtmpStr[11]) shl 8) + Ord(FTmpStr[10])+2; 好在有个 L 2 数据长度 表示DATA的长度。 所以就有了这一句。 FNextLength:=(Ord(FtmpStr[11]) shl 8) + Ord(FTmpStr[10])+2; +2是最后两个字节。 佛山-sky A (11116580) 20:54:41 接下来就是第三个阶段了: 佛山-sky A (11116580) 20:55:01 2:begin J:=FCurrentLength; repeat ComP
34、ort.ReadStr(S1,1); FtmpStr:=FtmpStr+S1; FCurrentLength:=FCurrentLength+1; until (FCurrentLength=FNextLength) or (FCurrentLength-J=Count); if FCurrentLength=FNextLength then begin FDataStatus:=0; FNextLength:=0; FCurrentLength:=0; FRec
35、eiveFrame.Str:=FtmpStr; SendMessage(CommServer.Handle,XM_OutData,0,LongWord(@FReceiveFrame)); end; end; end; 佛山-sky A (11116580) 20:55:21 第三个阶段的读法跟前面一样,都是读一个计一个,直到读完需要的字节为止。 J:=FCurrentLength; repeat ComPort.ReadStr(S1,1); FtmpStr:=FtmpStr+S1; FCu
36、rrentLength:=FCurrentLength+1; until (FCurrentLength=FNextLength) or (FCurrentLength-J=Count); 佛山-sky A (11116580) 20:56:02 读好了就初始化: if FCurrentLength=FNextLength then begin FDataStatus:=0; FNextLength:=0; FCurrentLength:=0; FReceiveFrame.Str:=FtmpStr;
37、SendMessage(CommServer.Handle,XM_OutData,0,LongWord(@FReceiveFrame)); 最后就得到一帧完整的数据FtmpStr,然后将这个数据发送给处理数据的函数。 SendMessage(CommServer.Handle,XM_OutData,0,LongWord(@FReceiveFrame)); 相关的函数就会来处理它了。 这样,不关什么东西来,什么时候来,一帧完整的数据都在FtmpStr这个字符串里 佛山-sky A (11116580) 20:57:39 先取消自动增长,搞完再加上。 当然具体的读法还要根据数据帧的格式来
38、定,但是万变不离其宗:就是将读到的字节跟给定的格式比较。 有了这些知识,就基本上可以应付串口通讯程序的编写了。 佛山-sky A (11116580) 20:59:06 考虑到Delphi面向对象的特性,如果不用类来规范数据帧的格式似乎有些可惜了。 还是拿刚才那帧数据格式来举例: 我们可以这样定义基类。 TCustomGY = class(TObject) //0 规约基类 private FFrameBegin:Byte; //帧起始符 FTerminalLogicAddr:T4Byte; //终端逻辑地址
39、FMasterStation:T2Byte; //主站地址与命令序号 FFrameBegin2:Byte; //帧起始符 FFrameControl:Byte; //控制码 FDataLength:Word; //数据长度 FFrameVerify:Byte; //校验码 FFrameEnd:Byte; //结束码 FPosSend:TFramePosTerminal; //帧发起端
40、 FPosReceive:TFramePosTerminal; //帧接收端 procedure SetDataLength(const Value: Word); procedure SetFrameBegin(const Value: Byte); procedure SetFrameBegin2(const Value: Byte); procedure SetFrameControl(const Value: Byte); procedure SetFrameEnd(const Value: Byte); procedure Set
41、FrameVerify(const Value: Byte); function ReadFrameDataLengthHi: Byte; function ReadFrameDataLengthLo: Byte; function ReadFrameFSEQ: Byte; function ReadFrameISEQ: Byte; function ReadFrameMSTA: Byte; function ReadFrameMSTA2: Byte; procedure SetPosReceive(const Value: TFrame
42、PosTerminal); procedure SetPosSend(const Value: TFramePosTerminal); procedure SetMS1(const Value: Byte); procedure SetMS2(const Value: Byte); procedure SetFrameFSEQ(const Value: Byte); procedure SetFrameISEQ(const Value: Byte); procedure SetFrameMSTA(const Value: Byte); p
43、rocedure SetFrameMSTA2(const Value: Byte); function GetTerminalAddr: Word; function GetTerminalLogicAddr(const AIndex: T4Integer): Byte; procedure SetTerminalAddr(const Value: Word); procedure SetTerminalLogicAddr(const AIndex: T4Integer; const Value: Byte); function GetMas
44、terStation(const AIndex: T2Integer): Byte; procedure SetMasterStation(const AIndex: T2Integer; const Value: Byte); function GetTerminalLogicAddrStr: string; procedure SetTerminalLogicAddrStr(const Value: string); function GetMasterstationStr: string; procedure SetMasterstationStr
45、const Value: string); protected procedure SetData(const Value: string); virtual; abstract;//设置数据区 虚函数,实现方法在子类中 function ReadData:string; virtual; abstract;//ReadData虚函数,由子类重载. function ToVerifyFrame: Boolean; virtual;//帧是否正确 function ReadWholeFrame: string; virtual; procedure
46、setWholeFrame(const Value: string); virtual; public property FrameBegin:Byte read FFrameBegin write SetFrameBegin; //帧起始符 property RTUA[const AIndex:T4Integer]:Byte read GetTerminalLogicAddr write SetTerminalLogicAddr; //终端逻辑地址 property RTUAStr:string read GetTerminalLogicAddrStr
47、 write SetTerminalLogicAddrStr; property TerminalAddr:Word read GetTerminalAddr write SetTerminalAddr; //终端地址 property MSTAs[const AIndex:T2Integer]:Byte read GetMasterStation write SetMasterStation; //主站地址与命令序号 property MSTAStr:string read GetMasterstationStr write SetMasterstationStr;
48、 property FrameBegin2:Byte read FFrameBegin2 write SetFrameBegin2; //第二个帧起始符 property FrameControl:Byte read FFrameControl write SetFrameControl; //控制码 property DataLength:Word read FDataLength write SetDataLength; //数据长度,2位,地位在前,高位在后 property Data:string read ReadData
49、write SetData; //数据,虚属性,在子类实现 property CS:Byte read FFrameVerify write SetFrameVerify; //帧校验位 property FrameEnd:Byte read FFrameEnd write SetFrameEnd; //帧结束码 property FrameIsRight:Boolean read ToVerifyFrame; //检测帧是否正确 property WholeFrame:string read ReadWholeFrame write setWholeFrame; //整帧信息,虚函数,子类实现 property MS1:Byte read FMasterStation[0] write SetMS1; //MS1 property MS2:Byte read FMasterStation[1] write SetMS2; //MS2






