资源预览内容
第1页 / 共19页
第2页 / 共19页
第3页 / 共19页
第4页 / 共19页
第5页 / 共19页
第6页 / 共19页
第7页 / 共19页
第8页 / 共19页
第9页 / 共19页
第10页 / 共19页
亲,该文档总共19页,到这儿已超出免费预览范围,如果喜欢就下载吧!
资源描述
今天给大家简单讲讲 Delphi 中串口通信中的数据处理 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 码形式存储的。 一个数据可用二进制形式存储,可以占多个字节。在通信领域,常常把这种类型的资料叫做二进制数据。 今天要讲的就是有关二进制数据的处理方法。文本的处理方法比较简单。我以前写过一个测试软件发布在盒子上。可以从这个地址下载:http:/www.delphibox.com/article.asp?articleid=2877几个概念:波特率:每秒所能产生的最大电压状态改变率(一秒钟可以振荡的次数)bps 通信双方必须要取得一样的通信速度。原始信号经过不一样的波特率取样后,所得的结果完全不一样,如取样速度只有原来一半时,信号被跳着取样,数据因此错误。数据位:有 5,6,7,8 四种停止位:在奇偶位(选择有奇偶校验)或数据位(选择无奇偶校验)之后发送或接收的停止位。停止位的长度可在 1、15 或 2 位 三者中选择) 。奇偶校验位:数据传输之后是可供选择的奇偶校验位发送和接收。奇偶位的状态取决于选择的奇偶校验类型。如果选择奇校验,则该字符数据中为 1 的位数与校验位相加,结果应为奇数。可选奇,偶或无。如果要保证通讯畅通。通讯双方以上 4 项设置必须一致。一个字节是 8 位,数据位可以 7 位,然后一位校验位就 8 位了。就是说数据占 5.6。7 或 8 位。这些参数可以自己设置。但是如果要保证通讯畅通。通讯双方以上 4 项设置必须一致。2.Delphi 中串口通信常用的常用控件进行串口通讯可以用 Windows 的 Api 函数:Delphi 的 Windows.pas 单元文件中已经将 Win32 API 均声明进去,因此在 Delphi 里面使用API 时只要在 uses 区段中加入 Windows,使其引用该单元文件即可。串行通信相关函数:CreateFile:建立文件,在此用打开通信端口CloseHandle:关闭由 CreateFile 建立的文件,在此用于关闭通信端口GetCommState:取得计算机串口的设置参数SetCommState:设置计算机串口的参数WriteFile:将数据写入文件,在此用来将数据由串口送出ReadFile:由文件中读取数据,在此用来取得送到串口的数据ClearCommError:清除串行端口的错误,并取得信息PurgeComm:清除串口上的缓冲区EscapeCommFunction:控制串口的硬件状态SetCommMask:设置事件的掩码,用以触发事件WaitCommEvent:等待设置事件的发生GetCommModemStatus:取得串口上的硬件线路状态这里不推荐使用 Windows API 函数。虽然用 API 函数可以实现很强大很灵活的功能,但是势必要花更多的时间和精力在通讯细节上。而 Dephi 的是 RAD 的经典代表,当然会有更简单的方法,那就是使用封装好的控件。较常用的控件有 spcomm,mscomm ,comport ,apro 等。其中 mscomm 是 ActiveX 控件,另外 3 个控件都是 Delphi 控件,自带源码,可以到 delphi 盒子,Delphi 园地,sourceforge等网站下载。具体使用方法这里不详细介绍。3.数据帧的概念今天我们主要讲的是二进制数据的处理,所以先介绍下数据帧的概念。我们要进行数据通讯,那么通讯双方必须遵循一定的协议,这样,通讯双方才能够相互理解从对方所接收过来的数据。帧是传送信息的基本单元,每帧由帧起始符标志域,控制域,数据长度域,数据域,帧信息纵向校验域及帧结束域等 6 个域组成。每个域由若干字节组成。比如有这样一个帧格式:代码 字节数 说明68H 1 帧起始符RTUA 4 终端逻辑地址MSTA 2 主站地址与命令序号68H 1 帧起始符C 1 控制码L 2 数据长度DATA 变长 数据域CS 1 校验码16H 1 结束码从这个数据帧格式可以看出,一个数据帧至少有 13 个字节。而且前后中间都有规定。这样我们就可以通过处理分析其中的某些字节来判断这一个数据帧的意义,来进行其他相关的工作。当然不同的系统数据帧格式会有不同。我们今天就用这个格式作例子。4.数据的接收与发送今天我只介绍下使用 Comport 控件接收和发送数据。接收数据:在 OnRxChar 事件中。onRxChar 的原型:procedur TForm1.ComPortRxChar(Sender: TObject; Count: Integer)这个事件当接收缓冲区中有数据时触发,count 为缓冲区中的字节数。发送数据:发送数据本控件提供了 6 个函数:WaitForAsyncWaitForEventWriteWriteAsyncWriteStrWriteStrAsync较常使用的是 WriteStr。function WriteStr(const Str: String): Integer;参数为字符串类型,返回实际发送的字节数。 安徽刀(297099102) 20:28:27spcomm,mscomm,comport,apro 佛山-sky A (11116580) 20:28:31我感觉 comport 比较好。 佛山-sky A (11116580) 20:29:00我感觉 comport 比较好。 安徽刀(297099102) 20:29:17哦 佛山-sky A (11116580) 20:29:47apro 功能很强大,而且开发这个控件组的公司已经倒闭,贡献了所有的源代码。除了 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);A1:=Chr(68);A2:=Chr(80);。 。 。 。A9:=Chr(00)A10:=Chr(20)writestr(A);当然看起来很烦琐,其实这不是 String 的优势所在。它真正的优势在于 1.无须管理内存,交给 Delphi 来管理。2.可以很方便的作为参数或者变量来进行处理。后面讲。 5.数据的处理如果从终端不断的发送数据到服务器上来,例如每隔 10 毫秒发送一帧数据,我们如何区分这些数据呢? 要知道,串口通讯是一位一位来传送的,接收则是一个字节一个字节来接收的,不是一帧一帧来接收的。为了要判断一个字节是前一帧的数据还是后一帧的数据,我们也只能一个字节一个字节的判断。先看一段代码,然后我再解释这段代码。这样我们就可以明确地获取每一帧的数据了。讲完这个之后,我再解释如何利用 Delphi 的面向对象特性来处理收到的这一帧数据。帧格式就用刚才介绍的那个格式。 先定义几个全局变量:FDataStatus:Word; /0 就绪 1.帧头 1 2.帧头 2FNextLength:Word; /接下来要读的长度FCurrentLength:Word; /当前的长度FtmpStr:string;/一帧数据代码如下: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 thenbeginFDataStatus:=0;FNextLength:=0;FCurrentLength:=0;FReceiveFrame.Str:=FtmpStr;SendMessage(CommServer.Handle,XM_OutData,0,LongWord(FReceiveFrame);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 就是读到的数据,Jcount 表示读完了缓冲区。Ord(S11)=$68,S1 是个字符串, ORD(S11)表示 S1 的第一个字节。新乡-和尚(66927785) 20:42:06Re
收藏 下载该资源
网站客服QQ:2055934822
金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号