MAXQ3120电表(EM)参考设计构建了一款多功能、多费率电表,它符合世界范围的全部可用标准。参考设计构成了一款能够适合各地要求和各种性能要求的电表原型。这篇文档将指导软件工程师,通过定制代码实现一些特殊的需求。
目标读者
本文档假定读者熟悉C语言、MAXQ20微控制器架构以及汇编语言。读者也需熟知全电子式电表的基理。
工具
电表参考设计采用IAR Embedded Workbench工具进行编译。为便于将软件移植到其它开发环境中,除了一种例外情况外,整个软件避免了与IAR相关的语言特性。这种例外情况位于汇编语言文件中,其中包括了一些对标准汇编伪指令集的特定IAR扩展。这些特定IAR扩展命令,不仅可告知连接器各不同段的分配情况,而且告知调试器有关某些机器资源的变化情况。在其它开发环境下构建工程,可将这些伪指令去除。
高层硬件描述
硬件的核心器件是MAXQ3120微控制器。MAXQ3120几乎囊括了实现多功能、多费率电表所需要的所有功能,这些功能包括:双通道、高精度A/D转换器(ADC),一个乘法累加器(MAC),通信端口和一个显示控制器。完成一个电表设计,仅需要少量的外部元件。
在参考设计中,提供两个通信通道:一路红外通道,包含一个可解码38kHz载波频率的接收模块和一个直接由微控制器驱动的红外LED,一路完全隔离的RS-485通道;用作非易失存储器的128kb I2C EEPROM;一个可视LED和一路隔离光耦通道,用于指示电表脉冲;一个用于设置网络地址的按钮;和一个用于显示的LCD。
这种硬件构成预示着以下一些应用信息。选择一个外置I2C EEPROM,意味着系统中必须包含I2C软件,而不提供硬件I2C主机。电表脉冲硬件意味着软件必须能够产生极为精确的脉冲定时。两路通信端口表明,微控制器有限的资源要被两路通道所共享。
软件系统综述
软件系统必须同时跟踪多个进程。首先也是最重要的一点,软件系统必须监测ADC,计算用电量并报告其它额外信息,这些信息包括RMS电压和电流、功率因数和峰值功率。这个基本进程非常关键,其它任何进程都不能干扰这个最重要的基础任务。在持续监视用电量的同时,软件还必须驱动显示、监视两路通信端口、监视按钮以及电力线路上的电源失效事件,完成从外部EEPROM获取信息的请求,并跟踪费率时段的变化。
任务管理方式
初始一看,要完成以上多个实时任务,迫切需要某种实时操作系统(RTOS)来进行调度管理和资源分配。但进一步分析后,就会发现不用传统RTOS的两个充分理由。
首先,要求即时响应ADC中断。当ADC有可用的采样数据时,必须在48μs内提取该采样数据。并且,当检测到一个过零点时,电源周期处理程序为了在下一个电源周期之前完成执行操作,必须独占CPU资源。(电源周期处理程序将占用CPU运算能力的25%到30%。) 尽管RTOS可以满足这些要求,却不能最有效地利用资源。
其次,用于保存任务上下文的空间非常有限。大多数RTOS都要给每个任务提供一个完整的虚拟处理器,以在其中执行操作,而这需要保存各个任务的上下文。由于仅有256个16位字RAM可供使用,少量任务就会耗尽存储器空间。
所以,本参考设计选择了一个简单的任务轮。在这种配置方式下,任务会被按顺序调用,而每个任务在锁定事件发生时,都要释放CPU的控制权。锁定事件是指所有其它任务都必须等待的事件,它包括:从EEPROM中提取数据,等待一个电源周期或是等待通信通道上的字符。如果当前任务需要等待其它任务完成时才能结束自身任务,这时也会产生一个锁定事件。在任何锁定事件中,任务必须存储它的当前状态并返回任务轮。这种协作式多任务机制,使得一个处理能力相对低些的控制器就能够胜任工作。
任务间的通信是通过一组公共数据结构来完成的,这些数据结构要根据一套严格的规则才允许被修改。这些数据结构中最重要的部分是消息板,当发生某个事件时,一个任务要设置消息板中的一组数据位以通知另一个任务。例如,假设接收到一个消息并将其正确译码,则消息译码器任务会告知另一个需要该消息的任务(比如寄存器管理器)已经收到了消息,并要求第二个任务必须执行某些操作。
缺省任务列表
以下是参考设计中采用的缺省任务列表:
DSP:对应每个电源周期,这个程序会计算电力线路的所有参数,并累加本电源周期的用电量。
串口驱动器:检测两路通信通道的状态,并将第一个发出字符的通道置为“活动”通道。在消息检查器任务确定消息完成或产生超时之前,通道将始终保持活动状态。
消息检查器:验证输入字符串符合协议规范,并在完整接收消息后通知消息译码器。
消息译码器:解释接受到的消息并执行相应的请求操作。
异步事件管理器:执行那些不是按照时间表进行的事件任务,比如峰值检测和电能累计。
时段表管理器:周期性检查时钟,并按照时段表调整费率寄存器的值。
显示管理器:根据时间和其它事件刷新LCD显示。
消息格式器:为消息译码器解释的消息准备回复信息。
消息构建器:接收格式化后的消息并加上用于传输的消息头和消息尾。
寄存器管理器:执行读/写EEPROM操作。
计时管理器:通告按固定时基启动的任务。
负载曲线记录器:被请求时,向EEPROM记入用电量,便于将来报告这些数据。
添加任务
如电表参考设计中所定义,任务是一段单线程代码,它执行电表要求的某项功能,并快速(通常只有几毫秒)返回调用函数。然而,大多数任务都需要比这更长的时间才能完成。比如,在任何合理的速率下发送一个消息都需要多个周期。因此,大多数任务都需要一个状态变量,以便将其分解为数个子任务。
一旦任务编写完成,你就可以在spintaskwheel.c文件的任务列表中加入该调用。注意,你可以将任务加在执行流程的任何位置,并根据你的需要多次频繁调用它。你将发现,DSP任务调用非常频繁,串口驱动器SerialPortDriver任务也被调用了几次。因为要保持电能测量的完整性,DSP任务不允许被搁置数个周期,同时不允许SerialPortDriver任务错过输入字符。
最后,测试你的代码。任务轮循环时,你的新任务将伴随其它任务被调用。
全局变量
由于未使用真正意义上的多任务操作系统,也就意味着不会有编程人员所熟知的、真正意义上的消息传递、信号量或其它机制。通信是通过上文提到的消息板以及一组全局变量实现的,各个任务必须按照严格的规则来设置和读取这些变量信息。这些全局变量列举如下:
g_CommSystEMState: 这个变量包括一组通信通道控制位。具体来说,每个通道包括:一个active (活动)位,用于指明某个特定通道处于活动状态(从而可丢弃到达另一个通道的字符);一个TBE位,用于使闲置通道做好工作准备;以及一个data loss (数据丢失)位,当闲置通道收到字符而另一通道正忙于通信时,该位被置高。
g_TransmitByte; g_ReceiveByte: 分别保存着下一个要传送的字节和最新接收到的字节。
g_CommBuffer: 一个50字节数组,包含刚接收到的消息或要发送的消息。注意系统仅有一个通信缓存。它不仅被两个通信通道所共享,也被发送和接收通道所共享。
g_MeterAddress: 一个包含电表网络地址的6字节数组。初始化时从EEPROM内读取该信息,并存放在RAM中。
g_MessageFormatterData; g_DispFormatterData; g_ScheduleManagerData; g_AEMData; g_LCLRegData: 这些寄存器在寄存器管理器和各种任务间传送数据。例如,一个需要发送的寄存器内容,会被寄存器管理器放入g_MessageFormatterData中。
g_AEMRegisterNeeded; g_DispFormatterRegRequest; g_RequestScheduleManager; g_LCLRegRequest: 这些寄存器里,包含了特定任务需要读或写的寄存器。注意,消息译码器没有全局地址寄存器:寄存器管理器可以智能地从消息缓存中找出这个信息。
g_LCDMode: 包含显示器的模式字节。见下面的显示定制部分。
g_TariffInEffect: 包含当前有效的费率号码。这个函数有自己的全局变量,以便每次累计电能时,无需通过多次EEPROM读操作来确定将采样值存在什么位置。
g_PW: 包含当前有效的各个通信通道的口令号码。
g_irTimer; g_rsTimer: 用于计数各个通道口令有效时间的定时器。一旦接收到口令后,它的有效期限是60秒。一个口令的有效时间结束后,g_PW中相关的4位数据就会被清零。
g_LoadCurveUsage; g_LoadCurvePeak; g_LoadCurveTimeStamp: 与负载曲线记录任务相关的变量。g_LoadCurveUsage累计用电量,并会最终报告给负载曲线记录任务。负载曲线记录任务会定
期地将该值写入EEPROM并随后清除该变量。
g_LoadCurvePeak和g_LoadCurveTimeStamp跟踪负载曲线的最大功率值,并记录峰值功率产生的间隔和时间。
AEMState: 包含一组与异步事件相关的变量。当接收到一个设置电表地址消息时,msg_rx标志被置为高。地址设置逻辑电路被激活后,变量timer包含恢复正常显示所需的秒数。DSPState和Register变量跟踪寄存器用电量信息从DSP逻辑传送到用电量报告函数的过程。通常,寄存器变量包括所有用电类型(有功、无功、正功率和负功率等)。
g_new_baud: DL/T 645协议规范提供了一种只改变单个消息波特率的机制。当收到波特率变更请求并得到确认后,下一个消息就会以更高的波特率传送。随后,波特率恢复到正常值(本设计中采用1,200bps)。g_new_baud总是保存下一个消息的波特率。
g_TransmitDelay: 一些RS-485转换器在发送完最后一个字符后会延迟一段固定时间,随后切换回接收模式。因此,当主机传送完一个请求后,它可能会丢失电表发送的前几个字符,因为与主机串口相连的RS-485转换器仍处在发送模式下。这个变量保存了发送状态保持的固定延时,延时结束后主机的RS-485转换器切换回接收模式。
current_temp: 如果引用该变量,它将包含从DS3231 RTC/温度传感器中读出的最新数值。
定制功能
本参考设计符合DL/T 645-多功能、瓦时电表通信协议。但这篇文档不仅仅对通信协议进行说明。DL/T 645确实对一个多功能电表需要执行的操作进行了规定,包括测量、时段管理和报告功能。因此,如果你要选择其它电表协议,你必须替换掉寄存器管理器以及除串口管理器之外的所有消息函数,或者至少对其进行重大修改。修改的细节不在本文讨论范畴内。
本文档将着重讨论三个定制领域:显示定制、寄存器映射定制和DSP函数定制。 [page]
显示定制
显示器完全由显示管理器控制。其它任何任务都不会向MAXQ3120的LCD寄存器写入数据。DisplayFormatter.c模块包含了显示管理器及其主要子程序UpdateLCD。
如果你只是想在电表中使用一个不同的LCD模块,则只需修改UpdateLCD。所以我们将从这个模块的定制开始说起。如果你想改变显示信息的类型,你就要修改DisplayManager,并且可能需要给电表的其它部分提供额外的钩子(hook)函数。
定制UpdateLCD
UpdateLCD接收两个参数:一个待显示的32位数值和一个8位信号指示器数值 。32位显示值包括8个4位数值。因此,UpdateLCD支持8位、7段显示器。注意,MAXQ3120支持112段显示,所以可以定制该程序以支持更大规模的显示器。 如果想用不同的显示器,你需要修改LCDFont结构。它被定义为static const类型。这样定义的结构进行编译和连接后,将驻留在程序空间,而不是数据空间。
LCD空间分配表:
这里有个重要的假设:每个字符都可填入一个LCD寄存器。如果所采用的LCD结构中,属于1位显示的某些段要占用多个LCD寄存器,则需要修改整个UpdateLCD。
数字的显示顺序是什么?
程序假设最右端的显示数字,是32位显示参数的低四位。这是最自然的顺序;如果你将“123456”传递给参数,则显示器会显示“123456”。
信号指示器
如果你想在显示特定信息的情况下,同时点亮特定的信号指示器,则需要另外一个8位变量来存储指示信息。UpdateLCD程序使用一个switch结构,以在显示数字之后马上点亮这些指示器。
特殊状态显示
在displayformatter.c文件的最后还有一组程序。这些程序控制特殊状态显示,例如电表初始化、EEPROM初始化和程序故障(异常)。它们被直接写入LCD寄存器,而且要针对不同的显示进行定制。
定制显示管理器
除了显示用电量、时间和日期以外,如果你还想显示其它信息,则需要修改显示管理器。
显示管理器的第一部分,处理电表地址设置信息的显示。仅当地址设置按钮被按下时才起作用,不需要修改这一部分。
显示管理器的其它部分,通过全局变量g_LCDMode来获取类别。为确定要显示的下一个条目,这个变量在一个字节内包括了所有必要的信息。它的格式如下所示:
总会显示电表使用过程中累计的总用电量,并显示由g_LCDMode字节所指定的条目。在本参考设计中,这个变量被固定为1―除了显示总用电量以外,只显示时间和日期。
控制变量
显示管理器由状态变量disp所控制,该变量有两个元素:ItEM和State。由名字可以得知,disp.State存放显示控制器的当前状态,而disp.Item跟踪将要显示的信息,具体含义如下:
定制这个程序提供两种选项。你可以选择改变disp.Item的赋值,以及改变程序中它们的选择顺序,或者你可以选择完全替换掉该程序。后一种选择可能更好。如果为可能显示的每个条目指定一个独立位,或为可显示条目分配一个列表索引,显然这样的条目选择结构更加灵活。选择上面的结构是因为它需要的RAM空间最小。
添加寄存器
DL/T 645规定了大量寄存器,用于控制电表运行的各个方面。每个寄存器由一个16位寄存器号指定。在参考设计中,增加了很多寄存器来控制电表运行的各个方面;在代码中给出了这些寄存器的说明。本讨论内容提供了必要的信息,以便通过扩展寄存器映射从电表中获取更多信息,或者控制新的电表运行特性。
寄存器管理器如何工作
所有任务都不能挂起正常的任务轮操作,寄存器管理器任务要遵循这一原则有很大难度。这是因为寄存器管理器是唯一能够读/写EEPROM的任务,并且EEPROM写操作需要(相对)较长的时间―几个毫秒。因为每20ms (60Hz环境下是16.7ms)就要为DSP程序提供处理器时间,寄存器管理器在EEPROM写周期过程中,绝不允许将系统挂起几十毫秒的。
要解决EEPROM写入时间问题,一个显而易见的方法是将I2C程序置为中断处理方式。这样一来,寄存器管理器可以启动一个EEPROM传输过程,随即返回主函数入口main();之后每次被调用时,寄存器管理器都会通过检查EEPROM子系统的状态,来确定任务是否已经完成。采用这种方案带来一个问题,ADC周期非常短,以至于ADC中断服务程序需要独占中断子系统。因此,必须采取一些其它保障机制。
解决的方法是采用一个全局标志位:EEPROMOpPending。当这个标志位为低时,任务轮实质上是一个无限循环过程,反复调用系统中的每一个任务。当标志位为高时,任务轮被调用时执行一次并返回,并不调用寄存器管理器。这样有什么帮助吗?
当寄存器管理器需要执行一个耗时很长的功能时,它启动这个功能并通过轮询来确定其是否完成。在轮询期间,寄存器管理器将EEPROMOpPending置为高,并递归调用任务轮。下面的代码给出了一个实际例子:
01: uint8 ReadEEPROM(uint16 Address, uint8 Length, uint8 *pData)
02: {
03: int i;
04: g_MessageBoard.EEPROMOpPending = 1;
05: for(i=0; i
06: {
07: if(i>0)SpinTaskWheel();
08: eeprom_address = Address++;
09: while(eeprom_read_byte())
10: S
pinTaskWheel();
11: *pData++ = eeprom_data;
12: } // for
13: g_MessageBoard.EEPROMOpPending = 0;
14: return 1;
15: }
在上面的第4行,EEPROMOpPending标志位被置为高。在第7和10行中,SpinTaskWheel被调用。如果EEPROM标志位为高时调用任务轮,则SpinTaskWheel函数运行一次,并在不调用寄存器管理器的情况下返回。这样,即使由于寄存器管理器等候EEPROM完成操作而停止下来,电表的其它部分仍可持续正常运行。
哪些任务知晓这些寄存器?
只有两个任务知道寄存器号:寄存器管理器和消息译码器。这些程序中,通常只需要对寄存器管理器进行修改。消息译码器识别出与口令管理和其它监控功能有关的寄存器,并且必须在采用正常处理规则之前获取这些信息。因此,要构建自己的寄存器,只需要熟悉寄存器管理器。 三类寄存器
通常,有三类寄存器:只读、读写和具有额外功能的读写寄存器。只读寄存器的一个例子是B611,RMS Volts、phase A。主机向这个寄存器写数据是不能执行的;实际上,如果电表收到写数据会将其丢弃。而且,多数只读寄存器都不在EEPROM中:通常,在线计算这些寄存器的结果,并根据需要报告结果。
读写寄存器的一个例子是C032,Meter Number (电表号)。写入数值不会对电表操作产生任何影响,而且可以随时提取该数据。最后,一个具有额外功能的读写寄存器例子是C030,Meter Constant, active (有效电表常数)。当这个寄存器被写入数据时,寄存器管理器不仅要更新EEPROM,同时也要更新DSP程序使用的电表常数。
哪些任务需要寄存器信息?
下表列出了需要寄存器信息的任务。
通常,你主要考虑添加可通过消息译码器访问的寄存器。你可以增加用于显示的寄存器(或者用于其它任务的寄存器,但是依据惯例,你会主要考虑那些可通过通信端口检索的寄存器)。
读写寄存器
首先考虑第一种情况,即存储和读取无额外功能的读写寄存器。为了添加一个存储于EEPROM内的寄存器,你必须添加两处信息:MAXQ3120RD.h文件和寄存器管理器中的ProcessRegisterNumber程序。
MAXQ3120RD.h包含一个由typedef定义的名为EEPROM_DATA的数据类型。这个定义并没有被真正实例化;而仅仅是作为模板,用于定义数据如何存入EEPROM。在EEPROM_DATA定义的下面,还定义了两个宏,用来返回两个值,分别是结构中某成员的偏移地址和某成员占用的字节数。定义新寄存器的第一步,是在结构中添加成员(最好是在尾部),从而为寄存器分配EEPROM存储空间。
下一步是定义寄存器号。这需要编辑寄存器管理器中定义的RegParmTable结构。这个表包含了电表中定义的每个寄存器,并按编号排序。每个成员包括:
寄存器号,16位无符号值。
物理数据单元编号,用于计算实际寄存器值。例如,寄存器9110请求当月总的正向无功用电量。它是两个电能累加器的和:包括1象限的用电量和4象限的用电量。因此,物理单元的个数是二。寄存器管理器必须提取指定单元(CurrentQuadrant1AccumTariff)和下一个单元(CurrentQuadrant4AccumTariff)的数据,并求和以获得所需信息。
每个单元的长度,以字节为单位。[page]
存储的数据类型:INT_REG,表示寄存器包含被视为整数的二进制数据;
BCD_REG,表示寄存器包含的是传输前无需进一步转换的BCD码数据;或者MDH_REG,表示寄存器包含的是日期信息(月:日:小时)。
EEPROM中数据的偏移量(单位为字节数)。
为了节约处理时间,ProcessRegisterNumber程序采用二元搜索算法找出寄存器地址。因此,表格保持排序状态是非常重要的。如果寄存器表变得无序,结果就无法预料了。
一旦表格被更新,新的寄存器可以通过通信通道进行读写。电表到底如何处理该信息,是下一部分的主要内容。
具有额外功能的读写寄存器
还有一种应用情况,即你想让一个写事件触发额外的功能。为了达到这种效果,必须让寄存器管理器向额外任务发送一个消息,或者更新执行额外功能所涉及的RAM内容。作为样例说明,可在寄存器管理器中搜索C030,你会找到下面这段代码:
switch(Register.Word)
{
case 0xC030: // Meter constant, real
action_value = 0;
for(i=4; i>1; i--)
{
action_value *= 100;
action_value += (g_CommBuffer.Message[ i] & 0xf) +
(g_CommBuffer.Message [ i] >> 4) * 10;
}
set_E_pulse(action_value); // this will set E_pulse
break;
这段代码在EEPROM的寄存器数据更新完毕之后运行。在这个条件下,主机请求改变电表常数。存储在EEPROM中的电表常数寄存器更新过后,传输到通信缓冲器的毫秒数值被转换成内部电表单位,并通过set_E_pulse函数发送给DSP程序。
只读寄存器
一些只读寄存器只是简单地从EEPROM中读取数据(如用电量),并通过电表的其它进程来更新其中的数据。然而,另外一些只读寄存器(如RMS电压)并未存储在EEPROM内。这些寄存器数据存储在EEPROM内是没有任何意义的,而且如果这样做并连续更新数据,会迅速损耗EEPROM!你可以在ProcessRegisterNumber中的表格注释里找到这些寄存器,表述为“not stored in EEPROM”(未存储在EEPROM内)。
这些寄存器由寄存器管理器的GetSpecialRegister程序来控制。对应每个只读寄存器,程序都在switch分支选择语句中提供相应的条件。例如:
case 0xB611:// voltage (phase A)
g_MessageBoard.EEPROMOpPending = 1;
Request_RMS(RMS_VOLTAGE_REQUEST);
SpinTaskWheel();
while(!(DSP_CTRL & 0x20))
SpinTaskWheel();
*value = Get_RMS() / 1000;
g_MessageBoard.EEPROMOpPending = 0;
*size = 2;
break;
这个例子阐明了一个重要事实,即任何任务都不能挂起任务轮。case的第一条语句将消息板中的EEPROMOpPending标志位置为高。然后它要求DSP函数计算RMS电压值,并在DSP函数忙时递归调用任务轮。当EEPROMOpPending标志位置为高后,执行一次任务轮循环,并且不调用寄存器管理器,从而避免了无限递归。一旦DSP函数完成,将提取RMS值并清除EEPROMOpPending标志位。
请注意,对于这种类型的只读寄存器,不必在MAXQ3120RD.h文件中添加结构来保留EEPROM存储空间。也不必向ProcessRegisterNumber表添加成员。在处理基于EEPROM的寄存器之前,寄存器管理器主程序总要调用GetSpecialRegister。
定制DSP程序
参考设计的DSP程序是一套汇编语言模块,它负责处理从ADC到脉冲生成以及报告电压、电流、功率和用电量的整个信号流。大部分程序不需要修改,但也许你希望修改以下方面:
采用一个不同的电流或电压变换器,从而需要不同的增益因子。
改 变系统生成电表脉冲的方式。
改变前端滤波。
DSP程序是如何工作的,以及你可以安全地改变哪些单元,以下部分从较高的层次对此进行了说明。
注意:DSP模块以预编译的目标文件形式公开发布。只有在签署了保密协议(NDA)的情况下才可以提供汇编语言源代码。更多信息,请联系Dallas SEMiconductor/Maxim。
存储
DSP程序用到RAM空间的低地址部分。在DSP模块中搜索“Data Memory Map”,可以看到DSP程序用到的一系列RAM变量。前两个字节是一组控制DSP函数运行的数据位。
常数
可通过调整两个常数来设置电压和电流通道的满量程读数。它们分别是W_V_Scale和W_I_Scale。缺省情况下,这两个常量被设置为400V和250A。电压被设置为正常条件下不会超越的电平值(280VRMS以上),而电流设定值与可能的电表分流值相一致(250μ至500μ,典型值)。
接口程序
用户程序可以直接使用一些内置程序的返回值。如果可能,你应该通过这些内置程序与DSP函数接口,而不是直接与DSP函数使用的内部变量接口。
Get_and_Clear_Usage: 这是C代码用来提取电量累计值的主程序。通常情况下,需要对用电量进行累计时,DSP程序会通知异步事件管理器。然而,随时都可以调用这个程序以获取精确的用电量读数(截至当前)。注意,IAR编译器会自动传递A[0]内的函数参数,并将结果返回给A[0]。
Get_Frequency: 返回0.1mHz步长的线路频率。值得注意的是,这个子程序缺省情况下并未加载;DL/T 645标准并未要求频率结果。
Get_Power_Factor: 返回负载的功率因子。
Get_Power: 根据参数不同,返回无功或有功功率。
Get_MaxD: 返回自上次调用该函数后,电表记录的最大需量(功率)值。
Request_RMS: 根据参数不同,要求DSP计算RMS电流或电压值。
Get_RMS: 返回最近一次请求的RMS值。
set_E_pulse: 接受一个电表常数,并设置适当的DSP变量以使该电表常数生效。
中断服务程序
参考设计只使能了一个中断:就是AFE中断,ADC上有一组新的采样数据时产生该中断。因为ADC采样周期为48μs,实际上中断服务程序会很快地结束它的工作,并返回到主代码中―在两个中断之间只有384个指令周期!
中断服务程序执行以下功能:
生成输出脉冲:如果需要一个脉冲,则启动它。如果脉冲正在进行中,则递减持续时间计数器的值,并在计数器回零时终止脉冲。
累加求和:将最近的能量采样值累加到所有适当的寄存器中。
累计RMS值:如果被请求,则累计I2或V2。
检查电压下限:如果电压低于门限值,则递增一个计数器值。
过零检测:如果电压信号正向过零,则设置一个标志位。
关键字:MAXQ3120 电表 定制功能
引用地址:MAXQ3120电表参考设计的定制功能
目标读者
本文档假定读者熟悉C语言、MAXQ20微控制器架构以及汇编语言。读者也需熟知全电子式电表的基理。
工具
电表参考设计采用IAR Embedded Workbench工具进行编译。为便于将软件移植到其它开发环境中,除了一种例外情况外,整个软件避免了与IAR相关的语言特性。这种例外情况位于汇编语言文件中,其中包括了一些对标准汇编伪指令集的特定IAR扩展。这些特定IAR扩展命令,不仅可告知连接器各不同段的分配情况,而且告知调试器有关某些机器资源的变化情况。在其它开发环境下构建工程,可将这些伪指令去除。
高层硬件描述
硬件的核心器件是MAXQ3120微控制器。MAXQ3120几乎囊括了实现多功能、多费率电表所需要的所有功能,这些功能包括:双通道、高精度A/D转换器(ADC),一个乘法累加器(MAC),通信端口和一个显示控制器。完成一个电表设计,仅需要少量的外部元件。
在参考设计中,提供两个通信通道:一路红外通道,包含一个可解码38kHz载波频率的接收模块和一个直接由微控制器驱动的红外LED,一路完全隔离的RS-485通道;用作非易失存储器的128kb I2C EEPROM;一个可视LED和一路隔离光耦通道,用于指示电表脉冲;一个用于设置网络地址的按钮;和一个用于显示的LCD。
这种硬件构成预示着以下一些应用信息。选择一个外置I2C EEPROM,意味着系统中必须包含I2C软件,而不提供硬件I2C主机。电表脉冲硬件意味着软件必须能够产生极为精确的脉冲定时。两路通信端口表明,微控制器有限的资源要被两路通道所共享。
软件系统综述
软件系统必须同时跟踪多个进程。首先也是最重要的一点,软件系统必须监测ADC,计算用电量并报告其它额外信息,这些信息包括RMS电压和电流、功率因数和峰值功率。这个基本进程非常关键,其它任何进程都不能干扰这个最重要的基础任务。在持续监视用电量的同时,软件还必须驱动显示、监视两路通信端口、监视按钮以及电力线路上的电源失效事件,完成从外部EEPROM获取信息的请求,并跟踪费率时段的变化。
任务管理方式
初始一看,要完成以上多个实时任务,迫切需要某种实时操作系统(RTOS)来进行调度管理和资源分配。但进一步分析后,就会发现不用传统RTOS的两个充分理由。
首先,要求即时响应ADC中断。当ADC有可用的采样数据时,必须在48μs内提取该采样数据。并且,当检测到一个过零点时,电源周期处理程序为了在下一个电源周期之前完成执行操作,必须独占CPU资源。(电源周期处理程序将占用CPU运算能力的25%到30%。) 尽管RTOS可以满足这些要求,却不能最有效地利用资源。
其次,用于保存任务上下文的空间非常有限。大多数RTOS都要给每个任务提供一个完整的虚拟处理器,以在其中执行操作,而这需要保存各个任务的上下文。由于仅有256个16位字RAM可供使用,少量任务就会耗尽存储器空间。
所以,本参考设计选择了一个简单的任务轮。在这种配置方式下,任务会被按顺序调用,而每个任务在锁定事件发生时,都要释放CPU的控制权。锁定事件是指所有其它任务都必须等待的事件,它包括:从EEPROM中提取数据,等待一个电源周期或是等待通信通道上的字符。如果当前任务需要等待其它任务完成时才能结束自身任务,这时也会产生一个锁定事件。在任何锁定事件中,任务必须存储它的当前状态并返回任务轮。这种协作式多任务机制,使得一个处理能力相对低些的控制器就能够胜任工作。
任务间的通信是通过一组公共数据结构来完成的,这些数据结构要根据一套严格的规则才允许被修改。这些数据结构中最重要的部分是消息板,当发生某个事件时,一个任务要设置消息板中的一组数据位以通知另一个任务。例如,假设接收到一个消息并将其正确译码,则消息译码器任务会告知另一个需要该消息的任务(比如寄存器管理器)已经收到了消息,并要求第二个任务必须执行某些操作。
缺省任务列表
以下是参考设计中采用的缺省任务列表:
DSP:对应每个电源周期,这个程序会计算电力线路的所有参数,并累加本电源周期的用电量。
串口驱动器:检测两路通信通道的状态,并将第一个发出字符的通道置为“活动”通道。在消息检查器任务确定消息完成或产生超时之前,通道将始终保持活动状态。
消息检查器:验证输入字符串符合协议规范,并在完整接收消息后通知消息译码器。
消息译码器:解释接受到的消息并执行相应的请求操作。
异步事件管理器:执行那些不是按照时间表进行的事件任务,比如峰值检测和电能累计。
时段表管理器:周期性检查时钟,并按照时段表调整费率寄存器的值。
显示管理器:根据时间和其它事件刷新LCD显示。
消息格式器:为消息译码器解释的消息准备回复信息。
消息构建器:接收格式化后的消息并加上用于传输的消息头和消息尾。
寄存器管理器:执行读/写EEPROM操作。
计时管理器:通告按固定时基启动的任务。
负载曲线记录器:被请求时,向EEPROM记入用电量,便于将来报告这些数据。
添加任务
如电表参考设计中所定义,任务是一段单线程代码,它执行电表要求的某项功能,并快速(通常只有几毫秒)返回调用函数。然而,大多数任务都需要比这更长的时间才能完成。比如,在任何合理的速率下发送一个消息都需要多个周期。因此,大多数任务都需要一个状态变量,以便将其分解为数个子任务。
一旦任务编写完成,你就可以在spintaskwheel.c文件的任务列表中加入该调用。注意,你可以将任务加在执行流程的任何位置,并根据你的需要多次频繁调用它。你将发现,DSP任务调用非常频繁,串口驱动器SerialPortDriver任务也被调用了几次。因为要保持电能测量的完整性,DSP任务不允许被搁置数个周期,同时不允许SerialPortDriver任务错过输入字符。
最后,测试你的代码。任务轮循环时,你的新任务将伴随其它任务被调用。
全局变量
由于未使用真正意义上的多任务操作系统,也就意味着不会有编程人员所熟知的、真正意义上的消息传递、信号量或其它机制。通信是通过上文提到的消息板以及一组全局变量实现的,各个任务必须按照严格的规则来设置和读取这些变量信息。这些全局变量列举如下:
g_CommSystEMState: 这个变量包括一组通信通道控制位。具体来说,每个通道包括:一个active (活动)位,用于指明某个特定通道处于活动状态(从而可丢弃到达另一个通道的字符);一个TBE位,用于使闲置通道做好工作准备;以及一个data loss (数据丢失)位,当闲置通道收到字符而另一通道正忙于通信时,该位被置高。
g_TransmitByte; g_ReceiveByte: 分别保存着下一个要传送的字节和最新接收到的字节。
g_CommBuffer: 一个50字节数组,包含刚接收到的消息或要发送的消息。注意系统仅有一个通信缓存。它不仅被两个通信通道所共享,也被发送和接收通道所共享。
g_MeterAddress: 一个包含电表网络地址的6字节数组。初始化时从EEPROM内读取该信息,并存放在RAM中。
g_MessageFormatterData; g_DispFormatterData; g_ScheduleManagerData; g_AEMData; g_LCLRegData: 这些寄存器在寄存器管理器和各种任务间传送数据。例如,一个需要发送的寄存器内容,会被寄存器管理器放入g_MessageFormatterData中。
g_AEMRegisterNeeded; g_DispFormatterRegRequest; g_RequestScheduleManager; g_LCLRegRequest: 这些寄存器里,包含了特定任务需要读或写的寄存器。注意,消息译码器没有全局地址寄存器:寄存器管理器可以智能地从消息缓存中找出这个信息。
g_LCDMode: 包含显示器的模式字节。见下面的显示定制部分。
g_TariffInEffect: 包含当前有效的费率号码。这个函数有自己的全局变量,以便每次累计电能时,无需通过多次EEPROM读操作来确定将采样值存在什么位置。
g_PW: 包含当前有效的各个通信通道的口令号码。
g_irTimer; g_rsTimer: 用于计数各个通道口令有效时间的定时器。一旦接收到口令后,它的有效期限是60秒。一个口令的有效时间结束后,g_PW中相关的4位数据就会被清零。
g_LoadCurveUsage; g_LoadCurvePeak; g_LoadCurveTimeStamp: 与负载曲线记录任务相关的变量。g_LoadCurveUsage累计用电量,并会最终报告给负载曲线记录任务。负载曲线记录任务会定
期地将该值写入EEPROM并随后清除该变量。
g_LoadCurvePeak和g_LoadCurveTimeStamp跟踪负载曲线的最大功率值,并记录峰值功率产生的间隔和时间。
AEMState: 包含一组与异步事件相关的变量。当接收到一个设置电表地址消息时,msg_rx标志被置为高。地址设置逻辑电路被激活后,变量timer包含恢复正常显示所需的秒数。DSPState和Register变量跟踪寄存器用电量信息从DSP逻辑传送到用电量报告函数的过程。通常,寄存器变量包括所有用电类型(有功、无功、正功率和负功率等)。
g_new_baud: DL/T 645协议规范提供了一种只改变单个消息波特率的机制。当收到波特率变更请求并得到确认后,下一个消息就会以更高的波特率传送。随后,波特率恢复到正常值(本设计中采用1,200bps)。g_new_baud总是保存下一个消息的波特率。
g_TransmitDelay: 一些RS-485转换器在发送完最后一个字符后会延迟一段固定时间,随后切换回接收模式。因此,当主机传送完一个请求后,它可能会丢失电表发送的前几个字符,因为与主机串口相连的RS-485转换器仍处在发送模式下。这个变量保存了发送状态保持的固定延时,延时结束后主机的RS-485转换器切换回接收模式。
current_temp: 如果引用该变量,它将包含从DS3231 RTC/温度传感器中读出的最新数值。
定制功能
本参考设计符合DL/T 645-多功能、瓦时电表通信协议。但这篇文档不仅仅对通信协议进行说明。DL/T 645确实对一个多功能电表需要执行的操作进行了规定,包括测量、时段管理和报告功能。因此,如果你要选择其它电表协议,你必须替换掉寄存器管理器以及除串口管理器之外的所有消息函数,或者至少对其进行重大修改。修改的细节不在本文讨论范畴内。
本文档将着重讨论三个定制领域:显示定制、寄存器映射定制和DSP函数定制。 [page]
显示定制
显示器完全由显示管理器控制。其它任何任务都不会向MAXQ3120的LCD寄存器写入数据。DisplayFormatter.c模块包含了显示管理器及其主要子程序UpdateLCD。
如果你只是想在电表中使用一个不同的LCD模块,则只需修改UpdateLCD。所以我们将从这个模块的定制开始说起。如果你想改变显示信息的类型,你就要修改DisplayManager,并且可能需要给电表的其它部分提供额外的钩子(hook)函数。
定制UpdateLCD
UpdateLCD接收两个参数:一个待显示的32位数值和一个8位信号指示器数值 。32位显示值包括8个4位数值。因此,UpdateLCD支持8位、7段显示器。注意,MAXQ3120支持112段显示,所以可以定制该程序以支持更大规模的显示器。 如果想用不同的显示器,你需要修改LCDFont结构。它被定义为static const类型。这样定义的结构进行编译和连接后,将驻留在程序空间,而不是数据空间。
LCD空间分配表:
这里有个重要的假设:每个字符都可填入一个LCD寄存器。如果所采用的LCD结构中,属于1位显示的某些段要占用多个LCD寄存器,则需要修改整个UpdateLCD。
数字的显示顺序是什么?
程序假设最右端的显示数字,是32位显示参数的低四位。这是最自然的顺序;如果你将“123456”传递给参数,则显示器会显示“123456”。
信号指示器
如果你想在显示特定信息的情况下,同时点亮特定的信号指示器,则需要另外一个8位变量来存储指示信息。UpdateLCD程序使用一个switch结构,以在显示数字之后马上点亮这些指示器。
特殊状态显示
在displayformatter.c文件的最后还有一组程序。这些程序控制特殊状态显示,例如电表初始化、EEPROM初始化和程序故障(异常)。它们被直接写入LCD寄存器,而且要针对不同的显示进行定制。
定制显示管理器
除了显示用电量、时间和日期以外,如果你还想显示其它信息,则需要修改显示管理器。
显示管理器的第一部分,处理电表地址设置信息的显示。仅当地址设置按钮被按下时才起作用,不需要修改这一部分。
显示管理器的其它部分,通过全局变量g_LCDMode来获取类别。为确定要显示的下一个条目,这个变量在一个字节内包括了所有必要的信息。它的格式如下所示:
总会显示电表使用过程中累计的总用电量,并显示由g_LCDMode字节所指定的条目。在本参考设计中,这个变量被固定为1―除了显示总用电量以外,只显示时间和日期。
控制变量
显示管理器由状态变量disp所控制,该变量有两个元素:ItEM和State。由名字可以得知,disp.State存放显示控制器的当前状态,而disp.Item跟踪将要显示的信息,具体含义如下:
定制这个程序提供两种选项。你可以选择改变disp.Item的赋值,以及改变程序中它们的选择顺序,或者你可以选择完全替换掉该程序。后一种选择可能更好。如果为可能显示的每个条目指定一个独立位,或为可显示条目分配一个列表索引,显然这样的条目选择结构更加灵活。选择上面的结构是因为它需要的RAM空间最小。
添加寄存器
DL/T 645规定了大量寄存器,用于控制电表运行的各个方面。每个寄存器由一个16位寄存器号指定。在参考设计中,增加了很多寄存器来控制电表运行的各个方面;在代码中给出了这些寄存器的说明。本讨论内容提供了必要的信息,以便通过扩展寄存器映射从电表中获取更多信息,或者控制新的电表运行特性。
寄存器管理器如何工作
所有任务都不能挂起正常的任务轮操作,寄存器管理器任务要遵循这一原则有很大难度。这是因为寄存器管理器是唯一能够读/写EEPROM的任务,并且EEPROM写操作需要(相对)较长的时间―几个毫秒。因为每20ms (60Hz环境下是16.7ms)就要为DSP程序提供处理器时间,寄存器管理器在EEPROM写周期过程中,绝不允许将系统挂起几十毫秒的。
要解决EEPROM写入时间问题,一个显而易见的方法是将I2C程序置为中断处理方式。这样一来,寄存器管理器可以启动一个EEPROM传输过程,随即返回主函数入口main();之后每次被调用时,寄存器管理器都会通过检查EEPROM子系统的状态,来确定任务是否已经完成。采用这种方案带来一个问题,ADC周期非常短,以至于ADC中断服务程序需要独占中断子系统。因此,必须采取一些其它保障机制。
解决的方法是采用一个全局标志位:EEPROMOpPending。当这个标志位为低时,任务轮实质上是一个无限循环过程,反复调用系统中的每一个任务。当标志位为高时,任务轮被调用时执行一次并返回,并不调用寄存器管理器。这样有什么帮助吗?
当寄存器管理器需要执行一个耗时很长的功能时,它启动这个功能并通过轮询来确定其是否完成。在轮询期间,寄存器管理器将EEPROMOpPending置为高,并递归调用任务轮。下面的代码给出了一个实际例子:
01: uint8 ReadEEPROM(uint16 Address, uint8 Length, uint8 *pData)
02: {
03: int i;
04: g_MessageBoard.EEPROMOpPending = 1;
05: for(i=0; i
07: if(i>0)SpinTaskWheel();
08: eeprom_address = Address++;
09: while(eeprom_read_byte())
10: S
pinTaskWheel();
11: *pData++ = eeprom_data;
12: } // for
13: g_MessageBoard.EEPROMOpPending = 0;
14: return 1;
15: }
在上面的第4行,EEPROMOpPending标志位被置为高。在第7和10行中,SpinTaskWheel被调用。如果EEPROM标志位为高时调用任务轮,则SpinTaskWheel函数运行一次,并在不调用寄存器管理器的情况下返回。这样,即使由于寄存器管理器等候EEPROM完成操作而停止下来,电表的其它部分仍可持续正常运行。
哪些任务知晓这些寄存器?
只有两个任务知道寄存器号:寄存器管理器和消息译码器。这些程序中,通常只需要对寄存器管理器进行修改。消息译码器识别出与口令管理和其它监控功能有关的寄存器,并且必须在采用正常处理规则之前获取这些信息。因此,要构建自己的寄存器,只需要熟悉寄存器管理器。 三类寄存器
通常,有三类寄存器:只读、读写和具有额外功能的读写寄存器。只读寄存器的一个例子是B611,RMS Volts、phase A。主机向这个寄存器写数据是不能执行的;实际上,如果电表收到写数据会将其丢弃。而且,多数只读寄存器都不在EEPROM中:通常,在线计算这些寄存器的结果,并根据需要报告结果。
读写寄存器的一个例子是C032,Meter Number (电表号)。写入数值不会对电表操作产生任何影响,而且可以随时提取该数据。最后,一个具有额外功能的读写寄存器例子是C030,Meter Constant, active (有效电表常数)。当这个寄存器被写入数据时,寄存器管理器不仅要更新EEPROM,同时也要更新DSP程序使用的电表常数。
哪些任务需要寄存器信息?
下表列出了需要寄存器信息的任务。
通常,你主要考虑添加可通过消息译码器访问的寄存器。你可以增加用于显示的寄存器(或者用于其它任务的寄存器,但是依据惯例,你会主要考虑那些可通过通信端口检索的寄存器)。
读写寄存器
首先考虑第一种情况,即存储和读取无额外功能的读写寄存器。为了添加一个存储于EEPROM内的寄存器,你必须添加两处信息:MAXQ3120RD.h文件和寄存器管理器中的ProcessRegisterNumber程序。
MAXQ3120RD.h包含一个由typedef定义的名为EEPROM_DATA的数据类型。这个定义并没有被真正实例化;而仅仅是作为模板,用于定义数据如何存入EEPROM。在EEPROM_DATA定义的下面,还定义了两个宏,用来返回两个值,分别是结构中某成员的偏移地址和某成员占用的字节数。定义新寄存器的第一步,是在结构中添加成员(最好是在尾部),从而为寄存器分配EEPROM存储空间。
下一步是定义寄存器号。这需要编辑寄存器管理器中定义的RegParmTable结构。这个表包含了电表中定义的每个寄存器,并按编号排序。每个成员包括:
寄存器号,16位无符号值。
物理数据单元编号,用于计算实际寄存器值。例如,寄存器9110请求当月总的正向无功用电量。它是两个电能累加器的和:包括1象限的用电量和4象限的用电量。因此,物理单元的个数是二。寄存器管理器必须提取指定单元(CurrentQuadrant1AccumTariff)和下一个单元(CurrentQuadrant4AccumTariff)的数据,并求和以获得所需信息。
每个单元的长度,以字节为单位。[page]
存储的数据类型:INT_REG,表示寄存器包含被视为整数的二进制数据;
BCD_REG,表示寄存器包含的是传输前无需进一步转换的BCD码数据;或者MDH_REG,表示寄存器包含的是日期信息(月:日:小时)。
EEPROM中数据的偏移量(单位为字节数)。
为了节约处理时间,ProcessRegisterNumber程序采用二元搜索算法找出寄存器地址。因此,表格保持排序状态是非常重要的。如果寄存器表变得无序,结果就无法预料了。
一旦表格被更新,新的寄存器可以通过通信通道进行读写。电表到底如何处理该信息,是下一部分的主要内容。
具有额外功能的读写寄存器
还有一种应用情况,即你想让一个写事件触发额外的功能。为了达到这种效果,必须让寄存器管理器向额外任务发送一个消息,或者更新执行额外功能所涉及的RAM内容。作为样例说明,可在寄存器管理器中搜索C030,你会找到下面这段代码:
switch(Register.Word)
{
case 0xC030: // Meter constant, real
action_value = 0;
for(i=4; i>1; i--)
{
action_value *= 100;
action_value += (g_CommBuffer.Message[ i] & 0xf) +
(g_CommBuffer.Message [ i] >> 4) * 10;
}
set_E_pulse(action_value); // this will set E_pulse
break;
这段代码在EEPROM的寄存器数据更新完毕之后运行。在这个条件下,主机请求改变电表常数。存储在EEPROM中的电表常数寄存器更新过后,传输到通信缓冲器的毫秒数值被转换成内部电表单位,并通过set_E_pulse函数发送给DSP程序。
只读寄存器
一些只读寄存器只是简单地从EEPROM中读取数据(如用电量),并通过电表的其它进程来更新其中的数据。然而,另外一些只读寄存器(如RMS电压)并未存储在EEPROM内。这些寄存器数据存储在EEPROM内是没有任何意义的,而且如果这样做并连续更新数据,会迅速损耗EEPROM!你可以在ProcessRegisterNumber中的表格注释里找到这些寄存器,表述为“not stored in EEPROM”(未存储在EEPROM内)。
这些寄存器由寄存器管理器的GetSpecialRegister程序来控制。对应每个只读寄存器,程序都在switch分支选择语句中提供相应的条件。例如:
case 0xB611:// voltage (phase A)
g_MessageBoard.EEPROMOpPending = 1;
Request_RMS(RMS_VOLTAGE_REQUEST);
SpinTaskWheel();
while(!(DSP_CTRL & 0x20))
SpinTaskWheel();
*value = Get_RMS() / 1000;
g_MessageBoard.EEPROMOpPending = 0;
*size = 2;
break;
这个例子阐明了一个重要事实,即任何任务都不能挂起任务轮。case的第一条语句将消息板中的EEPROMOpPending标志位置为高。然后它要求DSP函数计算RMS电压值,并在DSP函数忙时递归调用任务轮。当EEPROMOpPending标志位置为高后,执行一次任务轮循环,并且不调用寄存器管理器,从而避免了无限递归。一旦DSP函数完成,将提取RMS值并清除EEPROMOpPending标志位。
请注意,对于这种类型的只读寄存器,不必在MAXQ3120RD.h文件中添加结构来保留EEPROM存储空间。也不必向ProcessRegisterNumber表添加成员。在处理基于EEPROM的寄存器之前,寄存器管理器主程序总要调用GetSpecialRegister。
定制DSP程序
参考设计的DSP程序是一套汇编语言模块,它负责处理从ADC到脉冲生成以及报告电压、电流、功率和用电量的整个信号流。大部分程序不需要修改,但也许你希望修改以下方面:
采用一个不同的电流或电压变换器,从而需要不同的增益因子。
改 变系统生成电表脉冲的方式。
改变前端滤波。
DSP程序是如何工作的,以及你可以安全地改变哪些单元,以下部分从较高的层次对此进行了说明。
注意:DSP模块以预编译的目标文件形式公开发布。只有在签署了保密协议(NDA)的情况下才可以提供汇编语言源代码。更多信息,请联系Dallas SEMiconductor/Maxim。
存储
DSP程序用到RAM空间的低地址部分。在DSP模块中搜索“Data Memory Map”,可以看到DSP程序用到的一系列RAM变量。前两个字节是一组控制DSP函数运行的数据位。
常数
可通过调整两个常数来设置电压和电流通道的满量程读数。它们分别是W_V_Scale和W_I_Scale。缺省情况下,这两个常量被设置为400V和250A。电压被设置为正常条件下不会超越的电平值(280VRMS以上),而电流设定值与可能的电表分流值相一致(250μ至500μ,典型值)。
接口程序
用户程序可以直接使用一些内置程序的返回值。如果可能,你应该通过这些内置程序与DSP函数接口,而不是直接与DSP函数使用的内部变量接口。
Get_and_Clear_Usage: 这是C代码用来提取电量累计值的主程序。通常情况下,需要对用电量进行累计时,DSP程序会通知异步事件管理器。然而,随时都可以调用这个程序以获取精确的用电量读数(截至当前)。注意,IAR编译器会自动传递A[0]内的函数参数,并将结果返回给A[0]。
Get_Frequency: 返回0.1mHz步长的线路频率。值得注意的是,这个子程序缺省情况下并未加载;DL/T 645标准并未要求频率结果。
Get_Power_Factor: 返回负载的功率因子。
Get_Power: 根据参数不同,返回无功或有功功率。
Get_MaxD: 返回自上次调用该函数后,电表记录的最大需量(功率)值。
Request_RMS: 根据参数不同,要求DSP计算RMS电流或电压值。
Get_RMS: 返回最近一次请求的RMS值。
set_E_pulse: 接受一个电表常数,并设置适当的DSP变量以使该电表常数生效。
中断服务程序
参考设计只使能了一个中断:就是AFE中断,ADC上有一组新的采样数据时产生该中断。因为ADC采样周期为48μs,实际上中断服务程序会很快地结束它的工作,并返回到主代码中―在两个中断之间只有384个指令周期!
中断服务程序执行以下功能:
生成输出脉冲:如果需要一个脉冲,则启动它。如果脉冲正在进行中,则递减持续时间计数器的值,并在计数器回零时终止脉冲。
累加求和:将最近的能量采样值累加到所有适当的寄存器中。
累计RMS值:如果被请求,则累计I2或V2。
检查电压下限:如果电压低于门限值,则递增一个计数器值。
过零检测:如果电压信号正向过零,则设置一个标志位。
上一篇:伊顿新发布的白皮书评估 Ex ic
下一篇:嵌入式软件的覆盖测试
推荐阅读最新更新时间:2024-03-16 11:13
一种智能电表集中器设计方案
引言 目前,我国城市居民用户的电表、水表、天然气表很多是人工抄表,由抄表工作人员每月逐个查抄各种仪表,也有很多地区已经通过抄表改造工程实现了集中抄表。 由于目前已经使用的远程抄表还面临一些挑战:比如初期成本较高,同时总线上传输的数据是终端用户所消费的水、电、气等重要数据,对总线的抗干扰性要求非常高,要具有抵抗容性、感性的偶合干扰的能力,为节约成本,要采用远程供电的方式给从设备提供电源,以尽可能减少元器件的使用。 为了解决以上问题,本文设计了一种基于CAN总线的远程电表抄表系统集中器。基于CAN总线的智能电表系统具有造价较低,可靠性高,组网简单,管理方便,操作简捷等优点,并且可以通过扩展和升级硬件,利用有线网络或无
[单片机]
瑞萨电子芯片的智能电表市场份额已达到60%
自去年12月 国家电网 新规约颁布之后的第一次招标到最近的一次招标,采用瑞萨电子 MCU 芯片的 智能电表 市场份额已达到60%。新的智能电表标准需要芯片提供更大的存储空间、更为可靠的性能、以及更高的性价比。
瑞萨电子上海分公司MCU产品中心市场部经理李唐山
瑞萨电子(中国)有限公司 MCU产品中心市场经理李唐山表示:“瑞萨电子之所以能取得这么好的成绩,是因为它的产品具有以下四个关键决胜特性:1)涵盖单相、三相智能电表、集中器和终端设备的产品线;2)更高的性价比及强有力的技术支持;3)不断推陈出新的产品;4)稳定的供货。”
设计新标准要求的智能电表的难点在于:在芯片面对高集成度
[工业控制]
关于ATT7022B高精度智能电表的设计
随着电子技术和计算机技术的发展以及配电网自动化系统的实施,进一步促进了电能质量问题的研究及其检测装置的研制,以往采用多个采样模块加上多路转换开关和高分辨率的模拟数字转换器构成一个同步采样模块的方式逐渐被带DSP功能的专用高精度计量芯片所替代。与传统电表相比,本文方案采用低功耗单片机 STC89C51和炬力公司的三相电能专用计量芯片ATF7022B来实现防窃电电能表,具有高精度、低功耗、防窃电等特点,用RS485通信可以方便远程抄表,远程校表等功能。 1 电能计量芯片ATT7022B 1.1 ATT7022B的功能及结构 ATT7022B是一款多功能防窃电三相电能计量专用芯片,该芯片适用于三相三线和三相四线的应用。它集成了7路二
[单片机]
配合智能电表趋势的安森美半导体PLC技术及解决方案
当今很多国家都已采用或即将部署智能电表系统,并采用自动远程集抄方式。目前备受关注的是法国ERDF的Linky电表项目。欧盟最大的电力配电网运营商、法国电力集团(EDF)的子公司——法国电网输送公司(ERDF)已经启动了一个涉及总数目3,500万只电表的项目。从2012年至2017年,该项目将把法国国内的传统电表统一更换成新型的Linky智能电表。这类智能电表通信采用了扩频的频移键控(S-FSK)电力线载波(PLC)技术。
安森美半导体在电表领域积累了十多年的丰富经验,为这一重要且快速增长的智能电表市场提供通用及稳定的方案,包括最新推出的PLC调制解调器系统级芯片(SoC),可广泛用于智能电表、远程控制/家居显示屏(IHD)、太
[电源管理]
智能电表技术门槛高 关键是零部件差异
智能电网的发明,彻底改变人类对电力的认识,目前西欧、美、日等国皆为节能减碳而积极发展智能电网。整体的智能电网包括发电、输电、配电及用户端。在国际市场上,台湾的产品,已经逐渐打入智能电网的供应链,但都集中在属于智能电网末端的“用户端”,也就是智能电表。 智能电表基础建设(AMI)主要由智能电表(Smart Meter)、通讯系统、电表信息管理系统(MDMS)所组成,除了能取代人工抄表外,还可支援各种不同电价费率、提供用户能源使用信息,并具有让用户自发性节能、停复电管理、进行电表设备资产管理等优点。 智能电表表体的制造技术门槛虽然不高,但是跨入该市场的门槛很高。首先,智能电表的主要客户不是电力公司,不然就是公共事业业者
[工业控制]
一种新型智能电表的电路设计图
智能电表属机电式智能电表,它由硬件电路、相应软件及发行系统三部分构成,可实现某一电力公司不同时间段不同电价的计费,从而可实现用电监管的智能化。用户的购电信息实行微机管理,方便进行查询、统计、收费及打印票据等。 工作原理: 用户持IC卡到供电部门交款购电,供电部门用售电管理机将购电量写入IC卡中,用户持IC卡在感应区刷非接触式IC卡(简称刷卡,下同),即可合闸供电,供电后将卡拿走。当表内剩余电量等于报警电量时,拉闸断电报警(或蜂鸣器报警),此时用户在感应区刷卡即可恢复供电;当剩余电量为零时,自动拉闸断电,用户必须再次持卡交费购电,才可以恢复用电。 电表硬件装置: 本电表装置的硬件包括接口卡、手持单元及电表费率
[电源管理]
万用表(数字多电表)的认识与使用
本文以胜利仪器VICTOR VC9806+为例,简单的介绍了万用表,并给出了一些使用技巧。 数字电表是常用的测量仪器。从功能的角度出发,万用表主要用来测交(直)电压、电阻阻值、电容、电路通断等,电流主要测小电流,大电流建议使用电流钳等专业设备来测。接下来,先认识一下表盘,然后再谈使用功能的实现。 旋转按钮拨至相应档位,即可实现相应的测量。此时红表笔的接口仅可实现电压、阻值、频率的测量,测交(直)电流、电导需要更换红表笔插口。下面给出一些测量图片。 1、测量100Ω OmegaΩ的电阻 将旋钮拨至200Ω OmegaΩ档位,当不知所测电阻阻值时,建议将档位拨至最大档位,然后逐档降低,直至找到合适的档位。出现读数并稳定后,
[测试测量]
美信收购电表SoC商Teridian 扩大智能电网
在模拟等半导体产品领域拥有强大实力的美国美信集成产品(Maxim Integrated Products)于2010年4月宣布,将收购因从事智能电表用SoC业务而广为人知的美国Teridian Semiconductor。日前,本站记者就该公司收购Teridian的目的,采访了美信转换、计算及安全产品部部门副总裁(Conversion,Computing and Secure Products Division,Division Vice President)Chris Neil。(采访人:Phil Keys) ——请问贵公司收购Teridian的原因有哪些? 智能电网的应用方法之一,包括电力运营商考虑导入的新型收费制
[工业控制]
- 热门资源推荐
- 热门放大器推荐
最新安防电子文章
更多精选电路图
更多热门文章
更多每日新闻
更多往期活动
厂商技术中心
随便看看