CN101351803B - 用于多通道电力计量的装置和方法 - Google Patents

用于多通道电力计量的装置和方法 Download PDF

Info

Publication number
CN101351803B
CN101351803B CN200680049289XA CN200680049289A CN101351803B CN 101351803 B CN101351803 B CN 101351803B CN 200680049289X A CN200680049289X A CN 200680049289XA CN 200680049289 A CN200680049289 A CN 200680049289A CN 101351803 B CN101351803 B CN 101351803B
Authority
CN
China
Prior art keywords
pic
status
comm
data
operated
Prior art date
Legal status (The legal status is an assumption and is not a legal conclusion. Google has not performed a legal analysis and makes no representation as to the accuracy of the status listed.)
Expired - Fee Related
Application number
CN200680049289XA
Other languages
English (en)
Other versions
CN101351803A (zh
Inventor
塞尔·A·斯瓦茨特劳贝
多龙·沙夫瑞尔
西达尔塔·马利克
罗伯特·海沃德
Current Assignee (The listed assignees may be inaccurate. Google has not performed a legal analysis and makes no representation or warranty as to the accuracy of the list.)
Quadlogic Controls Corp
Original Assignee
Quadlogic Controls Corp
Priority date (The priority date is an assumption and is not a legal conclusion. Google has not performed a legal analysis and makes no representation as to the accuracy of the date listed.)
Filing date
Publication date
Priority claimed from US11/431,849 external-priority patent/US7539581B2/en
Application filed by Quadlogic Controls Corp filed Critical Quadlogic Controls Corp
Publication of CN101351803A publication Critical patent/CN101351803A/zh
Application granted granted Critical
Publication of CN101351803B publication Critical patent/CN101351803B/zh
Expired - Fee Related legal-status Critical Current
Anticipated expiration legal-status Critical

Links

Images

Classifications

    • GPHYSICS
    • G01MEASURING; TESTING
    • G01RMEASURING ELECTRIC VARIABLES; MEASURING MAGNETIC VARIABLES
    • G01R22/00Arrangements for measuring time integral of electric power or current, e.g. electricity meters
    • G01R22/06Arrangements for measuring time integral of electric power or current, e.g. electricity meters by electronic methods
    • G01R22/061Details of electronic electricity meters
    • G01R22/066Arrangements for avoiding or indicating fraudulent use
    • HELECTRICITY
    • H04ELECTRIC COMMUNICATION TECHNIQUE
    • H04QSELECTING
    • H04Q9/00Arrangements in telecontrol or telemetry systems for selectively calling a substation from a main station, in which substation desired apparatus is selected for applying a control signal thereto or for obtaining measured values therefrom
    • GPHYSICS
    • G01MEASURING; TESTING
    • G01RMEASURING ELECTRIC VARIABLES; MEASURING MAGNETIC VARIABLES
    • G01R22/00Arrangements for measuring time integral of electric power or current, e.g. electricity meters
    • G01R22/06Arrangements for measuring time integral of electric power or current, e.g. electricity meters by electronic methods
    • G01R22/061Details of electronic electricity meters
    • G01R22/063Details of electronic electricity meters related to remote communication
    • HELECTRICITY
    • H02GENERATION; CONVERSION OR DISTRIBUTION OF ELECTRIC POWER
    • H02JCIRCUIT ARRANGEMENTS OR SYSTEMS FOR SUPPLYING OR DISTRIBUTING ELECTRIC POWER; SYSTEMS FOR STORING ELECTRIC ENERGY
    • H02J13/00Circuit arrangements for providing remote indication of network conditions, e.g. an instantaneous record of the open or closed condition of each circuitbreaker in the network; Circuit arrangements for providing remote control of switching means in a power distribution network, e.g. switching in and out of current consumers by using a pulse code signal carried by the network
    • H02J13/00006Circuit arrangements for providing remote indication of network conditions, e.g. an instantaneous record of the open or closed condition of each circuitbreaker in the network; Circuit arrangements for providing remote control of switching means in a power distribution network, e.g. switching in and out of current consumers by using a pulse code signal carried by the network characterised by information or instructions transport means between the monitoring, controlling or managing units and monitored, controlled or operated power network element or electrical equipment
    • H02J13/00007Circuit arrangements for providing remote indication of network conditions, e.g. an instantaneous record of the open or closed condition of each circuitbreaker in the network; Circuit arrangements for providing remote control of switching means in a power distribution network, e.g. switching in and out of current consumers by using a pulse code signal carried by the network characterised by information or instructions transport means between the monitoring, controlling or managing units and monitored, controlled or operated power network element or electrical equipment using the power network as support for the transmission
    • HELECTRICITY
    • H02GENERATION; CONVERSION OR DISTRIBUTION OF ELECTRIC POWER
    • H02JCIRCUIT ARRANGEMENTS OR SYSTEMS FOR SUPPLYING OR DISTRIBUTING ELECTRIC POWER; SYSTEMS FOR STORING ELECTRIC ENERGY
    • H02J13/00Circuit arrangements for providing remote indication of network conditions, e.g. an instantaneous record of the open or closed condition of each circuitbreaker in the network; Circuit arrangements for providing remote control of switching means in a power distribution network, e.g. switching in and out of current consumers by using a pulse code signal carried by the network
    • H02J13/00032Systems characterised by the controlled or operated power network elements or equipment, the power network elements or equipment not otherwise provided for
    • H02J13/00034Systems characterised by the controlled or operated power network elements or equipment, the power network elements or equipment not otherwise provided for the elements or equipment being or involving an electric power substation
    • HELECTRICITY
    • H04ELECTRIC COMMUNICATION TECHNIQUE
    • H04QSELECTING
    • H04Q2209/00Arrangements in telecontrol or telemetry systems
    • H04Q2209/30Arrangements in telecontrol or telemetry systems using a wired architecture
    • HELECTRICITY
    • H04ELECTRIC COMMUNICATION TECHNIQUE
    • H04QSELECTING
    • H04Q2209/00Arrangements in telecontrol or telemetry systems
    • H04Q2209/60Arrangements in telecontrol or telemetry systems for transmitting utility meters data, i.e. transmission of data from the reader of the utility meter
    • YGENERAL TAGGING OF NEW TECHNOLOGICAL DEVELOPMENTS; GENERAL TAGGING OF CROSS-SECTIONAL TECHNOLOGIES SPANNING OVER SEVERAL SECTIONS OF THE IPC; TECHNICAL SUBJECTS COVERED BY FORMER USPC CROSS-REFERENCE ART COLLECTIONS [XRACs] AND DIGESTS
    • Y02TECHNOLOGIES OR APPLICATIONS FOR MITIGATION OR ADAPTATION AGAINST CLIMATE CHANGE
    • Y02EREDUCTION OF GREENHOUSE GAS [GHG] EMISSIONS, RELATED TO ENERGY GENERATION, TRANSMISSION OR DISTRIBUTION
    • Y02E60/00Enabling technologies; Technologies with a potential or indirect contribution to GHG emissions mitigation
    • YGENERAL TAGGING OF NEW TECHNOLOGICAL DEVELOPMENTS; GENERAL TAGGING OF CROSS-SECTIONAL TECHNOLOGIES SPANNING OVER SEVERAL SECTIONS OF THE IPC; TECHNICAL SUBJECTS COVERED BY FORMER USPC CROSS-REFERENCE ART COLLECTIONS [XRACs] AND DIGESTS
    • Y04INFORMATION OR COMMUNICATION TECHNOLOGIES HAVING AN IMPACT ON OTHER TECHNOLOGY AREAS
    • Y04SSYSTEMS INTEGRATING TECHNOLOGIES RELATED TO POWER NETWORK OPERATION, COMMUNICATION OR INFORMATION TECHNOLOGIES FOR IMPROVING THE ELECTRICAL POWER GENERATION, TRANSMISSION, DISTRIBUTION, MANAGEMENT OR USAGE, i.e. SMART GRIDS
    • Y04S40/00Systems for electrical power generation, transmission, distribution or end-user application management characterised by the use of communication or information technologies, or communication or information technology specific aspects supporting them
    • Y04S40/12Systems for electrical power generation, transmission, distribution or end-user application management characterised by the use of communication or information technologies, or communication or information technology specific aspects supporting them characterised by data transport means between the monitoring, controlling or managing units and monitored, controlled or operated electrical equipment
    • Y04S40/121Systems for electrical power generation, transmission, distribution or end-user application management characterised by the use of communication or information technologies, or communication or information technology specific aspects supporting them characterised by data transport means between the monitoring, controlling or managing units and monitored, controlled or operated electrical equipment using the power network as support for the transmission

Landscapes

  • Engineering & Computer Science (AREA)
  • Computer Networks & Wireless Communication (AREA)
  • Power Engineering (AREA)
  • Physics & Mathematics (AREA)
  • General Physics & Mathematics (AREA)
  • Arrangements For Transmission Of Measured Signals (AREA)
  • Remote Monitoring And Control Of Power-Distribution Networks (AREA)
  • Measuring And Recording Apparatus For Diagnosis (AREA)
  • Selective Calling Equipment (AREA)

Abstract

一方面,本发明包括用于测量用电量的装置,包括:用于通过电力线通信进行远程断开的装置;用于探测窃电的装置;用于窜改检测的装置;以及用于反向电压检测的装置。另一方面,本发明包括用于进行多通道电力计量的装置,包括:(a)计量表头,其可操作以对多个电用户线路的用电量进行计量;(b)转发器,其可操作以将通过电力线通信从计量表头接收到的数据传送到远程计算机,并将通过电力线通信接收到的数据从远程计算机传送到计量表头,以及(c)负荷控制模块,其可操作以启动对多个继电器中每个继电器的连接和断开,多个继电器中的每个继电器都对应于多个电力用户线路之一。

Description

用于多通道电力计量的装置和方法
相关申请的交叉引用
本申请要求以下专利申请的优先权:2005年11月15日提交的第60/737,580号美国临时专利申请、2005年11月23日提交的第60/739,375号美国临时专利申请和2006年6月15日提交的第60/813,901号美国临时专利申请。本申请是2006年5月9日提交的第11/431,849号美国专利申请的部分延续。第11/431,849号美国专利申请是2005年1月6日提交的第11/030,417号美国专利申请(现在是第7,054,770号美国专利)的分案申请。第11/030,417号美国专利申请又是2001年2月28日提交的第09/795,838美国专利申请(现在是第6,947,854号美国专利)的分案申请。上述每个申请的全部内容都通过引用并入本文。
技术背景和发明内容
本发明的一个实施方式包括与基于Quadlogic ASIC(阔德逻辑专用集成电路)的计量表族相关的计量装置(参见第6,947,854号美国专利和公开号为20060036388的美国专利申请,这两个专利的全部内容都通过引用并入本文)。特别地,该实施方式(在这里,为了方便,将其称作“能量防卫装置(Energy Guard)”是多通道计量表,其优选地能够提供前述计量表族的大多数功能,并进一步提供以下改进、特征和组件。
在至少一个实施方式中,微型橱(MiniCloset)是24通道的计量装置,其可测量高达24个单相客户、12个双相客户、或者8个三相的客户的电力使用。优选地,下文将讨论的一个或多个LCM(负荷控制模块)与微型橱相连。
能量防卫装置优选地包括微型橱计量表探头模块和安装在钢盒的两个LCM。供远程电用户断开和再连接的继电器以及当前的变压器也安装在该钢盒内,如图1所示。
安装好之后,电用户的供电线路从主馈电线分接出,穿过能量防卫装置,并直接到达用户家中。通过以下说明和相关附图,对于本领域技术人员而言,能量防卫装置的结构和使用将显而易见。源代码提供在所附的附录中。
能量防卫装置计量表优选地可操作以提供:
(A)远程断开/重连:该计量表支持通过PLC(电力线通信)的全双工(双向的)通信,并且可配备有远程操作的继电器(60安培、100安培或200安培),该继电器用于实现远程电力用户的断开和重连。
(B)防盗:该系统设计具有三个具体特征来防盗。第一,能量防卫装置优选地安装在中压以上的电线杆上,从而使得顾客很难对其接触和篡改(tamper)。第二,因为该系统没有额外的信号线(即,所有的通信都是通过电力线),因此任何切断的通信线都能被立即检测到。也就是说,如果通信线断了,那么就服务断了,这是很容易发现的。第三个防盗特征是该计量表可用于测量变压器能量,以确认测得的各客户的总量。差值就是盗用的能量。
(C)篡改检测:该能量防卫装置优选地提供了2种光学篡改检测模式。每个单元都包含从镜似的小粘附物反射的光。如果没有这种反射光,则说明盒子被打开了。这种检测将使由能量防卫装置单元测量的所有客户都自动断开。另外,如果能量防卫装置的外壳被打开并且有环境光进入,那么也将会使由能量防卫装置单元测量的所有客户自动断开。这两种篡改检测模式持续使用并在每秒钟内改变多次,以最大化地保障安全。
(D)反向电压检测:在某些情况下,电力公司能够断开个别用户的供电,而该用户能够通过替代的馈电获得电力。如果该电力公司在这些情况下重新供给电力,那么计量装置和/或分配系统可能发生毁坏。能量防卫装置优选地能检测出这种故障状态。该能量防卫装置能通过连接到用户住所的线路检测反馈到断开处的任何电压。如果检测到了电压,那么能量防卫装置固件将自动地阻止重连。
(E)预付款:能量的预付款可通过电话、电子交易或者亲自办理等方式进行。将购买的度数传送到计量表并存储在其存储器中。计量表采用倒计数的方式,显示出在到达0而断开连接之前还有多少能量可使用。只要用户持续购买电能,服务就不会中断,并且电力公司将具有每天的活动报告。
(F)负荷限制:作为由于未付款而断开连接的一个选择或者或作为预付款系统的一部分,能量防卫装置计量表能允许电力公司远程地将输出电能限制为固定标准,当负荷超出了该标准时则断开连接。如果用户超出了负荷并且断开了连接,那么该用户可将可选的远程显示器上的按钮复位来恢复负荷,只要连接上的负荷小于预设的限制。作为一种选择,客户能通过电话呼叫电业服务线以使服务恢复。这种特征允许电力公司为重要系统提供电能,即使是在例如顾客未付款的情况下。
(G)每月的耗能限制:某些客户得益于补贴价率并获得最大的每月总消耗。当达到某个消耗线时,能量防卫装置固件能够断开供电。然而,当提供了提前通知客户的服务时,这种程序才能最好地执行。这能够通过将消息送到客户家里来通知客户:其月耗能费用快达到计划的月耗能量了。作为一种选择(或结合),可编程设置定时的供电中断,从而使得当快达到限量的时候,将电能断开一段时间,以越来越长的中断时间来通知住户。服务中这些有计划的中断是用来作为给用户的警告,告诉他们已经接近限量了,从而使其有时间来改变耗电方式。
(H)计量表验证:系统的集成模块优选地为可移除的。这就允许在发生客户计费纠纷的情况下容易地在实验室重新验证计量表精度。
(I)电力公司的运行效益:能量防卫装置具有详尽的机载事件日志和诊断功能,为现场技术人员提供了大量数据,用于电力和通信系统的试运行及故障检修。非计费参数包括:电流,电压,温度,总谐波失真,频率,瞬时的瓦特、乏和伏安值,V2小时,12小时,功率因数,以及相角。
在查看了所附说明书、软件代码和图表之后,对于本领域技术人员而言,这些和其它特征将显而易见。
一方面,本发明包括用于计量电力使用的装置,包括:用于通过电力线通信进行远程断开的装置;用于探测窃电的装置;用于窜改检测的装置;以及反向电压检测的装置。
另一方面,本发明包括利用电力线通信进行远程多通道电力计量的装置,包括:多个计量点,位于配电变压器的副边,并能够操作以对多个电力用户线路中的每个的电力使用分别进行测量;位于所述配电变压器的原边的转发器,所述装置能够操作以通过直接电力线通信向所述转发器发送数据或从所述转发器接收数据,所述转发器能够操作以向远程设置的计算机发送数据或从其接收数据;一个或多个负荷控制模块,所述负荷控制模块能够操作以启动多个继电器中的每个继电器的连接和断开,所述多个继电器中的每个继电器都对应所述多个电力用户线路中之一;以及包含所述多个计量点、所述负荷控制模块和所述继电器的盒,其中,所述配电变压器将中压配电电压转化为适于向用户供电的低压电压,并且所述装置能够操作以将信号注入向用户供电的低压电力线或从该电力线接收信号,所述信号在所述计量表头和所述转发器之间提供双向通信并经过所述配电变压器。
再一方面,本发明包括一种用于多通道电力计量的装置,包括:与配电变压器的副边电路通信的控制模块,所述配电变压器将中压配电电压转换为适于向用户供电的低压电压;转发器,所述转发器与所述变压器的原边电路通信,所述控制模块能够操作以通过所述配电变压器经由直接电力线通信向所述转发器发送数据或从所述转发器接收数据,所述转发器能够操作以向远程设置的计算机发送数据或从其接收数据;多个计量模块,每个计量模块都能够操作以对从所述配电变压器的所述副边电路馈送的、多个电力用户线路中之一上的电力使用进行测量;一个或多个继电器,能够操作以启动到所述电力用户线路的电力的连接和断开;以及包含所述控制模块、所述计量模块和所述继电器的盒,其中,所述装置能够操作以将信号注入向用户供电的低压电力线或从该电力线接收信号,所述信号在所述计量表头和所述转发器之间提供双向通信,并经过所述配电变压器,以至少部分地在中压电力线上向所述远程设置的计算机通信。
在不同的实施方式中:(1)计量装置进一步包括与所述计量表头通信的篡改检测器;(2)所述篡改检测器包括光源和反射面,其中,如果所述篡改检测器提供通知,告知未检测到从所述反射面反射的光线,那么所述计量表头则能够操作以指示所述负荷控制模块断开全部所述用户线路;(3)所述计量装置进一步包括包含所述计量表头、所述负荷控制模块和所述继电器的盒,其中,所述篡改检测器包括对进入所述盒中的环境光进行检测的检测器;(4)所述计量装置进一步包括包含所述计量表头、所述负荷控制模块和所述继电器的盒,其中,所述盒安装在电线杆上;(5)所述计量装置进一步包括用于将变压器能量与所述用户线路使用的总能量进行比较的装置;(6)所述计量装置进一步包括,用于检测通过所述用户线路的反向电压流的装置;(7)所述计量装置进一步包括,与所述计量表头通信的计算机可读的存储器以及与所述计量表头通信的计数器,所述计数器对应用户线路并且能够操作以对存储在所述存储器中的能量的量进行倒数,当所述计数器数到0时,所述计量表头能够操作以向所述负荷控制模块发送断开信号,以断开所述用户线路;(8)所述计量装置进一步包括与所述计量表头通信的计算机可读的存储器,所述存储器能够操作以存储用于用户线路的负荷限度,当超出所述负荷限度时,所述计量表头能够操作以向所述负荷控制模块发送断开信号,以断开所述用户线路;(9)所述计量装置进一步包括与所述计量表头通信的计算机可读的存储器,所述存储器能够操作以存储用于用户线路的使用限度,当超出所述使用限度时,所述计量表头能够操作以向所述负荷控制模块发送断开信号,以断开所述用户线路;(10)所述转发器能够操作以通过中压电力线与所述远程设置的计算机通信;(11)所述计量装置进一步包括与所述计量表头通信的显示单元,所述显示单元能够操作以显示从所述计量表头接收到的数据;(12)所述显示单元能够操作以显示与用户的能耗有关的信息;(13)所述显示单元能够操作以显示与用户的能量使用或能量的可疑窃取有关的警告;(14)所述显示单元能够操作以将用户输入的信息传送给所述计量表头。
附图说明
图1示出了优选实施方式的连接的方块图/接线图;
图2示出了优选实施方式的物理配置的方块图;
图3A-3B是检测转发器和微型橱的优选CPU板的原理图;
图4是优选的检测转发器电源的原理图;
图5是优选的微型橱电源的原理图;
图6是用于将当前的变压器信息返回到微型橱表头的优选电路板的原理图;
图7A-7C是优选的负荷控制模块电路板的原理图;
图8A-8D是用于光学篡改检测的优选的电源板的原理图;
图9A-9C是优选的能量防卫装置连接板的原理图;
图10是用于可操作以提供继电控制的控制电路板的原理图;
图11是优选的能量防卫装置的基座装配的示图;
图12和13分别是优选的相相母线及其构造的示图;
图14示出了优选的中性线的框架构造和装配的示图;
图15示出了优选的过渡线;
图16描述了优选的过渡线的布置;
图17和18描述了优选的接收器模块构造;
图19示出了优选的集成的电流传感和继电模块;
图20示出了优选的集成的电流传感和继电模块的分解图;
图21示出了优选的计量模块的分解图;
图22示出了放置在EG框架装配和接受器模块中的计量模块;
图23示出了能量防卫装置的优选实施方式的分解图;
图24示出了优选的EG装配和基座装配的分解图;
图25示出了优选的EG布局;
图26和27示出了优选的计量模块示意图;
图28示出了优选的后板示意图;
图29是电源板的优选示图;
图30是I/O扩展板的优选示图;
图31是CPU板的优选示图;
图32是优选的控制模板的图;
图33是用于用户显示模块的计量和供电电路的优选示图;
图34是用于CDM的显示板的优选示图;
图35是用于计量的优选模拟前端的框图;
图36和37示出了优选的DSP实现;
图38示出了优选的同相滤波器频率和冲击响应曲线;
图39示出了为60Hz的半奇次谐波的注入PLC信号;
图40示出了计量表接收到的FFT帧与扫描转发的FFT帧可为异相的12种方式;
图41示出了优选的FIR滤波器技术要求;以及
图42示出了由优选的FFT得到的电压和电流。
具体实施方式
在一个实施方式中,能量防卫装置计量装置包括微型橱(也就是,可操作以对多个用户线路进行计量的计量装置);扫描转发器;一个或多个可操作以将所选用户的服务断开的继电器;负荷控制模块;以及光学篡改检测装置。
本文所述的微型橱和扫描转发器与第6,947,854号美国专利所述的微型橱和扫描转发器大体相同。也就是说,尽管其在这些年都有了改进,但是与本说明书相关的功能和结构都可认为与该专利所描述的是相同的。
本发明的一个方面包括:利用微型橱中现有的多通道计量功能,并增加了通过PLC的远程连接和断开。需要增加新的硬件和软件才能提供这样的附加功能。增加的硬件包括:LCM(负荷控制模块)和连接/断开继电器。还增加了支持电路,以将信号轨迹路由至主计量表处理机-微型橱5计量表头,并对来自主计量表处理机-微型橱5计量表头的信号进行路由。增加的软件包括:如下文中的表格所述的、与增加的硬件进行通信的编码模块。
图1是优选实施方式的连接的结构图。中压电力线A、B、C和N(中性的)都插入配电变压器110。低压电力线(通过变流器120)将配电变压器110连接至能量防卫装置单元140。能量防卫装置单元140监控变流器120,并为单相用户线1-24供电。
图2是能量防卫装置单元140的优选结构框图。
扫描转发器210是单元140的优选数据采集器,其可位于微型橱的外部或内部,并可为同时用于一个以上微型橱的主数据采集器。优选地,扫描转发器210执行以下功能:(a)检验数据(每次通信优选地从时钟和计量表身份认证开始,以确保数据完整);(b)采集数据(周期地从每个计量表单元采集数据块,每个数据库都包含先前采集的计量表读数、间隔读书以及日志);(c)储存数据(优选地,将数据在非易失存储器中存储指定的时间(例如40天);以及(d)报告数据(通过PLC、电话调制器、RS-232线路或者其它装置)。
滑板280包括微型橱表头和提供激活继电器的控制信号的负荷控制模块240。所有电子设备都由电源250供电。后板装配270包括多个(例如24个)CT(变流器)和继电器,在本实施例中,分为3组每组8个CT和继电器。用户电缆通过CT连接并连接到用户住所290的电路上。位于远端的扫描转发器210通过电力线载波通信接入能量防卫装置表头并进行双向通信。
图1和2示出的信号流优选地是通过执行不同的软件代码模块来完成的,这些代码模块同时工作的以允许微型橱具有远程连接/断开的能力。下面附录里提供的软件模块是:
  代码模块   位置   功能
  lcm.def和pic.def   负荷控制模块   启动对继电器的连接和断开
  pulse.c和pulse.h   表头   建立与LCM的通信
  picend.def和  picvars.def   表头   为LCM提供控制信号
  pulselink.def和  pulseoutm.c   表头   为LCM提供用于连接和断开  继电器的脉冲
图3-10是优选组件的示图,如下所述。优选的连接/断开继电器是K850KG系列继电器,但是本领域技术人员将认识到,也可使用其它继电器,而不偏离本发明的范围。
  图   示意图   详细描述
  3   PCB 107D   扫描转发器和微型橱的CPU板
  4   PCB 135C   扫描转发器的电源
  5   PCB 144C   微型橱的电源
  6   PCB 146C   负荷控制模块的板
  7   PCB 160A   该板将变流器信息返回至微型橱表头
  8   PCB 170   增加了光学篡改探测能力的EG电源板
  9   PCB 171   EG连接板,其具有对信号进行路由的轨迹
  10   PCB 172   用于继电器控制的控制电路板
在另一个实施方式中,能量防卫装置的实现利用了传统断路器面板架构的相似性。在断路器面板中,将电能馈送到面板上,然后通过电路断路器将电能分布到各个用户电路上,所述电流断路器提供了连接或端口用户线路的能力。
在微型橱/能量防卫装置中,多个变流器测量用户电路中的电流并把数据传回到计算计量量的中央处理器。然而,微型橱/能量防卫装置与断路器面板具有几个显著的差别。例如,尽管断路器位于用户住所附近,但是能量防卫装置通常安装配电变压器附近。这种可选择的实施方式的优点对本领域技术人员是显而易见的。例如,本实施方式相对于前面讨论的实施方式而言提供了改善的尺寸和总体大小。当在现有的电力装置中增加设备中时,空间总是受限的。当空间受限时,具有28″×22″×11″的优选尺寸的EG(能量防卫装置)版本具有极大优势。
下面的描述包括了优选的构造细节、详细示图以及软件描述。与上文讨论的实施方式一样,本该实施例可操作以提供远程断开/连接操作、防止窃电、窜改检测、反向电压检测、执行预付款和限制载荷、以及执行计量表验证。
优选的EG构造细节
在本实施方式中,EG的主要组件为:
1.能量防卫装置基座装配
2.能量防卫装置装配
  a.相(phase)母线和中性线
  b.过渡线
  c.接受器模块
3.能量防卫装置计量模块
  a.计量模块
  i.集成的电流传感和继电模块
4.能量防卫装置电子设备
  a.PCB 203
  b.PCB 204
  c.PCB 234
  d.PCB 235
  e.PCB 202
  f.PCB 210
  g-PCB 230
h.PCB 206
EG基座装配
EG基座装配包括外壳底座,其上具有螺钉和保持垫圈作为用于EG顶盖的锁定机构,该外壳底座的一个侧面上具有铰链连接。如图11所示。该外壳底座提供了用于用户电缆的布线。
EG装配-相母线
三条铝制的相母线朝向EG装配的中心错列地放置。如图12和13所示。这样,通过使用过渡线提供到用户计量模块的连接。错列排布的母线布局如图13所示。母线用黑色示出。
中性线
EG优选地包括四条中性线,这四条中性线形成EG装配的框架,从而为中性线电流提供路径。如图14所示。横杆上的接线片提供来自电力分配变压器的中性线馈电。同时,还有2个母板中性线将中性线电流传送到控制模块。
过渡线
过渡线实现用户计量模块和相母线之间的机械连接和电连接。如图15所示。用于相A和C的过渡线如图15A所示;用于相B的过渡线如图15B所示。图16用黑色示出了过渡线。
接受器模块
接受器模块优选地由塑料制成,并且在机械上接受可容易地安装到EG装配中的计量模块。每个EG都具有4个堆叠在一起的接受器模块并且能够容纳12个2相的或者8个3相的计量模块。如图17所示。接受器模块还提供用于连接于控制模块的母版中性线的机械路线,如图18所示。
用户计量模块
优选的计量模块提供了单相、双相或三相用户的耗电量测量所需的计量法。单个模块用作完全独立计量表,其可作为分离的计量单元来被测试和评估。每个模块优选地包括集成的电流传感和继电模块以及计量电子设备,并在用户电路和相母线之间提供连接。图19示出了优选的集成的电流传感和继电模块。图20示出了集成的电流传感和继电模块的分解图。
图21示出了优选计量模块的分解图。图22示出了放置在EG框架装配和接受器模块中的计量模块(用黑色示出)。
图23示出了能量防卫装置的分解图,图24示出了优选的EG装配和EG基座装配的分解图。
电于设备
控制模块箱优选地包括各种PCB,这些PCB同时从各计量模块收集计量数据,并通过电力线将这些数据传送给例如ST(扫描转发器)的主要设备。
图25示出了本实施方式的优选能量防卫装置布局。每条用户线都具有相应的计量模块(下面将讨论的PCB 203和PCB 204)(如图26和27所示)
图25示出的后板2510(PCB 234;结构示意图如图28所示)是在EG中传送信号的公共母线。后板2510上有两种类型的通信选择来允许将数据从控制模块2520传送到单个计量模块PCB 203。这可通过2线I2C选项或者通过1线串行选项来完成。
控制模块2520包含电源板(PCB 210;示意图如图29所示),它是还具有PLC传送和接收电路的电源板。该电源板为CPU板和203板上的电子设备供电。控制模块2520还包含I/O扩展板(PCB 230;示意图如图30所示),它是具有能实现计量模块和CPU板之间的通信的多个I/O扩展选项的板。
控制模块2520还包含CPU板(PCB 202;示意图如图31所示),该板上具有DSP(数字信号处理)器。
最后,控制模块2520包含布线板(PCB 235;示意图如图32所示),该板具有迹线和没有电子组件的表头。
每个CDM(用户显示模块)2530都安装在用户住所处,并且能与安装在服务于用户的配电变压器上的EG进行双向通信。双向PLC允许通过低压电力线实现电力公司和用户之间的通信,并允许电力公司向用户发送常规信息、警告、关于断电的专门信息等。
每个CDM 2530包括计量和电源的选定组合以及在同一个板上的PLC电路(PCB 240;示意图如图33所示)。每个CDM优选地还具有9-位的显示器板(PCB 220;示意图如图34所示)。该显示器与EG通信,并显示关于消耗、警告、预告和其它电力公司消息的信息。
硬件实现
在一个实施方式中,能量防卫装置对ST和计量表上的PLC通信信号进行FFT(快速傅立叶变换),同时为了计量目的而进行详细的谐波分析。这部分将讨论计量模型的实施框架、与控制模块之间的通信、以及控制模块和远程设置的扫描转发器之间的PLC通信。
控制模块2520包括电源和PLC电路(PCB 210;如图25和29所示);I/O扩展(PCB 230;如图30所示)以及称为D计量表的CPU板(PCB 202;如图31所示)。电源向D计量表和I/O扩展供电,并且包含PLC发送器和接收器电路。PCB 235提供了轨迹布线和各板之间的表头连接。
计量模型可具有两个版本:2相或者3相。2相版本能够通过软件编程以作为单一的2相计量表或者2个1相计量表使用。2相版本包含B2计量表(PCB 203,示意图如图26所示),而3相版本则包括B3计量表(PCB 204,示意图如图27所示)。在控制模块2520中,B计量表作为D计量表的从计量表。D计量表和B计量表可能够通过串行ASCII协议来通信。
各个B计量表可通过BPB 2510到2520相互连接,BPB 2510到2520向D计量表供电并提供1Hz参考以及串行通信。用于B计量表的优选DSP引擎是Freescale 56F8014VFAE芯片。用于在D计量表上实现CPU的优选的微处理器是ColdFire集成微处理器族中的MCF5207。具体处理器的使用是由计量表版本规定的RAM和Flash需求决定的。单独的电源及LCD板将D计量表的电子部分实现为产品。D计量表除了作为B计量表的主计量表外,还是3相计量表并测量安装有EG的变压器上的总输出。因为具有防盗特性,因此将这个总输出与各B计量表报告的总消耗进行比较。
Figure S200680049289XD00121
信号流的全部选项如下所示:
B2:2个电压,2个电流,无PLC(电力线载波)通道。
B3:3个电压,3个电流,无PLC通道。
D:3个电压,3个电流,一个PLC通道。
每个流都具有相关的电路来实现模拟放大和抗混叠。
D计量表具有以下优选的实现:
·PLL(锁相环),其将信号流的采样锁定到多个输入A/C线(对电力线的同步采样)。
·VCO(压控振荡器),其工作在90-100MHz并由DSP处理器通过两个PWM模块控制,其直接驱动系统时钟,从而使DSP与PLL相干。
·同步相检测器,其仅对输入线路频率(line frequency)的基波做出响应,而对该频率的谐波不做出响应。
·执行FSK和PSK调制方案的选择。
每个计量和通信通道都优选地包括前端模拟电路,其后是信号处理。仅模拟电路才具有的是固定增益的抗混叠滤波器,其提供了一阶温度跟踪,从而在遇到温度漂移时不必再次校准计量表。这一点将在下面讨论,然后还将讨论优选的信号处理实现方法。
电压和电流模拟信号链
用于电压(电流)通路的模拟前端包括电压(电流)传感元件和可编程的衰减器,之后是抗混叠滤波器。衰减器降低输入信号电平以使信号经过抗混叠滤波器之后不会发生削波。恒定增益的抗混叠滤波器在ADC(模数转换器)入口处将信号恢复为全值。为了进行计量,抗混叠滤波器将高于5kHz的频率去除。然后将输入信号馈送到为DSP的一部分的ADC中。如图35所示,其为用于计量的优选模拟前端的框图。
尽管典型的实施方式将包括跟随有低增益抗混叠滤波器的PGA(可编程增益放大器),但是,在本实施方式中,本发明实现了跟随有恒定大增益滤波器的可编程衰减器。另外,通过利用相同的Quad OpAmp以及25 ppm电阻器和NPO/COG电容器,单一芯片上的两个抗混叠滤波器的实现是相同的。通过将抗混叠滤波器配对的这种独特的实现方法能够确保电压和电流通道中遇到的相漂移完全一致,并且因此不会影响功率计算(由V和I的乘积得到)的精确性。这就提供了一种用于V通道和I通道的装置,其对高达一阶的温度漂移进行跟踪,而不需要重新校准该计量表。
相反地,使用PGA和低增益滤波器则不能对由于温度而在V和I的信号中引入的相漂移进行跟踪。这是由于PGA引入的相漂移是增益的函数。
电压,电流和PLC数字信号链
图36是PCB 202板的方框图;每个方框的功能对于本领域技术人员而言都是显而易见的。图36示出了优选的DSP实现。
本实施方式优选地使用PLL将信号流的采样锁定到多个输入A/C频率。如前所述,在本实施方式中,采样是以与电力线同步的速率进行的。在计量表D中,具有工作在90-100MHz的VCO,该VCO由DSP引擎通过2个PWM模块来控制。VCO直接驱动DSP芯片的系统时钟(停止内部的PLL),从而使DSP成为PLL的主要部分。将DSP的系统时钟锁定于电力线有利于将采样与电力线的波形对准。相检测器应该只对输入的60Hz波的基波做出响应,而对其谐波不做出响应。图37该优选DSP实现的方框图。
DSP BIOS或者主动的上下文开关代码提供了3个堆栈,分别用于后台操作、PLC通信以及串行通信。小的微处理器使用I2C驱动器与DSP通信。MSP430F2002集成电路对电力供应、篡改端口、温度和电池电压进行测量。MSP430F2002的任务包括:
i.维持RTC;
ii.测量电池电压;
iii.测量温度;
iv.测量+U电源;
v.在部分停止供电时将DSP复位;
vi.提供附加的看门狗电路;以及
vii.提供1秒的参考时间到DSP,以相对于VCO的系统时钟对这1秒的参考时间进行测量。
计量表D的PLC通信信号链
典型的装置包括通过电力线通信的多个EG和ST。计量表D通过配电变压器与远程设置的扫描转发器进行双向通信。为了实现此功能,本实施方式中使用10-25kHz的频带进行PLC通信。与线路电压同步,对PLC信号以大约240kHz(212*60)的采样率采样,在采样之后应用FIR(有限脉冲响应)滤波器来抽取数据。优选的FIR规格如下:
10-25kHz频段
    分接头个数     65
    阻带衰减     71.23dB
    通带高频     25kHz
    阻带低频     35kHz
    采样输入     60*4096
    采样输出     30*2048
如图38,其示出了优选的同相滤波器频率响应和脉冲响应特征曲线。
在完成对60kHz(211*30)的抽取之后,对抽取后的数据进行2048点FFT。因此,根据FIR滤波器的选择,将数据速率确定为30波特。当在10-25kHz的频带内使用FIR时,每个FFT在大约每66msec产生2比特,以通过配电变压器进行通信。
为了避免在存在线路噪声的情况下进行通信的问题,本实施方式优选地执行独特的技术以稳定并可靠的通信。这是通过注入PLC信号而实现的,注入的PLC信号的频率等于线路频率(60Hz)的半奇次谐波(half-odd harmonics)的频率。这一点将通过AC线路上发现的范围在12-12.2kHz的典型的噪声频谱在下文中的实施方式中讨论。
图39示出了频率为60Hz的半奇次谐波的频率的注入PLC信号。因为FFT每30Hz完成一次,并且谐波间隔为60Hz,因此在图39中,数据位位于对应于60Hz的第201.5次和第202.5次谐波的频段(bin)中。这种算法考虑这两个频点并比较其中的信号幅度以决定取1或者0。这种FSK方案使用2段频率,并产生30波特的数据速率。可选地,能实现使用4个频率的QFSK以产生60波特的数据速率。
当穿过变压器时,ST计量表和D计量表都优选地在PLC上进行FFT变换,并且在10-25kHz范围内,数据每30Hz发一次信号。因为ST计量表和D计量表中的PLL(锁相环)都锁定在线路上,因此数据帧和线路频率(60Hz)也是同步的。然而,数据帧可由于以下原因而在相上漂移:
1.存在于ST和计量表(delta-Wye等)之间的路径上的不同的变压器配置;以及
2.由于ST被锁定在特定的相、而单相或者多相计量表可通过其它相上电而导致的相漂移。
当计量表数据帧和ST数据帧接近完美的对准时,SNR(信噪比)达到最佳值。从计量表的角度来看,这需要从全部可能“听到”的ST处接收PLC信号,将信号解码,通过对准数据帧来检查SNR,以及对产生最大SNR的ST做出响应。图40示出了12个可能的方式,在这些方式中,由计量表接收到的FFT帧可以与ST FFT帧异相。虚线对应于说明ST和计量表之间的信号路径中的差量变压器(deltatransformer)的30度旋转。
另外,因为在60Hz线路上每隔30Hz的数据帧就是可利用的,因此,具有两种可能性,对应于通过将60Hz除以2得到的2个可能的相。因此,计量表数据帧可能存在24种与ST数据帧未对准的方式。
在ST的每个帧中,具有奇数个载频周期。由于优选的调制方式是FSK(频移键控),因此,如果第n周期用于传送位1,那么,位0则由载频的第n+2周期传送。对于计量表而言,辨识其60Hz的两个周期以能够对每1/30秒可用的数据位进行解码是很重要的。
如果D计量表对具有未对准的数据帧的信号进行解码,那么就会有能量溢出到邻近的(距离半个基波频率)频率。如果落入“邻近”频率点的信号电平比噪声基底小,那么该信号能够正确地被解码。然而,如果溢出大于噪声基底,那么在1和0之间进行区分的能力就会减小,并因此整体SNR就会降低,从而导致解码错误。总之:
a.如果帧未对准,那么就会发生数据位的拖尾效应,并且SNR降低。
b.在频率改变且具有未对准的数据帧的情况下,会具有大量能量溢出到邻近的FFT频点上,从而干扰系统中使用这些具体频点内的频率进行通信的其它ST。
一旦确定了对应于最大SNR的时钟位移,计量表就锁定了,直到计量表遇到了很大的SNR比率变化。在这种情况下,处理将重复。
使用FFT实现D计量表和B计量表中的计量
尽管使用B计量表和D计量表完成计量,但是D计量表还负责通过PCB 234收集来自B计量表的计量信息。这些计量表中的每个数据流都具有实现模拟放大和抗混叠的相关电路。每个模拟前端部分都具有由更高级代码控制的可编程衰减器。数据流以60kHz(210*60)采样,并且使用FIR滤波器将数据流抽取至~15kHz(28*60)。优选的滤波器的规格如下表和图41所示:
    分接头个数     29
    阻带衰减     80.453dB
    通带高频     3kHz
    阻带低频     12kHz
因为仅对高达3kHz的数据感兴趣,因此,优选地,抽取FIR上3-12kHz滚降与~15KHZ的采样率一起使用。将0-3kHz或者12-15kHz的频率映射到0-3kHZ。执行实FFT来产生2个数据流,这2个数据流能够被进一步分解成4个数据流:实部和虚部电压以及实部和虚部电流。这一点通过分别在实部和虚部增加或减去正负镜像频率来实现。因为12-15kHz范围内的混叠信号降到80dB以下,因此通过前面讨论的FIR滤波器将能够达到精度要求。可选择地,可在抽样数据流的每个相上执行256点复FFT。这将产生2对数据流:表示电压的实部和表示电流的虚部。这个方法需要每16.667毫秒进行一次256点复FFT。
执行任一种FFT的结果为图42所示的电压或电流,其中,符号Vm,n表示第n个周期的第m次谐波。例如,V11和I11对应于第一个周期的基波,而V21和I21对应于第一个周期的第一个谐波,等等,如图42所示,其示出了指示谐波的电压的FFT帧。
第k个周期的谐波的实部和虚部由下式给出:
Vmk=Re(Vmk)+i*Im(Vmk);m=1...M
Imk=Re(Imk)+i*Im(Imk);k=1...n
电压的虚部是PLL和线路频率之间的不同步的测量。为了计算计量量,该计算是在时域完成的。在时域中,通过仅基波或者包含谐波,FFT功能性为计算计量量提供了灵活性。使用从FFT得到的电压或者电流的复形式,计量量可通过下式计算: 
P = V mk * I mk *
W=Re(P)=Re(Vmk)*Re(Imk)+Im(Imk)*Im(Vmk)
Var=Im(P)=Re(Imk)*Im(Vmk)-Re(Vmk)*Im(Imk)
PowerFactor=W/P
然而,在上面的公式中,当包含谐波时(Vmk和Imk;m=1...M,k=1...n),所有的计量量都包括谐波的作用。换句话说,当仅使用基波时(V1k和I1k),所有的计算量都只表示60Hz的贡献。例如,我们示出了只使用基波进行计算时的计算。仅使用来自于所有FFT数据帧的V1和I1。对于给定的一组N个帧和fline的线路频率,计算以下量:
kWh = Σ t = 1 N [ Re ( V 1 t ) * Re ( I it ) + Im ( V 1 t ) * Im ( I it ) ] * Δt t * 10 - 3
kVAr = Σ t = 1 N [ Re ( I 1 t ) * Im ( V it ) - Re ( V 1 t ) * Im ( I it ) ] * Δt t * 10 - 3
kVAh = Σ t = 1 N | V 1 t | * | I 1 t | * Δt t * 10 - 3 ;  Δt=1/fline
V 2 h = Σ t = 1 N | V 1 t | 2 * Δt t
I 2 h = Σ t = 1 N | I 1 t | 2 * Δt t
置换功率因子由下式给出:
cos ( θ ) = | W VA | ; 其中,W和VA只包含基波,并且:
VA1=V1RMS*I1RMS,其中:
对于N次循环, V 1 RMS = Σ n = 1 N | V 1 , n | 2 & I 1 RMS = Σ n = 1 N | I 1 , n | 2
计算计量量时包含或者排除谐波灵活性转化为对前述实施方式的性能的极大改进。本实施方式提供的另一个性质是计算THD(总谐波失真)。THD是对谐波失真存在的度量,并定义为所有谐波分量的总能量与基波能量的比值。对于第n个周期,该值为:
VTHD n = Σ m = 2 M V mn 2 V 1 n & ITHD n = Σ m = 2 M I mn 2 I 1 n ;
Vmn(Imn)是由FFT得到的第n个周期的第m次谐波,其中
V m , n 2 = Re ( V m , n ) 2 + Im ( V m , n ) 2 & I m , n 2 = Re ( I m , n ) 2 + Im ( I m , n ) 2
用户显示模块
用户显示模块安装在用户住所处,与变压器附近的能量防卫装置通信,并且包括:PCB 240、电源和PLC电路(如图33所示);以及PCB 220、LCD显示器(如图34所示)。在一个实施方式中,安装在用户住所的用户显示单元是与EG通信的双向PLC单元。例如,不仅电力公司可发送消息,用户也可要求安装在电线杆上的EG进行耗电检测。
尽管本文示例性地描述了本发明的某些具体实施方式,但是本发明并不局限与这些具体细节、典型设备以及本文描述和示出的示例性的实施例。在不偏离权利要求及其等同所定义的本发明的精神和范围的前提下,可做出各种调整。
附录
                                   LCM.DEF
;QLC LCM (Load Control Module)program for PIC 16C63A;
; 
       include′C:\pictools\16c63a.inc′
;     include′C:\pictools\16c63.inc′    ;
;Configuration bits
       FUSES_BODEN_OFF;Brown-out reset disabled
       FUSES_CP_OFF           ;No code protect
       FUSES_PWRTE_OFF;Disable power-up timer
       FUSES_WDT_ON           ;Watchdog Timer Enabled
       FUSES_RC_OSC           ;Oscillator=RC
;Program Parameter Equates
Software_type  equ   7      ; Which PIC program is this?
                            ;7=LCM program
Software_version equ 2      ;Version #
LCM_base_addr equ    16     ;Address of first LCM
Ram_start      equ   020h   ;Beginning of available RAM
RESET_VECTOR         equ    0      ;Location of reset vector
ROM_start       equ  008h   ;first available program location
Nurn_start_bits equ  12     ;Number of start bits
;   Port definitions
;   
comm_port     equ      PORTA
data_out      equ      3
data_in       equ      4
clock_in      equ      5
ctl_portequ   PORTA
driver_enable equ      0             ;output bit to turn on the drivers
Driver_enable_mask     equ    1<<driver_enable
;     Initialization values for I/O ports
init_TRISA    equ      00110000b        ;Data direction for port A
init_TRISB    equ      000h             ;B port data direction-all ports output
init_TRISC    equ      000h             ;C port data direction-all out
read_TRISC     equ      01fh       ;C port data direction for jumper read-0-4 in
Init_comm_port_value equ    1<<data_out+Driver_enable_mask
option_reg_val equ   10001111b;Option register init value
;             bit7=1:         Port B pullups disabled
;             bit6=0:         Int on falling edge
;             bit5=0:         Timer 0 uses inst clock
;             bit4=0:         Timer 0 counts on rising edge
;             bit3=1:         Prescaler used by WDT
;             bit2,1,0=111:Prescaler divide by 128
; NOTE-interrupts and timer 0 are not used by this program
ms_preset      equ    700      ;Time set for millisecond delay
; RAM locations
       ORG  Ram_start
Status_reg         ds      4      ;status register
            ORG    Status_reg
Status_MSB         ds      1
Clk_timeout_flag   equ     7      ; Timeout waiting for comm clock edge
bad_reset_flag     equ     6      ; Non-POR, non-WDT reset encountered
POR_flag           equ     5      ; Power-on reset detected
WDT_reset_flag             equ    4      ; WDT reset,not from sleep
Status LSB          ds     1
CPU_reset_flag      equ    7
Need_param_refresh_flag    equ    6
Parity_err_flag     equ    5
Global_cmd_timer    ds     1
Jumper_state        ds     1      ; current state of input jumpers
Parameter_reg       ds     4      ; Communication parameters
                    org    Parameter_reg
                    ds     1      ;
                    ds     2      ;
                    ds     1      ;
; Fast communication variables
Comm_state          ds     1      ; Stored state of fast comm uart
Wstate              ds     1      ; Stored state of fast comm word handler
Comm_bit_count             ds     1        ; Bit counter for fast comm
Comm_buffer         ds     1      ; fast comm word buffer
Work_addr           ds      1      ;Address read from jumpers
Temp                ds      1      ;temporary register
Tpar                ds      1      ;Transverse parity
Word_count          ds      1      ;Counter for sending and receiving 5-bit words
Command                     ds     1      ;Command received over comm link 
Register_ID         ds      1      ;Register specified in comm command
PIC_addr            ds      1      ;Address of this PIC chip
Comm_buf            ds      5      ;Communication buffer
Input_hold          ds      1      ;Hold register for comm rcv value
Output_bit_reg      ds      4      ;Hold register for output bit mask
Flags               ds      1      ;Program control flags
CIk_wait_flag       equ     7      ;indicates which clock edge we are waiting for
Global_cmd_flag             equ    6        ;Processing global command
scratch             ds      1      ;Work register
Timeout_ctr         ds      2      ;Counter for pulse duration
Millisecs           ds      1      ;Counter for pulse duration milliseconds
Clk_timeout_ctr             ds     2      ;counter for clock timeout
NPR_timer           ds      2      ;counter for need parameter refresh
        ORG  0a0h
;Bank 1 RAM locations
       IF     $-1 and 0100h
       error-RAM  overflow
       ENDIF
       ORG      RESET_VECTOR
       jmp      start                   ;Jump to first program location
       Start of program space
       ORG      ROM_start
; 
;     Initialization
Start
       setb    RP0                   ;point to upper register bank
       jnb     NOT_POR,got_POR               ; Power on reset,set flags
       clrb    RP0                   ;point to RAM bank 0
       jnb     NOT_TO,WDT_reset     ;Watchdog reset
       setb    status_MSB.bad_reset_flag    ;Indicate unknown reset condition
       jmp     Do_initialize
WDT_reset
      setb  Status_MSB.WDT_reset_flag
      jmp   do_initialize
got_POR
     clrb   RP0                 ;point to RAM bank 0
     mov    Status_MSB,#1<<POR_flag;Set POR flag
     clr    Status_LSB
Do_initialize
      mov   FSR,#Ram_start+2     ;Point past status flags
:clr_loop
      clr    INDF                 ;Clear RAM location
      inc    FSR                  ;Increment pointer
      jz     Init_state           ;If zero,done
      mov    W,FSR               ;get pointer
      and    W,#7fH              ;look at 7 LSB′s
      jnz    :clr_loop            ;Not end of segment,continue
      add    FSR,#20h            ;Point to next segment
      jmp    :clr_loop            ;Not last segment,continue
Init_state
      setb   Status_LSB.CPU_reset_flag           ;Indicate CPU reset
      setb   Status_LSB.Need_param_refresh_flag  ;Indicate parameter refresh needed
      mov    comm_port,#Init_comm_port_value             ;initialize comm port state
      mov    Comm_state,#Edge_wait
      mov    Comm bit count,#Num_start_bits              ;Initialize fast comm state
machine
      clr    PORTB
      clr    PORTC
      jmp   Main_loop             ;start running main program
; Comm Receive routines
Edge_wait
                                            ;Initialize Watchdog timer
      mov   !OPTION,#option_reg_val                 ;Set option reg
      setb   comm_port.data_out             ;send a 1
      dec    Comm_bit_count                          ;decrement bit count
      jz     See_edge_one                   ;if zero,looking for a 1
      jb     Input_hold.data_in,Set_edge_wait       ;Looking for 0,reset bit count if 1
      jmp    Comm_ret                                ;done
See_edge_one
      jnb    Input_hold.data_in,Set_edge_wait;looking for 1,reset if 0
      mov   Wstate,#Rcv_addr               ;First word is address
      mov   Tpar,#01fh                     ;Init parity
      jmp   Rcv_next_word
 Rcv_stop
      mov   Comm_state,#Edge_wait
      mov   Comm_bit_count,#Num_start_bits          ;Preset state to wait for edge
      jnb   Input_hold.data_in,Parity_error ;stop bit must be 1
      jmp   Cmd_exec                         ;Done,process received buffer
Rcv bits
      clc                                    ;copy...
       snb   Input_hold.data_in             ;    ...input bit...
       setc                                 ;        ...to carry
       rl    Comm_buffer                    ;shift buffer
       jmp   Rcv_word_handler               ;Check for complete word
;Comm Transmit routines
Send_edge
       dec   Comm_bit_count                          ;decrement bit count
       jz    :One                           ;ifzero,send a 1
       clrb  comm_port.data_out             ;send a 0
       jmp   Comm_ret
:One
       setb  comm_port.data_out             ;send a 1
       jmp   Do_xmit_word
Send bits
       rl    Comm_buffer                    ;put xmit bit into carry
       jc    :one
       clrb  comm_port.data_out             ;send a ′0′
       jmp   :check
:one
       setb  comm_port.data_out             ;send a ′1′
:check
       jmp   Xmit_word_handler
       Comm receive word handler routines
Rcv_word_handler
       djnz  Comm_bit_count,Comm_ret        ;If word not complete,continue
       and   Comm_buffer,#03fh              ;only 6 bits
       clc
       mov   W,>>Comm_buffer              ;get 5 MSBs of received word
       call  parity_lookup
       xor    W,Comm_buffer                 ;compare with received word
       jnz    Parity_error
       rr     Comm_buffer
       and    Comm_buffer,#01fh             ;extract 5-bit value
       xor    Tpar,Comm_buffer              ;calculate total parity
       mov    PCLATH,#Rcv_addr<
       mov    W,Wstate
       jmp    W                             ;Execute word handler routine
Rcv_addr
       clrb   Flags.Global_cmd_flag ;Clear global command flag
       mov    W,Comm_buffer                ;Get received address
       mov    PIC_addr, W          ;save it
       xor    W,#1fh               ;is it global command
       jnz    See_if_us             ;No,check for address match
       setb   Flags. Global_cmd_flag;Set global command flag
       jmp    Its_us                ;process rest of command
See_if_us
      mov   !PORTC,#read_TRISC         ;Switch C port bit 0-4 to input
      clrb  ctl_port. driver_enable      ;Disable output drivers,enable jumper read
      mov   temp,#9
:loop
      djnz  temp,:loop                  ;Wait at least 20 uSec
      mov   W,/PORTC                    ;Get inverse of jumpers in W
      mov   Work_addr,W                 ;Save jumper value
      setb  ctl_port. driver_enable      ;Enable output drivers
      mov   !PORTC,#init_TRISC         ;Restore C port status
      mov   Jumper_state,Work_addr      ;Save jumper state
      and   Work_addr,#03h              ;Ignore all but 2 LSBs
      add   Work_addr,#LCM_base_addr    ;Add base offset
      cjne  Work_addr,PIC_addr,Set_edg_wait
Its_ us
      mov  Wstate,#Rcv_cmd               ;point to next routine
      jmp   Rcv_next_word
Rcv_cmd
      mov   Command,Comm_buffer                 ;save command
      jnb   Command.4,Comm_get_fast             ;Fast read command,skip Reg ID
      mov   Wstate,#Rcv_reg_ID           ;point to next routine
      jmp   Rcv_next_word
Comm_get_fast
      mov   Wstate,#Rcv_tpar              ;point to next routine
      jmp   Rcv_next_word
Rcv_reg_ID
      mov   register_ID,Comm_buffer       ;save register number
      mov   Wstate,#Rcv_tpar              ;point to next routine
      jnb   Command.3,Rcv_next_word               ;If no value,done
      mov   word_count,#7                 ;Init word count
      mov   Wstate,#Rcv_value             ;point to next routine
      jmp   Rcv_next_word
Rcv_value
      rl    Comm_buffer
      rl    Comm_buffer
      rl    Comm_buffer                     ; Shift rcvd bits to MSBs
      mov   Comm_bit_count,#5                        ;shift 5 bits
:shift_loop
      rl    Comm_buffer
      rl    Comm_buf+4
      rl    Comm_buf+3
      rl    Comm_buf+2
      rl    Comm_buf+1
      rl    Comm_buf                         ;Shift a bit from Comm_buf to comm_buf
      djnz  Comm_bit_count,:shift_loop
      djnz  word_count,Rcv_next_word        ;any more words?
      mov   Wstate,#Rcv_tpar                ;point to next routine
      jmp   Rcv_next_word
Rcv_tpar
      mov   W,Tpar                          ;Get result of parity calculations
      jnz   Parity_error                     ;If not 0, parity error
      jmp   Set_rcv_stop                     ;set up to receive stop bit
;Comm transmit word handler routines
; 
Xmit_word_handler
      djnz  Comm_bit_count, Comm_ret           ;If word not complete,continue
Do_xmit_word
      mov   PCLATH,#$<
      mov   W,Wstate
      jmp   W                               ;Execute word handler routine
Send addr
      mov   Wstate,#Send_cmd>             ;point to next word routine
      mov   W,PIC_addr                     ;get address
      jmp   Send_next_word
Send cmd
      mov   Wstate,#Send_value>           ;point to send value
      jnb   Command.4,Value is next             ;Is it fast read command?
      mov   Wstate,#Send_reg_ID>          ;point to next word routine
Value_is_next
      mov   W,Command                      ;get command
      jmp   Send_next_word
Send_reg_ID
      mov   Wstate,#Send_value>           ;point to next word routine
      mov   W,Register_ID                  ;get Register ID
      jmp   Send_next_word
Send_value
      mov   Wstate,#Next_value>           ;point to next word routine
      mov   Word_count,#7                  ;value is 7 words long
Next value
      mov   Comm bit count,#5
:loop
      rl    comm_buf+4
      rl    comm_buf+3
      rl    Comm_buf+2
      rl    Comm_buf+1
      rl    Comm_buf
      rl    Comm_buffer
      djnz  Comm_bit_count,:loop
      mov   W,Comm_buffer                  ;Get 5-bit word
      djnz  word_count,Send_next_word      ;if not last word,all set
      mov   Wstate,#Send_Tpar>            ;send parity next
      mov   W,Comm_buffer
      jmp   Send_next_word
Send_Tpar
      mov   Wstate,#Send_stop              ;point to next word routine
      mov   W,Tpar                         ;get transverse parity
      jmp     Send_next_word
Send_stop
      jmp     Set_edge_wait               ;Go back to receive mode
      Process received buffer
      org     100h
Cmd exec
Process_cmd
      cjbe    Command,#7h,Fast_register_read          ;is it fast read?
      cje     Command,#10h,read_register    ;is it read register command?
      cje     Command,#18h,write_register   ;is it write register?
      cje     Command,#19h,reset_status_bits          ;is it reset status?
      jmp     Cmd_process_done
Fast_register_read
      mov     register_ID,command    ;Register number is same as command code
Read_register
      mov     W,#27
      mov     W,register_ID-W                ;Get index of register to read
      jnc     Cmd_process_done        ;ifnegative,not a valid register
      mov     Temp,W                         ;saveindex
      mov     PCLATH,#$<            ;set up High-order PC bits
      mov     W,Temp                         ;get index
      jmp     PC+W
      jmp     cpy_output_reg
      jmp     cpy_reg_28
      jmp     cpy_reg_29
      jmp     cpy_reg_30
Cpy_reg_31                          ;Reg 31=Status register
      mov     Comm_buf,Status_reg
      mov     Comm_buf+1,Status_reg+1
      mov     Comm_buf+2,Status_reg+2
      mov     Comm_buf+3,Status_reg+3
      jmp     Setup_reply
Cpy_reg_30                          ;Reg 30=Serial number
      call    serno
      mov     comm_buf+3,W
      call    serno+1
      mov     comm_buf+2,W
      call    serno+2
      mov     comm_buf+1,W
      call    serno+3
      mov     comm_buf,W
      jmp     Setup_reply
Cpy_reg_29                         ;Reg 29=Software type and version
      mov     Comm_buf,#Software_type
      mov     Comm_buf+1,#Software_version
      mov     Comm_buf+2,#0
      mov     Comm_buf+3,#0             ;Send Software type and version
     jmp   Setup_reply
Cpy_reg_28                        ;Reg 28=Parameter reg
      mov   Comm_buf,Parameter_reg
      mov   Comm_buf+1,Parameter_reg+1
      mov   Comm_buf+2,Parameter_reg+2
      mov   Comm_buf+3,Parameter_reg+3
      jmp   Setup_reply
Cpy_output_reg                    ;Reg 27=Output state
      mov   Comm_buf,Output_bit_reg
      mov   Comm_buf+1,Output_bit_reg+1
      mov   Comm_buf+2,Output_bit_reg+2
      mov   Comm_buf+3,Output_bit_reg+3
      jmp   Setup_reply
Write_register
      mov   Comm bit count,#5                        ;need to shift buffer by 5
bits
:loop
        rl     comm_buf+4
        rl     comm_buf+3
        rl     comm_buf+2
        rl     comm_buf+1
        rl     comm_buf
        djnz   Comm_bit_count,:loop
        cjne   Register_ID,#28,See_write_output_reg ;Not reg 28,see if output reg
        mov    Parameter_reg,Comm_buf
        mov    Parameter_reg+1,Comm_buf+1
        mov    Parameter_reg+2,Comm_buf+2
        mov    Parameter_reg+3,Comm_buf+3            ;Copy received data to reg
        clrb   Status_LSB.Need_param_refresh_flag     ;Reset need parameter refresh flag
        jmp   Cpy_reg_28                              ;send contents back in reply
 See_write_output_reg
        cjne   Register_ID,#27,Cmd_process_done     ;if not output reg,ignore
        mov   Output_bit_reg,Comm_buf
        mov   Output bit_reg+1,Comm_buf+1
        mov   Output_bit_reg+2,Comm_buf+2
        mov   Output_bit_reg+3,Comm_buf+3            ;Copy received data to reg
        call    Update_outputs
        jmp   Cpy_output_reg                          ;send contents back in reply
 Reset_status_bits
        mov   Comm_bit_count,#5                            ;need to shift buffer by 5
 bits
 :loop
        rl     comm_buf+4
        rl     comm_buf+3
        rl     comm_buf+2
        rl     comm_buf+1
        rl     comm_buf
        djnz   Comm_bit_count,:loop
        mov   W,/Comm_buf+1                            ;get byte
        and   Status_reg+1,W                  ;Clear bits
        mov   W,/Comm_buf                     ;get MSB
       and    Status_reg,W                         ;Clear bits
       mov    Register_ID,#31                               ;indicate status reg in reply
       jmp    Cpy_reg_31
Setup_reply
       jb     Flags.Global_cmd_flag,Set_edge_wait  ;If it was global,don′t reply
       mov    W,Status_LSB                         ;Get status LSB
       mov    Comm_buf+4,W                                  ;preset stored flags
       and    W,#01fh                                       ;Turn off3 MSBs
       or     W,Status_MSB                         ;Combine 5 LSbs with Status_MSB
       sz
       setb   Comm_buf+4.7                          ;If any other flag bits set,indicate in
MSB
       mov    Tpar,#1fh                            ;Initialize parity word
       mov    Comm_state,#Send_edge                          ;Go to send_edge state
       mov    Wstate,#Send_addr                    ;Point to next routine
       mov    Comm_bit_count,#Num_start_bits                 ;Init number of bits
       jmp    Comm_ret
Cmd_process_done
       jmp    Set_edge_wait                         ;No reply needed,done
; Exit routines for comm
Parity_error
       setb   status_LSB.Parity_err_flag            ;Indicate parity error
Set_edge_wait
       mov    Comm_state,#Edge_wait                          ;Go to edge wait state
       mov    Comm_bit_count,#Num_start_bits                 ;Init number of bits
       jmp    Comm_ret
Set_send_reply
       mov    Comm_state,#Send_edge                          ;Go to send edge state
       mov    Comm_bit_count,#Num_start_bits
       jmp    Comm_ret
Rcv_next_word
       mov    Comrm_state,#Rcv_bits                  ;set up to receive 6-bit word
       mov    Comm_bit_count,#6
       jmp    Comm_ret
Send_next_word
       and    W,#01fh                                         ;only 5 bits
       xor    Tpar,W                                 ;update parity calculation
       call   parity_lookup
       mov    Comm_buffer,W                                   ;Save word with parity(6 bits)
       rl     Comm_buffer
       rl     Comm_buffer                             ;move to MSbs
       mov    Comm_state,#Send_bits                  ;set up to send 6-bit word
       mov    Comm_bit_count,#6
       jmp    Comm_ret
Set_rcv_stop
        mov    Comm_state,#Rcv_stop       ;point to next routine
        jmp    Comm_ret
        ORG    200h
Serno
;      retw   05ah,092h,05fh,000h
;      retw   0ffh,0ffh,0ffh,0ffh
        ds     4
        ret
;      Returns 6-bit value corresponding to passed 5-bit value with odd parity
parity_lookup
        mov    Temp,W                   ;Save index
        mov    PCLATH,#:table<        ;Set up high-order bits
        mov    W,Temp                   ;get index
        jmp    pc+w
:table
        retw
        1,2,4,7,8,11,13,14,16,19,21,22,25,26,28,31,32,35,37,38,41,42,44,47,49,50,52,55,56,5
9,61,62
;      Sets output bits according to received data
;      Comm=buf=Pulse duration in milliseconds
;                   0:     Continuous output(infinite duration)
;                   1-255: Set output state for specified duration
;                             After duration is over, turn all outputs off
;      Comm_buf+1[3]=Bit map of output states -MSB first
;                   bits 23-18:   Unused
;                   bits 17-0:    Outputs 18-1
Update_outputs
       mov    W,Comm_buf+3                        ;get lsbs
       and    W,#03h                     ;only need 2 bits
       mov    Temp,W
       add    Temp,W                              ;Shift into bits 1 and 2 (X1 and X2)
       mov    W,PORTA                             ;Get present status of port A pins
       and    W,#0F9h                             ;clear output control bits
       or     W,Temp                              ;Set desired output state
       mov    PORTA,W                             ;output new value
       rr     comm_buf+ 1
       rr     comm_buf+2
       rr     comm buf+3
       rr     comm_buf+1
       rr     comm_buf+2
       rr     comm buf+3                 ;shift buffer left 2 bits
       mov    PORTB,comm_buf+2
       mov    PORTC,comm_buf+3
       mov    !PORTA,#init_TRISA
      mov   !PORTB,#init_TRISB
      mov   !PORTC,#init_TRISC
      mov   Millisecs,Comm_buf      ;first byte is pulse duration
      jz    done_output_set
ms_loop
      mov   Timeout_ctr,#ms_preset<
      mov   Timeout_ctr+1,#ms_preset>
:loop
      djnz  Timeout_ctr+1,:loop
      djnz  Timeout_ctr,:loop
      djnz  Millisecs,ms_loop         ;delay for pulse duration
      and   PORTA,#0f9h               ;turn offX1 and X2
      clf   PORTB
      clr   PORTC                      ;turn off other outputs
done_output_set
      ret
;    Main Program start
Main_loop
      mov   !PORTA,#Init_TRISA   ;Initialize port A direction
      mov   !PORTB,#Init_TRISB   ;Initialize port B direction
      mov   !PORTC,#Init_TRISC   ;Init port C direction
      mov   Clk_timeout_ctr,#12   ;preset ...
      clr   Clk_timeout_ctr+ 1     ; ... clock timeout counter
      clrb  Flags.Clk_wait_flag    ;Indicate waiting for clock low
 Clkwait_loop
      djnz   scratch,Clk_cont
      clr     WDT                         ;Reset watchdog
      djnz   Clk_timeout_ctr+1,Clk_cont
      djnz   Clk_timeout_ctr,Clk_cont
      jb     Status_MSB.POR_flag,got_POR        ;Ignore clock timeout until POR
flag cleared
      setb   Status_MSB.Clk_timeout_flag ;Indicate timeout on comm clock
      jmp    do_initialize
 Clk_cont
      jb     Comm_port.clock_in,:high  ;clock high
 :low
      jb     Flags.Clk_wait_flag,Clkwait_loop
      mov   Input_hold,Comm_port        ;Save Data port value
      setb   Flags.Clk_wait_flag         ;Indicate waiting for clock high
      jmp   Clkwait_loop
:high
      jnb    Flags.Clk_wait_flag,Clkwait_loop
      djnz   NPR_timer+l,:cont          ;Dec LSB of need parm timer
      djnz   NPR_timer,:cont                   ;Dec MSB
      setb   Status_LSB.Need_param_refresh_flag  ;set flag every 64k clocks
:cont
      mov   PCLATH,#0                    ;Set up high-order bits for routines in page 0
      mov   W,Comm_state                 ;get vector
      jmp   W                             ;Execute comm state machine
Comm_ret
      jmp   Main_loop
                                           PIC.DEF
/*
include file for serial communication with PIC chips
*/
#pragrma switch(ALL,FREQ)
switch (PIC_serial_status)
 {
 case sending_bits:
 case sending_st5_bits:
#ifdef VATEST
    out_bit_value=(PICxmitBuf. bits.bufLong[0]and 0x80000000)!=0;/* out bit value=
MSB */
   PICxmitBuf.bits.bufLong[0]=PICxmitBuf.bits.bufLong[0]<<1;
   if(PICxmitBuf.bits.bufLong[1]and 0x80000000)
     PICxmitBuf.bits.bufLong[0]++;
   PICxmitBuf.bits.bufLong[1]=PICxmitBuf.bits.bufLong[1]<<1;
   if(PICxmitBuf.bits.bufLong[2]and 0x80000000)
     PICxmitBuf.bits.bufLong[1]++;
   PICxmitBuf.bits.bufLong[2]=PICxmitBuf.bits.bufLong[2]<<1;/* Shift 96-bit
buffer */
#else
    out bit value=0;
    shift_LSB_ptr=andPICxmitBuf.bits.bufByte[12];/* point past least significant word
of 96-bit register */
     asm(″MOVE.L_shift_LSB_ptr,A0″,             /* Get pointer to buffer,clear carry */
       ″ROXL.W  -(A0)″,                /* rotate left and decrement pointer */
       ″ROXL.W  -(A0)″,                /* rotate left and decrement pointer */
       ″ROXL.W  -(A0)″,                /* rotate left and decrement pointer */
       ″ROXL.W  -(A0)″,                /* rotate left and decrement pointer */
       ″ROXL.W  -(A0)″,                /* rotate left and decrement pointer */
       ″ROXL.W  -(A0)″,                /* 96 bits have been shifted,MSB is in carry
*/
       ″ROXI.W  _out_bit_value″          /* Put MSB in out bit value */
       );
#endif
    break;
  case do_send_cmd:
    bit_count=NUM_START_BITS-1;
    PIC_serial_status=sending_start;
    out bit value=0;
    break;
  case do_PIC_start:
    bit count=3*BITS_PER_SEC;
    out_bit_value=1;
    PIC_serial_status=sending_PIC_start;
    break;
  case sending_start:
    out_bit_value=0;
    break;
  case sending_stop:
  case sending_start_1:
    out_bit_value=1;
    break;
  default:
   out_bit_value=1;
  }
if(out_bit_value)
  fs1004.io.pulseOut2Off=1;
else
  fs1004.io.pulseOut2Off=0;        /* Send bit out */
in_bit_value=fs1004.io.pulseIn1State; /* Getrcvd bitvalue */
fs1004.io.pulseOutlOff=1;          /* Send clock rising edge */
switch(PIC_serial_status)
 {
 case waiting_for_start:
   if(in_bit_value=0)
     zero_count++;
   else 
     {
     if(zero_count=(NUM_START_BITS-1))
       {
       PIC_serial_status=rcving_bits;
       bit_count=PICrcvBuf.bitCount+1;
       }
     else
       zero_count=0;
      }
    break;
  case rcving_bits:
#ifdef VATEST
  PICrcvBuf.bits.bufLong[0]=PICrcvBuf.bits.bufLong[0]<<1;
  if(PlCrcvBuf.bits.bufLong[1]and 0x80000000)
    PICrcvBuf.bits.bufLong[0]++;
  PICrcvBuf.bits.bufLong[1]=PICrcvBuf.bits.bufLong[1]<<1;
  if(PICrcvBuf.bits.bufLong[2]and 0x80000000)
    PICrcvBuf.bits.bufLong[1]++;
  PICrcvBuf.bits.bufLong[2]=(PICrcvBuf.bits.bufLong[2]<<1)+
   in_bit_value;
#else
     shift_LSB_ptr=andPICrcvBuf.bits.bufByte[12]; /* point past least significant word
of 96-bit.register */
     asm(″MOVE.L_shift_LSB_ptr,A0″,           /* Get pointer to buffer,clear carry */
       ″ROXL.W  -(A0)″,              /* rotate left and decrement pointer */
       ″ROXL.W  -(A0)″,              /* rotate left and decrement pointer */
       ″ROXL.W  -(A0)″,              /* rotate left and decrement pointer */
       ″ROXL.W  -(A0)″,              /* rotate left and decrement pointer */
       ″ROXL.W  -(A0)″,              /* rotate left and decrement pointer */
       ″ROXL.W  -(A0)″                /* 96 bits have been shifted,LSb is unknown
*/
       );
     PICrcvBuf.bits.bufByte[11]=
      (PICrcvBuf.bits.bufByte[11]and 0xfe)|in_bit_value;      /* add in received bit */
#endif
    break;
  default:
    {
    }
   }
 if(--bit_count<=0)
   {
   switch(PIC_serial_status)
     {
     case rcving_bits:
      PIC_serial_status=rcving_stop;
      bit_count=1;
      break;
    case sending_bits:
      PIC_serial_status=sending_stop;
      bit_count=1; 
      break;
    case sending_stop:
      if(PICxmitBuf. PIC_addr=GLOBAL_PIC_ADDR)
        PIC_serial_status=idle;
      else
        {
        PIC_serial_status=waiting_for_start;
        bit_count=PIC_wait_limit;
        zero_count=0;
        }
      break;
     case sending_PIC_start:
       PIC_serial_status=idle;
       break;
     case sending_start:
       PIC_serial_status=sending_start_1;
       bit_count=1;
       break;
     casc sending_start_1:
       PIC_serial_status=sending_bits;
       bit_count=PICxmitBuf.bitCount;
       break;
     case waiting_for_start:
       PICrcvBuf.flags|=rcv_timeout_flag|rcv_data_ready_flag;
       PIC_serial_status=idle;
       break;
     case rcving_stop:
       if(in_bit_value=0)
          PICrcvBuf.flags|=rcv_bad_length_flag;
       PIC serial status=idle;
       PICrocvBuf.flags|=rcv_data_ready_flag;
       bit_count=1;
       break;
     default:
      PIC_serial_status=idle;
     }
    }
#pragma switch(ALL,NOFREQ)
                               PULSE.C
#include ″mtrlink.def″
/* #include ″flash.def″*/
#define PSTRU_DEFINED
#include ″pulselink.def″
#include ″pulse.h″
#include ″ufloat.h″
#include ″log.h″
#include ″alarm.h″
#include ″copymem.h″
#include ″plcctrl.h″
#include<stdio.h>
#ifdef fakeMC5
  #undef NUMPH
  #define NUMPH 24
#endif
/*definc WDT flags for the PIC communication routine */
#pragma region (″ram=WDTFlags″)
short int WDTpulseSec;
#pragma region(″ram=ram″)
#pragma region(″data=secondBack″)
void(*pulseSecondp)(void)=pulseSecond;
#pragma region(″data=data″)
#ifndef IS_MC5
#pragma region(″data=everySubsecond″)
#ifdef IS_RSM
void(*pulseSubsecp)(void)=pulseSubsecond;
#else
void(*pulseSubsecp)(void)=pulseService;
#endif
#pragma region(″data=data″)
#endif
#pragma region(″data=powerUp″)
void(*pulseStartupp)(void)=pulseStartup;
#pragma region(″data=data″)
#pragma region(″data=dayBack″)
void(*pulseDayp)(void)=pulseDay;
#pragma region(″data=data″)
/* clear out PIC */
void pulseColdstart()
{
   inti;
   for(i=0;i<num_PICs;i++)
   if(PIC_status[i].software_type=3)
     {
     PIC_status[i].clear_pulse_regs=TRUE;
     PIC_status[i].get_status=TRUE;
     }
 clear_state=SEND_GLOBAL_CLR;
}
void pulseStartup(void)
   ihti;
 #ifndef IS_RSM
   iht work_PIC_addr;
 #endif
 #ifdefIS_MC5
   int work_num_pulses;
 #endif
 #ifdef VATEST
 !*test !!!!!*/
    temp_command=SYSTEM_CONTROL;
    temp_reg_ID=0;
    temp_command_data=READ_ENCODER_ID;
    temp_flags=rcv_data_ready_flag;
 #endif
   for(i=0;(!dont_clear_PIC_stats)andand(i<(2*NUMPH);i++)
     {
     pulseData[i].error_cnt=0;
     pulseData[i].ID_fleld[0]=0;
     pulscData[i].reading=0;
     }
   for(i=0;i<MAX_PICS;i++)
     PIC_status[i].PIC_addr=0;
   hold_num_pulse_ctrs=releaseCodep->option.numPulseCounters;
   if(hold_num_pulse_ctrs>NUMPH)
     num_pulse_ctrs=NUMPH;
   else
     num_pulse_ctrs=hold_num_pulse_ctrs;
   num_PICs=1;
 #ifdef IS_MC5
    PIC_status[0].PIC_addr=MC5_MUX_PIC_ADDR;/* IfMC5,add PDM PIC(s)to PIC
 table */
    if(int_configltmessg.configLTM[PULSE1].accum)
      {
     work_num_pulses=num_pulse_ctrs;
     work_PIC_addr=0;
     while(work_num_pulses>0)
      {
     PIC_status[num_PICs++].PIC_addr=work_PIC_addr++;/* Pulse counters for Q13
*/
     work_num_pulses=4;
      }  
    }
  if(int_configltmessg.configLTM[PULSE2].accum)
    { 
    work_num_pulses=num_pulse_ctrs;
    work_PIC_addr=6;
    while(work_num_pulses>0)
     {
     PIC_status[num_PICs++].PIC_addr=work_PIC_addr++;/* Pulse counters for Q14
*/
     work_num_pulses=4;
     }
   }
  num_LCMs=releaeCodep->option.LCM_flags and 0x03;
  work_PIC_addr=LCM_BASE_ADDR;
  for(i=0;i<num_LCMs;i++)
    {
    PIC_status[num_PICs++].PIC_addr=work_PIC_addr++; /* LCM′s */
    }
#else
#ifdef IS_ST5
  PIC_status[0].PIC_addr=ST5_MUX_PIC_ADDR;/* If ST5, add mux to PIC table */
  ATM_work=releaseCodep->option.couplers_mask;
  work_PIC_addr=ATM_BASE_ADDR;
  for(i=0;i<4;i++)
    {
   if((ATM_work and 0x08)!=0)
     {              /* Bit is set in mask, add ATM PIC to table */
     PIC_status[num_PICs++].PIC_addr=work_PIC_addr;
     }
    work_PIC_addr++;
    ATM_work=ATM_work<<1;
    }
#else
  if(num_pulse_ctrs=0)
    num_PICs=0;
#endif
#endif 
  for(i=0;i<MAX_PICS;i++)
     {                        /* Build PIC table */
     PIC_status[i].get_serno=TRUE;
     PIC_status[i].get_version=TRUE;
     PIC_status[i].get_status=FALSE;
     PIC_status[i].reset_status=FALSE;
     PIC_status[i].update_parameter=FALSE;
     if(!dont_clear_PIC_stats)
       }
       PIC_status[i].PIC_reset_ount=0;
       PIC_status[i].comm_error_count=0;
       PIC_status[i].PIC_data_err_count=0;
       PIC_status[i].software_type=0;
       PIC_status[i].software_version=0;
       PIC_status[i].serial_number=0;
       }
     PIC_status[i].curr_pulse_reg=0;
#ifdef IS_MC5
     if(PIC_status[i].PIC_addr>=ST5_MUX_PIC_ADDR)
       PIC_status[i].reply_wait_limit=DIRECT_PIC_WAIT_LIMIT;
     else
       PIC_status[i].reply_wait_limit=BUFFERED_PIC_WAIT_LIMIT;
#else
     PIC_status[i].reply_wait_limit=DIRECT_PIC_WAIT_LIMIT;
#endif
    if(PIC_status[i].PIC_addr<=MAX_PULSE_PIC_ADDR)
      PIC_status[i].num_pulse_regs=PULSES_PE_PIC;
    else
      PIC_status[i].num_pulse_regs=0;
    }
 current_PIC_index=0;
 rcv_PIC_index=0;
 if(dont_clear_PIC_stats)
   dont_clear_PIC_stats=FALSE; /* Clear flag */
 else
   {
   PIC_bad_addr_count=0;
   PICrcvBuf.flags=0;
   PIC_serial_status=do_PIC_start;
   PIC_clk_state=clk_low;           /* Initialize serial comm variables */
   }
   clear_state=NO_GLOBAL_SEND;
   pulseOutMode=releaseCode.option.picMode;  /* for compatibility with old code */
   if(startup.coldStart)
     {
     pulseColdstart();
     }
}
const unsigned char parity6[32]=
{1,2,4,7,8,11,13,14,16,19,21,22,25,26,28,31,32,35,37,38,41,42,44,47,49,50,52,55,56,59,61,62
};
void pulseDay?()
{
  dont_clear_PIC_stats=TRUE;  /* Tell pulseStartup not to clear error counts */
  rebuild_timer=REBUILD_DELAY; /* Set up for delayed table rebuild */
}
void pulseSecond()
{
#ifndefIS_ST5
  pulseService();
#endif
 if(Comm_background_flags.do_rebuild)
   {
   pulseStartup();
   Comm_background_flags.do_rebuild=FALSE;
   }
 if(Comm_background_flags.do_alarm)
   {
   putAlarm(andPIC_alarm,4);
   Comm_background_flags.do_alarm=FALSE;
   }
 }
/* set_PLC_relays function              */
/* Called from PLC routines to request update of  */
/* PLC port multiplexer PIC chip on ST5 power board */
 #ifdef IS_ST5
 void set_PLC_elays(int xmitRelay,int rcvRelay)
 {
  while(MUX_control.active_flag||MUX_control.request_flag)
   {
   ccwait();
   }
  MUX_control.xmit_mask=xmitRelay;
  MUX_control.rcv_mask=rcvRelay;
  MUX_control.done_flag=FALSE;
  MUX_control.request_flag=TRUE;
  if((MUX_control.xmit_mask!=MUX_control.last_xmit_mask)||
    (MUX_control.rcv_mask!=MUX_control.last_rcv_mask))
    {
    while(!MUX_control.done_flag andand
        !(MUX_control.active_flag andand(PIC_serial_status=rcving_bits)))
      {
      ccwait();
      }
    }
 }
#endif
void pulseService(void)
{
  BOOLEAN  need_pulse_read,
      copy_rcvd_data,
      rcv_buf_err;
#ifdef IS_MC5
  BOOLEAN
       got_ver_3,
       got_ver_3_3;
  int   j;
  unsigned char *work_char_ptr;
  unsigned long work_bit_mask;
#endif
  int    work_pulse_index;
  phaccum accumXfer;
  inti;
  if(num_PICs=0)
     PIC_serial_status=idle;
  if(PIC_serial_status=idle)
     {
     if(!WDTpulseSec)
        WDTpulseSec=1; /*Tell WDT controller that we are OK*/
     }
   if(hold_num_pulse_ctrs!=releaseCodep->option.numPulseCounters)
     {                          /* hdwr-n has changed */
     dont_clear_PIC_stats=FALSE;
     rebuild_timer=1;   /* Force immediate table rebuild */
     }
   if((PIC_serial_status=idle)andand
     (rebuild_timer!=0)andand
     (--rebuild_timer=0))
     {
     Comm_background_flags.do_rebuild=TRUE;
     }
   else if((PIC_serial_status=idle)andand
          (num_PICs!=0)andand
          (pulseOutMode!=PIC_MC_SERIAL)andand
          (!Comm_background_flags.do_rebuild))    /* Serial processing enabled?*/
     {
     if(PICrcvBuf.flags and rcv_data_ready_flag)
       {                         /* Process received message */
       PICrcvBuf.flags and=~rcv_data_ready_flag;
        rcv_buf_err=!decode_rcv_buffer();
        if((PIC_comm_mon.control_flags and RCV_DATA_RDY)=0)
          {
          PIC_comm_mon.rcv_buf=PICrcvBuf;
          PIC_comm_mon.control_flags|=RCV_DATA_RDY;
          }
        if((ext_comm.control_flags and CPY_RCV_DATA)!=0)
          {
          ext_comm.rcv_buf=PICrcvBuf;
          ext_comm.control_flags and=~CP.Y_RCV_DATA;
          ext_comm.control_flags|=RCV_DATA_RDY;
          }
#ifdef IS_ST5
        if(ATM_control.active_flag)
          {
          ATM_control.result_flags=PICrcvBuf.flags;
          if(rcv_buf_err)
            {
            if(ATM_control.state!=WAIT_ALIGN)
              {
              ATM_control.error_flag=TRUE;
              ATM_control.active_flag=FALSE;
              ATM_control.done_flag=TRUE;
              }
            }
          else
            {
            switch(ATM_control.state)
              {
              case DO_PRESET:
                {
                ATM_control.xmit level=PICrcvBuf.command_data>>24;
                ATM_control.coupler_level=(PICrcvBuf.command_data>>16) and 0x0ff;
                ATM_control.active_flag=FALSE;
                }
                break;
              case SET_ALIGN:
                {
                ATM_control.state=WAIT_ALIGN;
                }
                break;
              case WAIT_ALIGN:
                {
                ATM_control.optimum_cap_code=PICrcvBuf.command_data and
       ATM_RC_CAP_MASK;
                ATM_control.optimum_reading=PICrcvBuf.command_data>>16;
                ATM_control.result_flags|=(PICrcvBuf.command_data and 0xe000);
                                /* Copy flags from reply */
                if((ATM_control.result_flags and 0xc000)!=0)
                  {                   /* Analog levels out of range */
                  ATM_control.error_flag=TRUE;
                  }
           if(ATM_control.optimum_reading<ATM_MIN_READING)
             {
             ATM_control.result_flags|=0x1000; /* Indicate reading too low */
             ATM_control.error_flag=TRUE;
             }
            ATM_control.active_flag=FALSE;
            }
            break;
          case DO_PLC_SET:
          case DO_ATM_DISCONNECT:
          {
          ATM_control.active_flag=FALSE;
          }
          break;
        default:
          {
          ATM_control.active_flag=FALSE;
          ATM_control.error_flag=TRUE;
          }
          break;
         }
        } 
     if(!ATM_control.active_flag)
        ATM_control.done_flag=TRUE;
       }
     if(MUX_control.active_flag)
       {
       MUX_control.result_flags=PICrcvBuf.flags;
       if(rcv_buf_err)
         {
         MUX_control.error_flag=TRUE;
         MUX_control.last_xmit_mask=0;
         MUX_control.last_rcv_mask=0;
         }
       clse
         {
         MUX_control.last_xmit_mask=PICrcvBuf.command_data and 0xff;
         MUX_control.last_rcv_mask=(PICrcvBuf.command_data>>8) and 0xff;
         }
        MUX_control.active_flag=FALSE;
        MUX_control.done_flag=TRUE;
        }
#endif
      if(rcv_buf_err)
        {
#ifdef IS_ST5
         if(!ATM_control.active_flag||(ATM_control.state!=WAIT_ALIGN))
#endif
          {
          last_comm_err_flag=PICrcvBuf.flags;
          copymem(sizeof(PICbitBuf),(char *)(andHoldrcvBuf),(char *)
(andPICrcvBuf));
          if((PICrcvBuf flags and rcv_bad_addr_flag)!=0)
         {     /* past end of valid PICs,address error */
         PIC_bad_addr_count++;
         set_PIC_alarm(PIC_adderr_0,PICrcvBuf.PIC_addr,
                (PICxmitBuf.PIC_addr<<8)+PICxmitBuf.command);
          }
        else
          {    /* PIC address was valid,but comm failed */
          PIC_status[rcv_PIC_index].comm_error_count++;
          if(PIC_status[rcv_PIC_index].comm_error_count>2)
            {
           set_PIC_alarm(PIC_comerr_0,PIC_status[rcv_PIC_index].PIC_addr,
                    PICrcvBuf.flags);
           }
                /* Lost contact with PIC,read serial number and software version */
          PIC_status[rcv_PIC_index].get_serno=TRUE;
          PIC_status[rcv_PIC_index].get_version=TRUE;
          }
        }
      }
    else
       {                       /* Valid message received */
       if((PICrcvBuf.command=READ_REGISTER)andand(PICrcvBuf.reg_ID=
STATUS_REG))
        {
        process_status_bits();
        }
     else if(PICrcvBuf.command=SYSTEM_CONTROL)
        {
        if(PICrcvBuf.reg_ID=STATUS_REG)
          {                 /* Response frome reset status bits cmd */
          PIC_status[rcv_PIC_index].reset_status=FALSE;
          process_status_bits();
          }
#ifdef IS_MC5
           else if((PIC_status[rcvPIC_index].software_type=4)andand
                  ((PIC_status[rcv_PIC_index].last_cmd_data and 0xffff0000)=
READ_ENCODER_ID))
         {                        /* response from encoder read ID comd */
         work_pulse_index=(PICrcvBuf.PIC_addr*PULSES_PER_PIC)+
PICrcvBuf.reg_ID;
            i=(PIC_status[rcv_PIC_index].last_cmd_data and 0x0000ff00)>>8;
            work_char_ptr=(unsigned char*)andPICrcvBuf.command_data;
            for(j=0;j<4;j++) 
              {
              if((*work_char_ptr=0)||(i>=ID_FIELD_LENGTH))
                {
                j=10;  /* indicate end of message found */
                } 
              else
                {
                pulseData[work_pulse_index]ID_buffer[i]=*work_char_ptr;
                i++;
                work_char_ptr++;
                }
               }
               if(j>5)
                   {                /* found end of ID field from remote encoder */
                   for(i=0;i<ID_FIELD_LENGTH;i++)
               {
                      pulseData[work_pulse_index].ID_field[i]=
pulseData[work_pulse_index].ID_buffer[i];
               pulseData[work_pulse_index].ID_buffer[i]=0;
               }
             }
           }
         }
      else if((PICrcvBuf.command=READ_REGISTER)andand(PICrcvBuf.reg_ID
=ERROR_REG))
        {
        if(PIC_status[rcv_PIC_index].software_type=4)
            {             /* Remote encoder interface module */
            work_pulse_index=(PICrcvBuf.PIC_addr*PULSES_PER_PIC)+
(PICrcvBuf.command_data>>24);
              if(work_pulse_index<(2*NUMPH))
                {
                pulseData[work_pulse_index].error_cnt++;
                for(i=0;i<ID_FIELD_LENGTH;
pulseData[work_pulse_index].ID_buffer[i++]=0);
                }
              }
#endif
          }
       else if((PICrcvBuf.command=WRITE_REGlSTER)andand(PICrcvBuf.reg_ID
=PARM_REG))
        {
        PIC_status[rcv_PIC_index]update_parameter=FALSE;
        }
      else if((PICrcvBuf.command=READ_REGISTER)andand(PICrcvBuf.reg_ID
=VERS_REG))
        {
        PIC_status[rcv_PIC_index].get_version=FALSE;
        PIC_status[rcv_PIC_index].software_type=
        (PICrcvBuf.command_data and 0xff000000)>>24;
        PIC_status[rcv_PIC_index].software_version=
        (PICrcvBuf.command_data and 0x00ff0000)>>16;
        PIC_status[rcv_PIC_index].loop_rate=
        (PICrcvBuf.command_data and 0x0000ff00)>>8;
        }
     else if((PICrcvBuf.command=READ_REGISTER)andand(PICrcvBuf.reg_ID
=SERNO_REG))
        {
        PIC_status[rcv_PIC_index].get_serno=FALSE;
        PIC_status[rcv_PIC_index].serial_number=PICrcvBuf.command_data;
        }
       else if(((PICrcvBuf.command=READ_REGISTER)|!(PICrcvBuf.command<=
 MAX_FAST_READ))
          andand(PICrcvBuf.reg_ID<=MAX_PULSE_REG))
         {     /* Pulse reading */
         work_pulse_index=(PICrcvBuf.PIC_addr*PULSES_PER_PIC)+ 
 PICrcvBuf:reg_ID;
          if(work_pulse_index<(NUMPH*2))
            {
            pulseData[work_pulse_index].reading=PICrcvBuf.command_data;
            copy_rcvd_data=FALSE; 
            if(PIC_status[rcv_PIC_index].get_version)
              {
              }
            else if(PIC_status[rcv_PIC_index].software_type=4)
              {             /* Remote encoder interface module */
              copy_rcvd_data=TRUE;
              accumXfer.low=pulseData[work_pulse_index].reading;
              }
           else if(PIC_status[rcv_PIC_index].software_type=3)
             {              /* Remote pulse counter module */
             copy_rcvd_data=TRUE;
             if(!PIC_status[rcv_PIC_index].get_serno)
               {
               sprintf((char *) pulseData[work_pulse_index].ID_field,″S%081dP%d″,
                     PIC_status[rcv_PIC_index].serial_number,
                     PICrcvBuf.reg_ID);
                }
              if(releaseCode.option.countEveryEdge)
                {
                accumXfer.low=pulseData[work_pulse_index].reading;
                }
              else
                {
               accumXfer.low=pulseData[work_pulse_indcx].reading>>1;
               }
             }
            accumXfer.high=0L;
#ifndef VATEST
            if(copy_rcvd_data)
              {
#ifndef IS_MC5
          /* It is an RSM or ST5,so mapping for pulse 1 thru 4 is M1Q13,M1Q14,M2Q13,
M2Q14 */
ph[0][work_pulse_index/2][(work_pulse_indexand0x01)?PULSE2:PULSE1].accum=
ph[1][work_pulsc_index/2][(work_pulse_indexand0x01)?PULSE2:PULSE1].accum=
                accumXfer;
#else
        /* It is an MC5,so mapping for pulse 1 thru 48 is M1Q13..M24Q13,
M1Q14..M24Q14 */
ph[0][work_pulse_index%NUMPH][(work_pulse_index/NUMPH)?PULSE2:PULSE1].accu
m=
ph[1][work_pulse_index%NUMPH][(work_pulse_index/NUMPH)?PULSE2:PULSE1].accu
m=
                accumXfer;
#endif
               }
#endif
            }
          }
        if((PICrcvBuf.flags and(PIC_error_flag|PIC_invalid_data_flag))!=0)
          PIC_status[rcv_PIC_index].get_status=TRUE;
        if((PICrcvBuf.flags and PIC_need_refresh_flag)!=0)
          PIC_status[rcv_PIC_index].update_parameter=TRUE;
        /* check status flags */
        }
      }
     /* Decide what command to send */
     PICxmitBuf.flags=0;
#ifndef IS_ST5
/* MC5 or RSM,check for cold-start processing to clear pulse regisers */
   if(clear_state=SEND_GLOBAL_CLR)
      {                    /* Cold start,send global clr */
      PICxmitBuf.PIC_addr=GLOBAL_PIC_ADDR;
      PICxmitBuf.command=CLEAR_PULSE_REGISTERS;
      format_xmit_buffer();
      clear_state=SENDING_GLOBAL_CLR;
      PIC_serial_status=do_send_cmd; /* Start UART */
      }
    else if(clear_state=SENDING_GLOBAL_CLR)
      {
      clear_state=GLOBAL_CLR_SENT;
      }
 #else
  /* ST5,check for ATM (Automatic Tuning Module) operations */
      if(ATM_control.request_flag)
        {
        ATM_control.request_flag=FALSE;
        ATM_control.error_flag=FALSE;
        ATM_control.active_flag=TRUE;
        ATM_control.state=ATM_DONE;
        PICxmitBuf.PIC_addr=ATM_control.ATM_number+ATM_BASE_ADDR;
        switch(ATM_control.operation)
         {
         case SET_PRE_ALIGN:
       PICxmitBuf.command=WRITE_REGISTER;
       PICxmitBuf.reg_ID=OUTPUT_REG;
       PICxmitBuf.command_data=ATM_control.start_cap_code and
ATM_RC_CAP_MASK;
       PICxmitBuf.command_data|=ATM_PRESET_CODE;
       ATM_control.state=DO_PRESET;
       break;
     case DO_ALIGN:
       PICxmitBuf.command=WRITE_REGISTER;
       PICxmitBuf.reg_ID=CONTROL_REG;
       if(ATM_control.start_cap_code>ATM_control.end_cap_code)
          ATM_control.end_cap_code=ATM_control.start_cap_code;
       PICxmitBuf.command_data=ATM_control.start_cap_code and
ATM_RC_CAP_MASK;
       PICxmitBuf.command_data=(PICxmitBuf.command_data<<12)|
                    (ATM_control.end_cap_code and ATM_RC_CAP_MASK)|
                     (ATM_MEAS_TIME<<24);
       ATM_control.state=SET_ALIGN;
       ATM_control.align_timer=ATM_control.end_cap_code-
ATM_control.start_cap_code;
       ATM_control.align_timer*=((ATM_DISC_TIME+ATM_MEAS_TIME+4)*
(1.25/62.5));
       ATM_control.align_timer+=13;/* Time in 1/64 sec to wait before checking
 result */
                        /* Number of steps * time per step+25%+2 second */
       break;
     case SET_NORMAL_PLC:
       PICxmitBuf.command=WRITE_REGISTER;
       PICxmitBuf.reg_ID=OUTPUT_REG;
       PICxmitBuf.command_data=ATM_control.optimum_cap_code and
 ATM_RC_CAP_MASK;
       PICxmitBuf.command_data|=ATM_PLC_CODE;
       ATM_control.state=DO_PLC_SET;
       break;
      case DISCONNECT_COUPLER:
       PICxmitBuf.command=WRITE_REGISTER;
       PICxmitBuf.reg_ID=OUTPUT_REG;
       PICxmitBuf.command_data=ATM_controloptimum_cap_code and
 ATM_RC_CAP_MASK;
       PICxmitBuf.command_data|=ATM_DISC_CODE;
       ATM_control.state=DO_ATM_DISCONNECT;
       break;
      default:
      case READ_XMIT_LEVEL:
       ATM_control.error_flag=TRUE;
       ATM_control.done_flag=TRUE;
       ATM_control.active_flag=FALSE;
       break;
      }
      if(ATM_control.active_flag)
        {
        format_xmitbuffer();
        PIC_wait_limit=DIRECT_PIC_WAIT_LIMIT;
        PIC_serial_status=do_send_cmd; /* Start UART */
        }
      }
    else if(ATM_control.active_flag):
      {
     if((ATM_control.state!=WAIT_ALIGN) ||
        (--ATM_control.align_timer<=0))
        {
        ATM_control.error_flag=TRUE;
        ATM_control.done_flag=TRUE;
        ATM_control.active_flag=FALSE;
        }
    else
      {                       /* poll ATM for auto-tune end */
      PICxmitBuf.command=0;
      format_xmit_buffer();
      PIC_wait_limit=DIRECT_PIC_WAIT_LIMIT;
      PIC_serial_status=do_send_cmd;/* Start UART */
      }
    }
  else if(MUX_control.request_flag)
    {
    MUX_control.request_flag=FALSE;
    MUX_control.error_flag=FALSE;
    if((pulseOutMode=PIC_ST_SERIAL))
      {
      PICxmitBuf.bits.bufByte[0]=((MUX_control.rcv_mask and 0x03)<<5)|
                       ((MUX_control.xmit_mask and 0x7f)>>2);
      PICxmitBuf.bits.bufByte[1]=((MUX_control.xmit_mask and 0x03)<<6);
      bit_count=11;
      PIC_serial_status=sending_st5_bits;  /* Start UART */
      MUX_control.last_xmit_mask=MUX_control.xmit_mask;
      MUX_control.last_rcv_mask=MUX_control.rcv_mask;
      MUX_control.done_flag=TRUE;
      }
    else
      {
      MUX_control.active_flag=TRUE;
      PICxmitBuf.PIC_addr=ST5_MUX_PIC_ADDR;
      PICxmitBuf.command=WRITE_REGISTER;
      PICxmitBuf.reg_ID=OUTPUT_REG;
      PICxmitBuf.command_data=(MUX_control.rcv_mask<<8)+
MUX_control.xmit_mask,
      format_xmit_buffer();
      PIC_wait_limit=DIRECT_PIC_WAIT_LIMIT;
      PIC_serial_status=do_send_cmd;/* Start UART */
         }
       }
#endif
     else if((ext_comm.control_flags and(XMIT_DATA_RDY|XMIT_REQUEST))=
           (XMIT_DATA_RDY|XMIT_REQUEST))
       {                   /* Send command for external routine */
       PICxmitBuf=ext_comm.xmit_buf;
       ext_comm.control_flags and=~XMIT_REQUEST;
       ext_comm.control_flags|=CPY_RCV_DATA;
       /*  Look up correct PIC_status index for reuested PIC */
       for(i=0;((i<MAX_PICS)andand(PIC_status[i].PIC_addr!=PICxmitBufPIC_addr));
i++); 
       if(i<num_PICs)
         {
         PIC_status[i].last_cmd_data=PICxmitBuf.command_data;
         PIC_status[i].last_command=PICxmitBuf.command;
         }
#ifdef IS_MC5
       if(ext_comm.xmit_buf.PIC_addr<ST5_MUX_PIC_ADDR)
          PIC_wait_limit=BUFFERED_PIC_WAIT_LIMIT;
       else
#endif
        PIC_wait_limit=DIRECT_PIC_WAIT_LIMIT;
       format_xmtit_buffer();
       PIC_serial_status=do_send_cmd;    /* Start UART */
       } 
     else if(((ext_comm.control_flags and SUPPRESS_NORMAL_COMM)=0)
#ifdef IS_ST5
           andand(--ST5_PIC_delay_ctr<=0))
       {
        ST5_PIC_delay_ctr=ST5_PIC_DELAY;  /* Slow down routine communications in
the ST5 */
#else
                                          {                      
      {
#endif
       PICxmitBuf.PIC_addr=PIC_status[current_PIC_index].PIC_addr;
       need_pulse_read=TRUE;    /* Set defaults */
#ifdefIS_ST5
       if((pulseOutMode=PIC_ST_SERIAL)andand
         (PICxmitBuf.PIC_addr=ST5_MUX_PIC_ADDR))
         {
         }
       else
#endif
       if(PIC_status[current_PIC_index].force_pulse_read andand
         (!PIC_status[current_PIC_index].get_version) andand
         (PIC_status[current_PIC_index].PIC_addr<ST5_MUX_PIC_ADDR))
         {
         PIC_status[current_PIC_index].force_pulse_read=FALSE;
         }
       else 
         {
         PIC_status[current_PIC_index].force_pulse_read=TRUE;
#ifndef IS_ST5
          if(PIC_status[current_PIC_index].clear_puls_regs andand
            (clear_state=GLOBAL_CLR_SENT))
            {                    /* Global clear sent,get status */
            need_pulse_read=FALSE;
            PICxmitBuf.command=READ_REGISTER;
            PICxmitBuf.reg_ID=STATUS_REG;
            format_xmit_buffer();
            }
          else
 #endif
             if(PIC_status[current_PIC_index].get_version)
              {
              need_pulse_read=FALSE;
              PICxmitBuf.command=READ_REGISTER;
              PICxmitBuf.reg_ID=VERS_REG;
              format_xmit_buffer();
              }
            else if(PIC_status[current_PIC_index].get_serno)
              {
              need_pulse_read=FALSE;
              PICxmitBuf.command=READ_REGISTER;
              PICxmitBuf.reg_ID=SERNO_REG;
              format_xmit_buffer();
              }
            else if(PIC_status[current_PIC_index].update_parameter)
              {
              PICxmitBuf.command=WRITE_REGISTER;
              if(PIC_status[current_PIC_index].software_type=3)
                {                              /* Pulse ctr */
                /* Pulse ctr parameters:       */
                /* Power-On sample rate: 42/sec */
                /* Power-off sample rate: 1/sec  */
                /* Days to count if rcving pulses: */
                /*      RSM: 5 days       */
                /*      PDM: 35 days      */
                /* Days to count ifno pulses rcvd: */
                /*      RSM: 1 day        */
                /*      PDM: 3 days       */
                /* on RSM, the 2 1sbs of       */
             /* load_shed_mask[0] are sent to  */
             /* the PIC output bits       */
#ifdef IS_RSM
             PICxmitBuf.command_data=0x01150507 and
                          (load_shed_state[0]|0xfffffffc);
#else
              PICxmitBuf.command_data=0x0115230d;
#endif
             }
#ifdef IS_MC5
           else if(PIC_status[current_PIC_index].software_type=4)
             {                                /* Remote encoder reader */
             PICxmitBuf.command_data=READ_NCODER_PARM;
             if((releaseCodep->option.couplers_mask and 0x01)=0)
               {                       /* If mask bit 0 is 0,no touch-pad compatibility */
               PICxmitBuf.command_data and=0xff00ffff;
               }
              }
            else if(PIC_status[current_PIC_index].software_type=5)
               {                               /* MC5 mux */
               got_ver_3=got_ver_3_3=FALSE;
               for(i=0;i<num_PICs;i++)
                  {
                  if(PIC_status[i].get_version)
                    {
                    got_ver_3=TRUE;
                    got_ver_3_3=TRUE;
                    }
                  else if(PIC_status[i].software_type=3)
                    {
                    got_ver_3=TRUE;
                    if(PIC_status[i].software_version=3)
                      got_ver_3_3=TRUE;
                    }
                   }
                   if(got_ver_3)
                     {
                     if(got_vet_3_3 andand
                       ((releaseCodep->option.couplers_mask and 0x02)!=0))
                       {
                       PICxmitBuf.ommand_data=0x0e007000;/* 32 bps,periodic wake-up
  */
                       }
                     else
                       {
                       PICxmitBuf.command_data=0x0c007080; /* 32 bps,no wake-up */
                       }  
                     }
                   else
                     PICxmitBuf.command_data=0x02030080;/* 205 bps,no wake-up */
                  }
  #endif
  #ifdcf IS_ST5
          else if(PIC_status[current_PIC_index].software_type=8)
             {                             /* Auto tune module */
             PICxmitBuf.command_data=0x02030000|(ATM_DISC_TIME<<8)|
                             (ATM_RC_XMIT_ON>>8)|ATM_NUM_CAP_BITS;
             /* xmit offset=2,cplr offset=3,               */
             /* relay delay=ATM_DISC_TIME,Xmit mask = ATM_RC_XMIT_ON,  */
             /* number of capacitor relays=ATM_NUM_CAP_BITS        */
              }
           else if(PIC_status[current_PIC_index].software_type=6)
              {                              /* ST5 mux */
              PICxmitBuf.command_data=0x00000000;
              }
#endif
           else if(PIC_status[current_PIC_index].software_type=7)
              {                              /* Load Control Module */
              PICxmitBuf.command_data=0x00000000;
              }
            else
              {
              PIC_status[current_PIC_index].update_parameter=FALSE;
                          /* unknown software type,cancel command */
               } 
             if(PIC_status[current_PIC_index].update_parameter)
               {
               need_pulse_read=FALSE;
               PICxmitBuf.reg_ID=PARM_REG;
               format_xmit_buffer();
               }
             }  
          else if(PIC_status[current_PIC_index].reset_status)
             {
             need_pulse_read=FALSE;
             PICxmitBuf.command=SYSTEM_CONTROL;
             PICxmitBuf.command_data=
             (PIC_status[current_PIC_index].status_reg_value and 0xffbf);
             PICxmitBuf command_data=PICxmitBuf.command_data<<16;/* Move
 status bits to MSb′s */
             PICxmitBuf.rcg_ID=STATUS_REG;
             format_xmit_buffer();
             }
          else if(PIC_status[current_PIC_index].get_status)
             {
             need_pulse_read=FALSE;
             PICxmitBuf.command=READ_REGISTER;
             PICxmitBuf.reg_ID=STATUS_REG;
             format_xmit_buffer();
             }
 #ifdef IS_MC5
           if(need_pulse_read andand(PIC_status[current_PIC_index].software_type=4))
             {
             need_pulse_read=FALSE;
             PICxmitBuf.command=SYSTEM_CONTROL;
        if(++PIC_status[current_PIC_index].curr_ID_reg>=PULSES_PER_PIC)
          PIC_status[current_PIC_index].curr_ID_reg=0;
        if((((PIC_status[current_PIC_index].PIC_addr*PULSES_PER_PIC)+
            PIC_status[current_PIC_index].curr_ID_reg)%24)>=num_pulse_ctrs)
                         PIC_status[current_PIC_index].curr_ID_reg=0;
        PICxmitBuf.reg_ID=PIC_status[current_PIC_index].curr_ID_reg;
        work_pulse_index=(PIC_status[current_PIC_index].PIC_addr *
PULSES_PER_PIC)+PICxmitBuf.reg_ID;
        for(i=0;i<ID_FIELD_LENGTH;i++)
          {
          if(pulseData[work_pulse_index].ID_buffer[i]=0)
           {
           j=i-1;
           i=ID_FIELD_LENGTH;
           }
         }
       if(j<0)
          {
          j=0;
          }
        else if(j>(ID_FIELD_LENGTH-4))
          {
          j=ID_FIELD_LENGTH-4;
          }
          PICxmitBuf.command_data=READ_ENCODER_ID|(j<<8);;
          format_xmit_buffer();
#endif    }
        }
       if(need_pulse_read)
          {
  #ifdef IS_MC5
            if(PIC_status[current_PIC_index].software_type=7)
              {
              i=PIC_status[current_PIC_index].PIC_addr-LCM_BASE_ADDR;/* get
 LCM # */
              work_bit_mask=(load_shed_state[0]>>(9*i))and 0x000001ff;
              PICxmitBuf.command_data=0;
              for(i=0;i<9;i++).
              {
              if((work_bit_mask and 0x100)!=0)
                PICxmitBuf.command_data=(PICxmitBuf.command_data<<2)+1;/*lsb
 turns relay on */
              else
                PICxmitBuf.command_data=(PICxmitBuf.command_data<<2)+2;/* msb
   turns relay on */
                work_bit_mask=work_bit_mask<<1;
                }
               PICxmitBuf.command_data|=0x32000000; /* Set pulse time=50mS*/
           PICxmitBuf.command=WRITE_REGISTER;
           PICxmitBuf.reg_ID=OUTPUT_REG;
           format_xmit_buffer();
           need_pulse_read=FALSE;
           }
         else
#endif
            if(PIC_status[current_PIC_index].num_pulse_regs=0)
            {
#ifndef IS_ST5
            PICxmitBuf.command=READ_REGISTER;
            PICxmitBuf.reg_ID=VERS_REG;
            format_xmit_buffer();
            need_pulse_read=FALSE;
#endif
            }
          else
            {
#ifdef IS_MC5
           if((((PIC_status[current_PIC_index].PIC_addr*PULSES_PER_PIC)+
                    PIC_status[current_PIC_index].curr_pulse_reg)%24)>=
num_pulse_ctrs)
               PIC_status[current_PIC_index].curr_pulse_reg=0;
#endif
           if(PIC_status[current_PIC_index].curr_pulse_reg<=MAX_FAST_READ)
             PICxmitBuf.command=PIC_status[current_PIC_index].curr_pulse_reg;
           else
             PICxmitBuf.command=READ_REGISTER;
             PICxmitBuf.reg_ID=PIC_status[current_PIC_index].curr_pulse_reg;
             format_xmit_buffer();
             need_pulse_read=FALSE;
             if(++PIC_status[current_PIC_index].curr_pulse_reg>=
 PIC_status[current_PIC_index].num_pulse_regs)
              { 
              PIC_status[current_PIC_index].curr_pulse_reg=0;
 #ifdef IS_RSM
             PIC_status[current_PIC_index].update_parameter=TRUE;
 #endif
             }
           }
         }
        PIC_status[current_PIC_index].last_cmd_data=PICxmitBuf.command_data;
        PIC_status[current_PIC_index].last_command=PICxmitBuf.command;
        PIC_wait_limit=PIC_status[current_PIC_index].reply_wait_limit;
        rcv_PIC_index=current_PIC_index;
        if(++current_PIC_index=num_PICs)
        current_PIC_index=0;
        if(!need_pulse_read)
          PIC_serial_status=do_send_cmd;  /* Start UART */
      }
   }
}
#ifdefIS_RSM/* In RSM,generate serial stream from subseconds */
void pulseSubsecond(void)
{
  if(num_PICs!=0)
    {
    if(PIC_clk_state=clk_high)
      {
      /* Falling edge,just set clock low */
      fs1004.io.pulseOutlOff=0;
      PIC_clk_state=clk_low;
      }
    else
      { 
      PIC_clk_state=clk_high;
#include ″pic.def″ /* Do PIC serial comm on clock rising edge */
    }
  }
}
#endif
void process_status_bits(void)
{
  unsigned int  work_pulse_index,work_status_bits;
  PIC_status[rcv_PIC_index].get_status=FALSE;
  PIC_status[rcv_PIC_index].status_reg_value=PICrcvBuf.command_data>>16;
  PIC_status[rcv_PIC_index].time_since_global=(PICrcvBuf.command_data>>8)and
0xff;
  if(PIC_status[rcv_PIC_index].status_reg_value!=0)
    {
    PIC_status[rcv_PIC_index].reset_status=TRUE;
    if((PIC_status[rcv_PIC_index].status_reg_value and 0x8f10)|=0)
      {
      PIC_status[rcv_PIC_index].PIC_data_err_count++;/* PIC detected bad data */
      set_PIC_alarm(PIC_flags_0,PIC_status[rcv_PIC_index].PIC_addr,
              PIC_status[rcv_PIC_index].status_reg_value);
      work_status_bits=(PIC_status[rcv_PIC_index].status_reg_value>>8)and 0x0f;
      work_pulse_index=PIC_status[rcv_PIC_index].PIC_addr*PULSES_PER_PIC;
      while(work_status_bits>0)
       {
       if(work_status_bits and 0x01)
         pulseData[work_pulse_index].error_cnt++;
      work_status_bits=work_status_bits>>1;
      work_pulse_index++;
      }     
    }
  if(((PIC_status[rcv_PIC_index]status_reg_value and 0x20)!=0)andand
    !PIC_status[rcv_PIC_index].clear_pulse_regs)
    }
    PIC_status[rcv_PIC_index].comm_error_count++;/* PIC detected comm parity err
*/
    if(PIC_status[rcv_PIC_index].comm_error_count>2)
      set_PIC_alarm(PIC_comerr_0,PIC_status[rcv_PIC_index].PIC_addr,
              PICrcvBuf.flags|0x0800);
      }
     }
  if((PIC_status[rcv_PIC_index].status_reg_value and 0x3080)!=0)
    {
    PIC_status[rcv_PIC_index].PIC_reset_count++; /* PIC was reset */
    if(PIC_status[rcv_PIC_index].PIC_reset_count>1) 
      {
      set_PIC_alarm(PIC_reset_0,PIC_status[rcv_PIC_index].PIC_addr,
              PIC_status[rcv_PIC_index].status_reg_value);
      }
    }
   }
 if(PIC_status[rcv_PIC_index].clear_pulse_regs andand
   (clear_state=GLOBAL_CLR_SENT))
   { 
   PIC_status[rcv_PIC_index].clear_pulse_regs=FALSE;
   if(((PIC_status[rcv_PIC_index].status_reg_value and 0x0f)!=0x0f)andand
      (PIC_status[rcv_PIC_index].software_type=3))
     {
     PIC_status[rcv_PIC_index].PIC_data_err_count++;/* Clear cmd failed */
     set_PIC_alarm(PIC_flags_0,PIC_status[rcv_PIC_index].PIC_addr,
             PIC_status [rcv_PIC_index].status_reg_value);
     } 
    }
 else if(((PIC_status[rcv_PIC_index].status_reg_value and 0x0f)!=0)andand
        ((PIC_status[rcv_PIC_index].status_reg_value and 0xf10)=0))
 {
   PIC_status[rcv_PIC_index].PIC_data_err_count+=1000; /* Spurious clr cmd */
   set_PIC_alarm(PIC_flags_0,PIC_status[rcv_PIC_index].PIC_addr,
           PIC_status[rcv_PIC_index].status_reg_value);
   }
 }
 void set_PIC_alarm(alarmcodes pass_alarm_codes,
            int pass_PIC_addr,
            unsigned int pass_alarm_data)
  {
   if(!Comm_background_flags.do_alarm)
     {
     PIC_alarm.alarm_codes=pass_alarm_codes+pass_PIC_addr;
   PIC_alarm.ack=pass_alarm_data;
   Comm_background_flags.do_alarm=TRUE;
   }
}
unsigned char workTpar;
BOOLEAN decode_rcv_buffer(void)
{
  int     i;
  unsigned int workInt;
  workTpar=0xlf;
  if(PICrcvBuf.flags=0)
    {
    work_PIC_addr=Get5();
    if(PICrcvBuf.flags=0)
      PICrcvBuf.PIC_addr=work_PIC_addr;/* Valid address received */
    PICrcvBuf.command=Get5();
    if(PICrcvBuf.command>0x0f)
      PJCrcvBuf.reg.ID=Get5();
    else
      PICrcvBuf.reg_ID=PICrcvBuf.command;
    PICrcvBuf.command_data=0;
    for(i=0;i<6;i++)
       PICrcvBuf.command_data=(PICrcvBuf.command_data<<5)+Get5();
    workInt=Get5();
    PICrcvBuf.command_data=(PICrcvBuf.command_data<<2)+(workInt>>3);
    PICrcvBuf.flags|=workInt and 0x07;
    workInt=Get5();
    if(workTpar!=0)
      PICrcvBuf.flags|=rcv_tpar_error_flag;
    }
  /* Look up correct PIC_status index for data in rcv buffer */
  for(i=0;((i<MAX_PICS)andand(PIC_status[i].PIC_addr!=PICrcvBuf.PIC_addr));i++);
  if(i>=num_PICs)
    PICrcvBuf.flags|=rcv_bad_addr_flag;/* past end of valid PICs,address error */
  if(i=MAX_PICS)
    rcv_PIC_index=0;
  else
    rcv_PIC_index=i;
 #ifdefVATEST
 #ifVATEST=1
   PICrcvBuf.command=temp_command;
   PICrcvBuf.reg_ID=tcmp_reg_ID;
   PICrcvBuf.command_data=temp_command_data;
   PICrcvBuf.flags=temp_flags;
 #endif
 #endif
   return((PICrcvBuf.flags and
      ~(PIC_error_flag|PIC_need_refresh_flag|PIC_invalid_data_flag))=0);
}
void format_xnit_buffer(void)
{
   int     i,j,ShiftCount;
   unsigned int WorkInt;
   unsigncd long WorkData;
   PICxmitBuf.bitCount=0;
   PICxmitBuf.bits.bufLong[0]=0;
   PICxmitBuf.bits.bufLong[1]=0; 
   PICxmitBuf.bits.bufLong[2]=0;/* Clear xmit bit buffer */
   workTpar=0x1f;           /* I nitializa Tpar */
   Stuff6(PICxmitBuf.PIC_addr);
   Stuff6(PICxmitBuf.command);
   if(PICxmitBuf.command>0x0f)
     {
     Stuff6(PICxmitBuf.rcg_ID);
     if(PICxmitBuf.command>0x17)
       {
       WorkData=PICxmitBuf.command_data;
       ShiftCount=32;
       for(i=0,i<7;i++)
          {
          WorkInt=0;
          for(j=0;j<5;j++)
             {
             WorkInt=WorkInt<<1;
             if(WorkData and 0x80000000)
               WorkInt+=1;
             WorkData=WorkData<<1;
             if(--ShiftCount=0)
               {
               WorkInt=(WorkInt<<3)+(PICxmitBuf.flags and 0x07);
               j=5;
               }
           }
         Stuff6(WorkInt);
          }
        }
       }
     Stuff6(workTpar);
                         /* Buffer set,set up UART control */
     PICrcvBuf.bitCount=66;
     if((PIC_comm_mon.control_flags and XMT_DATA_RDY)=0)
       {
       PIC_comm_mon.xmit_buf=PICxmitBuf;
       PIC_comm_mon.control_flags|=XMIT_DATA_RDY;
       }
    PICrcvBuf.flags=0;
    PICrcvBuf.PIC_addr=PICxmitBuf.PIC_addr;/* preset address of remote PIC */
}
unsigned int Get5(void)
{
   int      byte_index,bit_index;
   unsigned int work_result;
   work_result=0;
   if((PICrcvBuf.flags and
     ~(PIC_error_flag|PIC_need_refresh_flag|PIC_invalid_data_flag))=0)
     {
     byte_index=96-PICrcvBuf.bitCount;
     bit_index=byte_index and 0x07;
     byte_index=byte_index>>3;
     work result=(PICrcvBuf.bits.bufByte[byte_index]<<8)+
PICrcvBuf.bits.bufByte[byte_index+1];
     work_result=work_result>>(10-bit_index);
     work_result and=0x3f;
     if(parity6[work_result>>1]=work_result)
       {
       work_result=0;
       PICrcvBuf.flags|=rcv_parity_err_flag;
       }
    else
      {
      work_result=work_result>>1;
      workTpar^=work_result;
      PICrcvBuf.bitCount=6;
      if(PICrcvBuf.bitCount<0)
        PICrcvBuf.flags|=rcv_bad_length_flag;
      }
    }
   return(work_result);
 }
 void Stuff6(int pass_data)
 {
   int byte_index,bit_index;
   workTpar^=pass_data;
   byte_index=PICxmitBuf.bitCount>>3;
   bit_index=PICxmitBuf.bitCount and 0x07;
   pass_data=parity6[pass_data]<<(10-bit_index);
   PICxmitBuf.bits.bufByte[byte_index]|=pass_data>>8;
   PICxmitBuf.bits.bufByte[byte_index+1]|=pass_data and 0xff;
   PICxmitBuf.bitCount+=6;
}
                          PULSE.H
/*
*/
#ifndef BOOLEAN_DEFINED
#define BOOLEAN_DEFINED
typedefint BOOLEAN;
#endif
/*subsecond processing for pulse counters */
void pulseSubsecond(void);
/* Daily PIC table rebuild */
void pulseDay(void);
/* Main PIC communication routine */
void pulseService(void);
/* PIC comm routine-once-per-second code */
void pulseSecond(void);
/* Subroutines for PIC communication */
void Stuff6(int pass_data);
void format_xmit_buffer(void);
BOOLEAN decode_rcv_buffer(void);
void process_status_bits(void);
unsigned int Get5(void);
void set_PIC_alarm(alarmcodes pass_alarm_type,
            int pass_PIC_addr,
            unsigned int pass_alarm_data);
/* Startup code for PIC communication */
void pulseStartup(void);
/* Routine to clear pulse registers after cold start */
void pulseColdstart(void);
/* defined in pt.c */
#define RELAY_A 0
#define RELAY_B 1
void pulseOut(int picNbr,int relayNbr,int ONoff);
void ptEveryMinute(void);
void ptEverySecond(void);
void set_PLC_relays(int xmitRelay,int rcvRelay);
                                          PICEND.DEF
/*
include file at end of mtrsamp to control MC and ST pic chips from mtrsamp interrupt
*/
#ifdef IS_MC5
if(pulseOutMode=PIC_MC_SERIAL)
        {
        asm(″MOVE.L #0x80400E,A0″);
        asm(″AND.W #0xFCFF,(A0)″);  /* Clear clock and data ports */
        }
 #endif
 #ifdef IS_ST5
  asm(″MOVE.L #0x80400E,A0″);
  asm(″AND.W #0xFEFF,(A0)″);/* Insert clock falling edge */
 if(PIC_serial_status=sending_st5_bits)
        {
  asm(″NOP″);
  asm(″NOP″);
  asm(″NOP″);
  asm(″NOP″);
  asm(″NOP″);
  asm(″NOP″);
  asm(″NOP″);
  asm(″NOP″);
  asm(″NOP″);
  asm(″NOP″);
  asm(″NOP″);
  asm(″NOP″);
  asm(″NOP″);
  asm(″MOVE.L #0x80400E,A0″);
  asm(″OR.W #0x0100,(A0)″); /* If sending bits, activate clock*/
        }
 #endif
                                     PICVARS.DEF
/*
local variables to control MC and ST pic chips from mtrsamp interrupt
meter/c/lib/picvars.def
*/
unsigned long bitOneFlag;
                                        PULSELINK.DEF
/* determine ifvariables are external or defned here */
#undefref
#ifdef PSTRU_DEFINED
#define ref
#else
#define ref extern
#endif
#if(NUMPH>6)
#define IS_MC5
#else
#ifdef MAX_SCAN_METERS
#define IS_ST5
#else
#define IS_RSM
#endif
#endif
/* Values for hdwr-p(pulseOutMode) */
#define STANDARD_PIC_COMM 0
#if0    /* remove these equates from mtrlink.def */
#define PIC_PULSE_SERIAL 1
#define PIC_MC_SERIAL 2
#define PIC_ST_SERIAL 3
#endif   /* then uncomment them here */
/* #define VATEST    1 */
#ifdef VATEST
 #undef IS_MC5
 #undef IS_RSM
 #undef IS_ST5
 #define IS_RSM
 #undefNUMPH
 #define NUMPH 3
 #undef MAX_SCAN_METERS
 #endif
 /* Uncomment for water meters(Oakville Hydro) */
 #define READ_ENCODER_ID 0x49ff0000
 #define READ_ENCODER_PARM 0x0312500c
 /*Uncomment for gas meters (Sonix)
 #define READ_ENCODER_ID 0x49fe0389
#define READ_ENCODER_PARM 0x0300500c
                 */
#define ID_FIELD_LENGTH  13
#define PULSES_PER_PIC    4
#ifdef IS_MC5
#define BITS_PER_SEC      822
#define MAX_PICS  16
#else
#ifdef IS_ST5
#define BITS_PER_SEC      942
#define MAX_PICS   5
#else
#define BITS_PER_SEC  32
#define MAX_PICS   1
#endif
#endif
#define DIRECT_PIC_WAIT_LIMIT  24
#define BUFFERED_PIC_WAIT_LIMIT 10 * BITS_PER_SEC
#define NUM_START_BITS  12
#ifdef IS_ST5
#define REBUILD_DELAY 30000
#else
#define REBUILD_DELAY 1000
#endif
typedef
        struct{
                unsigned long serial_number;
  unsigned long last_cmd_data;
  unsigned char      PIC_addr;
  unsigned char      software_type;
  unsigned char      software_version;
              unsigned char  loop_rate;
              unsigned iht   status_reg_value;
              unsigned char  time_since_global;
              unsigned char  num_pulse_regs;
              unsigned char  curr_pulse_reg;
  unsigned char curr_ID_reg;
  unsigned char last_command;
              unsigned int   reply_wait_limit;
              unsigned int   PIC_data_err_count;
              unsigned int   PIC_reset_count;
              unsigned int   comm_error_count;
              unsigned      force_pulse_read:1;
              unsigned      get_serno      :1;
              unsigned      get_version    :1;
              unsigned      get_status     :1;
              unsigned      reset_status   :1;
                    unsigned      update_parameter:1;
                    unsigned      clear_pulse_regs:1;
                    }
                           PIC_status_t;
typedef
         enum   {
  sending_bits,
  sending_st5_bits,
              rcving_bits,
              do_PIC_start,
              sending_PIC_start,
              do_send_cmd,
              sending_start,
              sending_start_1,
              sending_stop,
              waiting_for_start,
              rcving_stop,
              idle
              }
                           PIC_s_stat_t;
typedef
      enum  {
   SET_PRE_ALIGN,
   DO_ALIGN,
   SET_NORMAL_PLC,
   DISCONNECT_COUPLER,
   READ_XMIT_LEVEL
          }
                ATM_op_t;
 typedef
       enum   {
   DO_PRESET,
   DO_PLC_SET,
   SET_ALIGN,
   WAIT_ALIGN,
   DO_ATM_DISCONNECT,
   ATM_DONE
           }
                           ATM_state_t;
 typedef
     struct{
         unsigned char   PIC_addr;
         unsigned char   command;
         unsigned char   reg_ID;
         unsigned long   command_data;
                    unsigned int      flags;
         int           bitCount;
         union {
             unsigned long bufLong[3];
             unsigned char bufByte[12];
            }bits;
         }
            PICbitBuf;
#ifndef BOOLEAN_DEFINED
#define BOOLEAN_DEFINED
typedef int BOOLEAN;
#endif
/* Definition of bits in Flags field of PIC comm buffers */
/* NOTE- Top 4 bits (0xf000) reserved for use by ATM code */
#define rcv_bad_addr_flag  0x0100
#define rcv_tpar_error_flag 0x0080
#define rcv_data_ready_flag 0x0040
#define rcv_bad_length_flag 0x0020
#define rcv_timeout_flag   0x0010
#define rcv_parity_err_flag 0x0008
#define PIC_error_flag    0x0004
#define PIC_need_refresh_flag 0x0002
#define PIC_invalid_data_flag 0x0001
/* Command codes for PIC communication */
#define MAX_FAST_READ          0x07
#define CLEAR_PULSE_REGISTERS  0x08
#define READ_REGISTER          0x10
#define WRITE_REGISTER         0x18
#define SYSTEM_CONTROL 0x19
/* Register ID codes for PIC communication */
#define MAX_PULSE_REG         15
#define CONTROL_REG    16
#define ERROR_REG     26
#define OUTPUT_REG     27
#define PARM_REG             28
#define VERS_REG              29
#define SERNO_REG           30
#define STATUS_REG          31
/* Special-purpose PIC addresses */
#define GLOBAL_PIC_ADDR  31 
#define MC5_MUX_PIC_ADDR 30
#define ST5_MUX_PIC_ADDR 29
#define LCM_BASE_ADDR   16/* First LCM is at address 16 */
#define ATM_BASE_ADDR   20/* First ATM is at address 20 */
#define MAX_PULSE_PIC_ADDR 15/* pulse couters are from 0 to 15 */
/* Bit usage in the ATM relay control word */
#define ATM_RC_XMIT_ON  0x00008000
#define ATM_RC_MEAS_XMIT 0x00004000
#define ATM_RC_MEAS_CPLR 0x00002000
#define ATM_RC_RES_SHORTED 0x00001000
#define ATM_RC_CAP_MASK  0x000003ff
#deftne ATM_NUM_CAP_BITS  10
#define ATM_PRESET_CODE ATM_RC_XMIT_ON|ATM_RC_MEAS_XMIT|
ATM_RC_MEAS_CPLR
#define ATM_PLC_CODE  ATM_RC_XMIT_ON|ATM_RC_RES_SHORTED
#define ATM_DISC_CODE   0
/* Other ATM control equates */
#define ATM_MEAS_TIME   20L   /* mSec to wait between cap change and ADC
reading */
#define ATM_DISC_TIME   20L   /* mSec to wait before switching cap relays */
#define ATM_MIN_READING  0x0038 /* If reading at end of autotune less than this,fail
*/
/* Equates for ST5 comm */
#define ST5_PIC_DELAY   66
#pragma region(″ram=ram″)
ref unsigned short      current_PIC_index, rcv_PIC_index;
ref PIC_status_t  PIC_status[MAX_PICS];
struct      {
    unsigned long  reading;
    int        error_cnt;
    unsigned char  ID_field[ID_FIELD_LENGTH];
    unsigned char  ID_buffer[ID_FIELD_LENGTH];
               } ref  pulseData[2*NUMPH];
 struct     {
     PICbitBuf  xmit_buf;
     PICbitBuf   rcv_buf;
     int      control_flags;
              } ref     ext_comm,PIC_comm_mon;
 struct       {
     ATM_op_t   operation;
     unsigned int ATM_number;
     ATM_state_t  state;
     unsigned    request_flag:1;
     unsigned    done_flag:1;
     unsigned    error_flag:1;
     unsigned     active_flag:1;
     unsigned int start_cap_code;
     unsigned int end_cap_code;
     unsigned int optimum_cap_code;
    unsigned int optimum_reading;
    unsigned int xmit_level;
    unsigned int coupler_level;
    unsigned int result_flags;
    long int   align_timer;
            } ref      ATM_control;
struct        {
    unsigned    request_flag:1;
    unsigned    done_flag:1;
    unsigned    error_flag:1;
    unsigned    active_flag:1;
    unsigned int xmit_mask;
    unsigned int rcv_mask;
    unsigned int result_flags;
    unsigned int last_xmit_mask;
    unsigned int last_rcv_mask;
             }ref     MUX_control;
struct        {
    unsigned   do_rebuild:1;
    unsigned   do_alarm:1;
            } ref     Comm_background_flags;
/* Bit definitions in ext_buf.control_flags */
#define SUPPRESS_NORMAL_COMM  0x0001
#define XMIT_REQUEST      0x0002 /* External routine requests send ofxmit_buf*/
#define CPY_RCV_DATA       0x0004 /* External cmd was sent,copy rcvd buffer to
rcv_buf */
#define RCV_DATA_RDY      0x0008 /* Got reply from external cmd,reply is in
rcv_buf */
#define XMIT_DATA_RDY      0x0010 /* xmit_bufhas copy of last cmd sent*/
ref PICbitBuf          PICxmitBuf,PICrcvBuf,HoldrcvBuf;
ref PIC_s_stat_t  PIC_serial_status;
ref unsigned int  num_PICs;
ref unsigned int  num_LCMs;
ref unsigned int  rebuild_timer;
ref unsigned int  ATM_work;
ref unsigned int  work_PIC_addr;
ref unsigned int  num_pulse_trs;
ref unsigned int  hold_num_pulse_ctrs;
ref unsigned int  bit_count;
ref unsigned int        out_bit_value;
refunsigned char  *shift_LSB_ptr;
refunsigned char  in_bit_value;
refunsigned int  PIC_wait_lirnit;
ref unsigned int  zero_count;
refunsigned int  last_comm_err_flag;
refBOOLEAN     dont_clear_PIC_stats;
ref int        ST5_PIC_delay_ctr;
ref unsigned int  PIC_bad_addr_count;
ref alarmstru    PIC_alarm;
#ifdef VATEST
/* test !!!! */
ref int              temp_command;
ref int              temp_reg_ID;
ref long       temp_command_data;
ref int              temp_flags;
/* test !!!! */
#endif
ref enum{
       clk_high,
       clk_low
       }            PIC_clk_state;
ref enum{
       NO_GLOBAL_SEND,
       SEND_GLOBAL_CLR,
       SENDING_GLOBAL_CLR,
       GLOBAL_CLR_SENT
       }         clear_state;
/* Old equates maintained for compatibility */
#if 0
#define RELAY_A_BIT 1
#define RELAY_B_BIT 2
#define IDLE 0
#define TX 1
#define RX 2
#define DATA_READY 3
#define WAKE 4
#define PIC_RESET 5
#define WAKE_COUNT_RELOAD(64*4)    /* Four Seconds */
#define RESET_COUNT_RELOAD 10    /* 1/4 Seconds */
#define RELAY_A_OFF_CMD 5               /*active low trigger*/
#define RELAY_A_ON_CMD 4
#define RELAY_B_OFF_CMD 7
#define RELAY_B_ON_CMD 6
#define CLEAR_ACC_CMD 8
#define SUBACC_CMD 12
#define ECHO_CMD 14
#define SLEEP_CMD 15
#define PULSE_SERIAL_COM_MAX 15
#define WAKE_CMD 16
#define RESET_CMD 17
#define PULSE_COM_NUM 18
#define NO_PULSE_BIT_DATA 0xFFFFFFFF
#define RELAY_CMD_MIN 4
#define RELAY_CMD_MAX 7
#endif
                           PULSEOUTM.DEF
#include ″clklink.def″
#include ″mtrlink.def″
#include ″plc.def″
#include ″serlink.def″
#include ″pulselink.def″
#ifndef NO_PULSES
#include ″scan.h″
#include ″pulse.h″
#include ″log.h″
void pulseout_second_back(void);
void pulseout_ram_init1(void);
ADDRFN pulseoutaddrfn;
#pragma region (″data=rarnInitl″)
void(*pulseout_rarn_init1p)(void)=pulseout_ram_init1;
#pragma region(″data=data″)
#pragma region(″data=secondBack″)
void(*pulseout_second_backp)(void)=pulseout_second_back;
#pragma region(″data=data″)
ADDRFN_RET pulscoutaddrfn(reg8stru reg8)
{
 /*write the load shed event to flash */
 putEvent(LOAD_SHED_EVENT,1 ,andreg8.ulong);
 return(0);
}
void pulseout_ram_init1()
{
 addrfn_tbl[GET_FROM_SLAVE][PULSEOUT_STATE]=pulseoutaddrfn;
}
void pulseout_second_back()
{
}
#endif

Claims (20)

1.一种利用电力线通信进行远程多通道电力计量的装置,包括:
多个计量点,位于配电变压器的副边,并能够操作以对多个电力用户线路中的每个的电力使用分别进行测量;
位于所述配电变压器的原边的转发器,所述装置能够操作以通过直接电力线通信向所述转发器发送数据或从所述转发器接收数据,所述转发器能够操作以向远程设置的计算机发送数据或从其接收数据;
一个或多个负荷控制模块,所述负荷控制模块能够操作以启动多个继电器中的每个继电器的连接和断开,所述多个继电器中的每个继电器都对应所述多个电力用户线路中之一;以及
包含所述多个计量点、所述负荷控制模块和所述继电器的盒,
其中,所述配电变压器将中压配电电压转化为适于向用户供电的低压电压,并且
所述装置能够操作以将信号注入向用户供电的低压电力线或从该电力线接收信号,所述信号在所述计量表头和所述转发器之间提供双向通信并经过所述配电变压器。
2.如权利要求1所述的装置,进一步包括与所述计量表头通信的篡改检测器。
3.如权利要求2所述的装置,其中所述篡改检测器包括光源和反射面,并且如果所述篡改检测器提供告知未检测到从所述反射面反射的光线的通知,那么所述计量表头则能够操作以指示所述负荷控制模块断开全部所述用户线路。
4.如权利要求2所述的装置,其中,所述篡改检测器包括对进入所述盒中的环境光进行检测的检测器。
5.如权利要求1所述的装置,其中,所述盒安装在电线杆上。
6.如权利要求1所述的装置,进一步包括,用于将变压器能量与所述用户线路使用的总能量进行比较的装置。
7.如权利要求1所述的装置,进一步包括,用于检测通过所述用户线路的反向电压流的装置。
8.如权利要求1所述的装置,进一步包括与所述计量表头通信的计算机可读的存储器以及与所述计量表头通信的计数器,所述计数器对应于用户线路并且能够操作以对存储在所述存储器中的能量的量进行倒计数,当所述计数器数到0时,所述计量表头能够操作以向所述负荷控制模块发送断开信号,以断开所述用户线路。
9.如权利要求1所述的装置,进一步包括与所述计量表头通信的计算机可读的存储器,所述存储器能够操作以存储用于用户线路的输出电能限制标准,当超出所述输出电能限制标准时,所述计量表头能够操作以向所述负荷控制模块发送断开信号,以断开所述用户线路。
10.如权利要求1所述的装置,进一步包括与所述计量表头通信的计算机可读的存储器,所述存储器能够操作以存储用于用户线路的电能消耗限度,当超出所述电能消耗限度时,所述计量表头能够操作以向所述负荷控制模块发送断开信号,以断开所述用户线路。
11.如权利要求1所述的装置,其中所述转发器能够操作以通过中压电力线与所述远程设置的计算机通信。
12.如权利要求1所述的装置,进一步包括与所述计量表头通信的显示单元,所述显示单元能够操作以显示从所述计量表头接收到的数据。
13.如权利要求12所述的装置,其中所述显示单元能够操作以显示与用户的能耗有关的信息。
14.如权利要求12所述的装置,其中所述显示单元能够操作以显示与用户的能量使用或能量的可疑窃取有关的警告。
15.如权利要求12所述的装置,其中所述显示单元能够操作以将用户输入的信息传送给所述计量表头。
16.如权利要求1所述的装置,其中,所述转发器能够操作以经由无线通信、光线和电话线中的至少之一与所述远程设置的计算机通信。
17.如权利要求1所述的装置,其中所述装置能够操作以用10-25kHz范围内的频率向所述转发器直接发送数据。
18.如权利要求1所述的装置,其中所述装置能够操作以用与60Hz的半奇次谐波相对应的频率向所述转发器直接发送数据。
19.一种用于多通道电力计量的装置,包括:
与配电变压器的副边电路通信的控制模块,所述配电变压器将中压配电电压转换为适于向用户供电的低压电压;
转发器,所述转发器与所述变压器的原边电路通信,所述控制模块能够操作以通过所述配电变压器经由直接电力线通信向所述转发器发送数据或从所述转发器接收数据,所述转发器能够操作以向远程设置的计算机发送数据或从其接收数据;
多个计量模块,每个计量模块都能够操作以对从所述配电变压器的所述副边电路馈送的、多个电力用户线路中之一上的电力使用进行测量;
一个或多个继电器,能够操作以启动到所述电力用户线路的电力的连接和断开;以及
包含所述控制模块、所述计量模块和所述继电器的盒,
其中,所述装置能够操作以将信号注入向用户供电的低压电力线或从该电力线接收信号,所述信号在所述计量表头和所述转发器之间提供双向通信,并经过所述配电变压器,以至少部分地在中压电力线上向所述远程设置的计算机通信。
20.如权利要求19所述的装置,其中所述一个或多个继电器能够操作以控制所述电力用户线路的每一相。
CN200680049289XA 2005-11-15 2006-11-15 用于多通道电力计量的装置和方法 Expired - Fee Related CN101351803B (zh)

Applications Claiming Priority (9)

Application Number Priority Date Filing Date Title
US73758005P 2005-11-15 2005-11-15
US60/737,580 2005-11-15
US73937505P 2005-11-23 2005-11-23
US60/739,375 2005-11-23
US11/431,849 US7539581B2 (en) 2000-02-29 2006-05-09 System and method for on-line monitoring and billing of power consumption
US11/431,849 2006-05-09
US81390106P 2006-06-15 2006-06-15
US60/813,901 2006-06-15
PCT/US2006/044762 WO2007094837A2 (en) 2005-11-15 2006-11-15 Apparatus and methods for multi-channel metering

Publications (2)

Publication Number Publication Date
CN101351803A CN101351803A (zh) 2009-01-21
CN101351803B true CN101351803B (zh) 2010-11-17

Family

ID=39643015

Family Applications (1)

Application Number Title Priority Date Filing Date
CN200680049289XA Expired - Fee Related CN101351803B (zh) 2005-11-15 2006-11-15 用于多通道电力计量的装置和方法

Country Status (6)

Country Link
EP (1) EP1960932B1 (zh)
CN (1) CN101351803B (zh)
AR (1) AR057593A1 (zh)
ES (1) ES2554499T3 (zh)
PL (1) PL1960932T3 (zh)
WO (1) WO2007094837A2 (zh)

Families Citing this family (5)

* Cited by examiner, † Cited by third party
Publication number Priority date Publication date Assignee Title
KR101161982B1 (ko) 2010-09-03 2012-07-03 엘에스산전 주식회사 원격 전기자동차 관리 시스템
EP3107218B1 (de) * 2015-06-19 2023-06-14 Gwf Ag Verfahren und vorrichtung zur datenübertragung sowie zählereinheit
US10886728B2 (en) * 2018-07-12 2021-01-05 Ovh Circuit implementing an AC smart fuse for a power distribution unit
CN111679112B (zh) * 2020-06-18 2022-06-28 杭州炬华科技股份有限公司 电能表窃电类型判断方法、装置、计算机设备和存储介质
CN113163274B (zh) * 2021-06-24 2021-09-14 深之蓝(天津)水下智能科技有限公司 一种水下机器人通信系统

Citations (4)

* Cited by examiner, † Cited by third party
Publication number Priority date Publication date Assignee Title
US20030001754A1 (en) * 1990-02-15 2003-01-02 Itron, Inc. Wide area communications network for remote data generating stations
CN2658986Y (zh) * 2003-10-08 2004-11-24 吕学军 一种电力计量控制箱
US20040257005A1 (en) * 2002-07-31 2004-12-23 Tom Poehlman Transient detection of end of lamp life condition apparatus and method
US20050137813A1 (en) * 2000-02-29 2005-06-23 Swarztrauber Sayre A. System and method for on-line monitoring and billing of power consumption

Family Cites Families (5)

* Cited by examiner, † Cited by third party
Publication number Priority date Publication date Assignee Title
US5696501A (en) * 1994-08-02 1997-12-09 General Electric Company Method and apparatus for performing the register functions for a plurality of metering devices at a common node
US5995601A (en) * 1998-09-30 1999-11-30 Lucent Technologies, Inc. Automatic remote meter reading system and method employing selectable line interface
US6177884B1 (en) * 1998-11-12 2001-01-23 Hunt Technologies, Inc. Integrated power line metering and communication method and apparatus
EP1379012A1 (en) * 2002-07-03 2004-01-07 Aydin Özalp Integrated and automated water, gas and electricity meter reading via power line carrier
US7058524B2 (en) * 2002-10-25 2006-06-06 Hudson Bay Wireless, Llc Electrical power metering system

Patent Citations (4)

* Cited by examiner, † Cited by third party
Publication number Priority date Publication date Assignee Title
US20030001754A1 (en) * 1990-02-15 2003-01-02 Itron, Inc. Wide area communications network for remote data generating stations
US20050137813A1 (en) * 2000-02-29 2005-06-23 Swarztrauber Sayre A. System and method for on-line monitoring and billing of power consumption
US20040257005A1 (en) * 2002-07-31 2004-12-23 Tom Poehlman Transient detection of end of lamp life condition apparatus and method
CN2658986Y (zh) * 2003-10-08 2004-11-24 吕学军 一种电力计量控制箱

Non-Patent Citations (1)

* Cited by examiner, † Cited by third party
Title
US 20030001754 A1,全文.

Also Published As

Publication number Publication date
EP1960932A2 (en) 2008-08-27
EP1960932B1 (en) 2015-08-12
AR057593A1 (es) 2007-12-05
WO2007094837A2 (en) 2007-08-23
EP1960932A4 (en) 2012-10-31
ES2554499T3 (es) 2015-12-21
WO2007094837A3 (en) 2008-05-02
PL1960932T4 (pl) 2016-03-31
CN101351803A (zh) 2009-01-21
PL1960932T3 (pl) 2016-03-31

Similar Documents

Publication Publication Date Title
US7596459B2 (en) Apparatus and methods for multi-channel electric metering
US7064679B2 (en) Electronic electric meter for networked meter reading
US5994892A (en) Integrated circuit design automatic utility meter: apparatus & method
US20080136667A1 (en) Network for automated meter reading
US20110181438A1 (en) Meter device with supporting communications
CN101351803B (zh) 用于多通道电力计量的装置和方法
WO1998010299A1 (en) Electronic electric meter for networked meter reading
US8253585B2 (en) Three-phase multifunction verifier
CA2677499C (en) Self contained kilowatt-hour meter integral to standard load center
CN213715749U (zh) 一种台区综合分析仪
EP0742443A2 (en) Improvements in or relating to electricity meters
CA2527068C (en) Apparatus and methods for multi-channel metering
CA2567955A1 (en) Apparatus and methods for multi-channel metering
JP4433576B2 (ja) 遠隔検針用計量装置
KR200254759Y1 (ko) 통신 방식 선택식 원격 검침용 전자식 전력량계
MX2008007018A (en) Apparatus and methods for multi-channel metering
Al-Qatari et al. Microcontroller-based automated billing system
CN101496301A (zh) 用于电力计量的系统和方法
KR20050052872A (ko) 원격검침 일체형 전자식 전력량계 및 이를 이용한 원격검침 시스템
BRPI0806143B1 (pt) Aparelhos para medição de multi-canal de eletricidade
HRP980578A2 (en) Arrangement for measuring the electric power consumption in marinas, campsites and similar

Legal Events

Date Code Title Description
C06 Publication
PB01 Publication
C10 Entry into substantive examination
SE01 Entry into force of request for substantive examination
C14 Grant of patent or utility model
GR01 Patent grant
CF01 Termination of patent right due to non-payment of annual fee

Granted publication date: 20101117

Termination date: 20191115

CF01 Termination of patent right due to non-payment of annual fee