资源描述
通常的微处理器都集成有1 路或多路硬件UART 通道,可以非常方便地实现串行通讯。在工业控制、电力通讯、智能仪表等领域中,也常常使用简便易用的串行通讯方式作为数据交换的手段。但是,在工业控制等环境中,常会有电气噪声干扰传输线路,使用RS-232 通讯时经常因外界的电气干扰而导致信号传输错误;另外,RS-232 通讯的最大传输距离在不增加缓冲器的情况下只可以达到15 米。为了解决上述问题,RS-485/422 通讯方式就应运而生了。
1、RS-232/422/485 标准来历
RS-232、RS-422 与RS-485 最初都是由电子工业协会(EIA)制订并发布的。RS-232在1962 年发布,命名为EIA-232-E,作为工业标准,以保证不同厂家产品之间的兼容。RS-422是由RS-232 发展而来,它是为弥补RS-232 之不足而提出的。为改进RS-232 通信距离短、速率低的缺点,RS-422 定义了一种平衡通信接口,将传输速率提高到10Mbps,传输距离延长到4000 英尺(速率低于100kbps 时),并允许在一条平衡总线上连接最多10 个接收器。RS-422 是一种单机发送、多机接收的单向、平衡传输规范,被命名为TIA/EIA-422-A 标准。为扩展应用范围,EIA 又于1983 年在RS-422 基础上制定了RS-485 标准,增加了多点、双向通信能力,即允许多个发送器连接到同一条总线上,同时增加了发送器的驱动能力和冲突保护特性,扩展了总线共模范围,后命名为TIA/EIA-485-A 标准。由于EIA 提出的建议标准都是以“RS”作为前缀,所以在通讯工业领域,仍然习惯将上述标准以RS 作前缀称谓。
RS-232、RS-422 与RS-485 标准只对接口的电气特性做出规定,而不涉及接插件、电缆或协议,在此基础上用户可以建立自己的高层通信协议。但由于PC 上的串行数据通讯是通过UART 芯片(较老版本的PC 采用I8250 芯片或Z8530 芯片)来处理的,其通讯协议也规定了串行数据单元的格式(8-N-1 格式):1 位逻辑0 的起始位,6/7/8 位数据位,1 位可选择的奇(ODD)/偶(EVEN)校验位,1/2 位逻辑1 的停止位。基于PC 的RS-232、RS-422 与RS-485标准均采用同样的通讯协议。
表格 1-1 列出了RS-232、RS-422、RS-485 通讯方式的区别。
标准
RS-232
RS-422
RS-485
工作方式
单端
差分
差分
节点数
1收、1发
1发、10收
1发、32收
最大传输电缆长度
50英尺
4000英尺
4000英尺
最大传输速率
20Kbps
10Mbps
10Mbps
最大驱动输出电压 +/
25V
0.25V~+6V
7V~+12V
发送器输出信号电平
(负载最小值)
负载
+/-5V~+/-15V
±2.0V
±1.5V
发送器输出信号电平
(空载最大值)
空载
+/-25V
±6V
±6V
发送器负载阻抗(Ω)
3K~7K
100
54
摆率(最大值)
30V/μs
N/A
N/A
接收器输入电压范围
±15V
10V~+10V
7V~+12V
接收器输入门限
±3V
±200mV
±200mV
接收器输入电阻(Ω)
3K~7K
4K(最小)
≥12K
发送器共模电压
--
-3V~+3V
-1V~+3V
接收器共模电压
--
-7V~+7V
-7V~+12V
1、 RS-232 标准
RS-232 被定义为一种在低速率、近距离串行通讯的单端标准。RS-232 采取不平衡传输方式,即所谓单端通讯。
⑴、RS-232 的电气标准
电平为逻辑“0”时:+3V~+15V;
电平为逻辑“1”时:-3V~-15V;
未定义区:-3V~+3V。在此区域内的信号处理将由通讯接口的RS-232 收发器决定。
⑵、RS-422/485 标准
RS-422/485 标准的全称为TIA/EIA-422-B 和TIA/EIA-485 串行通讯标准。RS-422/485标准与RS-232 标准不一样,数据信号采用差分传输方式(Differential Driver Mode),也称作平衡传输。由于RS-422/485 标准在电气特性上非常相近,在传输方式上有所区别;为便于理解,下面将主要介绍应用比较普遍的RS-485 标准,并简单介绍RS-422 标准与RS-485 标准的区别。
1. RS-485 标准
RS-485 标准是为弥补RS-232 通信距离短、速率低等缺点而产生的。RS-485 标准只规定了平衡发送器和接收器的电特性,而没有规定接插件、传输电缆和应用层通信协议。
RS-485 标准与RS-232 不一样,数据信号采用差分传输方式(Differential Driver Mode),
也称作平衡传输,它使用一对双绞线,将其中一线定义为A,另一线定义为B,如图 1-1所示。
图 1-1 RS-485 发送器的示意图
通常情况下,发送发送器A、B 之间的正电平在+2~+6V,是一个逻辑状态;负电平在-2~-6V,是另一个逻辑状态。另有一个信号地C。在RS-485 器件中,一般还有一个“使能”控制信号。“使能”信号用于控制发送发送器与传输线的切断与连接,当“使能”端起作用时,发送发送器处于高阻状态,称作“第三态”,它是有别于逻辑“1”与“0”的第三种状态。
对于接收发送器,也作出与发送发送器相对的规定,收、发端通过平衡双绞线将A-A与B-B 对应相连。当在接收端A-B 之间有大于+200mV 的电平时,输出为正逻辑电平;小于-200mV 时,输出为负逻辑电平。在接收发送器的接收平衡线上,电平范围通常在200mV至6V 之间。定义逻辑1(正逻辑电平)为B>A 的状态,逻辑0(负逻辑电平)为A>B 的状态,A、B 之间的压差不小于200mV。
RS-485 标准的最大传输距离约为1219 米,最大传输速率为10Mbps。通常,RS-485 网络采用平衡双绞线作为传输媒体。平衡双绞线的长度与传输速率成反比,只有在20kbps 速率以下,才可能使用规定最长的电缆长度。只有在很短的距离下才能获得最高速率传输。一般来说,15 米长双绞线最大传输速率仅为1Mbps。
注意:并不是所有的RS-485 收发器都能够支持高达10Mbps 的通讯速率。如果采用光电隔离方式,则通讯速率一般还会受到光电隔离器件响应速度的限制。
RS-485 网络采用直线拓朴结构,需要安装2 个终端匹配电阻,其阻值要求等于传输电缆的特性阻抗(一般取值为120Ω)。在矩距离、或低波特率波数据传输时可不需终端匹配电阻,即一般在300 米以下、19200bps 不需终端匹配电阻。终端匹配电阻安装在RS-485 传输网络的两个端点,并联连接在A-B 引脚之间。
RS-485 标准通常被用作为一种相对经济、具有相当高噪声抑制、相对高的传输速率、传输距离远、宽共模范围的通信平台。同时,RS-485 电路具有控制方便、成本低廉等优点。在过去的20 年时间里,建议性标准RS-485 作为一种多点差分数据传输的电气规范,被应用在许多不同的领域,作为数据传输链路。目前,在我国应用的现场网络中,RS-485半双工异步通信总线也是被各个研发机构广泛使用的数据通信总线。但是基于在RS-485 总线上任一时刻只能存在一个主机的特点,它往往应用在集中控制枢纽与分散控制单元之间。
2. RS-422 标准
RS-422 标准的全称是“平衡电压数字接口电路的电气特性”,它定义了接口电路的电气特性。图 1-3 是典型的RS-422 四线接口。实际上还有一根信号地线,共5 根线通讯线。
图 1-3 RS-422 标准的通讯接口
由于RS-422 接收器采用高输入阻抗和发送器因此比RS-232 更强的驱动能力,故允许在相同传输线上连接多个接收节点,最多可接10 个节点。即一个主设备(Master),其余为从设备(Salve),从设备之间不能通信,所以RS-422 支持点对多点的双向通信。接收器输入阻抗为4k,故发端最大负载能力是10×4k+100Ω(终接电阻)。RS-422 四线接口由于采用单独的发送和接收通道,因此不必控制数据方向,各装置之间任何必须的信号交换均可以按软件方式(XON/XOFF 握手)或硬件方式(一对单独的双绞线)实现。
RS-422 的最大传输距离为4000 英尺(约1219 米),最大传输速率为10Mbps。其平衡双绞线的长度与传输速率成反比,在20kbps 速率以下,才可能达到最大传输距离。只有在很短的距离下才能获得最高速率传输。一般100 米长的双绞线上所能获得的最大传输速率仅为1Mbps。
RS-422 需要安装一个终接电阻,要求其阻值约等于传输电缆的特性阻抗(一般取值为120 欧)。在短距离、或低波特率数据传输时可不安装终接电阻,即一般在300 米以下不安装终接电阻。终接电阻安装在传输电缆的最远端。
⑶、RS-485/RS-422 芯片
作为一种常用的通讯接口器件,RS-485/RS-422 芯片可以在许多半导体公司的“标准接口器件”栏目中“收发器”类元件中找到对应的型号;比如Sipex 公司(器件前缀为SP)、Maxim 公司(器件前缀为MAX)、TI 公司(器件前缀为SN)、Intersil 公司(器件前缀为ISL 或LTC)等各大半导体公司。
⑷、RS-485接口电路
RS-485 接口电路的主要功能是:将来自微处理器的发送信号TX 通过“发送器”转换成通讯网络中的差分信号,也可以将通讯网络中的差分信号通过“接收器”转换成被微处理器接收的RX 信号。任一时刻,RS-485 收发器只能够工作在“接收”或“发送”两种模式之一,因此,必须为RS-485 接口电路增加一个收/发逻辑控制电路。另外,由于应用环境的各不相同,RS-485 接口电路的附加保护措施也是必须重点考虑的环节。
①、基本RS-485 电路
图 1-19 为一个经常被应用到的SP485R芯片的示范电路,可以被直接嵌入实际的RS-485应用电路中。微处理器的标准串行口通过RXD 直接连接SP485R 芯片的RO 引脚,通过TXD直接连接SP485R 芯片的DI 引脚。
由微处理器输出的R/D 信号直接控制SP485R 芯片的发送器/接收器使能:R/D 信号为“1”,则SP485R 芯片的发送器有效,接收器禁止,此时微处理器可以向RS-485 总线发送数据字节;R/D 信号为“0”,则SP485R 芯片的发送器禁止,接收器有效,此时微处理器可以接收来自RS-485 总线的数据字节。此电路中,任一时刻SP485R 芯片中的“接收器”和“发送器”只能够有1 个处于工作状态。连接至A 引脚的上拉电阻R7、连接至B 引脚的下拉电阻R8 用于保证无连接的SP485R芯片处于空闲状态,提供网络失效保护,以提高RS-485 节点与网络的可靠性。如果将SP485R 连接至微处理器80C51 芯片的UART 串口,则SP485R 芯片的RO 引脚不需要上拉;否则,需要根据实际情况考虑是否在RO 引脚增加1 个大约10K 的上拉电阻。
图 1-19 SP485R 的基本RS-485 电路
SP485R 芯片本身集成了有效的ESD 保护措施。但为了更加可靠地保护RS-485 网络,确保系统安全,我们通常还会额外增加一些保护电路。
电路图中,钳位于6.8V 的TVS 管V4、V5、V6 都是用来保护RS-485 总线的,避免RS-485总线在受外界干扰时(雷击、浪涌)产生的高压损坏RS-485 收发器。当然,也选择集成的总线保护元件,比如ONSemi 半导体的NUP2105L 器件(SOT-23 封装,集成2 个双向TVS器件),作为SP485R 芯片的附加保护措施。另外,电路中的L1、L2、C1、C2 是可选安装元件,用于提高电路的EMI 性能。图中附加的保护电路能够对SP485R 芯片起到良好的保护效果。
②、隔离RS-485 电路
图 1-20 为一个使用光电隔离方式连接的SP485R 芯片的示范电路,可以被直接嵌入实际的RS-485 应用电路中。微处理器的UART 串口的RXD、TXD 通过光电隔离电路连接SP485R 芯片的RO、DI 引脚,控制信号R/D 同样经光电隔离电路去控制SP485R 芯片的DE和/RE 引脚。
由微处理器输出的R/D 信号通过光电隔离器件控制SP485R 芯片的发送器/接收器使能:R/D 信号为“1”,则SP485R 芯片的DE 和/RE 引脚为“1”,发送器有效,接收器禁止,此时微处理器可以向RS-485 总线发送数据字节;R/D 信号为“0”,则SP485R 芯片的DE和/RE 引脚为“0”,发送器禁止,接收器有效,此时微处理器可以接收来自RS-485 总线的数据字节。任一时刻,SP485R 芯片中的“接收器”和“发送器”只能够有1 个处于工作状态。
连接至A 引脚的上拉电阻R7、连接至B 引脚的下拉电阻R8 用于保证无连接的SP485R芯片处于空闲状态,提供网络失效保护,以提高RS-485 节点与网络的可靠性。使用DC-DC 器件可以产生1 组与微处理器电路完全隔离的电源输出,用于向RS-485 收发器电路提供+5V 电源。电路中光耦器件的速率将会影响RS-485 电路的通讯速率。图 1-20 中选用了NEC 公司的光耦器件PS2501 芯片,受PS2501 芯片的响应速率影响,这一示范RS-485 接口电路的通讯速率只可保障在19200bps 速率下正常工作;如果需要达到更高的RS-485 通讯速率,则需要选用响应速度更快的光耦器件,比如Agilent 公司的超高速光耦元件。
图 1-20 SP485R 的隔离RS-485 电路
SP485R 芯片本身集成了有效的ESD 保护措施。但为了更加可靠地保护RS-485 网络,确保系统安全,我们通常还会额外增加一些保护电路。当然,我们使用在图 1-19 中介绍的保护电路,同样可以对SP485R 芯片起到良好的保护效果。
③、上电抑制电路
由多个RS-485 收发器连接而成的RS-485 多机网络中,任一时刻只能够有一个RS-485发送器工作在“发送”状态,其余节点必须工作在“接收”状态;这称为“单主/多从”通讯方式。在一个RS-485 网络中同时有2 个或更多个RS-485 收发器工作在“发送”状态将会导致数据丢失、产生错误,严重的甚至损坏RS-485 收发器,使RS-485 网络瘫痪。因此,在设计阶段时就应仔细考虑,避免后期可能出现的种种事故隐患。
图 1-21 所示实例介绍了在一个应用系统上电阶段的RS-485 接口电路设计窍门。RS-485接口电路实现系统的通讯功能,但仅是一个完整系统中的一个有机部分,当然受到微处理器的状态控制。当微处理器在上电时,串行通讯接口的控制信号SCI_DE 并不能够确定处于高或低电平状态,这可能会导致该单元在上电阶段向RS-485 网络发送一组“无效”数据,破坏原来正常的网络通讯功能。设计时增加一组由R1、C1、D1、U1 简单元件组成的上电抑制电路,即可以避免在应用系统上电时出现网络通讯事故。
图 1-21 RS-485 接口电路的上电抑制
1.3.4 RS-485 自动换向电路
前面的电路中,都使用了一个串行通讯接口的控制信号SCI_DE 来控制RS-485 收发器
的发送器/接收器使能引脚。图 1-22 则演示了另一种自动控制RS-485 芯片的发送器/接收器
使能引脚的方式,通常称作为RS-485 接口电路的自动换向功能。
图 1-22 RS-485 接口电路的自动换向
图 1-22 所示电路中,当TXD 信号为“1”,即无输入信号时,SP485R 芯片工作在“接收”状态;当TXD 为“0”,即有信号输入时,即执行发送功能时,来自TXD 信号上的有效电平将自动禁能接收器,使能发送器,从而将TXD 信号发送到RS-485 网络。
RS-485 接口电路的自动换向功能可以有很多种可实现的不同电路形式,但其基本内容都是由TXD 信号来控制RS-485 芯片中接收器/发送器的开关切换。由于RS-485 接口电路的自动换向将占用一部分接口电路的切换时间开销、信号驱动开销,因此,这一种低成本的RS-485 接口电路可能并不适合所有的RS-485 应用。比如,在需要可靠性或高速度长距离,尤其在节点较多、负载重的情况下,强烈建议选用前面介绍的独立控制的RS-485 接口电路收/发控制方法。
2、RS-485 通讯协议
RS-485 标准只对接口的电气特性做出规定,而不涉及接插件、电缆或协议;因此,用户需要在RS-485 应用网络的基础上建立自己的应用层通信协议。
由于RS-485 标准是基于PC 的UART 芯片上的处理方式,因此,其通讯协议也规定了串行数据单元的格式(8-N-1 格式):1 位逻辑0 的起始位,6/7/8 位数据位,1 位可选择的奇(ODD)/偶(EVEN)校验位,1/2 位逻辑1 的停止位。
目前,RS-485 在国内有着非常广泛的应用,许多领域,比如工业控制、电力通讯、智能楼宇等都经常可以见到具有RS-485 接口电路的设备。但是,这些设备采用的用户层协议都不相同;这些设备之间并不可以直接连接通讯。比如,很多具有RS-485 接口电路的用户设备采用自己制定的简单通讯协议,或是直接取自ModBus 协议(AscII/RTU 模式)中的一部分功能。
在电力通讯领域,当前国家现在执行的行业标准中,颁布有按设备分类的各种通讯规约,如CDT、SC-1801、u4F、DNP3.0 规约和1995 年的IEC60870-5-101 传输规约、1997 年的国际101 规约的国内版本DL/T634-1997规约;在电表应用中,国内大多数地区的厂商采用多功能电能表通讯规约(DL/T645-1997)。
下面将分别对多功能电能表通讯规约(DL/T645-1997)进行简单介绍,便于大家对应用层通信协议有一个基本的概念与理解。
1 多功能电能表通讯规约(DL/T645-1997)
国内江苏、浙江、上海地区的电表厂商采用多功能电能表通讯规约(DL/T645-1997)作为
电表的远程控制通讯协议;这是一个在RS-485 网络中实现应用的行业标准。
1. 通讯字节格式
传送方向从低到高位,一个起始位、一个停止位、一个偶校验位、8 位数据位,总共11位。
地址域A0~A5:当地址位999999999999H 时,为广播地址,同时当从控制器接收到一帧数据时,地址域相同时应响应命令,取得总线控制权,当响应命令之后,应把总线控制权归还给主控器。
命令码:执行操作的依据。
校验码:帧开始各个字节二进制算术和,不计溢出值。
前导字节:在发送信息之前,发送1 个或多个字节FEH,以唤醒接收方。
数据域:发送时数据加33H,接收时数据减33H。
1.5 RS-485 程序设计
以下章节将以多功能复费率电表的RS-485 通讯接口为设计原型,详细介绍RS-485 接口的程序设计方法。
1.5.1 RS-485 接口电路
RS-485 通讯接口电路是多功能复费率电表系统的一个重要的电路单元。
电表系统的微处理器芯片采用PHILIPS 公司的P89LPC931 单片机。P89LPC931 采用高性能的处理器结构,指令执行时间只需2~4 个时钟周期,6 倍于标准的80C51 微处理器。PHILIPS 公司LPC900 系列单片机是一个基于80C51 内核的高速、低功耗Flash 单片机,主要集成了字节方式的I2C 总线、SPI 接口、UART 通信接口、实时时钟、E2PROM、A/D 转换器、ISP/IAP 在线编程和远程编程方式等一系列有特色的功能部件,非常适合于许多要求高集成度、低成本、高可靠性的仪表应用领域。
微处理器P89LPC931 与SP-485E 芯片进行连接,构成RS-485 通讯接口电路,如图 1-25所示:
图 1-25 单片机与RS-485 通讯转换电路图
电路通过3 个光耦元件PS2501 对微处理器P89LPC931 和RS-485 总线电路进行隔离,提高系统的抗干扰能力,电路中的双向TVS 管P6KE6V8 并联在RS-485 总线A、B 线两端,对电路进行瞬态保护作用,R7 和R8 为偏置电阻,进行网络失效保护。但是这个电路中没有安装匹配电阻,在通讯网络设计中,应根据实际情况进行匹配电路的设计。
1.5.3 程序设计流程图
整个通讯程序分为3 个部分:数据接收部分、命令执行部分、数据发送部分。
1.5.4 数据接收部分
数据接收程序主要接收一帧正确的数据,数据帧错误的判断符合以下原则:
有一个字节偶校验错误,数据帧错误。
数据帧格式不正确,数据帧错误。
数据帧校验码不正确,数据帧错误。
整个程序是在接收中断服务程序中执行的。
接收中断开始
接收是前导字节吗?
接收地址域(A0~A5)
接收是前导字节吗?
接收是帧头吗?
接收是帧头吗?
接收命令字节(C)
接收数据长度字节(L)
接收L个数据(DATA)
接收校验字正确吗?
接收是帧尾吗?
置接收帧事件发生标志
关闭接收中断
结束接收中断
图 1-26 接收程序流程图
1.5.5 命令执行部分
这一部分是主程序执行部分,是从机接收一帧正确数据后,通过地址域判断RS-485 总
线中主控器是否呼叫本从机,如果是广播地址则所有接收到的从机都应响应命令,同时通过
密码的方式,可以设置权限,密码和地址是保存在E2PROM 中。
在地址和密码判断正确的时候,程序进行命令译码,对要求的命令执行相应的操作,同
时如果要通过总线发送数据,应准备好发送数据缓存器的内容,启动发送程序,发送完毕时
清除接收事件发生标志。
开始
程序初始化
接收帧事件发生吗?
是本机地址吗?
密码正确吗?
密码修改命令吗?
其他命令吗?
执行其他命令存取修改的密码?
置发送缓存相应数据
发送数据帧
结束
清除接收事件帧标志
图 1-27 命令执行流程图
1.5.6 数据发送部分
本程序的数据发送部分是在主程序中执行的。
广州周立功单片机发展有限公司 Tel:(020)38730977 38730977 Fax:38730925
31
发送程序开始
发送2~ 3个前导字节
发送帧头
发送地址域( A0~ A5 )
发送帧头
发送命令字节
发送数据长度字节
发送数据域
发送校验字节
发送帧尾
发送程序结束
打开接收中断, 置接收状态
置发送状态
图 1-28 发送程序流程图
1.5.7 RS-485 程序清单
/********************************************************************************
Serial.C
此程序是RS-485 从机通讯,包含3 部分:接收帧程序、发送帧程序及执行命令程序。
从机通讯地址储存在E2PROM 的0x00~0x05 中,密码在0x06~0x09。
程序是参照电能表通讯规约编写的,选择P89LPC931 单片机,内部振荡源
********************************************************************************/
#include<reg931.h>
#include<HI2C_C51.h> /*I2C通讯程序包, 网站下载*/
/*宏定义*/
#define uchar unsigned char
#define uint unsigned int
/*通讯变量定义*/
sbit CTRL485=P1^7; / *RS-485 切换控制信号*/
#define BRGR1_DATA 0x17 /*波特率1200bps*/
#define BRGR0_DATA 0xf0
#define N 32 /*通讯缓存区长度*/
uchar idata Serial_buf[N]; /*定义通讯缓存区*/
广州周立功单片机发展有限公司 Tel:(020)38730977 38730977 Fax:38730925
32
/*数据结构: 地址域A0A1A2A3A4A5 共6 个,命令字节1 个,长度字节1 个,
数据区(标识符2 个,密码,数据)*/
/*主程序变量定义*/
#define CAT24W08 0xa8 /*E2PROM的I2C 地址*/
uchar data Command_status1=0x00; /*程序运行状态字节*/
/********************************************************************
延时函数
原型:void Delay_T(uchar);
功能:延时1ms*i
入口参数: i 是设定延时时间
出口参数:无
********************************************************************/
void Delay_T(uchar i)
{
uint j;
for(;i>0;i--)
for(j=0;j<700;j++);/*1ms*/
}
/********************************************************************
CPU 各个部件的初始化函数
原型:void Ini_CPU();
功能:初始化CPU 各个部件
入口参数:无
出口参数:无
********************************************************************/
void Ini_CPU()
{
P1M1&=0x7e; /*设置P1.0,P1.7 为推挽输出,P1.1 为输入状态*/
P1M2|=0x81;
P1M1|=0x02;
P1M2&=0xfd;
Delay_T(100); /*延时100ms,以稳定CPU*/
CTRL485=1; /*485通讯为接收状态*/
/*串口初始化*/
PCON&=0x3f; /*UART 设置工作方式3,11 位数据*/
SCON=0xd0;
SSTAT=0x00;
BRGCON=0x00; /*装入波特率常数,1200bps*/
BRGR1=BRGR1_DATA;
BRGR0=BRGR0_DATA;
BRGCON=0x03;
广州周立功单片机发展有限公司 Tel:(020)38730977 38730977 Fax:38730925
33
ESR=1; /*启动接收状态*/
}
/********************************************************************
接收一个字节通讯函数
原型:uchar Receive_Data();
功能:接收一个字节通讯
入口参数:无
出口参数:返回接收值
********************************************************************/
uchar Receive_Data()
{
RI=0;
while(!RI);
RI=0;
ACC=SBUF;
if(P!=RB8) /*偶校验正确吗?*/
{
SP--;SP--;CY=0;return CY; /*错误返回*/
}
return (ACC); /*接收一个字节,并进行偶校验*/
}
/********************************************************************
接收一帧通讯函数
原型:void Receive_One(uchar *);
功能:接收一帧通讯
入口参数:接收存取地址指针
出口参数:接收正确标志,1 为接收正确
********************************************************************/
bit Receive_One(uchar *s)
{
uchar CS=0x00,Serial_data;
char i,j;
RI=0;
Serial_data=SBUF; /*接收第一字节*/
while(Serial_data!=0xfe)
return 0; /*不是前导字节*/
do
Serial_data=Receive_Data(); /*是前导字节,继续查询*/
while(Serial_data==0xfe); /*是前导字节吗?*/
if(Serial_data!=0x68) /*是帧头吗?*/
return 0;
CS+=0x68;
广州周立功单片机发展有限公司 Tel:(020)38730977 38730977 Fax:38730925
34
for(i=0;i<=5;i++) /*接收电表通讯地址*/
{
*(s+i)=Receive_Data();
CS+=*(s+i);
}
if(Receive_Data()!=0x68) /*是数据帧头吗?*/
return 0;
CS+=0x68;
CS+=(*(s+6)=Receive_Data()); /*接收通讯命令*/
j=*(s+7)=Receive_Data(); /*接收通讯数据长度*/
CS+=j;
for(i=0;i<=(j-1);i++) /*接收N 个数据*/
{
CS+=(*(s+i+8)=Receive_Data());
*(s+i+8)-=0x33;
}
if(CS!=Receive_Data()) /*校验正确吗?*/
return 0;
if(Receive_Data()!=0x16) /*是帧尾吗?*/
return 0;
ESR=0;
return 1; /*一帧接收成功,关闭接收通讯,处理一帧完后再打开*/
}
/********************************************************************
串口接收中断服务程序
功能:接收数据
********************************************************************/
void RXD_Int(void) interrupt 4
{
CY=Receive_One(Serial_buf);
if(CY)
Command_status1|=0x04; /*一帧接收成功,通知主程序进行通讯处理*/
}
/********************************************************************
串口发送一个字节
功能:发送一个字节数据
入口参数:发送数据
出口参数:无
********************************************************************/
void Send_Data(uchar Serial_data)
{
ACC=Serial_data;
TB8=P;TI=0;
广州周立功单片机发展有限公司 Tel:(020)38730977 38730977 Fax:38730925
35
SBUF=Serial_data;
while(!TI);
TI=0; /*发送一个字节,并进行偶校验*/
}
/********************************************************************
发送一帧数据函数
原型:void TXD_Int(uchar *);
功能:发送一帧数据
入口参数:发送数据帧地址指针
出口参数:无
********************************************************************/
void TXD_Int(uchar *s)
{
uchar CS=0x68;
char i,j;
CTRL485=0; /*RS-485 通讯,切换为发送状态*/
Delay_T(1);
TI=0;
Send_Data(0xfe); /*发送2 个前到字节*/
Send_Data(0xfe);
Send_Data(0x68); /*发送帧头*/
for(i=0;i<=5;i++) /*发送电表通讯地址*/
{CS+=*(s+i);Send_Data(*(s+i));}
CS+=0x68;Send_Data(0x68); /*发送数据帧头*/
CS+=*(s+6);Send_Data(*(s+6)); /*发送帧命令*/
CS+=*(s+7);j=*(s+7);Send_Data(j); /*发送数据长度*/
for(i=0;i<=j-1;i++) /*发送数据*/
{
(*(s+i+8))+=0x33;
Send_Data(*(s+i+8));
CS+=(*(s+i+8));
}
Send_Data(CS); /*发送校验字节*/
Send_Data(0x16); /*发送帧尾*/
RI=0;TI=0;
Delay_T(1);
CTRL485=1; /*一帧发送完毕,恢复信道切换功能*/
}
/********************************************************************
通讯地址判断函数
原型:uchar Serial_Address(uchar *);
广州周立功单片机发展有限公司 Tel:(020)38730977 38730977 Fax:38730925
36
功能:通讯地址判断,通讯地址存储E2PROM 0 区0x00~0x05 中
全局变量:
入口参数:s1 指向从通讯地址
出口参数:0x00 错误,0x01 正确,0x02 广播地址
********************************************************************/
uchar Serial_Address(uchar *s1)
{
uchar i,a[6];
IRcvStr(CAT24W08,0x00,a,6); /*读取电表通讯地址*/
for(i=0;i<=5;i++)
{
if((*(s1+i))!=0x99)
break; /*不是广播地址*/
if(i==5)
return(0x02); /*是广播地址*/
}
for(i=0;i<=5;i++)
{
if((*(s1+i))!=a[i])
return(0x00); /*地址不相同*/
}
retur
展开阅读全文