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

📄 pcnt.c

📁 TDK 6521 SOC 芯片 DEMO程序
💻 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 - Pulse counting.
//  Note that TDK electric power metering ICs have memory-mapped registers 
//  that provide the same data as the pulses.  Use of this module is 
//  deprecated because the counting interrupts can add a substantial
//  real time burden, especially at high pulse rates.  It is provided 
//  because several customers requested it.
// 
//  AUTHOR:  RGV
//
//  HISTORY: See end of file.
//**************************************************************************
// File: pcnt.c
//               
#include "options.h"
#if PULSE_CNT
#include "irq.h"
#include "wd.h"
#include "lcd.h"
#include "mmath.h"
#include "meter.h"
#include "pcnt.h"
#include "psoft.h"

/*** Public functions used by this module. ***/
// See "meter.h" & "pcnt.h".

/*** Public variables used by this module. ***/
// None.

/*** Private functions defined by this module. ***/
static void pcnt_w (void);                  // pulse counts from Watts LED to LCD
static void pcnt_r (void);                  // pulse counts from VAR LED to LCD
static void pcnt_3 (void);                  // pulse counts from third LED to LCD
static void pcnt_4 (void);                  // pulse counts from Watts LED to LCD

static void pcnt_diff_w (void);             // differential pulse counts from Watts LED to LCD
static void pcnt_diff_r (void);             // differential pulse counts from VAR LED to LCD
static void pcnt_diff_3 (void);             // differential pulse counts from Watts LED to LCD
static void pcnt_diff_4 (void);             // differential pulse counts from Watts LED to LCD

/*** Private variables defined by this module. ***/
static bool data_ready = 0;
static int16d_t pcnt_w_cache;  // Real-time count of pulses on watts led for a second.
static int16d_t pcnt_r_cache;  // Real-time count of pulses on VARs led for a second.

static int16x_t pcnt_w_1_sec;  // Count of pulses on watts led for a second.
static int16x_t pcnt_r_1_sec;  // Count of pulses on VARs led for a second.
#if PULSE_SOFT // software pulse outputs exist
static int16x_t pcnt_3_1_sec;  // Count of pulses on output 3 for a second.
static int16x_t pcnt_4_1_sec;  // Count of pulses on output 4 for a second.
#endif // software pulse outputs exist

static int16x_t pcnt_duration; // seconds remaining to count pulses

static bool pcnt_enable;       // 1 = counting is on
static bool pcnt_continuous;   // 1 = counting is always on

//====================================================================//
void pulse_cnt_lcd (uint8_t select_phase, uint8_t select_interval)
{
    switch (select_phase)
    {
       case 0:  case 1:
          switch (select_interval)         
          {
             case 0:  
             case 1:  pcnt_w ();        break;
             case 2:  pcnt_diff_w ();   break;
          }
          break;

       case 2:
          switch (select_interval)         
          {
             case 0:
             case 1:  pcnt_r ();        break;
             case 2:  pcnt_diff_r ();   break;
          }
          break;

       case 3:
          switch (select_interval)         
          {
             case 0:
             case 1:  pcnt_3 ();        break;
             case 2:  pcnt_diff_3 ();   break;
          }
          break;

       case 4:
          switch (select_interval)         
          {
             case 0:
             case 1:  pcnt_4 ();        break;
             case 2:  pcnt_diff_4 ();   break;
          }
          break;
    }
}

#pragma save
#pragma NOAREGS
// counts w pulses (rising edge of the W pulse LED output on DIO 6)
// The trick is that the "read" logic of the DIO pin can "see" the
// output of the pulse logic.
void pcnt_w_isr (void) small reentrant interrupt IO_INT0_IV
{
    ++pcnt_w_cache; // designed to be fast
}
#pragma restore

#pragma save
#pragma NOAREGS
// counts r pulses (rising edge of the R pulse LED output on DIO 7)
// The trick is that the "read" logic of the DIO pin can "see" the
// output of the pulse logic.
void pcnt_r_isr (void) small reentrant interrupt IO_INT1_IV
{
    ++pcnt_r_cache; // designed to be fast
}
#pragma restore

// accumulates and times the pulses, 
// called from 1 second interrupt by real-time-clock
#pragma save
#pragma NOAREGS
// since this is an interrupt, the saved value of EA is always 1
#define ea 1
// called from the interrupt decode routines in io65??.c
// in order to synchronize the counts with the wall-time clock.
void pcnt_accumulate (void) small reentrant
{
   if (pcnt_enable)
   {
       if (--pcnt_duration < 0)    // is pulse-counting interval ended?
       {
           pcnt_duration = -1;
           pcnt_enable = pcnt_continuous;   // stop counting
       }

       // add cached 16-bit counts to main 64-bit counts
       IRQ_DISABLE();                // Begin critical section. 
       pcnt_w_1_sec = pcnt_w_cache;
       pcnt_w_cache = 0;
       IRQ_ENABLE();                 // End critical section. 

       // add cached 16-bit counts to main 64-bit counts
       IRQ_DISABLE();                // Begin critical section. 
       pcnt_r_1_sec = pcnt_r_cache;
       pcnt_r_cache = 0;
       IRQ_ENABLE();                 // End critical section. 

       #if PULSE_SOFT           // software pulse outputs exist
       IRQ_DISABLE();                // Begin critical section. 
       pcnt_3_1_sec = dPulse3_Cnt;   // Count pulses on output 3 for 1 second.
       dPulse3_Cnt = 0;
       IRQ_ENABLE();                 // End critical section. 

       IRQ_DISABLE();                // Begin critical section. 
       pcnt_4_1_sec = dPulse4_Cnt;   // Count pulses on output 4 for 1 second.
       dPulse4_Cnt = 0;
       IRQ_ENABLE();                 // End critical section. 
       #endif // software pulse outputs exist

       data_ready = TRUE;
   }
}
#undef ea
#pragma restore

#define ONE_MILLION 1000000L

int32_t pcnt_w_mod;
int32_t pcnt_r_mod;
#if PULSE_SOFT                       // software pulse outputs exist
int32_t pcnt_3_mod;
int32_t pcnt_4_mod;
#endif

// keep the pulse output update in the noninterrupting code.
// This keeps the counts from being updated while they're displaying.
// Normally called from meter_run in meter.c
void pcnt_update (void)
{
    if (data_ready)
    {
        data_ready = FALSE;

        pcnt_w_mod += pcnt_w_1_sec;
        if (pcnt_w_mod < 0)
            pcnt_w_mod = 0;
        while (pcnt_w_mod > ONE_MILLION)
            pcnt_w_mod -= ONE_MILLION;

        pcnt_r_mod += pcnt_r_1_sec;
        if (pcnt_r_mod < 0)
            pcnt_r_mod = 0;
        while (pcnt_r_mod > ONE_MILLION)
            pcnt_r_mod -= ONE_MILLION;

        #if PULSE_SOFT                       // software pulse outputs exist
        pcnt_3_mod += pcnt_3_1_sec;
        if (pcnt_3_mod < 0)
            pcnt_3_mod = 0;
        while (pcnt_3_mod > ONE_MILLION)
            pcnt_3_mod -= ONE_MILLION;

        pcnt_4_mod += pcnt_4_1_sec;
        if (pcnt_4_mod < 0)
            pcnt_4_mod = 0;
        while (pcnt_4_mod > ONE_MILLION)
            pcnt_4_mod -= ONE_MILLION;
        #endif                                    // software pulse outputs exist
    }
}

// Put out a pulse count
static void pcnt_out (int32_t d)
{
    LCD_Number (d, 6, 0);   // Display up to six digits.
}

// LCD output of pulse count W
static void pcnt_w (void)
{
    pcnt_out (pcnt_w_mod);  // Display upto six digits.
}

// LCD output of pulse count R
static void pcnt_r (void)
{
    pcnt_out (pcnt_r_mod);  // Display upto six digits.
}

#if PULSE_SOFT // software pulse outputs exist
// LCD output of pulse count 3
static void pcnt_3 (void)
{
    pcnt_out (pcnt_3_mod);  // Display upto six digits.
}

// LCD output of pulse count 4
static void pcnt_4 (void)
{
    pcnt_out (pcnt_4_mod);  // Display upto six digits.
}
#endif // software pulse outputs

// LCD output of the pulse count for the last counting interval
static void pcnt_differential_out (int32_t d)
{
    LCD_Number (d, 6, 0);   // Display up to six digits.
}

//
static void pcnt_diff_w (void)
{
    pcnt_differential_out ((int32_t) pcnt_w_1_sec); // Display upto six digits.
}

static void pcnt_diff_r (void)
{
    pcnt_differential_out ((int32_t) pcnt_r_1_sec); // Display upto six digits.
}

#if PULSE_SOFT // software pulse outputs exist
static void pcnt_diff_3 (void)
{
    pcnt_differential_out ((int32_t) pcnt_3_1_sec); // Display upto six digits.
}

static void pcnt_diff_4 (void)
{
    pcnt_differential_out ((int32_t) pcnt_4_1_sec); // Display upto six digits.
}
#endif // software pulse outputs

// counts pulses for a count of seconds; if seconds is <= 0, counts forever
// The trick is that the "read" logic of the DIO pin can "see" the
// output of the pulse logic.
void pcnt_start (int16_t seconds)
{
   EX_IO_INT0 = FALSE; // disable the pulse counting interrupts
   EX_IO_INT1 = FALSE;

   #if M6520 || TRACE10
   // Assure that the pins are not LCD pins
   if ((LCDX & LCD_NUM) > 14)
        LCDX = 14 | (LCDX & ~LCD_NUM);

   // Enable both pulse R and pulse W outputs
   DIO |= (DIO_PW | DIO_PV);

   // Assure that the pins' DIO logic is for outputs
   DIR0 |= USER0_7_ | USER0_6_;

   // Set pulse W pin's DIO's external interrupt to "int0 falling"
   // Set pulse R pin's DIO's external interrupt to "int1 falling"
   DIO_R[3] = 0x76;

   // Make the interrupts edge-triggered
   IT0 = 1;
   IT1 = 1;

   // Interrupt priorities are set in main.

   // Clear the interrupts
   IE0 = 1;
   IE1 = 1;
   #else
   #error unknown configuration 
   #endif

   pcnt_w_cache = 0;
   pcnt_r_cache = 0;
   pcnt_duration = seconds;
   pcnt_continuous = FALSE;
   pcnt_enable = TRUE; // start counting when the next second starts

   // enable the pulse counting interrupts
   EX_IO_INT0 = TRUE;
   EX_IO_INT1 = TRUE;
}

// for starting continuous pulse counting at reset
void pcnt_init (void)
{
   pcnt_start (1); // 1 second prevents the interrupt from halting..
   pcnt_continuous = TRUE; // before this runs.
}

#endif

/***************************************************************************
 * History
 * $Log: pcnt.c,v $
 * Revision 1.26  2006/10/13 00:51:11  tvander
 * Removed compile options for 6530, 6515;
 * renamed 6511 and 6513 to trace11 and trace13;
 * Binary verified unchanged from previous version.
 *
 * Revision 1.25  2006/03/10 00:07:04  tvander
 * Remove unused 64-bit pulse counting variables.
 *
 * Revision 1.24  2006/09/20 23:59:21  tvander
 * Interrupt priorities set in one place, main.c
 *
 * Revision 1.23  2006/09/18 19:31:31  tvander
 * Sets the pulse count interrupt priority from the centralized priority.
 *
 * Revision 1.22  2006/09/14 00:39:50  tvander
 * spaces for tabs
 *
 * Revision 1.21  2006/09/13 21:39:02  gmikef
 * *** empty log message ***
 *
 * Revision 1.20  2006/09/12 02:45:06  gmikef
 * *** empty log message ***
 *
 * Revision 1.19  2006/09/09 01:14:27  gmikef
 * *** empty log message ***
 *
 * Revision 1.18  2006/07/25 18:07:48  tvander
 * Fixed the pulse counting interrupts
 *
 * Revision 1.17  2006/06/14 02:46:37  tvander
 * Faster LCD display.
 *
 * Revision 1.16  2006/05/18 23:18:52  tvander
 * 16K and 32K
 * First cut at new requirements.
 * 32K 6521 is grossly tested.
 * All others have a clean compile with C51 8.02
 *
 * Revision 1.15  2006/04/12 21:32:38  tvander
 * Check in pcnt_start() to see if pulse outputs is valid was inverted.
 *
 * Revision 1.14  2006/03/08 03:10:57  gmikef
 * *** empty log message ***
 *
 * Revision 1.13  2006/03/08 00:08:02  tvander
 * Multiplexed interrupts are in io65xx.c
 * Added stubbed interrupt to io65xx.c
 * Clean build
 *
 * Revision 1.12  2006/03/06 03:39:55  Michael T. Fischer
 * More 6530 prep.
 *
 * Revision 1.11  2006/03/03 11:30:29  Michael T. Fischer
 * Prep for 6530 LCD, etc.
 *
 * Revision 1.10  2006/01/16 20:11:28  tvander
 * Clean Keil build, all versions
 *
 * Revision 1.9  2006/01/04 04:47:53  gmikef
 * Switched RMS and VA calculations to use floating point. (and Calibration).
 *
 * Revision 1.9  2005/12/31 00:13:36  gmikef
 * Switched to floating point arithmetic. Decided it is high even precision.
 * It is faster and no more code space.
 *
 * Revision 1.7  2005/10/08 04:41:25  tvander
 * Fixed priority inversion.
 * Rewrote watchdog to work in brownout, but of course it doesn't work.
 * Watchdog can now be defeated by clearing watchdog option to 0.
 * Reorganized watt hour modules (at last!).
 * Disabled reading of STATUS in 6521_cli because the CE's status is always SAG.
 * Tested with 6521_CLI; measurements seem to work.
 * Fixed other builds.
 *
 * Revision 1.6  2005/09/22 23:45:18  tvander
 * Clean build all models and unit tests, updated copyright to be fore Teridian
 *
 * Revision 1.5  2005/08/30 18:18:36  gmikef
 * *** empty log message ***
 *
 * Copyright (C) 2005 Teridian Semiconductor Corp. All Rights Reserved.    *
 * this program is fully protected by the United States copyright          *
 * laws and is the property of Teridian Semiconductor Corporation.         *
 ***************************************************************************/
/* pcnt.c */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -