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

📄 main.c

📁 单相复费率MSP430硬件时钟参考代码,MSP413设计方案
💻 C
📖 第 1 页 / 共 2 页
字号:
#include "msp430x41x.h"
#include "string.h"
#include "general.h"
#include "protocol.h"

// 系统秒计数
//unsigned char TimerSecond=0;
// 系统分钟计数
//unsigned char TimerMinute=0;
// 系统中各种事件指示标志
unsigned char SystemIndication;
// 外电掉电或低电压标识
unsigned char BreakOrLowPowerFlag;
// 当前记量属性
unsigned char PowerAttribute=0;
// 最大功率限制
//unsigned long PowerLimit=0;
// 记量计数,分别是正峰/正平/正谷/正尖/反峰/反平/反谷/反尖/正向校验/反向校验
__no_init unsigned char PowerScalar[10];
unsigned char PowerPulseCounter=0;
unsigned char PowerPulseConstant_;
// 系统时间信息
#ifdef _HARDWARE_RTC
unsigned char g_time[8];
#else
__no_init unsigned char g_time[7];
#endif
#ifdef _HARDWARE_RTC
unsigned char SystemTime_MonthHex;
#endif
// 定时器定时时长数组 - 定时单位改为秒
unsigned short TimerCounter[TIMER_NUMBER];
// 反向累计时间
unsigned char TotleTimeOfMiuns=0;
// 定时器处理函数数组
PROC_FUNC TimerProc[TIMER_NUMBER];
// 系统定时器Tick记数
unsigned char SystemTimeTick=0;

// 定时器处理函数 - 定时器时长以秒为单位
void RedundancyTimerProc(void)
{
    unsigned char index;

    for(index=0;index<TIMER_NUMBER;index++)
    {
        if(TimerCounter[index])
        {
            TimerCounter[index]--;
            if(!TimerCounter[index])
            {
                TimerProc[index]();
            }
        }
    }
}

// 电量数据存储操作-该处的存储只是当前月数据存储
void PowerDataStoreSlave(unsigned short addr,unsigned char data)
{
    unsigned long resultdata,tempdata;

    tempdata=Hex2Bcd((unsigned long)data);
    E2promRead(addr,(unsigned char *)&resultdata,4);
    resultdata=__bcd_add_long(resultdata,tempdata);
    E2promWrite(addr,(unsigned char *)&resultdata,4);
}

// 电量数据存储
void PowerDataStoreProc(unsigned char addr_offset,unsigned char pwr_data)
{
    unsigned char temp;

    if(pwr_data)
    {
        temp=addr_offset*4;
        // 保存至全局记录区
        PowerDataStoreSlave(ADDRESS_OF_TOTAL_POWER_PLUS+temp,pwr_data);
        // 保存至当前月数据记录区
        PowerDataStoreSlave(ADDRESS_OF_MONTH_CURRENT+temp,pwr_data);
    }
}

void PowerDataStore(void)
{
    unsigned char ii,jj,zf_totle[2]={0,0};

    // 完成总电量的计算
    for(ii=0;ii<COUNT_OF_CHARGE_RATE;ii++)
    {
        zf_totle[0]+=PowerScalar[ii];//总正电量计算
        zf_totle[1]+=PowerScalar[ii+4];//总反电量计算
    }

    for(jj=0;jj<2;jj++)
    {
        // 如果校验不通过,则丢弃该次数据
        if(zf_totle[jj]==PowerScalar[8+jj])
        {
            // 数据校验通过,首先完成hex到bcd的转换,之后完成数据存储
            for(ii=0;ii<COUNT_OF_CHARGE_RATE;ii++)
            {
                // 保存峰,平,谷电量
                PowerDataStoreProc(jj*5+ii+1,PowerScalar[ii+jj*4]);
            }
            // 保存总电量
            PowerDataStoreProc(jj*5,zf_totle[jj]);
        }
    }
    // 清零计量数据
    MemSetTo0(PowerScalar,10);
    ReadPPC();
}

unsigned char GetPowerAttribute(void)
{
    return((unsigned char)(PowerAttribute&0x07));
}

// 电量脉冲计算
void PowerPulseCalculate(void)
{
    unsigned char pwr_attr;

    pwr_attr=(unsigned char)GetPowerAttribute();

    if((PowerPulseConstant_!=8)&&(PowerPulseConstant_!=16)&&(PowerPulseConstant_!=32))
    {
        PowerPulseConstant_=16;
    }

    while(PowerPulseCounter>=PowerPulseConstant_)
    {
            // 正向计量属性统计
        PowerScalar[pwr_attr&0x03]++;
        // 正向校验和累加
        PowerScalar[8]++; 
        // 如果是反向电量,则在相应费率的正向处也累加
        if(pwr_attr&ATTRIBUTE_OF_PLUS_MINUS)
        {
            // 反向计量属性统计
            PowerScalar[pwr_attr&0x07]++;
            // 反向校验和累加
            PowerScalar[9]++;
        }
        // 更新脉冲计数
        _DINT();
        PowerPulseCounter-=PowerPulseConstant_;
        _EINT();
    }

    // 之前的累计电量超过1度才保存,保存至临时数据区
    if(PowerScalar[8]>=PULSE_COUNT_OF_PER_DEGREE)
    {
        PowerDataStore();
    }
}

// 结算日,结算时间判断及历史数据存储
void MonthSpanDetect(void)
{
    unsigned char monthinfo,data[4],i,temp;
#ifndef _HARDWARE_RTC
    unsigned char time_bcd[7];
#endif
	
#ifndef _HARDWARE_RTC
    GetSystemTimeBcd(time_bcd);
#endif
MonthSpanDetectStart:
    // 设置本月为默认结算月
#ifdef _HARDWARE_RTC
    monthinfo=SystemTime_MonthHex;
#else
    monthinfo=g_time[SPACE_OF_MONTH];
#endif
    // 读取记录的数据信息
    E2promRead(ADDRESS_OF_SETTLEMENT_HOUR,data,3);
    // 如果本月不等于上次结算月
    if(monthinfo!=data[2])
    {
        // 计算本月与上次结算月之间的差
        temp=(unsigned char)((monthinfo-data[2]+12)%12);
        // 如果差大于1,则强制结算上月
        if(temp>=2)
        {
            // 查找上月的月信息
            monthinfo=(monthinfo+11)%12;
            goto SURE_TO_SETTLEMENT;
        }
        // 如果今天大于结算日的日期,则结算
#ifdef _HARDWARE_RTC
        if(g_time[SPACE_OF_DAY]>data[1])
#else
        if(time_bcd[SPACE_OF_DAY]>data[1])
#endif
        {
            goto SURE_TO_SETTLEMENT;
        }
        // 如果今天等于结算日的日期
#ifdef _HARDWARE_RTC
        else if(g_time[SPACE_OF_DAY]==data[1])
#else
        else if(time_bcd[SPACE_OF_DAY]==data[1])
#endif
        {
            // 如果结算时间到了,则结算
#ifdef _HARDWARE_RTC
            if(g_time[SPACE_OF_HOUR]>=data[0])
#else
            if(time_bcd[SPACE_OF_HOUR]>=data[0])
#endif
            {
                goto SURE_TO_SETTLEMENT;
            }
        }
    }
    return;  //未到结算时间,则退出
    
SURE_TO_SETTLEMENT:
	
    // 结算之前数据强制记录
    PowerDataStore();

    for(i=0;i<40;i+=4)
    {
        // 读出当月的数据记录
        E2promRead(ADDRESS_OF_MONTH_CURRENT+i,data,4);
	
        // 将读出的数据写入历史记录区
        E2promWrite(ADDRESS_OF_MONTH_LOG+40*(monthinfo)+i,data,4);
    }
    // 清零当月数据记录
    _memset0_and_write_e2prom_(ADDRESS_OF_MONTH_CURRENT,40);
	
    // 更新结算月份记录
    // 月信息从0开始至11代表1月至12月
    E2promWrite(ADDRESS_OF_SETTLEMENT_RECODE_MON,&monthinfo,1);
	
    // 清除对过时的标记
    _memset0_and_write_e2prom_(ADDRESS_OF_SUCCESSSETTIME_FLAG,1);

    // 如果本月不等于刚刚结算过的月,则重新判断是否结算结算
    // 这里的处理主要是为了解决不能实时结算多个月的问题
#ifdef _HARDWARE_RTC
    if(SystemTime_MonthHex!=monthinfo)
#else
    if(g_time[SPACE_OF_MONTH]!=monthinfo)
#endif
        goto MonthSpanDetectStart;
}

void SaveTimeOfMiuns(void)
{
    if(TotleTimeOfMiuns)
        PowerDataStoreSlave(ADDRESS_OF_POWER_TIME_MINUS,TotleTimeOfMiuns);
    TotleTimeOfMiuns=0;
}

// 计量属性之平/谷/峰/尖确认,每分钟执行一次
void ExesAttributeDetect()
{
    unsigned char data[6],ptcnt; // 时段信息临时存储
    unsigned char ii,idx,temp;
#ifndef _HARDWARE_RTC
    unsigned char time_bcd[7];
#endif

#ifndef _HARDWARE_RTC
    GetSystemTimeBcd(time_bcd);
#endif

    // 读取时段数
    ReadPeriodOfTimeCount(&ptcnt);
    if(ptcnt>12) ptcnt=12;
    // 置idx为时段数减1
    idx=ptcnt-1;
    // 如果时段数不只一个的话
    if(ptcnt>1)
    {
        // 读取前2个时段信息
        E2promRead(ADDRESS_OF_TIME_SECT,data,6);
        // 如果第一个时段比第二个时段的时间大
        if(data[2]>data[5])
        {
            idx=(idx+1)%ptcnt;
        }
        // 如果前两个时段的小时数相等
        else if(data[2]==data[5])
        {
            // 如果第一个时段比第二个时段的时间大
            if(data[1]>data[4])
            {
                idx=(idx+1)%ptcnt;
            }
        }
    }
    // 置费率初始值
    E2promRead(ADDRESS_OF_TIME_SECT+idx*3,&temp,1);
    // 查找目前所处时段
    for(ii=0;ii<ptcnt;ii++)
    {
        idx=(idx+1)%ptcnt;
        // 读取时段表
        E2promRead(ADDRESS_OF_TIME_SECT+idx*3,data,3);
        // 如果系统时间的小时大于时段表中的小时,则更新费率属性
#ifdef _HARDWARE_RTC
        if(g_time[SPACE_OF_HOUR]>data[2])
#else
        if(time_bcd[SPACE_OF_HOUR]>data[2])
#endif
        {
            temp=data[0];
        }
#ifdef _HARDWARE_RTC
        else if(g_time[SPACE_OF_HOUR]==data[2])
#else
        else if(time_bcd[SPACE_OF_HOUR]==data[2])
#endif
        {
            // 如果系统时间的分钟大于时段表中的分钟,则更新费率属性
#ifdef _HARDWARE_RTC
            if(g_time[SPACE_OF_MINUTE]>=data[1])
#else
            if(time_bcd[SPACE_OF_MINUTE]>=data[1])
#endif
            {
                temp=data[0];
            }
        }
    }
    if(temp!=0) temp--;

    // 反向累计时间
    if(GetPowerAttribute()&ATTRIBUTE_OF_PLUS_MINUS)

⌨️ 快捷键说明

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