⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 meter.c

📁 TDK 6521 SOC 芯片 DEMO程序
💻 C
📖 第 1 页 / 共 4 页
字号:
/***************************************************************************
 * 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 + -