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

📄 avr465.c

📁 使用AVR单片机设计的单相电表设计程序.不使用专用电表芯片,直接用AVR单片机AD采样交流电压电流,计算电压电流有效值和有功功率及有功电度和功率因数.
💻 C
📖 第 1 页 / 共 3 页
字号:
/*****************************************************************************
*
* Atmel Corporation
*
* File              : AVR465.c
* Compiler          : IAR EWAAVR 3.10C
* Revision          : $Revision: 1.31 $
* Date              : $Date: Friday, July 02, 2004 11:12:00 UTC $
* Updated by        : $Author: kmeyer $
*
* Support mail      : avr@atmel.com
*
* Supported devices : This example is written for the ATmega88. Firmware
*                     as such should fit in any other AVR with 8kB Flash.
*
* AppNote           : AVR465: Single-Phase Power/Energy Meter with
*                     Tamper Detection.
*
* Description       : Main file.
*
****************************************************************************/

/// DETAILS: ////////////////////////////////////////////////////////////////
//
//  Author............................ Kim Meyer, Atmel Finland Design Center
//  Compiler.................................... IAR Embedded Workbench 3.10C
//  Chip type (Flash/SRAM/EEPROM).................... ATmega88 (8kB/1kB/512B)
//  Program type................................................. Application
//  Clock frequency............................................. 4.000000 MHz
//  Average usage of program stack (RSTACK)......................0x0016 bytes
//  Average usage of data stack (CSTACK).........................0x00E0 bytes
//
//  Project Options for "Release":
//    General-Target-Processor Configuration........................ ATmega88
//    General-Target-Memory Model...................................... Small
//    General-Library Configuration-Enable bit definitions................ ON
//    General-Library Configuration-printf formater..................... Full
//    General-System Configuration-Data stack-Size..................... 0x0F0
//    General-System Configuration-Return address stack-Size.............. 24
//    ICCAVR-Optimisations........................................ Size, High
//    ICCAVR-Optimisations-Enabled-Common subexpression elimination....... NO
//    ICCAVR-Optimisations-Enabled-Function inlining...................... NO
//    ICCAVR-Optimisations-Enabled-Code motion........................... YES
//    ICCAVR-Optimisations-Enabled-Cross call............................ YES
//    ICCAVR-Optimisations-Enabled-Clustering of variables................ NO
//
//  Memory Usage for "Release":
//    Program (Code)...................................... 7743 bytes (94.5%)
//    Variables (Data)..................................... 709 bytes (69.2%)
//
/////////////////////////////////////////// All your base are belong to us //


/////////////////////////////////////////////////////////////////////////////
//  I N C L U D E S
/////////////////////////////////////////////////////////////////////////////

#include <iom88.h>
#include <stdio.h>
#include <math.h>           // This is to be able to calculate square roots
#include <inavr.h>          // This is for EEPROM routines
#include "defines.c"        // Definitions
#include "AVR465.h"            


/////////////////////////////////////////////////////////////////////////////
//  G L O B A L   V A R I A B L E S
/////////////////////////////////////////////////////////////////////////////

struct  AccDataStructure    { signed long PL, PN, U2, IL2, IN2;
                            } Accumulator, Sum;
struct	ResultDataStructure { float PL, PN, U, IL, IN;
                              char ADC0_Gain, ADC1_Gain;
                            } Result;
struct	CalDataStructure    { unsigned int PCC[3];
                              float ILG[3], ING[3];
                              float UG;
                              unsigned int MC, DPC;
                            } CalCoeff={{0,24576,49152},
                                        {0.01,0.001,0.0002},
                                        {0.01,0.001,0.0002},
                                        0.2,10000,100};
struct        SampleStructure {
                                signed int Fresh, Previous;
                                signed long Filtered,PreviousFiltered,Calibrated;
                              } Sample[3];

signed long   Temp[5];
unsigned int  TC1ext,TC1extTOP,TC1extRem;
unsigned int  DisplayCounter,DPCActive,DPCIncrement;
unsigned int  GainHysteresis;
unsigned char Index,ADC0_Gain=0xFF,ADC1_Gain=0xFF,Flags;
int           SampleCounter,RxBuffer;
float         Tnum;


/////////////////////////////////////////////////////////////////////////////
//  I N T E R R U P T   S E R V I C E   R O U T I N E S
/////////////////////////////////////////////////////////////////////////////

// Watchdog timeout handler
#pragma vector=WDT_vect
__interrupt void WFT_ISR(void)
{
  // put timeout handler here
}

// USART Receiver interrupt service routine
#pragma vector=USART_RX_vect
__interrupt void USART_RX_ISR(void)
{
  char Status,Data;
  
  Status=UCSR0A;
  Data=UDR0;
  if ((Status & ((1<<FE0)|(1<<UPE0)|(1<<DOR0)))==0)
  {
    RxBuffer=Data;
    Flags=Flags|KEY_PRESSED;
  }
  else
    RxBuffer=0x00;
}

// USART Transmitter interrupt service routine
#pragma vector=USART_TX_vect
__interrupt void USART_TX_ISR(void)
{
  // use this ISR if buffered data output is needed
}

// Timer 1 overflow interrupt service routine
#pragma vector=TIMER1_OVF_vect
__interrupt void TC1_OVF_ISR(void)
{
  // this should never occur
}

// Timer 1 output compare A ISR: output is set or cleared on compare match
#pragma vector=TIMER1_COMPA_vect
__interrupt void TC1_COMPA_ISR(void)
{
  // DPCIncrement should be zero when OC1A is cleared and one when OC1A is set
  DisplayCounter=DisplayCounter+DPCIncrement;

  // Prepare to set or clear output, if counter extension active
  if (TC1extTOP>0)
  {
    TC1ext++;               // Increase extended counter
    if (TC1ext<TC1extTOP)   // Extended counter not yet reached TOP
    {
      TCCR1A=0x80;          // CLEAR output on next match
      DPCIncrement=0;       // Do not increment display counter on next match
    }
    else                    // Extended counter has reached TOP
    {
      if (TC1ext>TC1extTOP)
      { // Output has now been set: start all over
        TC1ext=0;           // Clear extended counter
        OCR1A=0xFFFF;       // Count full 16-bit cycles until extended TOP
        TCCR1A=0x80;        // CLEAR output on next match
        DPCIncrement=0;     // Do not increment display counter on next match
      }
      else
      { // All 16-bit full cycles done: now do remainder and then set output
        OCR1A=TC1extRem;    // Remainder to count on last extended cycle
        TCCR1A=0xC0;        // SET output on next match
        DPCIncrement=1;     // Do increment display counter on next match
      }
    }
  }
  else
    TC1ext=0;
    
  if (CalCoeff.DPC==DisplayCounter)
  {
    DisplayCounter=0;
    PORTD=(PIND&DIRD)|DPP;  // Set DPP high, other outputs remain static
    DPCActive=1;            // Start counting active time for DPP/DPN
  }
}

// Timer 1 output compare B interrupt service routine
#pragma vector=TIMER1_COMPB_vect
__interrupt void TC1_COMPB_ISR(void)
{
  unsigned char Temp;
  
  // OC1A was set on OCR1A compare match, now clear output
  Temp=TCCR1A;        // Save current register (set/clear on next match?)
  TCCR1A=0x80;	      // Set mode: clear OC1A on compare match
  TCCR1C=0x88;	      // Now force a compare match to clear output
  TCCR1A=Temp;	      // Set mode: as was (set/clear on next match)
}

// ADC interrupt service routine with auto input scanning
#pragma vector=ADC_vect
__interrupt void ADC_ISR(void)
{
  signed int	TempI;
  signed long 	TempL;

  PORTB=(PINB&DIRB)|DUTY;               // For duty cycle monitoring
  
  // Sampled data from ADC:   ADCW      Range=[0000...03FF]
  // Copy of sampled data:    Sample    Range=[0000...03FF]
  // Scaled copy of data:     Temp      Range=[00000000...0003FB01]
  // DC filtered data:        Filtered  Range=[FFFE0280...0001FD80]
  
  // Save copy of fresh sample. Current samples are inverted; invert back.
  // Index variable keeps track of sampled channel, as follows:
  //
  // ISR:          |XXX|  |XXX|  |XXX|  |XXX|  |XXX|  |XXX|  |XXX|  |XXX|  |
  // Index/MUX:    XXX|000000|111111|222222|000000|111111|222222|000000|1111
  // Sampling:     |XXXXXX|000000|111111|222222|000000|111111|222222|000000|
  // Processing:   |XXXXXX|XXXXXX|000000|111111|222222|000000|111111|222222|
  // --------------+------+------+------+------+------+------+------+------+--
  // Conversion:   N     N+1    N+2    N+3    N+4    N+5    N+6    N+7    N+8
  //
  Sample[Index].Previous=Sample[Index].Fresh;	// x[n+1] <- x[n]
  if (0==Index)                                 // x[n] <- DATA
    Sample[Index].Fresh=ADC;            // save voltage sample as is
  else
    Sample[Index].Fresh=(0x03FF-ADC);   // save inverted current sample

  // Apply filter for DC offset removal. Must use long data types for
  // precision! The transfer function is as follows:
  //
  //	y[n] = 0.996*y[n-1] + 0.996*x[n] - 0.996*x[n-1]
  Sample[Index].PreviousFiltered=Sample[Index].Filtered;  // y[n] <- y[n-1]
  TempL=255*(long)Sample[Index].Filtered;
  TempL=TempL>>8;
  TempI=Sample[Index].Fresh-Sample[Index].Previous;
  TempL=TempL+255*(long)TempI;
  Sample[Index].Filtered=TempL;
  
  // Don't change gain settings until signals have settled
  if (GainHysteresis)
  {
    Flags=Flags&(0xFF-MOREGAIN0);
    Flags=Flags&(0xFF-MOREGAIN1);
    GainHysteresis--;
  }
  else
    // Gain control. Index=1 => ADC0, Index=2 => ADC1
    switch (Index)
    {
      case  1:  // Step down gain, if RAW sample has saturated at high limit
                if (Sample[Index].Fresh>SAT_HI)
                  Flags=Flags|LESSGAIN0;
                // Step down gain, if RAW sample has saturated at low limit
                if (Sample[Index].Fresh<SAT_LO)
                  Flags=Flags|LESSGAIN0;
                // Don't increase gain if FILTERED amplitude above threshold
                if (Sample[Index].Filtered>AMP_LO)
                  Flags=Flags&(0xFF-MOREGAIN0);
                break;
        case 2: // Step down gain, if RAW sample has saturated at high limit
                if (Sample[Index].Fresh>SAT_HI)
                  Flags=Flags|LESSGAIN1;
                // Step down gain, if RAW sample has saturated at low limit
                if (Sample[Index].Fresh<SAT_LO)
                  Flags=Flags|LESSGAIN1;
                // Don't increase gain if FILTERED amplitude above threshold
                if (Sample[Index].Filtered>AMP_LO)
                  Flags=Flags&(0xFF-MOREGAIN1);
    }
  
  // Apply phase calibration. Due to multiplexing, there will be a delay
  // between subsequent data chennels, as follows:
  //
  // 	Delay = [ 360 degrees * f(mains) ] / [ 3 * f(sampling) ]
  //
  // At 2400Hz sampling rate, this means that fresh samples from ADC0 
  // and ADC1, for example, will actually have a time difference of 
  // 1/2400 = 0.42ms, which corresponds to (50*360)/2400 = 7.5 degrees
  // in a 50Hz mains environment. In addition, current transformers in
  // the analogue front end may typically contribute up to six degrees
  // of additional phase lag. Phase distortions are calibrated using
  // linear interpolation, as follows:
  //
  //	Calibrated = x[n-1] + CalibCoefficient * ( x[n] - x[n-1] )
  //
  // Note that linear interpolation is the same as a fixed time delay.
  // This means that higher frequency componentes will not be adjusted
  // correctly. Typically, though, not enough energy is present in the
  // higher frequency components to cause this to degrade accuracy below
  // acceptable levels.
  //
  // Also note that the higher the sampling rate, the lower is the
  // calibration range in degrees. If the sampling rate is too high,
  // then the linear interpolation as such can not compensate for the
  // phase lag of some DC immuned current transformers. Such
  // transformers can have a phase lag in excess of six degrees.
  TempL=Sample[Index].Filtered-Sample[Index].PreviousFiltered;
  TempL=TempL*CalCoeff.PCC[Index];
  TempL=TempL>>16;
  Sample[Index].Calibrated=Sample[Index].Filtered-TempL;
  
  // Save measurement data for voltage, current and active power on all
  // channels. For active power measurements; accumulate instantaneous
  // power product. For current and voltage measurements: accumulate
  // square of samples
  //
  // Range check:
  //
  // 	Filtered data:		Filtered  Range=[FFFE0280...0001FD80]
  // 	Prescaled data (>>5):	TempX	  Range=[FFFFF014...00000FEC]
  // 	Multiplication result:	(n/a)	  Range=[FF027E70...00FD8190]
  // 
  // 	Prescaled data (>>6):	TempX	  Range=[FFFFF80A...000007F6]
  // 	Multiplication result:	(n/a)	  Range=[FFC09F9C...003F6064]
  // 
  // Assuming that sampled data is stuck at full-scale (which it can't
  // be, since the high-pass filter would bias such a signal to zero),
  // then for accumulation purposes the maximum number of samples that
  // can be integrated is:
  //
  // 	MaxSamples(presc=32) = 7FFFFFFFh / 00FD8190h = 0081h = 129d

⌨️ 快捷键说明

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