?? meter.c
字號:
/***************************************************************************
* This code and information is provided "as is" without warranty of any *
* kind, either expressed or implied, including but not limited to the *
* implied warranties of merchantability and/or fitness for a particular *
* purpose. *
* *
* Copyright (C) 2005 Teridian Semiconductor Corp. All Rights Reserved. *
***************************************************************************/
//**************************************************************************
// DESCRIPTION: 71M652x POWER METER - Display Routines.
//
// AUTHOR: MTF
//
// HISTORY: See end of file.
//**************************************************************************
// File: METER.C
//
#include "options.h"
#include <ctype.h> // Need for 'toupper' function.
//#include "OSCOPE.h"
#include "calibration.h"
#include "ce.h"
#include "batmodes.h" // battery modes
#include "battest.h" // battery test
#include "eeprom.h"
#include "cli.h"
#include "defaults.h"
#include "freq.h" // select, condition and display frequency
#include "io.h"
#include "lcd.h"
#include "library.h"
#include "irq.h"
#include "mmath.h"
#include "peak_alerts.h" // detect overvoltages and overcurrents
#include "pwrfact.h" // calculate & display power factors
#include "phase_angle.h" // calculate & display V/I phase angles
#include "vphase.h" // calculate & display V/V phase angles:w
#include "pulse_src.h"
#include "psoft.h"
#include "pcnt.h"
#include "rms.h" // manage Irms and Vrms
#include "rtc.h"
#include "wh.h"
#include "varh.h"
#include "vah.h"
#include "meter.h" // Test API for consistency
/*** Public variables declared within this module ***/
bool ce_totals_ready; // Enables update only if changed.
int32_t pdata va0sum, va1sum; // volt-amps, scaled like w0sum
#if VA_SUMS
int32_t pdata vasum;
#endif
#if PHASE_C_PRESENT
int32_t pdata va2sum;
#endif
#if FLAG
bool register_available = FALSE; // false = registers are invalid
bool register_locked = FALSE; // false = update registers
bool register_write = FALSE; // true = registers written by FLAG
struct Totals_t xdata Registers _at_ (0x0000); // Flag registers.
struct Totals_t xdata Totals; // Need to be in XDATA to be non-volatile store?
#else
struct Totals_t xdata Totals _at_ (0x0000);
#endif // Need to be in XDATA to be non-volatile store?
/*** Private functions declared within this module ***/
static void RescalePhaseB(void);
static void Gain_Compensation (void);
static void Compute_Small_Irms (void);
static void Apply_Creep_Threshold (void);
/*** Private variables used within this module ***/
extern const uint8x_t * code LcdSrc[];
//===========================================================================//
//---------------------------------------------------------------------------//
#if CLI
void cmd_meter (void)
{
uint8_t data c, d, r;
select_total = M_NONE;
select_phase = 0;
c = toupper (get_char_d (&d));
if ('R' == c) // detection of bad command when RMS not defined- see below
{
c = get_num_decimal ();
switch (c)
{
case 1: select_total = M_IRMS; break;
case 2: select_total = M_VRMS;
default: break;
}
}
else
{
cli_index = d; // Unget last character.
select_total = r = get_num_decimal ();
}
done (&c); // Skip delimiter, if any.
switch(select_total)
{
default:
cli_result = ERROR_ID;
case M_NONE:
select_total = M_WH;
break;
#if TEMPERATURE
case M_TEMP:
#endif
#if FREQUENCY
case M_FREQ:
#endif
#if OPERATING_TIME
case M_HOURS:
#endif
#if REAL_TIME_DATE
case M_TIME:
case M_DATE:
#endif
#if BATTERY_TEST
case M_BATTEST:
#endif
break;
#if WATT_ELEMENT
case M_WH:
#if EXPORT
case M_WHE:
#endif
#endif
#if VAR_ELEMENT
#if IMPORT
case M_VARH:
#endif
#if EXPORT
case M_VARHE:
#endif
#endif
#if VA_ELEMENT
#if IMPORT
case M_VAH:
#endif
#endif
#if POWER_FACTOR
case M_PF:
#endif
#if PHASE_ANGLES
case M_VI_ANGLE:
#endif
#if VOLTAGE_PHASES
case M_VPHASE:
#endif
#if RMS_VALUES
case M_IRMS:
case M_VRMS:
#endif
#if PHASE_ANGLES || VOLTAGE_PHASES || POWER_FACTOR || RMS_VALUES
select_phase = get_num_decimal ();
break;
#endif
#if PULSE_CNT
case M_PULSE:
c = get_num_decimal ();
select_pulse = min (c, MAX_PULSE);
done (&c); // Skip delimiter, if any.
c = get_num_decimal ();
select_interval = min (c, MAX_INTERVAL);
break;
#endif
#if MAIN_EDGE_COUNT
case M_EDGE_CNT:
c = get_num_decimal ();
select_phase = min (c, MAX_EDGE_TYPE);
break;
#endif
}
if (!(CE_ACTIVE))
ce_totals_ready = TRUE; // force a redisplay
}
#endif // CLI
void meter_initialize (void)
{
memset_x ((uint8x_t *) &Totals.Sums, 0x00, sizeof (Totals.Sums));
// read the revenue registers from the EEPROM
// There are two sets just in case the power failure occurs while
// one of the sets is being calculated.
// The two sets are the structures Totals.Acc and Totals.AccB
// In Totals, AccB follows Acc, so a single read reads both.
#if EEPROM
eeprom_enable();
memcpy_xpr (
(uint8x_t*)&Totals.Acc, // The start of the data
EEPROM_REGISTERS,
(2 * sizeof (Totals.Acc)) ); // get the revenue registers
#endif
// validate the saved revenue registers
if (!LRC_Calc_NVR ((uint8x_t *) &Totals.Acc, sizeof (Totals.Acc), FALSE))
{ // Copy A is Invalid. Try to fix it.
if (!LRC_Calc_NVR ((uint8x_t *) &Totals.AccB, sizeof (Totals.Acc), FALSE))
{
// Both copies are bad... so there's no recovery
Status |= POWER_BAD;
memset_x ((uint8x_t *) &Totals.Acc, 0x00, sizeof (Totals.Acc));
}
else
{
memcpy_xx ((uint8x_t *) &Totals.Acc, (uint8x_t *) &Totals.AccB, sizeof (Totals.Acc));
}
}
#if FLAG
register_available = FALSE; // false = registers are invalid.
register_locked = FALSE; // false = update registers.
register_write = FALSE; // true = registers written by FLAG.
#endif
#if PULSE_SOURCE && PULSE_SOFT
psoft_init (); // initialize software pulse outputs.
#endif
}
//===========================================================================//
// Perform the calculations for data just imported from the CE to the MPU
// This should be called from the main loop. It runs the electric-power-meter
// part of the logic.
uint8_t xdata count_errors = 0;
void meter_run (void)
{
if (xfer_update) // Did the CE transfer interrupt run recently?
{
if (CFG_CLEAR_ACC == (Config & CFG_CLEAR_ACC))
{ // Clear all accumulated values.
memset_x ((uint8x_t *) &Totals.Acc, 0, sizeof (Totals.Acc));
memset_x ((uint8x_t *) &Totals.Sums, 0, sizeof (Totals.Sums));
Config &= ~CFG_CLEAR_ACC;
}
cai += 1; // count accumulation intervals
while (xfer_update) // repeat this logic if a xfer-busy int happens
{
xfer_update = FALSE;
#if IMAX2
RescalePhaseB();
#endif
#if RMS_VALUES
Compute_RMS (); // compute the voltage and current
#endif
Compute_Small_Irms (); // figures VA to figure small Irms
Apply_Creep_Threshold ();
}
// OSCOPE_ZERO; OSCOPE_ONE;
// xfer update is set here and cleared at the end,
// because the flag protocol uses it to decide if the
// totals can be copied. At this point, the totals begin to change
xfer_update = TRUE;
#if WATT_ELEMENT
wh_accumulate ();
#endif
#if VAR_ELEMENT
VARh_Accumulate ();
#endif
#if VA_ELEMENT
VAh_Accumulate ();
#endif
#if PULSE_SOURCE
SelectPulses (); // for software generated pulse outputs
#endif
#if POWER_FACTOR
Compute_Power_Factor (); // computes the power factor for elements
#endif
#if PHASE_ANGLES
Compute_Phase_Angle (); // computes the V/I phase angle for each conductor
#endif
#if FREQUENCY || MAIN_EDGE_COUNT || RTC_LINE_LOCKED
Determine_Frequency ();
#endif
#if PEAKS
Determine_Peaks (); // Check if the voltage or current are too high
#endif
#if VOLTAGE_PHASES
Calc_Voltage_Phase (); // Calculate the angle between voltage inputs
#endif
Gain_Compensation (); // quadratic temperature compensation of the meter
#if RTC_COMPENSATION && (REAL_TIME_DATE || OPERATING_TIME)
RTC_Compensation (); // Do temperature compensation of the RTC.
#endif
#if REAL_TIME_DATE
RTClk_Read (); // Get current time.
#endif
#if BATTERY_TEST
battest_run (); // Run the battery test at midnight
#endif
// precalculate the value to be displayed in the autosleep mode
// This value is saved by the sag logic in ce.c
// The second copy is made when the accumulators are copied, below
#if AUTOSLEEP
brownout_cache_valid = 0;
#if WATT_SUMS
// save total kWh
brownout_cache = wh_to_long (LcdSrc[ 0 ]);
#else
// save kWh on phase A
brownout_cache = wh_to_long (LcdSrc[ 1 ]);
#endif
#if MODE_DISPLAY
brownout_cache_mode = M_WH;
#endif
brownout_cache_valid = YES;
#endif // autosleep
// keep interrupting clock stuff out
irq_disable();
LRC_Calc_NVR ((uint8x_t *) &Totals.Acc, sizeof (Totals.Acc), TRUE);
memcpy_xx (
(uint8x_t *) &Totals.AccB,
(uint8x_t *) &Totals.Acc,
sizeof (Totals.Acc));
irq_enable();
#if AUTOCAL
// cal flag is set in main.c if pin 3 of the debug
// connector is grounded, and watt hours are zero
if (Config & CFG_CAL)
// this call performs a state machine that
// measures volts and amps for a period,
// then adjusts the CE's calibration gains
// and saves them to nonvolatile memory
// After that, the LCD says "HELLO"
// to indicate completion.
Calibrate ();
#endif
#if FLAG
if (!register_locked) // If a flag interface is not signed on,
Update_register (); // move data in or out of the FLAG interface
#endif
xfer_update = FALSE; // The transfer interrupt's data is available
ce_totals_ready = TRUE;
// OSCOPE_ZERO;
}
#if WATCHDOG // if the watchdog hierarchy is enabled, fix up meter settings
else
{
// If the bits are set, but there's no interrupt, handle it.
// This happens in rare instances when high-voltage electromagnetic
// interference is inadequately handled by the PCB. In these cases,
// status bits in the controller can be inverted by noise. This
// interrupt is so crucial that it's worth handling it in this way.
//
// The interrupts are reenabled because that is one possible failure.
if (IE_RTC)
{
CLR_IE_RTC(); // Just clear IE_RTC bit.
#if REAL_TIME_DATE || OPERATING_TIME
rtc_isr (); // Compensate the clock
#endif // REAL_TIME_DATE.
#if 1 == PULSE_CNT
pcnt_accumulate (); // Sum timed counts of pulses
#endif
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -