📄 energyw.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 + -