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

📄 epm.c

📁 单相 CPU卡表复费率电能表,内部有提供I2C驱动,CPU卡驱动,NEC单片机0513等
💻 C
字号:
#include "sys_parameter.h"

byte data Timer0_Count = 0;
bit overload_ind=0;
unsigned char data real_pulse_count = 0;
/*
 * overload counter,6 minutes or 360 seconds polling
 *   10 --- 1.0 kW 4.5A
 *   20 --- 2.0 kW   9A
 *   40 --- 4.0 kW  18A
 *   80 --- 8.0 kW  36A
 *  120 ---  12 kW  54A
 */
byte overload_counter[4];
byte epm_state[2];
byte data pulse_counter;

/* pulse received, set to 1 when poweron */
bit    degree_ind = 1;

/*在中断里驱动用bit 就可以了*/
byte data pulse_tally = 0;

volatile unsigned short xdata Degree_Constant;
unsigned char pulse_constant_1_percent = 16;    //脉冲常数的1/100, 0.01KW


static uchar xdata temp;

void epmInit(void)
{
    epmOverloadChkInit();
    Timer0_Count=0;
	repair_relay_state();
    overload_ind=0;

    load_data(&temp,DB_MC,1);
	
    /* 获取上次记录的脉冲计数 */
	Count_direction=(bit)(0x01&ReadChar(DB_DSAVE+ReadChar(DB_MC)));
}

#define LOAD_CONTROL_THRESHOLD			0x89

void epmOverloadChkInit(void)
{
    load_data(&overload_counter[0],DB_LZFH,4);
    /* 拉闸负荷值不能为零 */
    if(isBCDZero(&overload_counter[0],POWER_DATA_LEN) == OK)
    {
        overload_counter[0]=LOAD_CONTROL_THRESHOLD;
    }
    overload_ind=0;
}

/*
 * 过载判断和处理函数,过载后拉闸一次
 */
void epmOverloadOper(void)
{
    /* 判断是否有过载 */
    if(overload_ind)
    {
        /* 当有过载指示时则拉闸一次 */
        epmUiDisplayCode(EPM_uP__);
        USR_RELAY_OFF_NO_SAVE();
		Sys_Timer.resume_power_supply_timer = RESUME_POWER_SUPPLY_TIME;
    }
    epmOverloadChkInit();
    overload_ind=0;
}

/*
 * 继电器开/关失败的处理函数(6分钟执行一次).处理项包括:
 *   1.继电器关失败时窃电电量的计算.
 */
void epmQDDLCalculate(void)
{
    byte  *qddl_data = data_buf;

    if(relay_fail_off)
    {
        /* 如果有继电器关失败,读取窃电电量值 */
        load_data(&qddl_data[0],DB_QDDL,POWER_DATA_LEN);
        /* 窃电电量值加一 */
        inc_bcd(&qddl_data[0]);
        /* 保存窃电电量数据 */
        save_data(&qddl_data[0],DB_QDDL,POWER_DATA_LEN);
    }
}

/*
 * 用户最大需求计算,并保存数据
 */
void epmZDXLCalculate(void)
{
    
	byte  *zdxl_data = data_buf;
    /*
     * 读取上一次记录的用户最大需量
     */
    load_data(&zdxl_data[0],DB_ZDXL,POWER_DATA_LEN);
    /*
     * 计算当前6分钟用户使用的电量
     */
    /* 读取拉闸负荷设置 */
    load_data(&zdxl_data[4],DB_LZFH,POWER_DATA_LEN);
    if(OK != isBCDZero(&zdxl_data[4],POWER_DATA_LEN))
    {
		if(compbcd(&zdxl_data[4],&overload_counter[0]))
	    {
		    /* 拉闸负荷-剩余负荷=已使用负荷 */
		    bcdsub(&zdxl_data[4],&overload_counter[0]);
		    /* 当前使用量与上一次使用量做比,记录大者 */
		    if(compbcd(&zdxl_data[0],&zdxl_data[4])==0)
		    {
		        save_data(&zdxl_data[4],DB_ZDXL,POWER_DATA_LEN);
		    }
	    }
    }

}

/*
 * 记录用户实际使用的电量
 */
static uchar xdata pulse_pos,pulse_num,pulse_dec,timer;
 
void epmPowerRecord(void)
{
    byte  *power_data = data_buf;
	byte  *powerbak_data = data_buf + POWER_DATA_LEN*5;

    timer=0;

	if(IsPowerOFF())
    {
		return;
	}
	/* 判断是否有脉冲计数 */
    if(pulse_counter)
    {
        /* 获取当前脉冲计数单元的位置 */
        load_data(&pulse_pos,DB_MC,1);
        /* 获取上次记录的脉冲计数 */
        load_data(&pulse_num,DB_DSAVE+pulse_pos,1);

        ET0=0;
        /* 上次记录的脉冲计数+当前的脉冲计数=总的脉冲计数 */
        pulse_num+=pulse_counter;
        pulse_dec=pulse_counter;
        /* 清零当前脉冲计数,重新开始计数 */
        pulse_counter=0;
        ET0=1;

        /*过负荷检查*/
        if(!overload_ind)
        {
            while(pulse_dec > 0) /*判断是否进入拉闸复合*/
            {
                if(OK == isBCDZero(&overload_counter[0],POWER_DATA_LEN))
                {
                    overload_ind=1;
                    break;
                }
                dec_bcd(&overload_counter[0]);
                pulse_dec --;
             }
        }

        /* 当当前脉冲大于100,表示用户已经用了1度电 */
        if(pulse_num>=PULSE_PER_KWH)
        {
            degree_ind=1; /* 每用一度电才进入一次epmPowerMonitor */

            pulse_num-=PULSE_PER_KWH;
            /* 获取过零电量,剩余电量,累计用电量数据 */
            load_data(&power_data[0],DB_SYDL,POWER_DATA_LEN*5);
            /* 判断剩余电量是否为零 */
            if(OK == isBCDZero(&power_data[DB_SYDL-DB_SYDL],POWER_DATA_LEN))
            {
                /* 当剩余电量等于零时,过零电量加1 */
                inc_bcd(&power_data[DB_GLDL-DB_SYDL]);
            }
            else
            {
                /* 当剩余电量大于零时,剩余电量减1 */
                dec_bcd(&power_data[DB_SYDL-DB_SYDL]);
            }
			
            /* 累计用电量加1 */
            inc_bcd(&power_data[DB_LJDL-DB_SYDL]);

            do{
                /* 保存过零电量,剩余电量,累计用电量数据 */
                save_data(&power_data[0],DB_GLDL,POWER_DATA_LEN*5);
                /* 回读数据 */
                load_data(&powerbak_data[0],DB_GLDL,POWER_DATA_LEN*5);
                if(OK == IsEqual(power_data,powerbak_data,POWER_DATA_LEN * 5))  break;
                    
                /*延迟回避干扰*/
                delays_sixteenth(2);
                
            }while(++ timer < 3);
            
            /* 获取记录当前脉冲计数单元的位置 */
            if((++pulse_pos) >= DEC_LOOP_NUMBER) pulse_pos=0;
            /* 保存当前脉冲计数 */
            save_data(&pulse_pos,DB_MC,1);
            save_data(&pulse_num,DB_DSAVE+pulse_pos,1);
        }
        else
        {
            /* 保存当前脉冲计数 */
            save_data(&pulse_num,DB_DSAVE+pulse_pos,1);
        }
    }
}

uchar get_epm_state(void)
{
	byte  *sydl = data_buf;
	byte  *yjmx = data_buf + 4;
	byte  *gldl = data_buf + 8;
	byte  *gjdl = data_buf + 12;


        load_data(&sydl[0],DB_SYDL,POWER_DATA_LEN);
        if(OK == isBCDZero(&sydl[0],POWER_DATA_LEN)) // == 0
        {
            load_data(&gldl[0], DB_GLDL, POWER_DATA_LEN);
            load_data(&yjmx[0], DB_YJMX, POWER_DATA_LEN);
            if(compbcd(&gldl[0],&yjmx[0])) // gldl >= yjmx
            {
                return DB_STA0_RUN_A4;
            }
            else // gldl < yjmx
            {
                return DB_STA0_RUN_A3;
            }
        }
        else // != 0
        {
            load_data(&gjdl[0],DB_BJDL1,POWER_DATA_LEN);
            if(compbcd(&gjdl[0],&sydl[0])) // gjdl1 >= sydl
            {
                //load_data(&gjdl[0],DB_BJDL2,3);
                //if(compbcd(&gjdl[0],&sydl[0])) // gjdl2 >= sydl
                //{
                //   return DB_STA0_RUN_A2;
                //}
                //else // gjdl2 < sydl
                //{
                return DB_STA0_RUN_A1;
                //}
            }
            else // gjdl1 < sydl
            {
                 return DB_STA0_RUN_A0;
            }
        }
}


static uchar xdata new_state;
void epmPowerMonitor(void)
{

    /* 只在有用1度电的时候或者子状态不正确的时候才进入检查电量操作 */
    if((1==degree_ind)|| epm_state[1]>DB_STA0_RUN_A4 )
    {
	    degree_ind=0;
		new_state=get_epm_state();
		if( (epm_state[1]&0xEF) == new_state )
		{
			if( epm_state[1]&0x10)//0x10
			{
				epm_state[1]=new_state;
				epmSubStateSet();		
			}
		}
		else//有了改变
		{
			if(new_state)
			{
				epmUiDisplayCode(EPM___A1+new_state-1);
			}
		
   			if(new_state>DB_STA0_RUN_A1)
			{
				USR_RELAY_OFF();
			}
			else
			{
				USR_RELAY_ON();
			}
		   epm_state[1]=new_state;
		   epmSubStateSet();
		   epmPowerDisplayOn();		

		}		
    }
    if(epm_state[1]) epmPowerDisplayOn();
    else epmPowerDisplayOff();
}

static uchar xdata relay_state_temp;
void repair_relay_state(void)
{
    /* 继电器should状态赋初值 */
    load_data(&relay_state_temp,DB_RELAY_STA,1);

    if(RELAY_STATUS_ON == relay_state_temp) 
		USR_RELAY_ON_NO_SAVE();
	else 
		USR_RELAY_OFF_NO_SAVE();

	
}

void delays_sixteenth(byte sixteenth_sec)
{
	uchar xdata  old_EA;
	old_EA = EA;
	EA = 1;

    while(sixteenth_sec)
    {
		if(sixteenth_flag)
		{
			sixteenth_flag=0;			
		    WDI_RESET();
			sixteenth_sec--;
		}
    }
	EA = old_EA;
}


⌨️ 快捷键说明

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