资源预览内容
第1页 / 共17页
第2页 / 共17页
第3页 / 共17页
第4页 / 共17页
第5页 / 共17页
第6页 / 共17页
第7页 / 共17页
第8页 / 共17页
第9页 / 共17页
第10页 / 共17页
亲,该文档总共17页,到这儿已超出免费预览范围,如果喜欢就下载吧!
资源描述
Delphi 中 ComPort 通信中的数据处理1. 串口通信的基本原理: 一般计算机与外部设备通讯有两种方式:并行传送(Parallel ):次的传输量为8个位(1字节),通过并行端口, 如打印机串行传送(Serial ):一次只传输1个位,通过串行端口,如RS-232 位与字节的概念: 二进制中的每一位0和1,被叫做一个位,每8个位构成一个字节 一个字节中最右面的位被称为第 0 位,最左面的位被称为第 7 位。 传输过程中的字节类型:一般有两种。1. 文本(字符字母、标点符号等)在计算机中存储时,每个不同的字符都用不同 的数值来表示。这些数值的范围通常在 0-127 或 0-255 范围。7 位: ASCII 码,每个字节留一个备用位8位:前128个遵循ASCII码规则,其余的128个用来做扩展字符、数字符号、 图形字符等编码。2. 二进制数据:某些可执行指令文件和图形图像文件就是以二进制形式而不是ASCII码形式存 储的。一个数据可用二进制形式存储,可以占多个字节。在通信领域,常常把这种类型 的资料叫做二进制数据。今天要讲的就是有关二进制数据的处理方法。几个概念: 波特率:每秒所能产生的最大电压状态改变率(一秒钟可以振荡的次数) bps 通信双方必须要取得一样的通信速度。原始信号经过不一样的波特率取样后,所 得的结果完全不一样,如取样速度只有原来一半时,信号被跳着取样,数据因此 错误。数据位:有5,6,7,8四种 停止位:在奇偶位(选择有奇偶校验)或数据位(选择无奇偶校验)之后发送或 接收的停止位。停止位的长度可在1、 15或2位 三者中选择)。奇偶校验位:数据传输之后是可供选择的奇偶校验位发送和接收。奇偶位的状态 取决于选择的奇偶校验类型。如果选择奇校验,则该字符数据中为 1 的位数与校 验位相加,结果应为奇数。可选奇,偶或无。如果要保证通讯畅通。通讯双方以上 4 项设置必须一致。 一个字节是8位,数据位可以7位,然后一位校验位就8位了。这些参数可以自己设置。但是如果要保证通讯畅通。通讯双方以上 4 项设置必须 一致。2. Delphi中串口通信常用的常用控件进行串口通讯可以用 Windows 的 Api 函数:Delphi的Windows.pas单元文件中已经将Win32 API均声明进去,因此在Delphi 里面使用API时只要在uses区段中加入Windows,使其引用该单元文件即可。串行通信相关函数:Crea teFile:建立文件,在此用打开通信端口CloseHandle:关闭由CreateFile建立的文件,在此用于关闭通信端口GetCommState: 取得计算机串口的设置参数Set CommS tate:设置计算机串口的参数Writ eF ile:将数据写入文件,在此用来将数据由串口送出ReadFile:由文件中读取数据,在此用来取得送到串口的数据ClearCommError:清除串行端口的错误,并取得信息PurgeComm:清除串口上的缓冲区EscapeCommFunc tion:控制串口的硬件状态Set CommMask :设置事件的掩码,用以触发事件Wai tCommEven t:等待设置事件的发生Get CommModemS tatus:取得串口上的硬件线路状态 这里不推荐使用 Windows API 函数。虽然用API函数可以实现很强大很灵活的功能,但是势必要花更多的时间和精力 在通讯细节上。而Delphi的是RAD的经典代表,当然会有更简单的方法,那就 是使用封装好的控件。较常用的控件有 spcomm, mscomm, comport, apro 等。其中 mscomm 是 ActiveX 控件,另外3个控件都是Delphi控件,自带源码,可以到delphi盒子,Delphi 园地, sourceforge 等网站下载。具体使用方法这里不详细介绍。3. 数据帧的概念 今天我们主要讲的是二进制数据的处理,所以先介绍下数据帧的概念。 我们要进行数据通讯,那么通讯双方必须遵循一定的协议,这样,通讯双方才能 够相互理解从对方所接收过来的数据。帧是传送信息的基本单元,每帧由帧起始符标志域,控制域,数据长度域,数据 域,帧信息纵向校验域及帧结束域等 6个域组成。每个域由若干字节组成。比如有这样一个帧格式:代码字节数说明68H 1帧起始符RTUA4终端逻辑地址MSTA2主站地址与命令序号68H1帧起始符C1控制码L2数据长度DATA变长数据域CS1校验码16H1结束码从这个数据帧格式可以看出,一个数据帧至少有13个字节。而且前后中间都有 规定。这样我们就可以通过处理分析其中的某些字节来判断这一个数据帧的意 义,来进行其他相关的工作。当然不同的系统数据帧格式会有不同。我们今天就用这个格式作例子。4. 数据的接收与发送今天我只介绍下使用 Comport 控件接收和发送数据。 接收数据:在 OnRxChar 事件中。onRxChar 的原型:procedur TForml.ComPortRxChar(Sender: TObject; Count: Integer)这个事件当接收缓冲区中有数据时触发,count为缓冲区中的字节数。 发送数据:发送数据本控件提供了 6 个函数:WaitForAsyncWaitForEventWriteWriteAsyncWriteStrWriteStrAsync 较常使用的是 WriteStr。function WriteStr(const Str: String): Integer; 参数为字符串类型,返回实际发送的字节数。apro 功能很强大,而且开发这个控件组的公司已经倒闭,贡献了所有的源代码 除了 mscomm以外,另外3个都有源代码。为什么用Wri teStr,这里要解释下st ring类型。Delphi 的 St ring 类型非常强大,可以兼容 PChar, Array of Char,WideS tring 等字符串或字符数组类型。还有一个很关键的作用是可以作为动态Byte数组来 使用。虽然很多参考书上没有介绍这种用法,但是经过我多次测试以及实践经验,发现 没有出现任何不良反应。比如你要发送$68 80 50 60 20 30 10 00 00 20 这几个字符,可以定义一个字 符串 A:string; 然后用下面的代码:setlength(A,10);A1:=Chr(68);A2:=Chr(80);。A9:=Chr(00)A10:=Chr(20) writestr(A);当然看起来很烦琐,其实这不是St ring的优势所在。它真正的优势在于1. 无须管理内存,交给 Delphi 来管理。2. 可以很方便的作为参数或者变量来进行处理。后面讲。5. 数据的处理前面讲了 4 节,都是废话。重点在这一节。 如果从终端不断的发送数据到服务器上来,例如每隔 10 毫秒发送一帧数据,我 们如何区分这些数据呢?要知道,串口通讯是一位一位来传送的,接收则是一个字节一个字节来接收的, 不是一帧一帧来接收的。为了要判断一个字节是前一帧的数据还是后一帧的数 据,我们也只能一个字节一个字节的判断。先看一段代码,然后我再解释这段代码。这样我们就可以明确地获取每一帧的数 据了。讲完这个之后,我再解释如何利用Delphi的面向对象特性来处理收到的 这一帧数据。帧格式就用刚才介绍的那个格式。 先定义几个全局变量:FDataStatus:Word; /0 就绪 1.帧头 1 2.帧头 2 FNextLength:Word; /接下来要读的长度FCurrentLength:Word; /当前的长度Ft mpS tR:s tring;/帧数据代码如下:procedure ComPortRxChar(Sender: TObject; Count: Integer);varS1:string;J:Integer;begincase FDataStatus of0:beginJ:=0;FtmpStr:=;repeatComPort.ReadStr(S1,1);J:=J+1;until (Ord(S11)=$68) or (J=Count);if Ord(S11)=$68 thenbeginFtmpStr:=S1;FDataStatus:=1;FNextLength:=10; FCurrentLength:=0;end;end;1:beginJ:=FCurrentLength;repeatComPort.ReadStr(S1,1);FtmpStr:=FtmpStr+S1;FCurrentLength:=FCurrentLength+1;until (FCurrentLength=FNextLength) or (FCurrentLength-J=Count); if FCurrentLength=FNextLength thenbeginFDataStatus:=2;FNextLength:=(Ord(FtmpStr11) shl 8) + Ord(FTmpStr10)+2; FCurrentLength:=0;end;end;2:beginJ:=FCurrentLength;repeatComPort.ReadStr(S1,1);FtmpStr:=FtmpStr+S1;FCurrentLength:=FCurrentLength+1;until (FCurrentLength=FNextLength) or (FCurrentLength-J=Count); if FCurrentLength=FNextLength then beginFDataStatus:=0;FNextLength:=0;FCurrentLength:=0;FReceiveFrame.Str:=FtmpStr;SendMessage(CommServer.Handle,XM_OutData,0,LongWord(FReceive Frame);end;end;end;end;case FDataStatus of 判断目前接收的数据段。0:beginJ:=0;FtmpStr:=;repeatComPort.ReadStr(S1,1);J:=J+1;until (Ord(S11)=$68) or (J=Count);if Ord(S11)=$68 thenbeginFtmpStr:=S1;FDataStatus:=1;FNextLength:=10; FCurrentLength:=0;end;end; 如果是一帧开始,那么就对相关参数进行初始化,数据帧初始化为空。 J:=0;FtmpStr:=;然后开始读,直到读到帧起始符$68 或者读完为止,没有的话,就抛弃读到的数据(当然你也可以另外记下来,不过意义不大)。 repeatComPort.ReadStr(S1,1);J:=J+1;until (Ord(S11)=$68) or (J=Count);J就是读到的数据,J=count表示读完了缓冲区。Ord(Sll)=$68, S1是个字符串,ORD (Sll
网站客服QQ:2055934822
金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号