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

📄 energyw.c

📁 一个电表的程序
💻 C
字号:
#ifndef _ENERGY_C_
#define _ENERGY_C_
#include "Energyw.h"
#define KWH_CONST 3200
#define I2CREAD  0x01
#define I2CWRITE 0x00
#define EE_DATA_START       0x00
#define EE_SETTING_START    0x20
#define EE_CAL_START        0x30
#define F                   0xff
__idata EEDATA        EEData;
__idata unsigned int Irms;
__idata unsigned int Vrms;
__idata unsigned int ActivePower;
__idata unsigned int ReactivePower;
__idata unsigned int ApparentPower;
//__idata unsigned int PowerFactor;
__idata unsigned int Frequency;
__idata unsigned int Temperature;
__idata unsigned char VGain;
__idata unsigned char IGain;
//底下这些变量都去新增加上去的
__idata unsigned int ILSB;
__idata unsigned int VLSB;
__idata unsigned int WATTHRLSB;
__idata unsigned int VARHRLSB;
__idata unsigned int VAHRLSB;
// FActivePower,FReactivePower,被用来记录有功,无功功率的方向,奇数为负, 偶数为正
// FActivePowerCounter ,FActivePowerCounter ,被用来记录有功,无功功率的方向变化的次数
__idata unsigned char CF1Counter=0;
__idata unsigned char PCF1Counter=0;
__idata unsigned char NCF1Counter=0;
__idata unsigned char CF2Counter=0;
__idata unsigned char PCF2Counter=0;
__idata unsigned char NCF2Counter=0;
__idata unsigned char TamperCounter=0;

__idata unsigned char  FActivePower=0;
__idata unsigned char  FActivePowerCounter=0;
__idata unsigned char  FReactivePower=0;
__idata unsigned char  FActivePowerCounter;



//#define EE_CAL_START        0x30
/*
*****************************************************************************************************
  I2C 的布局:
*************************************************************************************************************************************************************
*/
//0x30            eeIBGAIN          12S
//0x31
//0x32            WGAIN           12S
//0x33
//0x34            VARGAIN         12S
//0x35
//0x36            VAGAIN          12S
//0x37
//0x38            WATTOS          16S
//0x39
//0x3A            VAROS           16S
//0x3B
//0x3C            IRMSOS          12S
//0x3D
//0x3E            VRMSOS          12S
//0x3F
//0x40            CF1DEN          16U
//0x41
//0x42            CF2DEN          16U
//0x43
//0x44            PHCAL           8S
//0x45             ILSB           16U
//0x46
//0x47             VLSB           16U
//0x48
//0x49             WATTHRLSB      16U
//0x4A
//0x4B             VARHRLSB       16U
//0x4C
//0x4D             VAHRLSB        16U
//0x4E
//0x4F              VGAIN         8S
//0x50              IGAIN         8S

/*******************************************************************************/
void EnergyReload(void)
{
    I2C_Read(0xa8, EE_DATA_START, &EEData.AE,24);
}
void EnergySave(void)
{
 //   I2C_Write(0xa8, EE_DATA_START , &EEData.AE,len);// 把总有功,正向有功,反向有功,总无功,正向无功,反向无功写到EE里面
 // 因为EE(AT24C08)的缓冲区最大只能写入16个字节,所以大于16个字节的写入要分两次写
      I2C_Write(0xa8, EE_DATA_START , &EEData.AE, 16);
      I2C_Write(0xa8, EE_DATA_START+16 , &EEData.PRE, 8);

}

void EnergyInit(void)
{
    unsigned char i;
    unsigned char regnum;
    //Config the mode registers
    SetEnergyReg1(MODE2,    (ZXRMS|CF1_WATT|CF2_VAR|FREQSEL)); //在cheng_rom的基础上增加了一个FREQUENCY测量 FREQSEL,只有在校正CF 时,需要用到ACCMULATION TIME,此时,设置成测量PERIOD的状态
    SetEnergyReg1(MODE1,    0x00);                             // 使能了 CF1_WATT 和 CF2_VAR 的 输出,并且使能了LPF1
    SetEnergyReg1(CALMODE,  SEL_ICH_A);                        //选择电流通道IA为输入电流的通道
    SetEnergyReg1(NLMODE,   (VANOLOAD_OFF|VARNOLOAD_OFF|APNOLOAD_OFF));//设置无负载检测电压值
    SetEnergyReg1(GAIN,     (PGA2_X1|PGA1_X16));               //设置电流,电压采样通道的增益放大倍数
    SetEnergyReg1(ACCMODE,  (ABSVARM | ABSAM));                // 有功、无功按绝对值放式叠加
    SetEnergyReg1(LINCYC,   0x64);                             //
    SetEnergyReg2(SAGLVL,0xXX,0xXX);                         //设定掉电检测的阀值
    SetEnergyReg1(SAGCYC,0xXX);                                //设定时间,为掉电检测
    SetEnergyReg2(IPKLVL,0xXX,0xXX);                         //设定电流峰值检测的阀值
    SetEnergyReg2(VPKLVL,0xXX,0xXX);                         //设定电压峰值检测的阀值
    SetEnergyReg2(ZXOUT,0xXX,0xXX);                          //设定过零检测时间峰值的阀值
    SetEnergyReg2(WAVMODE, 0xXX,0xXX) ;                      // 配置 输出波形的种类(电流,电压,有功功率乘积等)和输出的速度
    SetEnergyReg2(CF1DEN,   0x08,       0x29);                 //被用来设置脉冲常数,这里面初步把脉冲常数设定为3200
    SetEnergyReg2(CF2DEN,   0x08,       0x29);                 //被用来设置脉冲常数,这里面初步把脉冲常数设定为3200

    //Reload the calibration data
    //todo: verify the calibration data before setting to registers
    for(i=EE_CAL_START, regnum = IBGAIN ; i < EE_CAL_START + 20; )
    {
        MDATL = I2C_ReadByte(0xa8,i++) ;
        MDATM = I2C_ReadByte(0xa8,i++) ;
        MADDPT= regnum ;
        SomeNops() ;                  // 从这里开始,用EE_CAL_START读回来的值覆盖ADE寄存器的值。这些寄存器分别是 IBGAIN(12S) ,WGAIN(12S),
        if(i>=16)                              // VARGAIN(12S) , VAGAIN(12S),WATTOS(16S),VAROS(16S),IRMSOS(12S),VRMSOS(12S),CF1DEN,CF2DEN
        {
        regnum++ ;
        regnum++ ;
        }
        else
           regnum++ ;
    }
    MDATL  = I2C_ReadByte(0xa8,i++); //也就是说 PHCAL的值放在 I2C的0x34 这个位置
    MADDPT = PHCAL; //
    SomeNops() ;
    I2C_ReadBlock(0xa8,i++,&ILSB,2);
    I2C_ReadBlock(0xa8,i++,&VLSB,2);
    I2C_ReadBlock(0xa8,i++,&WATTLSB,2);
    I2C_ReadBlock(0xa8,i++,&VARLSB,2);
    I2C_ReadBlock(0xa8,i++,&VALSB,2);
    VGain  = I2C_ReadByte(0xa8,i++);
    IGain  = I2C_ReadByte(0xa8,i++);
 //   Config the interrupts
    MIRQSTH = 0;
    MIRQSTM = 0;
    MIRQSTL = 0;
    MIRQENL = 0;
    MIRQENM = IE_CF2|IE_CF1;
    MIRQENH = IE_CYCEND|IE_PKV|IE_PKI|IE_WFSM;

    IEIP2_bit.EADE = 1;
//  IE_bit.EA=1;  中断允许位的设置

}

void MeasureAll(void)
{
    unsigned long temp32;
    static ADE_REGS temp;

    GetEnergySFR(VRMS,temp.bytes.DataL,temp.bytes.DataM,temp.bytes.DataH);
    temp32 = 0; //temp32 must be cleared before being used again
    temp32 = temp.wordH.high;
    Vrms = (unsigned int)((temp32 * (VLSB + VGain))>>11);

    GetEnergySFR(IRMS,temp.bytes.DataL,temp.bytes.DataM,temp.bytes.DataH);
    temp32 = 0;
    temp32 = temp.all>>4;
    Irms = (unsigned int)(temp32 * (ILSB + IGain) >> 15);//for shunt

    GetEnergyReg(LWATTHR,temp.bytes.DataL,temp.bytes.DataM,temp.bytes.DataH);
    temp32 = 0;
    temp32 = temp.all;
    ActivePower = (unsigned int)((temp32*WATTHRLSB)>>11);

    GetEnergyReg(LVARHR,temp.bytes.DataL,temp.bytes.DataM,temp.bytes.DataH);
    temp32 = 0;
    temp32 = temp.all;
    ReactivePower = (unsigned int)((temp32*VARHRLSB)>>11);

    GetEnergyReg(LVAHR,temp.bytes.DataL,temp.bytes.DataM,temp.bytes.DataH);
    temp32 = 0;
    temp32 = temp.all;
    ApparentPower = (unsigned int)((temp32*VAHRLSB)>>11);

   // PowerFactor =(unsigned int) ActivePower/ApparentPower ;

    GetEnergyReg(PER_FREQ,temp.bytes.DataL,temp.bytes.DataM,temp.bytes.DataH);
    Frequency = 40983607l/temp.wordL.low;//
    if((Frequency > 6500)||(Frequency < 4000))Frequency = 0;
}
#pragma vector = 0x4b
__interrupt void ADE_ISR(void)// 产生 ADE 中断的方式很多 ,有出脉冲的,有功率方向发生变化的 等等
{                             // 该中断处理程序只处理 1 出脉冲,2 功率方向发生变化,3 CYCEND 事件 引发的中断
    //temp    = MIRQSTL;
    if(MIRQSTM & IF_CF1)
    {
        //todo: Count CF1 for Active Energy
        MIRQSTM &= ~IF_CF1;// 清标志位
        CF1Counter++;//

        ActiveEnergy+=BCD32INC(CF1Counter * WATTHRLSB);
        if (FActivePower)
        {
            NCF1Counter++ ;
            NActiveEnergy+=BCD32INC(NCF1Counter*WATTHRLSB);
          //    //用于合成电流的方向

        }
        else
        {
            PCF1Counter++ ;
            PActiveEnergy+=BCD32INC(PCF1Counter*WATTHRLSB);
        }
//用来控制多少时间更新一次屏幕,并往EE里面写数据
        if(CF1Counter >= (KWH_CONST/100))
        {
            CF1Counter =0;
            NCF1Counter=0;
            PCF1Counter=0;

         ActiveEnergy = BCD32Inc(ActiveEnergy);
         PActiveEnergy= BCD32Inc(PActiveEnergy);
         NActiveEnergy= BCD32Inc(NActiveEnergy);
            //todo: set flag to save energy to eeprom
           // FlagTask_bit.FlagSaveData=1;
         I2C_Write(0xa8,EE_DATA_START,&EEData.AE,12);
        }
    }
    if(MIRQSTM & IF_CF2)
    {
        //todo: Count CF2 for Reactive Energy
        MIRQSTM &= ~IF_CF2;
        CF2Counter++ ;
        ReactiveEnergy+=BCD32INC(CF2Counter * VARHRLSB);
        if (FReactivePower)
        {
              NCF2Counter++;
              NReactiveEnergy+=BCD32INC(NCF2Counter* VARHRLSB);
        }
         else
         {
               PCF2Counter++;
               PReactiveEnergy+=BCD32INC(PCF2Counter * VARHRLSB);
         }
        if(CF2Counter >= (KWH_CONST/100))
        {
            CF2Counter =0;
            NCF2Counter=0;
            PCF2Counter=0;
           ReactiveEnergy = BCD32Inc(ReactiveEnergy);
           PReactiveEnergy= BCD32Inc(PReactiveEnergy);
           NReactiveEnergy= BCD32Inc(NReactiveEnergy);
            //todo: set flag to save energy to eeprom
            //FlagTask_bit.FlagSaveData=1;
            I2C_Write(0xa8,EE_DATA_START+12,&EEData.RE,12);
        }
    }
    if(MIRQSTH & IF_CYCEND)
    {
        //todo: Set Linecyc End Flag
        FlagTask_bit.FlagMeasure  = 1;
    }
    if (MIRQSTL&IF_APSIGN)
    {
      // todo: 记录功率的方向 , FActivePower用来表示功率的方向,奇数表示功率方向为负,偶数表示功率方向为正,和ACCMODE 的设置相关
           MIRQSTL &= ~IF_APSIGN;
           FActivePowerCounter++;
           if( FActivePowerCounter%=2)

              SetEnergyReg1(ACCMODE,  (ABSVARM | ABSAM| APSIGN_N_P ));
              Irms = (unsigned int)(temp32 * (ILSB + IGain) >> 15);
           else
              SetEnergyReg1(ACCMODE,  (ABSVARM | ABSAM| APSIGN_P_N ));
           FActivePower++;
           FActivePower %= 2;
    }
    if (MIRQSTL&IF_VARSIGN)
    {
      // todo: 记录功率的方向 ,奇数表示功率的方向为负,偶数表示功率的方向为正,和ACCMODE的设置相关
           MIRQSTL &= ~IF_VARSIGN;
           FReactivePowerCounter++;
           if( FReactivePowerCounter%=2)

               SetEnergyReg1(ACCMODE,  (ABSVARM | ABSAM| VARSIGN_N_P ));

           else
               SetEnergyReg1(ACCMODE,  (ABSVARM | ABSAM| VARSIGN_P_N ));

           FReactivePower++;
           FReactivePower% = 2;
    }
    if (MIRQSTL&IF_FAULTSIGN )
    {
      //todo: 记录偷电的次数
           MIRQSTL &= ~IF_FAULTSIGN;
           TamperCounter++;
    }
    if(MIRQSTH&IF_WFSM)
    {
    //todo: 处理波形数字信号生成其值并已经出现在波形寄存器里的中断事件

    }
    if(MIRQSTH&IF_PKI)
    {
    //todo: 处理超过电流信号峰值的中断事件

    }
        if(MIRQSTH&IF_PKI)
    {
    //todo: 处理超过电压信号峰值的中断事件

    }
    MIRQSTH = 0;
    MIRQSTM = 0;
    MIRQSTL = 0;
}
#endif

⌨️ 快捷键说明

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