基于MAXQ3120微控制器的電表(EM)參考設(shè)計
定制這個程序提供兩種選項。你可以選擇改變disp.Item的賦值,以及改變程序中它們的選擇順序,或者你可以選擇完全替換掉該程序。后一種選擇可能更好。如果為可能顯示的每個條目指定一個獨(dú)立位,或為可顯示條目分配一個列表索引,顯然這樣的條目選擇結(jié)構(gòu)更加靈活。選擇上面的結(jié)構(gòu)是因為它需要的RAM空間最小。
添加寄存器
DL/T 645規(guī)定了大量寄存器,用于控制電表運(yùn)行的各個方面。每個寄存器由一個16位寄存器號指定。在參考設(shè)計中,增加了很多寄存器來控制電表運(yùn)行的各個方面;在代碼中給出了這些寄存器的說明。本討論內(nèi)容提供了必要的信息,以便通過擴(kuò)展寄存器映射從電表中獲取更多信息,或者控制新的電表運(yùn)行特性。
寄存器管理器如何工作
所有任務(wù)都不能掛起正常的任務(wù)輪操作,寄存器管理器任務(wù)要遵循這一原則有很大難度。這是因為寄存器管理器是唯一能夠讀/寫EEPROM的任務(wù),并且EEPROM寫操作需要(相對)較長的時間D幾個毫秒。因為每20ms (60Hz環(huán)境下是16.7ms)就要為DSP程序提供處理器時間,寄存器管理器在EEPROM寫周期過程中,絕不允許將系統(tǒng)掛起幾十毫秒的。
要解決EEPROM寫入時間問題,一個顯而易見的方法是將I2C程序置為中斷處理方式。這樣一來,寄存器管理器可以啟動一個EEPROM傳輸過程,隨即返回主函數(shù)入口main();之后每次被調(diào)用時,寄存器管理器都會通過檢查EEPROM子系統(tǒng)的狀態(tài),來確定任務(wù)是否已經(jīng)完成。采用這種方案帶來一個問題,ADC周期非常短,以至于ADC中斷服務(wù)程序需要獨(dú)占中斷子系統(tǒng)。因此,必須采取一些其它保障機(jī)制。
解決的方法是采用一個全局標(biāo)志位:EEPROMOpPending。當(dāng)這個標(biāo)志位為低時,任務(wù)輪實(shí)質(zhì)上是一個無限循環(huán)過程,反復(fù)調(diào)用系統(tǒng)中的每一個任務(wù)。當(dāng)標(biāo)志位為高時,任務(wù)輪被調(diào)用時執(zhí)行一次并返回,并不調(diào)用寄存器管理器。這樣有什么幫助嗎?
當(dāng)寄存器管理器需要執(zhí)行一個耗時很長的功能時,它啟動這個功能并通過輪詢來確定其是否完成。在輪詢期間,寄存器管理器將EEPROMOpPending置為高,并遞歸調(diào)用任務(wù)輪。下面的代碼給出了一個實(shí)際例子:
01: uint8 ReadEEPROM(uint16 Address, uint8 Length, uint8 *pData)
02: {
03: int i;
04: g_MessageBoard.EEPROMOpPending = 1;
05: for(i=0; ilength; 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標(biāo)志位被置為高。在第7和10行中,SpinTaskWheel被調(diào)用。如果EEPROM標(biāo)志位為高時調(diào)用任務(wù)輪,則SpinTaskWheel函數(shù)運(yùn)行一次,并在不調(diào)用寄存器管理器的情況下返回。這樣,即使由于寄存器管理器等候EEPROM完成操作而停止下來,電表的其它部分仍可持續(xù)正常運(yùn)行。
哪些任務(wù)知曉這些寄存器?
只有兩個任務(wù)知道寄存器號:寄存器管理器和消息譯碼器。這些程序中,通常只需要對寄存器管理器進(jìn)行修改。消息譯碼器識別出與口令管理和其它監(jiān)控功能有關(guān)的寄存器,并且必須在采用正常處理規(guī)則之前獲取這些信息。因此,要構(gòu)建自己的寄存器,只需要熟悉寄存器管理器。 三類寄存器
通常,有三類寄存器:只讀、讀寫和具有額外功能的讀寫寄存器。只讀寄存器的一個例子是B611,RMS Volts、phase A。主機(jī)向這個寄存器寫數(shù)據(jù)是不能執(zhí)行的;實(shí)際上,如果電表收到寫數(shù)據(jù)會將其丟棄。而且,多數(shù)只讀寄存器都不在EEPROM中:通常,在線計算這些寄存器的結(jié)果,并根據(jù)需要報告結(jié)果。
讀寫寄存器的一個例子是C032,Meter Number (電表號)。寫入數(shù)值不會對電表操作產(chǎn)生任何影響,而且可以隨時提取該數(shù)據(jù)。最后,一個具有額外功能的讀寫寄存器例子是C030,Meter Constant, active (有效電表常數(shù))。當(dāng)這個寄存器被寫入數(shù)據(jù)時,寄存器管理器不僅要更新EEPROM,同時也要更新DSP程序使用的電表常數(shù)。
哪些任務(wù)需要寄存器信息?
下表列出了需要寄存器信息的任務(wù)。
通常,你主要考慮添加可通過消息譯碼器訪問的寄存器。你可以增加用于顯示的寄存器(或者用于其它任務(wù)的寄存器,但是依據(jù)慣例,你會主要考慮那些可通過通信端口檢索的寄存器)。
讀寫寄存器
首先考慮第一種情況,即存儲和讀取無額外功能的讀寫寄存器。為了添加一個存儲于EEPROM內(nèi)的寄存器,你必須添加兩處信息:MAXQ3120RD.h文件和寄存器管理器中的ProcessRegisterNumber程序。
MAXQ3120RD.h包含一個由typedef定義的名為EEPROM_DATA的數(shù)據(jù)類型。這個定義并沒有被真正實(shí)例化;而僅僅是作為模板,用于定義數(shù)據(jù)如何存入EEPROM。在EEPROM_DATA定義的下面,還定義了兩個宏,用來返回兩個值,分別是結(jié)構(gòu)中某成員的偏移地址和某成員占用的字節(jié)數(shù)。定義新寄存器的第一步,是在結(jié)構(gòu)中添加成員(最好是在尾部),從而為寄存器分配EEPROM存儲空間。
下一步是定義寄存器號。這需要編輯寄存器管理器中定義的RegParmTable結(jié)構(gòu)。這個表包含了電表中定義的每個寄存器,并按編號排序。每個成員包括:
寄存器號,16位無符號值。
物理數(shù)據(jù)單元編號,用于計算實(shí)際寄存器值。例如,寄存器9110請求當(dāng)月總的正向無功用電量。它是兩個電能累加器的和:包括1象限的用電量和4象限的用電量。因此,物理單元的個數(shù)是二。寄存器管理器必須提取指定單元(CurrentQuadrant1AccumTariff)和下一個單元(CurrentQuadrant4AccumTariff)的數(shù)據(jù),并求和以獲得所需信息。
每個單元的長度,以字節(jié)為單位。
存儲的數(shù)據(jù)類型:INT_REG,表示寄存器包含被視為整數(shù)的二進(jìn)制數(shù)據(jù);
BCD_REG,表示寄存器包含的是傳輸前無需進(jìn)一步轉(zhuǎn)換的BCD碼數(shù)據(jù);或者M(jìn)DH_REG,表示寄存器包含的是日期信息(月:日:小時)。
EEPROM中數(shù)據(jù)的偏移量(單位為字節(jié)數(shù))。
為了節(jié)約處理時間,ProcessRegisterNumber程序采用二元搜索算法找出寄存器地址。因此,表格保持排序狀態(tài)是非常重要的。如果寄存器表變得無序,結(jié)果就無法預(yù)料了。
一旦表格被更新,新的寄存器可以通過通信通道進(jìn)行讀寫。電表到底如何處理該信息,是下一部分的主要內(nèi)容。
具有額外功能的讀寫寄存器
還有一種應(yīng)用情況,即你想讓一個寫事件觸發(fā)額外的功能。為了達(dá)到這種效果,必須讓寄存器管理器向額外任務(wù)發(fā)送一個消息,或者更新執(zhí)行額外功能所涉及的RAM內(nèi)容。作為樣例說明,可在寄存器管理器中搜索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;
評論