stc单片机累计浮点数自动清零的问题

2019-07-15 21:13发布

本帖最后由 SHUAILONG2004 于 2013-12-24 16:22 编辑

写了个电表程序,把累计的电量值放在定义的一个浮点数中(float),一段时间后会自动清零,哪位大神知道是什么原因吗?程序在附件中,加了掉电存储和定时存入24C08,重启后读取,数值清零发生在芯片重启(可能是看门狗溢出)后,手动离线或断电,或者使看门狗启动都不会掉数据,但正常运行一段时间就会发生(E_Power)这个变量!

下面是主程序,后面是CS5460的程序




*************************************************************************/
#include <stdio.h>
#include <intrins.h>
#include <stc12c5a60s2.h>
#include "mytypes.h"
#include "i2c.h"
#include "spi.h"
#include "2send1re.H"
#include "net_com.h"
#include "DS1302.H"
#include "EEPROM.H"


//sbit RS485EE=P4^3;      //串口2定义485的使能脚A板
sbit RS485EE=P3^4;      //串口2定义485的使能脚B板
sbit RELAY=P4^1;      //RELAY3.5-4.1

sbit LED1=P3^6;      //led1  D14
sbit LED2=P3^5;      //led2 D15
sbit CP=P1^0;      //CP
unsigned char RELAY_val=0xff;     //继电器保存的值
unsigned char  SendFlag=0;
uchar g_eeprom_sector_cnt=0;
#define OFFLINE_tiME   130      //掉线检测周期130s
#define EEPROM_SECTOR_CNT 15  //16个扇区  
#define EEPROM_FLAG  0X66  //eeprom erase
#define S2RI 0x01
#define S2TI 0x02
bit RI2;
bit TI2;
//定时,延时用
unsigned int count=0;
unsigned int timer_count=0;
unsigned int gtimer_count2=0;
unsigned int gLoopQueryCount=0;
unsigned int g_comStat=0;
unsigned char g_ComCnt=0; //统计通信次数,离线判断用
volatile unsigned int His_data_len=0;
unsigned int E_Con=0;
unsigned int re_con=0;
//操作eeprom记录用
EEPROM_STAT g_eeprom_stat;
unsigned char xdata g_Address[56]={0};   //28K56个扇区
//数据集中器通信用变量
volatile uchar g_totalRvcCnt=0;
volatile uchar g_RvcCnt=0;
volatile bit g_NetStat;
uchar g_swStat,g_slaveId;
//延时用
volatile uint g_timeCnt;

unsigned char xdata E_Frame[20]={0};
unsigned char xdata EEPROM_Frame[25]={0}; //从EEPROM中读取的数据帧
float E_Power;
volatile unsigned char xdata Elect[6]={0};      //定义电量累计数据
unsigned char xdata UIData[6]={0};  //读取的电流和电压
unsigned char xdata N_Frame[20]={0};  //数据集中器对下发送的查询指令
typedef union
             {
      unsigned char var[4];
         float floatvar;
     }float_var;
float_var elevar;

/**************************************
           延时程序
**************************************/
void delay(uint i)
{
unsigned char j;
for(i; i > 0; i--)
  for(j = 200; j > 0; j--);
}
//*****************************************************************************
//函数名:     void save_parameter_toflash(void)
//函数功能描述: 保存参数到eerom
//函数参数:   无
//函数返回值:    无
//作者:    szl
//修改人:
//修改原因:
//*****************************************************************************
void save_parameter_toflash(void)
{
uint addr=0;
uchar xdata tmp[70];
addr=0x1fa4;
// addr=100;
// elevar.floatvar=E_Power;

tmp[0]=(uchar)g_eeprom_stat.last_write_addr;     //eeprom操作当前地址
tmp[1]=(uchar)g_eeprom_stat.last_write_addr>>8;     //eeprom操作当前地址
tmp[2]=g_eeprom_stat.record_cnt;     //记录数
tmp[3]=g_eeprom_stat.current_send_sector_num;     //已发送数据的当前扇区编号
tmp[4]=g_eeprom_stat.sector_send_up;     //上半部分记录已发送
tmp[5]=g_eeprom_stat.last_write_sector_num;     //最后一个扇区编号

tmp[6]=g_eeprom_stat.overflow_flag;     //溢出标志
tmp[7]=g_eeprom_stat.sector_cnt;     //扇区编号
tmp[8]=EEPROM_FLAG;     //parameter save flag,means save ok
       //
// tmp[9]=elevar.var[0];
// tmp[10]=elevar.var[1];
// tmp[11]=elevar.var[2];
// tmp[12]=elevar.var[3];    //保存累计电量
tmp[13]=RELAY_val;      //保存继电器状态
MyMemCpy(tmp+14,g_Address,56); //加入数据段
eeprom_data_write(tmp,addr,70);  //将数据存入eeprom
// write_i2c_data(addr,tmp,70);
}
//*****************************************************************************
//函数名:     void read_parameter_fromflash(void)
//函数功能描述: 从eerom读取参数
//函数参数:   无
//函数返回值:    无
//作者:    szl
//修改人:
//修改原因:
//*****************************************************************************
void read_parameter_fromflash(void)
{
uint addr=0;
uchar xdata tmp[70]={0};
addr=0x1fa4;
// addr=100;
eeprom_data_read(tmp,addr,70);
    eeprom_byte_erase(0x1e00);
// Uart2Send(tmp,70);
if(tmp[8]==EEPROM_FLAG)                    //保存过参数
{
  g_eeprom_stat.last_write_addr=tmp[0];     //eeprom操作当前地址
  g_eeprom_stat.last_write_addr=tmp[1]*256;     //eeprom操作当前地址 左移8位
  
  g_eeprom_stat.record_cnt=tmp[2];     //记录数
  g_eeprom_stat.current_send_sector_num=tmp[3];     //已发送数据的当前扇区编号
  g_eeprom_stat.sector_send_up=tmp[4];     //上半部分记录已发送
  g_eeprom_stat.last_write_sector_num=tmp[5];     //最后一个扇区编号
  
  g_eeprom_stat.overflow_flag=tmp[6];     //溢出标志
  g_eeprom_stat.sector_cnt=tmp[7];     //扇区编号
//  elevar.var[0]=tmp[9];
//  elevar.var[1]=tmp[10];
//  elevar.var[2]=tmp[11];
//  elevar.var[3]=tmp[12];
  RELAY_val=tmp[13];
//  E_Power=elevar.floatvar;
  MyMemCpy(g_Address,tmp+14,56); //加入数据段
   if(g_eeprom_stat.sector_cnt==0&&g_Address[0]==1)    //无离线保存的记录
  {
    His_data_len=1;
  }
  if(g_eeprom_stat.sector_cnt>0)    //有离线保存的记录
   {
    His_data_len=(g_eeprom_stat.sector_cnt-1)*30;
    His_data_len+=g_Address[g_eeprom_stat.last_write_sector_num];
    if(g_eeprom_stat.overflow_flag==1)
    {
     His_data_len=EEPROM_SECTOR_CNT*30;
     His_data_len+=g_Address[g_eeprom_stat.last_write_sector_num];
    }
   }
}else     //第一次使用
{
     EEPROM_Erase();
  delay(400);
  delay(400);
}
}
//*****************************************************************************
//函数名:     void poweroff_init(void)
//函数功能描述: 使能掉电检测中断
//函数参数:   无
//函数返回值:    无
//作者:    szl
//修改人:
//修改原因:
//*****************************************************************************
void poweroff_check_init(void)
{
P4SW&=0XBF;   //set p4.6 as lvd pin
WAKE_CLKO=0X08; //enable lvd signal wakeup mcu
ELVD=1;             //enable lvd interrupt
PCON&=0XDF;
}
//*****************************************************************************
//函数名:     void lvdint()
//函数功能描述: 掉电检测中断
//函数参数:   无
//函数返回值:    无
//作者:   szl
//修改人:
//修改原因:
//*****************************************************************************
void lvdint() interrupt 6
{
  uchar tmp;
PCON&=0XDF;  //clear LVD flag
tmp=(PCON&0X20);
if(tmp>0)  //还是1则是掉电了,否则是电源波动
{
   elevar.floatvar=E_Power;
   write_i2c_data(0,elevar.var,4);                      //掉电时保存电量数据
   save_parameter_toflash();    //保存数据
   PCON&=0XDF;  //clear LVD flag
   ELVD=0;             //disenable lvd interrupt
   PCON&=0Xfd;
}
}
//*****************************************************************************
//函数名:     void exint0()
//函数功能描述: 外部0中断处理 ,读取电表累计电量
//函数参数:   无
//函数返回值:    无
//作者:       szl
//修改人:
//修改原因:
//*****************************************************************************
void exint1() interrupt 2
  {
//   EA=0;
   SCAN_CS5460();
   SendFlag++;
//   EA=1;
  }

/**************************************
       取电表返回数据E_Frame中数据域处理并加入时钟nowTime组成新数组EEPROM_Frame
**************************************/
void NewFrame(void)
{
unsigned long elect ;
uchar xdata nowTime[7];
EX1=0;  //关闭外部中断
elect=E_Power;
Elect[2]=elect;
Elect[1]=elect>>8;
Elect[0]=elect>>16;
elect=E_Power;
Elect[3]=(E_Power-elect)*100;
//// if(Elect[3]==0xff)
//// {
////   unsigned char i;
////  for(i=0;i<6;i++)
////     {
////   Elect=0;
////   }
//// }
Elect[4]=0x01;       //表示后面没有其它电量数据
Elect[5]=0x04;       //电量值为四个字节
    EX1=1;    //打开外部中断
dsReadTime(nowTime);
Reverse(nowTime,7);
MyMemCpy(EEPROM_Frame,nowTime,7);  
MyMemCpy((EEPROM_Frame+7),UIData,6); ///----------------- 电流电压放入
MyMemCpy((EEPROM_Frame+13),Elect,6); //电量放入
MyMemCpy((EEPROM_Frame+19),Elect,4); //电量放入
// Uart2Send(EEPROM_Frame,17);
}


/*******************************************************
*******************************************************
                     主程序
*******************************************************
*******************************************************/
void main (void)
{

uint sysStat=0;
EA = 0;        // 关总中断
// LED1=1;
// LED2=0;
P0=0XFF;
PortsInit();  //set port0 input
GetSlaveId();
Uart2Init();  //1200   
// UartInit();  //4800
DS1302_init(); //DS1302 io初始化
// RtcInit();   //第一次使用时初始化DS1302时间
Timer0Init();
eeprom_op_init();
delay(1000);
    WDT_CONTR=0x3F;    //清狗指令
poweroff_check_init();  //使能掉电检测
read_parameter_fromflash();
//// P1DIR |= 0x60;  //P15、P16定义为输出
Init_5460(); //初始化SPI
// Sync_5460(); //5460校准
TR0=1;
g_comStat=0;      //默认不在线
//  
// RS485E=0; //串口2 485置接收
RS485EE=0; //串口1 485置接收
LED2=1;
read_i2c_data(0,elevar.var,4);
E_Power=elevar.floatvar;               //上电读取以前的累计电量
RELAY=RELAY_val;
IT1=0;        //外部1中断模式1 下降沿触发0低电平触发
EX1=1;        //外部1中断允许1允许中断 0禁止中断
EA =1;               // 开总中断
E_Con=0;
if(E_Power==0)                         //没读到数据再读一次
   {
     delay(100000);
     read_i2c_data(0,elevar.var,4);
     E_Power=elevar.floatvar;
       }
while(1)
   {
  sysStat++;
     WDT_CONTR=0x3F;    //清狗指令
  
  if(sysStat==120)   //灯闪一次
  {
   E_Con++;
   re_con++;
      if((g_comStat==0)&&(re_con>300))    //采集器离线
         {
       EA=0;
    elevar.floatvar=E_Power;
    write_i2c_data(0,elevar.var,4);
       ((void (code *) (void)) 0x0000) ();
      }
   sysStat=0;
      LED1=~LED1;   
   }
    //*******************************************************
//处理与主控制器的通信
//*******************************************************
  DealCmd();   //处理从控制器发来的命令
  LoopQueryStat();       //判断是否掉线
delay(20);
if(g_eeprom_stat.overflow_flag==1)
{
     g_eeprom_stat.read_start_sector=(g_eeprom_stat.last_write_sector_num+1);
}else
{
  g_eeprom_stat.read_start_sector=0;
}

//*******************************************************
//处理电表数据
//*******************************************************   
          if(g_comStat)  //如果控制器在线
   {
     if(g_Address[0]>1||g_eeprom_stat.sector_cnt>0)    //有离线保存的记录send and insert record
     {
         LostConnection_Process();  //处理从电表发来的数据(掉电存储)
     }
     else //没有离线保存的记录read and update data
     {
      
      if (SendFlag>=10)   //CS5460 转换就绪
      {
      //存储当前检测的数据
      SendFlag=0;      
      NewFrame();     //打包准备数据
      
      eeprom_byte_erase(0x0000);
      delay(100);
      eeprom_data_write(EEPROM_Frame,0x0000,23);   //将数据存入eeprom
      g_Address[0]=0x01;
      g_eeprom_stat.last_write_addr=0x00;       //存储记录
      g_eeprom_stat.last_write_sector_num=0;
      g_eeprom_stat.current_send_sector_num=0;
      His_data_len=1;
      if(E_Con==800)
      {
      E_Con=0;
      EA = 0;        // 关总中断
      while(1)
      {
      elevar.floatvar=E_Power;                   //定时保存电量数据至24C08
      write_i2c_data(0,elevar.var,4);
         read_i2c_data(0,elevar.var,4);
      if(elevar.floatvar==E_Power)
      break;
             WDT_CONTR=0x3F;    //清狗指令
      delay(100000);
      }
//      x24c08_write(5,RELAY_val);      
      EA = 1;
      }
      }
      }
   }
   else   //控制器离线
   {
               LostConnection_Process();  //处理从电表发来的数据(掉电存储)
   }
}
}


cs5460程序,只有最后涉及E_Power这个变量


void SCAN_CS5460(void)
   {

   VoltRMS = CS5460_GetRMS(12)*432.5;
   VoltRMS += 0.005;      //保留小数点后两位

   CurrentRMS = CS5460_GetRMS(11)*10.58;
   CurrentRMS += 0.005;    //保留小数点后两位
  
UIData[0]=CurrentRMS/256;
UIData[1]=CurrentRMS;
UIData[2]=(CurrentRMS-UIData[1])*100;
UIData[3]=VoltRMS/256;
UIData[4]=VoltRMS;
UIData[5]=(VoltRMS-UIData[4])*100;
if(UIData[2]>0)
  {
      ElectRMS=CS5460_GetElectRMS(10)*2.048*432.5*10.58;  //读取电量
   ElectRMS=ElectRMS/3600.0/1000.0 ;
   CurrentRMS=CurrentRMS/10000.0;
   if(ElectRMS<CurrentRMS)                          //过滤数据
   {
     float power;
  power=E_Power;
  power+=ElectRMS;
  if((power>0)&(ElectRMS<1))
     E_Power=power;
   }
   }
  Clear_DRDY();
}

友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
该问题目前已经被作者或者管理员关闭, 无法添加新回复
8条回答
SHUAILONG2004
1楼-- · 2019-07-16 03:07
本帖最后由 SHUAILONG2004 于 2013-12-24 16:04 编辑

a
SHUAILONG2004
2楼-- · 2019-07-16 08:48
本帖最后由 SHUAILONG2004 于 2013-12-24 16:06 编辑

b
SHUAILONG2004
3楼-- · 2019-07-16 13:44
 精彩回答 2  元偷偷看……
SHUAILONG2004
4楼-- · 2019-07-16 16:37
上面是CS5460程序,下面是主程序,主要是E_POWER这个变量


/*************************************************************************
* Copyright (c) 2012, 元澄智能科技有限公司
* All rights reserved.
* STC12C5A16S2
* 文件名称:2send1re.c
* 文件标识:2send1re.c
* 摘要:采集电表数据,存储,然后发送给网络控制器,如果控制器在线直接发送,不在线显存储,上线后发送
* 资源配置:UART1和网络控制器通信,UART2和电表通信
* 电表波特率:1200   和网络控制器通信波特率:4800
* eeprom分配最后一个扇区存放参数,其他的存放电量数据
*
* 当前版本:1.0.03
* 作者:wenzer
* 完成日期:2013-02-26
* 修改内容:
*
* 当前版本:1.0.04
* 修改者: 张振亮
* 完成日期:2012年11月10日
*
* 当前版本:1.0.05
* 修改者:         张振亮
*修改内容:命令接收函数,发送函数
* 完成日期:2013年03月18日
* 当前版本:1.0.07
* 修改者:         张振亮
*修改内容:命令接收函数,发送函数
* 完成日期:2013年03月25日
*************************************************************************/
#include <stdio.h>
#include <intrins.h>
#include <stc12c5a60s2.h>
#include "mytypes.h"
#include "i2c.h"
#include "spi.h"
#include "2send1re.H"
#include "net_com.h"
#include "DS1302.H"
#include "EEPROM.H"


//sbit RS485EE=P4^3;                           //串口2定义485的使能脚A板
sbit RS485EE=P3^4;                           //串口2定义485的使能脚B板

sbit RELAY=P4^1;                           //RELAY3.5-4.1


sbit LED1=P3^6;                           //led1  D14
sbit LED2=P3^5;                           //led2        D15

sbit CP=P1^0;                           //CP
unsigned char RELAY_val=0xff;                                 //继电器保存的值
unsigned char  SendFlag=0;
uchar g_eeprom_sector_cnt=0;

#define OFFLINE_TIME   130             //掉线检测周期130s
#define EEPROM_SECTOR_CNT 15                //16个扇区         
#define EEPROM_FLAG  0X66                //eeprom erase
#define S2RI 0x01
#define S2TI 0x02
bit RI2;
bit TI2;

//定时,延时用

unsigned int count=0;
unsigned int timer_count=0;
unsigned int gtimer_count2=0;
unsigned int gLoopQueryCount=0;
unsigned int g_comStat=0;
unsigned char g_ComCnt=0; //统计通信次数,离线判断用

volatile unsigned int His_data_len=0;
unsigned int E_Con=0;
unsigned int re_con=0;
//操作eeprom记录用
EEPROM_STAT g_eeprom_stat;
unsigned char xdata g_Address[56]={0};          //28K56个扇区






//数据集中器通信用变量
volatile uchar g_totalRvcCnt=0;
volatile uchar g_RvcCnt=0;
volatile bit g_NetStat;
uchar g_swStat,g_slaveId;

//延时用
volatile uint g_timeCnt;


unsigned char xdata E_Frame[20]={0};
unsigned char xdata EEPROM_Frame[25]={0};        //从EEPROM中读取的数据帧
float E_Power;
volatile unsigned char xdata Elect[6]={0};                    //定义电量累计数据
unsigned char xdata UIData[6]={0};                //读取的电流和电压
unsigned char xdata N_Frame[20]={0};                //数据集中器对下发送的查询指令
typedef union
             {
                           unsigned char var[4];
                       float floatvar;
                          }float_var;
float_var elevar;

//*****************************************************************************
//函数名:                  将一个数组所有元素清0
//函数功能描述:         
//函数参数:                 数组名,长度
//函数返回值:                  无
//作者:                  wenzer
//修改人:
//修改原因:
//*****************************************************************************
void my_bzero(unsigned char *arr,unsigned int len)
{
unsigned int i;
for(i=0;i<len;i++)
        {
          arr[i]=0;
        }
}
/**************************************
                  延时程序
**************************************/
void delay(uint i)
{
        unsigned char j;
        for(i; i > 0; i--)
                for(j = 200; j > 0; j--);
}
//*****************************************************************************
//函数名:                          void save_parameter_toflash(void)
//函数功能描述:        保存参数到24c08
//函数参数:                 无
//函数返回值:                  无
//作者:                  wenzer
//修改人:
//修改原因:
//*****************************************************************************
void save_parameter_toflash(void)
{
        uint addr=0;
        uchar xdata tmp[70];
        addr=0x1fa4;
//        addr=100;
//        elevar.floatvar=E_Power;
       
        tmp[0]=(uchar)g_eeprom_stat.last_write_addr;     //eeprom操作当前地址
        tmp[1]=(uchar)g_eeprom_stat.last_write_addr>>8;     //eeprom操作当前地址
        tmp[2]=g_eeprom_stat.record_cnt;     //记录数
        tmp[3]=g_eeprom_stat.current_send_sector_num;     //已发送数据的当前扇区编号
        tmp[4]=g_eeprom_stat.sector_send_up;     //上半部分记录已发送
        tmp[5]=g_eeprom_stat.last_write_sector_num;     //最后一个扇区编号
       
        tmp[6]=g_eeprom_stat.overflow_flag;     //溢出标志
        tmp[7]=g_eeprom_stat.sector_cnt;     //扇区编号
        tmp[8]=EEPROM_FLAG;     //parameter save flag,means save ok
                                                        //
//        tmp[9]=elevar.var[0];
//        tmp[10]=elevar.var[1];
//        tmp[11]=elevar.var[2];
//        tmp[12]=elevar.var[3];                  //保存累计电量
        tmp[13]=RELAY_val;                           //保存继电器状态
        MyMemCpy(tmp+14,g_Address,56);        //加入数据段

        eeprom_data_write(tmp,addr,70);  //将数据存入eeprom
//        write_i2c_data(addr,tmp,70);
}
//*****************************************************************************
//函数名:                          void read_parameter_fromflash(void)
//函数功能描述:        从24c08读取参数
//函数参数:                 无
//函数返回值:                  无
//作者:                  wenzer
//修改人:
//修改原因:
//*****************************************************************************
void read_parameter_fromflash(void)
{
        uint addr=0;
        uchar xdata tmp[70]={0};
        addr=0x1fa4;
//        addr=100;
        eeprom_data_read(tmp,addr,70);
    eeprom_byte_erase(0x1e00);
//        Uart2Send(tmp,70);

        if(tmp[8]==EEPROM_FLAG)                           //保存过参数
        {
                g_eeprom_stat.last_write_addr=tmp[0];     //eeprom操作当前地址
                g_eeprom_stat.last_write_addr=tmp[1]*256;     //eeprom操作当前地址 左移8位
               
                g_eeprom_stat.record_cnt=tmp[2];     //记录数
                g_eeprom_stat.current_send_sector_num=tmp[3];     //已发送数据的当前扇区编号
                g_eeprom_stat.sector_send_up=tmp[4];     //上半部分记录已发送
                g_eeprom_stat.last_write_sector_num=tmp[5];     //最后一个扇区编号
               
                g_eeprom_stat.overflow_flag=tmp[6];     //溢出标志
                g_eeprom_stat.sector_cnt=tmp[7];     //扇区编号
//                elevar.var[0]=tmp[9];
//                elevar.var[1]=tmp[10];
//                elevar.var[2]=tmp[11];
//                elevar.var[3]=tmp[12];
                RELAY_val=tmp[13];       
//                E_Power=elevar.floatvar;
                MyMemCpy(g_Address,tmp+14,56);        //加入数据段

                 if(g_eeprom_stat.sector_cnt==0&&g_Address[0]==1)                  //无离线保存的记录
                {
                  His_data_len=1;
                }
                if(g_eeprom_stat.sector_cnt>0)                  //有离线保存的记录
                        {
                                His_data_len=(g_eeprom_stat.sector_cnt-1)*30;
                                His_data_len+=g_Address[g_eeprom_stat.last_write_sector_num];
                                if(g_eeprom_stat.overflow_flag==1)
                                {
                                        His_data_len=EEPROM_SECTOR_CNT*30;
                                        His_data_len+=g_Address[g_eeprom_stat.last_write_sector_num];
                                }       
                        }
        }else                   //第一次使用
        {
            EEPROM_Erase();
                delay(400);
                delay(400);
        }

}
//*****************************************************************************
//函数名:                          void poweroff_init(void)
//函数功能描述:        使能掉电检测中断
//函数参数:                 无
//函数返回值:                  无
//作者:                  wenzer
//修改人:
//修改原因:
//*****************************************************************************
void poweroff_check_init(void)
{
        P4SW&=0XBF;   //set p4.6 as lvd pin
        WAKE_CLKO=0X08; //enable lvd signal wakeup mcu
        ELVD=1;             //enable lvd interrupt
        PCON&=0XDF;
}
//*****************************************************************************
//函数名:                          void lvdint()
//函数功能描述:        掉电检测中断
//函数参数:                 无
//函数返回值:                  无
//作者:                  wenzer
//修改人:
//修改原因:
//*****************************************************************************
void lvdint() interrupt 6
{
  uchar tmp;

        PCON&=0XDF;  //clear LVD flag
        tmp=(PCON&0X20);
        if(tmp>0)  //还是1则是掉电了,否则是电源波动
        {
          elevar.floatvar=E_Power;
          write_i2c_data(0,elevar.var,4);
          save_parameter_toflash();                                //保存数据
          PCON&=0XDF;  //clear LVD flag
          ELVD=0;             //disenable lvd interrupt
          PCON&=0Xfd;
        }
}

//*****************************************************************************
//函数名:                          void exint0()
//函数功能描述:        外部0中断处理 ,读取电表累计电量
//函数参数:                 无
//函数返回值:                  无
//作者:                     szl
//修改人:
//修改原因:
//*****************************************************************************
void exint1() interrupt 2
  {
//   EA=0;
   SCAN_CS5460();
   SendFlag++;
//   EA=1;
  }

//*****************************************************************************
//函数名:                          Timer0Init(void)
//函数功能描述:        定时器0初始化,初值设定1毫秒@11.0592MHz
//函数参数:         
//函数返回值:          
//作者:                  wenzer
//修改人:
//修改原因:
//*****************************************************************************
void Timer0Init(void)                //1毫秒@11.0592MHz
{
        AUXR |= 0x80;                //定时器时钟1T模式
        TMOD &= 0xF0;                //设置定时器模式
        TMOD |= 0x01;                //设置定时器模式
        TL0 = 0xCD;                //设置定时初值
        TH0 = 0xD4;                //设置定时初值
        TF0 = 0;                //清除TF0标志
        TR0 = 1;                //定时器0开始计时
        ET0 = 1;
        count = 1;

}
//*****************************************************************************
//函数名:                         tm0_isr() interrupt 1 using 1
//函数功能描述:        定时器1中断服务函数(1s)
//函数参数:         
//函数返回值:          
//作者:                  wenzer
//修改人:
//修改原因:
//*****************************************************************************
void tm0_isr() interrupt 1 using 1                  //定时器1中断,方式1(1s)
{

        TR0=0;
        TF0=0;
        TL0 = 0xCD;                //设置定时初值
        TH0 = 0xD4;                //设置定时初值
        if (count--==0)
        {               
        count =1000;
                timer_count++;
                gLoopQueryCount++;
                gtimer_count2++;
               
        }
        TR0=1;

}
/**************************************
       数组反转倒序输出
**************************************/
void Reverse(uchar * array, uchar len)
{
        uchar i;
        for ( i = 0; i < len / 2; ++ i)
        {
                uchar temp = array[i];
                array[i] = array[len - 1 - i];
                array[len - 1 - i] = temp;
        }
}
//*****************************************************************************
//函数名:                  
//函数功能描述:
//函数参数:          
//函数返回值:          
//作者:                  wenzer
//修改人:
//修改原因:
//*****************************************************************************
/*
uchar RolData(uchar x)
{
         x = ((x<<4) & 0xf0) | ((x>>4) & 0x0f);
         x = ((x<<2) & 0xcc) | ((x>>2) & 0x33);
         x = ((x<<1) & 0xaa) | ((x>>1) & 0x55);
         return x;
}
*/
//*****************************************************************************
//函数名:                  
//函数功能描述:
//函数参数:引脚序号,0输出1输入         
//函数返回值:          
//作者:                  wenzer
//修改人:
//修改原因:
//*****************************************************************************
void Port0Set(uchar pnum,uchar stat)
{
        if(stat)
        {
                P0M1|=pnum;
                P0M0&=(~pnum);
        }
        else
        {
                P0M0|=pnum;
                P0M1&=(~pnum);
        }
}
//*****************************************************************************
//函数名:                  
//函数功能描述:
//函数参数:          
//函数返回值:          
//作者:                  wenzer
//修改人:
//修改原因:
//*****************************************************************************
void PortsInit(void)
{
        Port0Set(0xff,1);
}
//*****************************************************************************
//函数名:                  
//函数功能描述:
//函数参数:          
//函数返回值:          
//作者:                  wenzer
//修改人:
//修改原因:
//*****************************************************************************
void GetSlaveId(void)
{
        volatile uchar st;
        CP=0;
        delay(50);
        CP=1;
        delay(50);
        st=P0;  
        g_swStat=~st;
        g_slaveId=(g_swStat&0x1f);
       
}
/**************************************
            串口2波特率设置
**************************************/
unsigned char SetBaudRate(void)
{
        unsigned char Baud,BaudRate;
        Baud=(g_swStat>>5);                                //PO口前三个引脚设置波特率4800/9600/14400/19200/38400
        Baud=(Baud&0x07);
        switch(Baud)
        {
        case 1:
                        BaudRate=0xF4;                        //2400
                        break;
        case 2:
                        BaudRate=0xFA;                        //4800
                        break;
        case 3:
                        BaudRate=0xFD;                        //9600
                        break;
        case 4:
                        BaudRate=0xFE;                        //19200
                        break;
        case 5:
                        BaudRate=0xFF;                        //38400
                        break;
        case 6:
                        BaudRate=0xFF;                        //38400
                        break;          
        default:
                        break;
        }
        return BaudRate;
}
//*****************************************************************************
//函数名:                  
//函数功能描述:
//函数参数:          
//函数返回值:          
//作者:                  wenzer
//修改人:
//修改原因:
//*****************************************************************************
void UartInit(void)                //14400bps@11.0592MHz
{
//        PCON &= 0x7F;                //波特率不倍速
//        SCON = 0x50;                //8位数据,可变波特率
//        AUXR |= 0x40;                //定时器1时钟为Fosc,即1T
//        AUXR &= 0xFE;                //串口1选择定时器1为波特率发生器
//        TMOD &= 0x0F;                //清除定时器1模式位
//        TMOD |= 0x20;                //设定定时器1为8位自动重装方式
//        TL1 = 0XE8        ;
//        TH1 = 0xE8  ;
//        ET1 = 0;                //禁止定时器1中断
//        TR1 = 1;                //启动定时器1
//        ES = 1;
        PCON &= 0x7F;                //波特率不倍速
        SCON = 0x50;                //8位数据,可变波特率
        AUXR &= 0xBF;                //定时器1时钟为Fosc/12,即12T
        AUXR &= 0xFE;                //串口1选择定时器1为波特率发生器
        TMOD &= 0x0F;                //清除定时器1模式位
        TMOD |= 0x20;                //设定定时器1为8位自动重装方式
        TL1 = 0xE8;                //设定定时初值
        TH1 = 0xE8;                //设定定时器重装值
        ET1 = 0;                //禁止定时器1中断
        TR1 = 1;                //启动定时器1
        ES = 1;
}
//*****************************************************************************
//函数名:                  
//函数功能描述:
//函数参数:          
//函数返回值:          
//作者:                  wenzer
//修改人:
//修改原因:
//*****************************************************************************
void Uart2Init(void)                //1200bps@11.0592MHz
{
/*        AUXR &= 0xF7;                //波特率不倍速
        S2CON = 0xD0;                //9位数据,可变波特率
        AUXR &= 0xFB;                //独立波特率发生器时钟为Fosc/12,即12T
        BRT = 0xE8;                //设定独立波特率发生器重装值
        AUXR |= 0x10;                //启动独立波特率发生器
*/
//        S2CON = 0xD0;                      //REN=1允许串行接受状态,串口工作模式3,数据位8、停止位1。偶校验 (11.0592)
//        PCON|= 0x00;                                //不加倍
//        AUXR = 0x11;                                //BRTx12=0,独立波特率发生器每12个时钟技计数一次
//        BRT = 0xfa;                          //波特率4800

        AUXR &= 0xF7;                //波特率不倍速
        S2CON = 0x50;                //8位数据,可变波特率
        AUXR &= 0xFB;                //独立波特率发生器时钟为Fosc/12,即12T
        BRT = SetBaudRate();                    //设定独立波特率发生器重装值
        AUXR |= 0x10;                //启动独立波特率发生器
        IE2 = 0x01;         //开串口2中断  
       
}

/**************************************
            串口2发送一字节(加偶校验)
**************************************/
void SendByte2(unsigned char dat)
{
//        unsigned char S2TB8;
////        ACC=dat;
//        S2TB8=P;                                                //偶校验位(P判断ACC的奇偶特性)
//
//
//        if (S2TB8)                                                //S2TB8发送校验位判断
//        {
//                S2CON|=0x08;                       
//        }
//        else
//        {
//                S2CON&=~0x08;
//        }

        S2BUF=dat;                                        //发送一个字节
        while(!(S2CON&0x02));        //等待发送标志位
        S2CON &=~S2TI;                                //清空发送标志位

}
/**************************************
            串口2发送一字符串meter
**************************************/
void Uart2Send(uchar *dat,uchar len)
{
        uchar tmp;
        RS485EE=1;                                            //485置1发送
        _nop_();                                                //485置1等待时间
        _nop_();
        _nop_();
        _nop_();
           _nop_();
        _nop_();

        for(tmp=0;tmp<len;tmp++)
        {
                SendByte2(*dat);
                dat++;
        }
        _nop_();
        _nop_();
        _nop_();                                                //485置0等待时间
        _nop_();
        _nop_();
        RS485EE=0;                                        //485置0接收
        _nop_();
        _nop_();
        _nop_();
       
}
/**************************************
            串口1发送一字节
//**************************************/
void SendByte1(unsigned char dat1)
{
        SBUF=dat1;
        while (!TI);                                //等待发送完成
        TI=0;                                                        //清空发送标志位
}

/**************************************
            串口1发送一字符串net
**************************************/
void Uart1Send(uchar *dat,uchar len)
{
        uchar tmp;
//        RS485EE=1;                                            //485置1发送
        _nop_();                                                //485置1等待时间
        _nop_();
        _nop_();
        _nop_();


        for(tmp=0;tmp<len;tmp++)
        {
                SendByte1(*dat);
                dat++;
        }
       
        _nop_();                                                //485置0等待时间
        _nop_();
        _nop_();
//        RS485EE=0;                                        //485置0接收
        _nop_();
        _nop_();
        _nop_();
       
}
/**************************************
               清空接收缓存区
**************************************/
void ClearComDat(void)
{
        g_RvcCnt=0;
        g_totalRvcCnt=0;


}
/****************************************************
               串口2中断程序(NET)
                           与网络控制器通信
******************************************************/
void UART2_int (void) interrupt 8 using 1
{


//        TI2=S2CON & S2TI;
        RI2=S2CON & S2RI;
//        if(TI2)         {S2CON=S2CON&0xfd;}                //TI标志清除

        if(RI2)                                        //RI接受中断标志
        {
                S2CON = S2CON&=~S2RI;
                N_Frame[g_RvcCnt]= S2BUF;                  //SUBF接受/发送缓冲器

                if(g_RvcCnt<5)
                {
       
                        switch(g_RvcCnt)
                        {
                        case 0:
                                if(N_Frame[0]==0x0a)
                                g_RvcCnt++;
                                break;
                        case 1:
                                if(N_Frame[1]==0x0c)
                                  {       
                                  g_RvcCnt++;
                                  }
                                else if(N_Frame[1]==0x0a)
                                        {
                                                 N_Frame[0]=N_Frame[1];
                                                }
                                else
                                        {
                                                 g_RvcCnt=0;
                                                }
                                break;
                        case 2:
                                if(N_Frame[2]==0x0e)
                                 {
                                 g_RvcCnt++;
                                 }
                                 else
                                 {
                                 g_RvcCnt=0;
                                 }
                                break;
                        case 3:
                                g_totalRvcCnt=N_Frame[3];  //计算数据总长度
                                g_RvcCnt++;
                                break;

                        case 4:
                                if(N_Frame[4]==g_slaveId)
                                {
                                g_RvcCnt++;
                                }
                                else
                                {
                                 g_RvcCnt=0;
                                }
                                break;
                        default:
                                break;               
                         }
                  }
        else{               
                                g_RvcCnt++;
                                if((g_RvcCnt==g_totalRvcCnt)&&(N_Frame[g_RvcCnt-1]==0x46))
                                {
//                                          Uart2Send(N_Frame, g_totalRvcCnt);
                                        g_RvcCnt=0;
                                        g_totalRvcCnt=0;
                                        g_NetStat=1;
                                        g_ComCnt=1;
                                        g_comStat=1;                                   //在线
                                LED2=0;
                                    re_con=0;
                                }
                        } //end s1

                }  //end s2




}

/****************************************************
               串口1中断程序(与电表通信)
******************************************************/

//void UART1_int (void) interrupt 4 using 1
//{
//
//   if(TI == 1)    TI =0;             //TI发送中断标志       
//   if(RI == 1)                                //RI接受中断标志
//        {
//                 RI = 0;       
//                E_Frame[i] = SBUF;                  //SUBF接受/发送缓冲器
////                if (E_Frame[i-1]==0x0a)
////                    LED2=0;
//                i++;
//
//                if(i==19)
//                {
//                        if((E_Frame[i-1]==0x16))
//                    SendFlag2=1;
//                        i=0;
////          Uart1Send("Meter data rcv",14);
//                }
//
//           }
//     }

//*****************************************************************************
//函数名:                  
//函数功能描述:
//函数参数:          
//函数返回值:          
//作者:                  wenzer
//修改人:
//修改原因:
//*****************************************************************************
void RelayCtl(uchar rel)
{
        if(rel==0)
        {
                  RELAY=1;
                RELAY_val=0xff;
//                LED2=0;
        }else
        {
                RELAY=0;
                RELAY_val=0;
//                LED2=1;
        }
}
/**************************************
       取电表返回数据E_Frame中数据域处理并加入时钟nowTime组成新数组EEPROM_Frame
**************************************/
void NewFrame(void)
{
        unsigned long elect ;
        uchar xdata nowTime[7];
        EX1=0;         //关闭外部中断
        elect=E_Power;
        Elect[2]=elect;
        Elect[1]=elect>>8;
        Elect[0]=elect>>16;
        elect=E_Power;
        Elect[3]=(E_Power-elect)*100;
////        if(Elect[3]==0xff)
////        {
////          unsigned char i;
////         for(i=0;i<6;i++)
////            {
////                 Elect[i]=0;
////                 }
////        }
        Elect[4]=0x01;                                   //表示后面没有其它电量数据
        Elect[5]=0x04;                                   //电量值为四个字节
    EX1=1;    //打开外部中断

        dsReadTime(nowTime);

        Reverse(nowTime,7);
        MyMemCpy(EEPROM_Frame,nowTime,7);  
        MyMemCpy((EEPROM_Frame+7),UIData,6); ///----------------- 电流电压放入
        MyMemCpy((EEPROM_Frame+13),Elect,6);        //电量放入
        MyMemCpy((EEPROM_Frame+19),Elect,4);        //电量放入
//        Uart2Send(EEPROM_Frame,17);

}
//*****************************************************************************
//函数名:LoopQueryStat
//函数功能描述:轮询就地控制器是否在线
//函数参数:
//函数返回值:
//作者:                  wenzer
//修改人:
//修改原因:
//*****************************************************************************
void LoopQueryStat(void)                                   //轮询就地控制器是否在线
{
        if(gLoopQueryCount>OFFLINE_TIME)
        {
                gLoopQueryCount=0;
                if(g_ComCnt)          //5分钟内有通信
                {
                        g_comStat=1;                                   //在线
                        LED2=0;

                }
                else
                {
                        g_comStat=0;
                        LED2=1;
                }
                g_ComCnt=0;                 //通信次数归0
        }
}

//*****************************************************************************
//函数名:void eeprom_op_init(void)
//函数功能描述:初始化eeprom操作参数
//函数参数:
//函数返回值:
//作者:                  wenzer
//修改人:
//修改原因:
//*****************************************************************************
void eeprom_op_init(void)
{

        g_eeprom_stat.sector_cnt=0;
        g_eeprom_stat.last_write_addr=0x00;
        g_eeprom_stat.record_cnt=0;

        g_eeprom_stat.read_start_sector=0;
        g_eeprom_stat.current_send_sector_num=0;
        g_eeprom_stat.current_send_cnt=0;

        g_eeprom_stat.last_write_sector_num=0;

        g_eeprom_stat.overflow_flag=0;
        g_eeprom_stat.sector_send_up=0;
        His_data_len=0;
    g_eeprom_sector_cnt=EEPROM_SECTOR_CNT;
        my_bzero(g_Address,56);
}
//*****************************************************************************
//函数名:                        Section_data_write(unsigned char num,unsigned char address)
//函数功能描述:        若一直掉线,存满一个扇区(一个23字节的数组存入一个扇区可以存22组);从第num扇区的address地址开始写数据
//函数参数:          
//函数返回值:          
//作者:                  wenzer
//修改人:
//修改原因:
//*****************************************************************************
void Section_data_write(unsigned char num,uint address)//num:第num扇区;addr:第一扇区:0x0000;第二扇区:0x0200;第三扇区:0x0400......
{
                num = num;
                if (timer_count>OFFLINE_TIME)        //每隔5分钟写入一组数组
                {
                        timer_count=0;
                        if (SendFlag>=10)
                        {
                                SendFlag=0;
                                NewFrame();                        //时间+电表数据
                                if(g_eeprom_stat.last_write_addr==0x00&&g_Address[0]==1)           //有一条记录
                                {
                                   g_eeprom_stat.last_write_addr+=23;
                                   address=g_eeprom_stat.last_write_addr;
                                   g_eeprom_stat.sector_cnt=1;                                        //CNT=1
                                   His_data_len=1;
                                }                                                                                                                                 
                                eeprom_data_write(EEPROM_Frame,address,23);               //将数据存入eeprom
                                g_eeprom_stat.last_write_addr+=23;
                                g_Address[g_eeprom_stat.last_write_sector_num]++;                 //本扇区记录数++
                                His_data_len++;                                          //all history record count

                                if(g_Address[g_eeprom_stat.last_write_sector_num]==22)          //此扇区已写满 22*23=506
                                {                                                                                                                                                  
                                        g_eeprom_stat.sector_cnt++;                    //有数据记录的扇区数加1 0-0 1-1
                                        g_eeprom_stat.last_write_sector_num++;        //指向下一个扇区   2

                                        if(g_eeprom_stat.last_write_sector_num==EEPROM_SECTOR_CNT)          //eeprom已满,从头写入0-14
                                        {
                                                 g_eeprom_stat.sector_cnt=EEPROM_SECTOR_CNT;
                                                 g_eeprom_stat.last_write_sector_num=0;
                                                 g_eeprom_stat.last_write_addr=0x00;
                                                 g_eeprom_stat.overflow_flag=1;
                                                 eeprom_byte_erase(0x0000);                 //擦除第一个扇区
                                                 g_Address[g_eeprom_stat.last_write_sector_num]=0;
                                        }else
                                        {
                                            g_eeprom_stat.last_write_addr=g_eeprom_stat.last_write_sector_num*0x0200;
                                                g_Address[g_eeprom_stat.last_write_sector_num]=0;
                                                eeprom_byte_erase(g_eeprom_stat.last_write_addr);                 //擦除下一个扇区
                                        }                               
                                }                                                                                                 
                               
                        } //have data?
                }          //five minitus?

}
//*****************************************************************************
//函数名:                 LostConnection_Process(void)
//函数功能描述:处理从电表发来的数据(掉电存储)
//函数参数:          
//函数返回值:          
//作者:                  wenzer
//修改人:
//修改原因:
//*****************************************************************************
void LostConnection_Process(void)                           //处理从电表发来的数据(掉电存储)
{
                Section_data_write(g_eeprom_stat.last_write_sector_num,g_eeprom_stat.last_write_addr);
}
//*****************************************************************************
//函数名:                  
//函数功能描述:发送历史记录数据
//函数参数:          
//函数返回值:          
//作者:                  wenzer
//修改人:
//修改原因:
//*****************************************************************************
void LostConnection_Send(unsigned char* addrLen)                   //处理从电表发来的数据(掉电存储后发送)
{
        unsigned char sendLen;
        unsigned char surplusRecord;
        uint address,address_bk;
        unsigned char xdata tmpData[256];         //从EEPROM中读取数据存入temData

        address=g_eeprom_stat.current_send_sector_num*0x0200;
        address_bk=address;


   //将某扇区的所有记录发送出给网络控制器
   //不足10条或下半部分
        if(g_eeprom_stat.sector_send_up>0)          //current page 已经发送sector_send_up条记录
                {
                        address+=(g_eeprom_stat.sector_send_up*23);   //剩下的半部分
                 }else
                 {
                           g_eeprom_stat.current_send_cnt=0;
                 }       
        //只要记录数还没发完,进入函数就发历史数据
        if(His_data_len>1)
        {
                   surplusRecord=(addrLen[g_eeprom_stat.current_send_sector_num]-g_eeprom_stat.current_send_cnt);        //how man records left
                   if(surplusRecord<11)                 //不足11条记录全读并发送
                   {
                                        eeprom_data_read(tmpData,address,surplusRecord*23);
                                        if(His_data_len>surplusRecord||His_data_len==surplusRecord)
                                        {
                                                His_data_len-=surplusRecord;                                       
                                        }else
                                        {
                                                His_data_len=0;
                                        }
                                        sendLen=SlaveDatPack(surplusRecord*23,tmpData,SLAVE_ID,0x0108);
                                        Uart2Send(g_slaveSendBuf,sendLen);

                                        g_eeprom_stat.current_send_cnt=addrLen[g_eeprom_stat.current_send_sector_num];
                        }else  //上半部分10records
                   {
                                eeprom_data_read(tmpData,address,11*23);
                                if(His_data_len>11)
                                {
                                        His_data_len-=11;
                                }else
                                {
                                   His_data_len=0;
                                }

                                sendLen=SlaveDatPack(11*23,tmpData,SLAVE_ID,0x0108);
                                Uart2Send(g_slaveSendBuf,sendLen);

                                g_eeprom_stat.current_send_cnt+=11;
                                g_eeprom_stat.sector_send_up+=11;                //上半部分已发送
                   }

                  if(g_eeprom_stat.current_send_cnt==addrLen[g_eeprom_stat.current_send_sector_num])        //本扇区已经发完
                                {
                               
                                        g_eeprom_stat.current_send_cnt=0;
                                        g_eeprom_stat.sector_send_up=0;
                                        g_eeprom_stat.current_send_sector_num++;

                                        if((g_eeprom_stat.current_send_sector_num-g_eeprom_stat.last_write_sector_num)==1)  //读取扇区和最后写入的扇区重叠,所有扇区全部发完
                                        {                 
                                                g_eeprom_stat.current_send_sector_num=g_eeprom_stat.read_start_sector;
                                                g_eeprom_stat.current_send_cnt=0;
                                                His_data_len=0;
                                        }                               
                                }//本扇区已经发完
                                //整片都发完了       
                         if(g_eeprom_stat.current_send_sector_num==EEPROM_SECTOR_CNT)
                         {         
                                 g_eeprom_stat.current_send_sector_num=0;
                                 g_eeprom_stat.current_send_cnt=0;       
                         }
         }   
}

/*******************************************************
*******************************************************
                            主程序
*******************************************************
*******************************************************/
void main (void)
{
       
        uint sysStat=0;
        EA = 0;                                    // 关总中断
//        LED1=1;
//        LED2=0;

        P0=0XFF;
        PortsInit();  //set port0 input
        GetSlaveId();
        Uart2Init();  //1200         
//        UartInit();  //4800

        DS1302_init(); //DS1302 io初始化
//        RtcInit();   //第一次使用时初始化DS1302时间
        Timer0Init();       
        eeprom_op_init();
        delay(1000);
    WDT_CONTR=0x3F;           //清狗指令
        poweroff_check_init();         //使能掉电检测
        read_parameter_fromflash();

////        P1DIR |= 0x60;  //P15、P16定义为输出
        Init_5460(); //初始化SPI
//        Sync_5460(); //5460校准

        TR0=1;
        g_comStat=0;                           //默认不在线
//               
//        RS485E=0;        //串口2 485置接收
        RS485EE=0;        //串口1 485置接收
        LED2=1;

        read_i2c_data(0,elevar.var,4);
        E_Power=elevar.floatvar;
        RELAY=RELAY_val;
        Uart2Send(elevar.var,4);                 //芯片重启发四个零
        IT1=0;                                           //外部1中断模式1        下降沿触发0低电平触发
        EX1=1;                                           //外部1中断允许1允许中断 0禁止中断
        EA =1;                                        // 开总中断
        E_Con=0;
        if(E_Power==0)

          {
                   delay(100000);
                   read_i2c_data(0,elevar.var,4);
            E_Power=elevar.floatvar;
       }
        while(1)
   {

                sysStat++;
            WDT_CONTR=0x3F;           //清狗指令
               
                if(sysStat==120)   //灯闪一次
                {
                        E_Con++;
                        re_con++;
                           if((g_comStat==0)&&(re_con>300))                         //采集器离线
                       {
                            EA=0;
                                elevar.floatvar=E_Power;
                                write_i2c_data(0,elevar.var,4);
                            ((void (code *) (void)) 0x0000) ();
                           }
                        sysStat=0;
                    LED1=~LED1;                       
                 }

    //*******************************************************       
        //处理与主控制器的通信
        //*******************************************************
                DealCmd();                 //处理从控制器发来的命令
                LoopQueryStat(); //判断是否掉线

        delay(20);
        if(g_eeprom_stat.overflow_flag==1)
        {
                   g_eeprom_stat.read_start_sector=(g_eeprom_stat.last_write_sector_num+1);
        }else
        {
                g_eeprom_stat.read_start_sector=0;
        }


        //*******************************************************       
        //处理电表数据
        //*******************************************************                       
          if(g_comStat)  //如果控制器在线
                        {
                                 if(g_Address[0]>1||g_eeprom_stat.sector_cnt>0)                  //有离线保存的记录send and insert record
                                 {

                                                   LostConnection_Process();         //处理从电表发来的数据(掉电存储)

                                 }
                                 else        //没有离线保存的记录read and update data
                                 {
                                         
                                         if (SendFlag>=10)          //CS5460        转换就绪
                                         {
                                                //存储当前检测的数据
                                                SendFlag=0;                                               
                                                NewFrame();                          //打包准备数据
                                          
                                                eeprom_byte_erase(0x0000);
                                                delay(100);
                                                eeprom_data_write(EEPROM_Frame,0x0000,23);          //将数据存入eeprom
                                                g_Address[0]=0x01;       
                                                g_eeprom_stat.last_write_addr=0x00;                                                        //存储记录
                                                g_eeprom_stat.last_write_sector_num=0;
                                                g_eeprom_stat.current_send_sector_num=0;
                                                His_data_len=1;
                                                if(E_Con==800)
                                                {
                                                E_Con=0;
                                                EA = 0;                                    // 关总中断
                                                while(1)
                                                {
                                                elevar.floatvar=E_Power;
                                                write_i2c_data(0,elevar.var,4);
                                                   read_i2c_data(0,elevar.var,4);
                                                if(elevar.floatvar==E_Power)
                                                break;
                                            WDT_CONTR=0x3F;           //清狗指令
                                                delay(100000);
                                                }
//                                                x24c08_write(5,RELAY_val);                                               
                                                EA = 1;
                                                }
                                         }
                                  }
                        }
                        else          //控制器离线
                        {
               LostConnection_Process();         //处理从电表发来的数据(掉电存储)
                        }

        }

}
SHUAILONG2004
5楼-- · 2019-07-16 17:29
SHUAILONG2004 发表于 2013-12-24 15:28
#include "mytypes.h"
#include
#include "2send1re.H"

/*************************************************************************
* Copyright (c) 2012, 元澄智能科技有限公司
* All rights reserved.
* STC12C5A16S2
* 文件名称:2send1re.c
* 文件标识:2send1re.c
* 摘要:采集电表数据,存储,然后发送给网络控制器,如果控制器在线直接发送,不在线显存储,上线后发送
* 资源配置:UART1和网络控制器通信,UART2和电表通信
* 电表波特率:1200   和网络控制器通信波特率:4800
* eeprom分配最后一个扇区存放参数,其他的存放电量数据
*
* 当前版本:1.0.03
* 作者:wenzer
* 完成日期:2013-02-26
* 修改内容:
*
* 当前版本:1.0.04
* 修改者: 张振亮
* 完成日期:2012年11月10日
*
* 当前版本:1.0.05
* 修改者:         张振亮
*修改内容:命令接收函数,发送函数
* 完成日期:2013年03月18日
* 当前版本:1.0.07
* 修改者:         张振亮
*修改内容:命令接收函数,发送函数
* 完成日期:2013年03月25日
*************************************************************************/
#include <stdio.h>
#include <intrins.h>
#include <stc12c5a60s2.h>
#include "mytypes.h"
#include "i2c.h"
#include "spi.h"
#include "2send1re.H"
#include "net_com.h"
#include "DS1302.H"
#include "EEPROM.H"


//sbit RS485EE=P4^3;                           //串口2定义485的使能脚A板
sbit RS485EE=P3^4;                           //串口2定义485的使能脚B板

sbit RELAY=P4^1;                           //RELAY3.5-4.1


sbit LED1=P3^6;                           //led1  D14
sbit LED2=P3^5;                           //led2        D15

sbit CP=P1^0;                           //CP
unsigned char RELAY_val=0xff;                                 //继电器保存的值
unsigned char  SendFlag=0;
uchar g_eeprom_sector_cnt=0;

#define OFFLINE_TIME   130             //掉线检测周期130s
#define EEPROM_SECTOR_CNT 15                //16个扇区         
#define EEPROM_FLAG  0X66                //eeprom erase
#define S2RI 0x01
#define S2TI 0x02
bit RI2;
bit TI2;

//定时,延时用

unsigned int count=0;
unsigned int timer_count=0;
unsigned int gtimer_count2=0;
unsigned int gLoopQueryCount=0;
unsigned int g_comStat=0;
unsigned char g_ComCnt=0; //统计通信次数,离线判断用

volatile unsigned int His_data_len=0;
unsigned int E_Con=0;
unsigned int re_con=0;
//操作eeprom记录用
EEPROM_STAT g_eeprom_stat;
unsigned char xdata g_Address[56]={0};          //28K56个扇区






//数据集中器通信用变量
volatile uchar g_totalRvcCnt=0;
volatile uchar g_RvcCnt=0;
volatile bit g_NetStat;
uchar g_swStat,g_slaveId;

//延时用
volatile uint g_timeCnt;


unsigned char xdata E_Frame[20]={0};
unsigned char xdata EEPROM_Frame[25]={0};        //从EEPROM中读取的数据帧
float E_Power;
volatile unsigned char xdata Elect[6]={0};                    //定义电量累计数据
unsigned char xdata UIData[6]={0};                //读取的电流和电压
unsigned char xdata N_Frame[20]={0};                //数据集中器对下发送的查询指令
typedef union
             {
                           unsigned char var[4];
                       float floatvar;
                          }float_var;
float_var elevar;

//*****************************************************************************
//函数名:                  将一个数组所有元素清0
//函数功能描述:         
//函数参数:                 数组名,长度
//函数返回值:                  无
//作者:                  wenzer
//修改人:
//修改原因:
//*****************************************************************************
void my_bzero(unsigned char *arr,unsigned int len)
{
unsigned int i;
for(i=0;i<len;i++)
        {
          arr=0;
        }
}
/**************************************
                  延时程序
**************************************/
void delay(uint i)
{
        unsigned char j;
        for(i; i > 0; i--)
                for(j = 200; j > 0; j--);
}
//*****************************************************************************
//函数名:                          void save_parameter_toflash(void)
//函数功能描述:        保存参数到24c08
//函数参数:                 无
//函数返回值:                  无
//作者:                  wenzer
//修改人:
//修改原因:
//*****************************************************************************
void save_parameter_toflash(void)
{
        uint addr=0;
        uchar xdata tmp[70];
        addr=0x1fa4;
//        addr=100;
//        elevar.floatvar=E_Power;
       
        tmp[0]=(uchar)g_eeprom_stat.last_write_addr;     //eeprom操作当前地址
        tmp[1]=(uchar)g_eeprom_stat.last_write_addr>>8;     //eeprom操作当前地址
        tmp[2]=g_eeprom_stat.record_cnt;     //记录数
        tmp[3]=g_eeprom_stat.current_send_sector_num;     //已发送数据的当前扇区编号
        tmp[4]=g_eeprom_stat.sector_send_up;     //上半部分记录已发送
        tmp[5]=g_eeprom_stat.last_write_sector_num;     //最后一个扇区编号
       
        tmp[6]=g_eeprom_stat.overflow_flag;     //溢出标志
        tmp[7]=g_eeprom_stat.sector_cnt;     //扇区编号
        tmp[8]=EEPROM_FLAG;     //parameter save flag,means save ok
                                                        //
//        tmp[9]=elevar.var[0];
//        tmp[10]=elevar.var[1];
//        tmp[11]=elevar.var[2];
//        tmp[12]=elevar.var[3];                  //保存累计电量
        tmp[13]=RELAY_val;                           //保存继电器状态
        MyMemCpy(tmp+14,g_Address,56);        //加入数据段

        eeprom_data_write(tmp,addr,70);  //将数据存入eeprom
//        write_i2c_data(addr,tmp,70);
}
//*****************************************************************************
//函数名:                          void read_parameter_fromflash(void)
//函数功能描述:        从24c08读取参数
//函数参数:                 无
//函数返回值:                  无
//作者:                  wenzer
//修改人:
//修改原因:
//*****************************************************************************
void read_parameter_fromflash(void)
{
        uint addr=0;
        uchar xdata tmp[70]={0};
        addr=0x1fa4;
//        addr=100;
        eeprom_data_read(tmp,addr,70);
    eeprom_byte_erase(0x1e00);
//        Uart2Send(tmp,70);

        if(tmp[8]==EEPROM_FLAG)                           //保存过参数
        {
                g_eeprom_stat.last_write_addr=tmp[0];     //eeprom操作当前地址
                g_eeprom_stat.last_write_addr=tmp[1]*256;     //eeprom操作当前地址 左移8位
               
                g_eeprom_stat.record_cnt=tmp[2];     //记录数
                g_eeprom_stat.current_send_sector_num=tmp[3];     //已发送数据的当前扇区编号
                g_eeprom_stat.sector_send_up=tmp[4];     //上半部分记录已发送
                g_eeprom_stat.last_write_sector_num=tmp[5];     //最后一个扇区编号
               
                g_eeprom_stat.overflow_flag=tmp[6];     //溢出标志
                g_eeprom_stat.sector_cnt=tmp[7];     //扇区编号
//                elevar.var[0]=tmp[9];
//                elevar.var[1]=tmp[10];
//                elevar.var[2]=tmp[11];
//                elevar.var[3]=tmp[12];
                RELAY_val=tmp[13];       
//                E_Power=elevar.floatvar;
                MyMemCpy(g_Address,tmp+14,56);        //加入数据段

                 if(g_eeprom_stat.sector_cnt==0&&g_Address[0]==1)                  //无离线保存的记录
                {
                  His_data_len=1;
                }
                if(g_eeprom_stat.sector_cnt>0)                  //有离线保存的记录
                        {
                                His_data_len=(g_eeprom_stat.sector_cnt-1)*30;
                                His_data_len+=g_Address[g_eeprom_stat.last_write_sector_num];
                                if(g_eeprom_stat.overflow_flag==1)
                                {
                                        His_data_len=EEPROM_SECTOR_CNT*30;
                                        His_data_len+=g_Address[g_eeprom_stat.last_write_sector_num];
                                }       
                        }
        }else                   //第一次使用
        {
            EEPROM_Erase();
                delay(400);
                delay(400);
        }

}
//*****************************************************************************
//函数名:                          void poweroff_init(void)
//函数功能描述:        使能掉电检测中断
//函数参数:                 无
//函数返回值:                  无
//作者:                  wenzer
//修改人:
//修改原因:
//*****************************************************************************
void poweroff_check_init(void)
{
        P4SW&=0XBF;   //set p4.6 as lvd pin
        WAKE_CLKO=0X08; //enable lvd signal wakeup mcu
        ELVD=1;             //enable lvd interrupt
        PCON&=0XDF;
}
//*****************************************************************************
//函数名:                          void lvdint()
//函数功能描述:        掉电检测中断
//函数参数:                 无
//函数返回值:                  无
//作者:                  wenzer
//修改人:
//修改原因:
//*****************************************************************************
void lvdint() interrupt 6
{
  uchar tmp;

        PCON&=0XDF;  //clear LVD flag
        tmp=(PCON&0X20);
        if(tmp>0)  //还是1则是掉电了,否则是电源波动
        {
          elevar.floatvar=E_Power;
          write_i2c_data(0,elevar.var,4);
          save_parameter_toflash();                                //保存数据
          PCON&=0XDF;  //clear LVD flag
          ELVD=0;             //disenable lvd interrupt
          PCON&=0Xfd;
        }
}

//*****************************************************************************
//函数名:                          void exint0()
//函数功能描述:        外部0中断处理 ,读取电表累计电量
//函数参数:                 无
//函数返回值:                  无
//作者:                     szl
//修改人:
//修改原因:
//*****************************************************************************
void exint1() interrupt 2
  {
//   EA=0;
   SCAN_CS5460();
   SendFlag++;
//   EA=1;
  }

//*****************************************************************************
//函数名:                          Timer0Init(void)
//函数功能描述:        定时器0初始化,初值设定1毫秒@11.0592MHz
//函数参数:         
//函数返回值:          
//作者:                  wenzer
//修改人:
//修改原因:
//*****************************************************************************
void Timer0Init(void)                //1毫秒@11.0592MHz
{
        AUXR |= 0x80;                //定时器时钟1T模式
        TMOD &= 0xF0;                //设置定时器模式
        TMOD |= 0x01;                //设置定时器模式
        TL0 = 0xCD;                //设置定时初值
        TH0 = 0xD4;                //设置定时初值
        TF0 = 0;                //清除TF0标志
        TR0 = 1;                //定时器0开始计时
        ET0 = 1;
        count = 1;

}
//*****************************************************************************
//函数名:                         tm0_isr() interrupt 1 using 1
//函数功能描述:        定时器1中断服务函数(1s)
//函数参数:         
//函数返回值:          
//作者:                  wenzer
//修改人:
//修改原因:
//*****************************************************************************
void tm0_isr() interrupt 1 using 1                  //定时器1中断,方式1(1s)
{

        TR0=0;
        TF0=0;
        TL0 = 0xCD;                //设置定时初值
        TH0 = 0xD4;                //设置定时初值
        if (count--==0)
        {               
        count =1000;
                timer_count++;
                gLoopQueryCount++;
                gtimer_count2++;
               
        }
        TR0=1;

}
/**************************************
       数组反转倒序输出
**************************************/
void Reverse(uchar * array, uchar len)
{
        uchar i;
        for ( i = 0; i < len / 2; ++ i)
        {
                uchar temp = array;
                array = array[len - 1 - i];
                array[len - 1 - i] = temp;
        }
}
//*****************************************************************************
//函数名:                  
//函数功能描述:
//函数参数:          
//函数返回值:          
//作者:                  wenzer
//修改人:
//修改原因:
//*****************************************************************************
/*
uchar RolData(uchar x)
{
         x = ((x<<4) & 0xf0) | ((x>>4) & 0x0f);
         x = ((x<<2) & 0xcc) | ((x>>2) & 0x33);
         x = ((x<<1) & 0xaa) | ((x>>1) & 0x55);
         return x;
}
*/
//*****************************************************************************
//函数名:                  
//函数功能描述:
//函数参数:引脚序号,0输出1输入         
//函数返回值:          
//作者:                  wenzer
//修改人:
//修改原因:
//*****************************************************************************
void Port0Set(uchar pnum,uchar stat)
{
        if(stat)
        {
                P0M1|=pnum;
                P0M0&=(~pnum);
        }
        else
        {
                P0M0|=pnum;
                P0M1&=(~pnum);
        }
}
//*****************************************************************************
//函数名:                  
//函数功能描述:
//函数参数:          
//函数返回值:          
//作者:                  wenzer
//修改人:
//修改原因:
//*****************************************************************************
void PortsInit(void)
{
        Port0Set(0xff,1);
}
//*****************************************************************************
//函数名:                  
//函数功能描述:
//函数参数:          
//函数返回值:          
//作者:                  wenzer
//修改人:
//修改原因:
//*****************************************************************************
void GetSlaveId(void)
{
        volatile uchar st;
        CP=0;
        delay(50);
        CP=1;
        delay(50);
        st=P0;  
        g_swStat=~st;
        g_slaveId=(g_swStat&0x1f);
       
}
/**************************************
            串口2波特率设置
**************************************/
unsigned char SetBaudRate(void)
{
        unsigned char Baud,BaudRate;
        Baud=(g_swStat>>5);                                //PO口前三个引脚设置波特率4800/9600/14400/19200/38400
        Baud=(Baud&0x07);
        switch(Baud)
        {
        case 1:
                        BaudRate=0xF4;                        //2400
                        break;
        case 2:
                        BaudRate=0xFA;                        //4800
                        break;
        case 3:
                        BaudRate=0xFD;                        //9600
                        break;
        case 4:
                        BaudRate=0xFE;                        //19200
                        break;
        case 5:
                        BaudRate=0xFF;                        //38400
                        break;
        case 6:
                        BaudRate=0xFF;                        //38400
                        break;          
        default:
                        break;
        }
        return BaudRate;
}
//*****************************************************************************
//函数名:                  
//函数功能描述:
//函数参数:          
//函数返回值:          
//作者:                  wenzer
//修改人:
//修改原因:
//*****************************************************************************
void UartInit(void)                //14400bps@11.0592MHz
{
//        PCON &= 0x7F;                //波特率不倍速
//        SCON = 0x50;                //8位数据,可变波特率
//        AUXR |= 0x40;                //定时器1时钟为Fosc,即1T
//        AUXR &= 0xFE;                //串口1选择定时器1为波特率发生器
//        TMOD &= 0x0F;                //清除定时器1模式位
//        TMOD |= 0x20;                //设定定时器1为8位自动重装方式
//        TL1 = 0XE8        ;
//        TH1 = 0xE8  ;
//        ET1 = 0;                //禁止定时器1中断
//        TR1 = 1;                //启动定时器1
//        ES = 1;
        PCON &= 0x7F;                //波特率不倍速
        SCON = 0x50;                //8位数据,可变波特率
        AUXR &= 0xBF;                //定时器1时钟为Fosc/12,即12T
        AUXR &= 0xFE;                //串口1选择定时器1为波特率发生器
        TMOD &= 0x0F;                //清除定时器1模式位
        TMOD |= 0x20;                //设定定时器1为8位自动重装方式
        TL1 = 0xE8;                //设定定时初值
        TH1 = 0xE8;                //设定定时器重装值
        ET1 = 0;                //禁止定时器1中断
        TR1 = 1;                //启动定时器1
        ES = 1;
}
//*****************************************************************************
//函数名:                  
//函数功能描述:
//函数参数:          
//函数返回值:          
//作者:                  wenzer
//修改人:
//修改原因:
//*****************************************************************************
void Uart2Init(void)                //1200bps@11.0592MHz
{
/*        AUXR &= 0xF7;                //波特率不倍速
        S2CON = 0xD0;                //9位数据,可变波特率
        AUXR &= 0xFB;                //独立波特率发生器时钟为Fosc/12,即12T
        BRT = 0xE8;                //设定独立波特率发生器重装值
        AUXR |= 0x10;                //启动独立波特率发生器
*/
//        S2CON = 0xD0;                      //REN=1允许串行接受状态,串口工作模式3,数据位8、停止位1。偶校验 (11.0592)
//        PCON|= 0x00;                                //不加倍
//        AUXR = 0x11;                                //BRTx12=0,独立波特率发生器每12个时钟技计数一次
//        BRT = 0xfa;                          //波特率4800

        AUXR &= 0xF7;                //波特率不倍速
        S2CON = 0x50;                //8位数据,可变波特率
        AUXR &= 0xFB;                //独立波特率发生器时钟为Fosc/12,即12T
        BRT = SetBaudRate();                    //设定独立波特率发生器重装值
        AUXR |= 0x10;                //启动独立波特率发生器
        IE2 = 0x01;         //开串口2中断  
       
}

/**************************************
            串口2发送一字节(加偶校验)
**************************************/
void SendByte2(unsigned char dat)
{
//        unsigned char S2TB8;
////        ACC=dat;
//        S2TB8=P;                                                //偶校验位(P判断ACC的奇偶特性)
//
//
//        if (S2TB8)                                                //S2TB8发送校验位判断
//        {
//                S2CON|=0x08;                       
//        }
//        else
//        {
//                S2CON&=~0x08;
//        }

        S2BUF=dat;                                        //发送一个字节
        while(!(S2CON&0x02));        //等待发送标志位
        S2CON &=~S2TI;                                //清空发送标志位

}
/**************************************
            串口2发送一字符串meter
**************************************/
void Uart2Send(uchar *dat,uchar len)
{
        uchar tmp;
        RS485EE=1;                                            //485置1发送
        _nop_();                                                //485置1等待时间
        _nop_();
        _nop_();
        _nop_();
           _nop_();
        _nop_();

        for(tmp=0;tmp<len;tmp++)
        {
                SendByte2(*dat);
                dat++;
        }
        _nop_();
        _nop_();
        _nop_();                                                //485置0等待时间
        _nop_();
        _nop_();
        RS485EE=0;                                        //485置0接收
        _nop_();
        _nop_();
        _nop_();
       
}
/**************************************
            串口1发送一字节
//**************************************/
void SendByte1(unsigned char dat1)
{
        SBUF=dat1;
        while (!TI);                                //等待发送完成
        TI=0;                                                        //清空发送标志位
}

/**************************************
            串口1发送一字符串net
**************************************/
void Uart1Send(uchar *dat,uchar len)
{
        uchar tmp;
//        RS485EE=1;                                            //485置1发送
        _nop_();                                                //485置1等待时间
        _nop_();
        _nop_();
        _nop_();


        for(tmp=0;tmp<len;tmp++)
        {
                SendByte1(*dat);
                dat++;
        }
       
        _nop_();                                                //485置0等待时间
        _nop_();
        _nop_();
//        RS485EE=0;                                        //485置0接收
        _nop_();
        _nop_();
        _nop_();
       
}
/**************************************
               清空接收缓存区
**************************************/
void ClearComDat(void)
{
        g_RvcCnt=0;
        g_totalRvcCnt=0;


}
/****************************************************
               串口2中断程序(NET)
                           与网络控制器通信
******************************************************/
void UART2_int (void) interrupt 8 using 1
{


//        TI2=S2CON & S2TI;
        RI2=S2CON & S2RI;
//        if(TI2)         {S2CON=S2CON&0xfd;}                //TI标志清除

        if(RI2)                                        //RI接受中断标志
        {
                S2CON = S2CON&=~S2RI;
                N_Frame[g_RvcCnt]= S2BUF;                  //SUBF接受/发送缓冲器

                if(g_RvcCnt<5)
                {
       
                        switch(g_RvcCnt)
                        {
                        case 0:
                                if(N_Frame[0]==0x0a)
                                g_RvcCnt++;
                                break;
                        case 1:
                                if(N_Frame[1]==0x0c)
                                  {       
                                  g_RvcCnt++;
                                  }
                                else if(N_Frame[1]==0x0a)
                                        {
                                                 N_Frame[0]=N_Frame[1];
                                                }
                                else
                                        {
                                                 g_RvcCnt=0;
                                                }
                                break;
                        case 2:
                                if(N_Frame[2]==0x0e)
                                 {
                                 g_RvcCnt++;
                                 }
                                 else
                                 {
                                 g_RvcCnt=0;
                                 }
                                break;
                        case 3:
                                g_totalRvcCnt=N_Frame[3];  //计算数据总长度
                                g_RvcCnt++;
                                break;

                        case 4:
                                if(N_Frame[4]==g_slaveId)
                                {
                                g_RvcCnt++;
                                }
                                else
                                {
                                 g_RvcCnt=0;
                                }
                                break;
                        default:
                                break;               
                         }
                  }
        else{               
                                g_RvcCnt++;
                                if((g_RvcCnt==g_totalRvcCnt)&&(N_Frame[g_RvcCnt-1]==0x46))
                                {
//                                          Uart2Send(N_Frame, g_totalRvcCnt);
                                        g_RvcCnt=0;
                                        g_totalRvcCnt=0;
                                        g_NetStat=1;
                                        g_ComCnt=1;
                                        g_comStat=1;                                   //在线
                                LED2=0;
                                    re_con=0;
                                }
                        } //end s1

                }  //end s2




}

/****************************************************
               串口1中断程序(与电表通信)
******************************************************/

//void UART1_int (void) interrupt 4 using 1
//{
//
//   if(TI == 1)    TI =0;             //TI发送中断标志       
//   if(RI == 1)                                //RI接受中断标志
//        {
//                 RI = 0;       
//                E_Frame = SBUF;                  //SUBF接受/发送缓冲器
////                if (E_Frame[i-1]==0x0a)
////                    LED2=0;
//                i++;
//
//                if(i==19)
//                {
//                        if((E_Frame[i-1]==0x16))
//                    SendFlag2=1;
//                        i=0;
////          Uart1Send("Meter data rcv",14);
//                }
//
//           }
//     }

//*****************************************************************************
//函数名:                  
//函数功能描述:
//函数参数:          
//函数返回值:          
//作者:                  wenzer
//修改人:
//修改原因:
//*****************************************************************************
void RelayCtl(uchar rel)
{
        if(rel==0)
        {
                  RELAY=1;
                RELAY_val=0xff;
//                LED2=0;
        }else
        {
                RELAY=0;
                RELAY_val=0;
//                LED2=1;
        }
}
/**************************************
       取电表返回数据E_Frame中数据域处理并加入时钟nowTime组成新数组EEPROM_Frame
**************************************/
void NewFrame(void)
{
        unsigned long elect ;
        uchar xdata nowTime[7];
        EX1=0;         //关闭外部中断
        elect=E_Power;
        Elect[2]=elect;
        Elect[1]=elect>>8;
        Elect[0]=elect>>16;
        elect=E_Power;
        Elect[3]=(E_Power-elect)*100;
////        if(Elect[3]==0xff)
////        {
////          unsigned char i;
////         for(i=0;i<6;i++)
////            {
////                 Elect=0;
////                 }
////        }
        Elect[4]=0x01;                                   //表示后面没有其它电量数据
        Elect[5]=0x04;                                   //电量值为四个字节
    EX1=1;    //打开外部中断

        dsReadTime(nowTime);

        Reverse(nowTime,7);
        MyMemCpy(EEPROM_Frame,nowTime,7);  
        MyMemCpy((EEPROM_Frame+7),UIData,6); ///----------------- 电流电压放入
        MyMemCpy((EEPROM_Frame+13),Elect,6);        //电量放入
        MyMemCpy((EEPROM_Frame+19),Elect,4);        //电量放入
//        Uart2Send(EEPROM_Frame,17);

}
//*****************************************************************************
//函数名:LoopQueryStat
//函数功能描述:轮询就地控制器是否在线
//函数参数:
//函数返回值:
//作者:                  wenzer
//修改人:
//修改原因:
//*****************************************************************************
void LoopQueryStat(void)                                   //轮询就地控制器是否在线
{
        if(gLoopQueryCount>OFFLINE_TIME)
        {
                gLoopQueryCount=0;
                if(g_ComCnt)          //5分钟内有通信
                {
                        g_comStat=1;                                   //在线
                        LED2=0;

                }
                else
                {
                        g_comStat=0;
                        LED2=1;
                }
                g_ComCnt=0;                 //通信次数归0
        }
}

//*****************************************************************************
//函数名:void eeprom_op_init(void)
//函数功能描述:初始化eeprom操作参数
//函数参数:
//函数返回值:
//作者:                  wenzer
//修改人:
//修改原因:
//*****************************************************************************
void eeprom_op_init(void)
{

        g_eeprom_stat.sector_cnt=0;
        g_eeprom_stat.last_write_addr=0x00;
        g_eeprom_stat.record_cnt=0;

        g_eeprom_stat.read_start_sector=0;
        g_eeprom_stat.current_send_sector_num=0;
        g_eeprom_stat.current_send_cnt=0;

        g_eeprom_stat.last_write_sector_num=0;

        g_eeprom_stat.overflow_flag=0;
        g_eeprom_stat.sector_send_up=0;
        His_data_len=0;
    g_eeprom_sector_cnt=EEPROM_SECTOR_CNT;
        my_bzero(g_Address,56);
}
//*****************************************************************************
//函数名:                        Section_data_write(unsigned char num,unsigned char address)
//函数功能描述:        若一直掉线,存满一个扇区(一个23字节的数组存入一个扇区可以存22组);从第num扇区的address地址开始写数据
//函数参数:          
//函数返回值:          
//作者:                  wenzer
//修改人:
//修改原因:
//*****************************************************************************
void Section_data_write(unsigned char num,uint address)//num:第num扇区;addr:第一扇区:0x0000;第二扇区:0x0200;第三扇区:0x0400......
{
                num = num;
                if (timer_count>OFFLINE_TIME)        //每隔5分钟写入一组数组
                {
                        timer_count=0;
                        if (SendFlag>=10)
                        {
                                SendFlag=0;
                                NewFrame();                        //时间+电表数据
                                if(g_eeprom_stat.last_write_addr==0x00&&g_Address[0]==1)           //有一条记录
                                {
                                   g_eeprom_stat.last_write_addr+=23;
                                   address=g_eeprom_stat.last_write_addr;
                                   g_eeprom_stat.sector_cnt=1;                                        //CNT=1
                                   His_data_len=1;
                                }                                                                                                                                 
                                eeprom_data_write(EEPROM_Frame,address,23);               //将数据存入eeprom
                                g_eeprom_stat.last_write_addr+=23;
                                g_Address[g_eeprom_stat.last_write_sector_num]++;                 //本扇区记录数++
                                His_data_len++;                                          //all history record count

                                if(g_Address[g_eeprom_stat.last_write_sector_num]==22)          //此扇区已写满 22*23=506
                                {                                                                                                                                                  
                                        g_eeprom_stat.sector_cnt++;                    //有数据记录的扇区数加1 0-0 1-1
                                        g_eeprom_stat.last_write_sector_num++;        //指向下一个扇区   2

                                        if(g_eeprom_stat.last_write_sector_num==EEPROM_SECTOR_CNT)          //eeprom已满,从头写入0-14
                                        {
                                                 g_eeprom_stat.sector_cnt=EEPROM_SECTOR_CNT;
                                                 g_eeprom_stat.last_write_sector_num=0;
                                                 g_eeprom_stat.last_write_addr=0x00;
                                                 g_eeprom_stat.overflow_flag=1;
                                                 eeprom_byte_erase(0x0000);                 //擦除第一个扇区
                                                 g_Address[g_eeprom_stat.last_write_sector_num]=0;
                                        }else
                                        {
                                            g_eeprom_stat.last_write_addr=g_eeprom_stat.last_write_sector_num*0x0200;
                                                g_Address[g_eeprom_stat.last_write_sector_num]=0;
                                                eeprom_byte_erase(g_eeprom_stat.last_write_addr);                 //擦除下一个扇区
                                        }                               
                                }                                                                                                 
                               
                        } //have data?
                }          //five minitus?

}
//*****************************************************************************
//函数名:                 LostConnection_Process(void)
//函数功能描述:处理从电表发来的数据(掉电存储)
//函数参数:          
//函数返回值:          
//作者:                  wenzer
//修改人:
//修改原因:
//*****************************************************************************
void LostConnection_Process(void)                           //处理从电表发来的数据(掉电存储)
{
                Section_data_write(g_eeprom_stat.last_write_sector_num,g_eeprom_stat.last_write_addr);
}
//*****************************************************************************
//函数名:                  
//函数功能描述:发送历史记录数据
//函数参数:          
//函数返回值:          
//作者:                  wenzer
//修改人:
//修改原因:
//*****************************************************************************
void LostConnection_Send(unsigned char* addrLen)                   //处理从电表发来的数据(掉电存储后发送)
{
        unsigned char sendLen;
        unsigned char surplusRecord;
        uint address,address_bk;
        unsigned char xdata tmpData[256];         //从EEPROM中读取数据存入temData

        address=g_eeprom_stat.current_send_sector_num*0x0200;
        address_bk=address;


   //将某扇区的所有记录发送出给网络控制器
   //不足10条或下半部分
        if(g_eeprom_stat.sector_send_up>0)          //current page 已经发送sector_send_up条记录
                {
                        address+=(g_eeprom_stat.sector_send_up*23);   //剩下的半部分
                 }else
                 {
                           g_eeprom_stat.current_send_cnt=0;
                 }       
        //只要记录数还没发完,进入函数就发历史数据
        if(His_data_len>1)
        {
                   surplusRecord=(addrLen[g_eeprom_stat.current_send_sector_num]-g_eeprom_stat.current_send_cnt);        //how man records left
                   if(surplusRecord<11)                 //不足11条记录全读并发送
                   {
                                        eeprom_data_read(tmpData,address,surplusRecord*23);
                                        if(His_data_len>surplusRecord||His_data_len==surplusRecord)
                                        {
                                                His_data_len-=surplusRecord;                                       
                                        }else
                                        {
                                                His_data_len=0;
                                        }
                                        sendLen=SlaveDatPack(surplusRecord*23,tmpData,SLAVE_ID,0x0108);
                                        Uart2Send(g_slaveSendBuf,sendLen);

                                        g_eeprom_stat.current_send_cnt=addrLen[g_eeprom_stat.current_send_sector_num];
                        }else  //上半部分10records
                   {
                                eeprom_data_read(tmpData,address,11*23);
                                if(His_data_len>11)
                                {
                                        His_data_len-=11;
                                }else
                                {
                                   His_data_len=0;
                                }

                                sendLen=SlaveDatPack(11*23,tmpData,SLAVE_ID,0x0108);
                                Uart2Send(g_slaveSendBuf,sendLen);

                                g_eeprom_stat.current_send_cnt+=11;
                                g_eeprom_stat.sector_send_up+=11;                //上半部分已发送
                   }

                  if(g_eeprom_stat.current_send_cnt==addrLen[g_eeprom_stat.current_send_sector_num])        //本扇区已经发完
                                {
                               
                                        g_eeprom_stat.current_send_cnt=0;
                                        g_eeprom_stat.sector_send_up=0;
                                        g_eeprom_stat.current_send_sector_num++;

                                        if((g_eeprom_stat.current_send_sector_num-g_eeprom_stat.last_write_sector_num)==1)  //读取扇区和最后写入的扇区重叠,所有扇区全部发完
                                        {                 
                                                g_eeprom_stat.current_send_sector_num=g_eeprom_stat.read_start_sector;
                                                g_eeprom_stat.current_send_cnt=0;
                                                His_data_len=0;
                                        }                               
                                }//本扇区已经发完
                                //整片都发完了       
                         if(g_eeprom_stat.current_send_sector_num==EEPROM_SECTOR_CNT)
                         {         
                                 g_eeprom_stat.current_send_sector_num=0;
                                 g_eeprom_stat.current_send_cnt=0;       
                         }
         }   
}

/*******************************************************
*******************************************************
                            主程序
*******************************************************
*******************************************************/
void main (void)
{
       
        uint sysStat=0;
        EA = 0;                                    // 关总中断
//        LED1=1;
//        LED2=0;

        P0=0XFF;
        PortsInit();  //set port0 input
        GetSlaveId();
        Uart2Init();  //1200         
//        UartInit();  //4800

        DS1302_init(); //DS1302 io初始化
//        RtcInit();   //第一次使用时初始化DS1302时间
        Timer0Init();       
        eeprom_op_init();
        delay(1000);
    WDT_CONTR=0x3F;           //清狗指令
        poweroff_check_init();         //使能掉电检测
        read_parameter_fromflash();

////        P1DIR |= 0x60;  //P15、P16定义为输出
        Init_5460(); //初始化SPI
//        Sync_5460(); //5460校准

        TR0=1;
        g_comStat=0;                           //默认不在线
//               
//        RS485E=0;        //串口2 485置接收
        RS485EE=0;        //串口1 485置接收
        LED2=1;

        read_i2c_data(0,elevar.var,4);
        E_Power=elevar.floatvar;
        RELAY=RELAY_val;
        Uart2Send(elevar.var,4);                 //芯片重启发四个零
        IT1=0;                                           //外部1中断模式1        下降沿触发0低电平触发
        EX1=1;                                           //外部1中断允许1允许中断 0禁止中断
        EA =1;                                        // 开总中断
        E_Con=0;
        if(E_Power==0)

          {
                   delay(100000);
                   read_i2c_data(0,elevar.var,4);
            E_Power=elevar.floatvar;
       }
        while(1)
   {

                sysStat++;
            WDT_CONTR=0x3F;           //清狗指令
               
                if(sysStat==120)   //灯闪一次
                {
                        E_Con++;
                        re_con++;
                           if((g_comStat==0)&&(re_con>300))                         //采集器离线
                       {
                            EA=0;
                                elevar.floatvar=E_Power;
                                write_i2c_data(0,elevar.var,4);
                            ((void (code *) (void)) 0x0000) ();
                           }
                        sysStat=0;
                    LED1=~LED1;                       
                 }

    //*******************************************************       
        //处理与主控制器的通信
        //*******************************************************
                DealCmd();                 //处理从控制器发来的命令
                LoopQueryStat(); //判断是否掉线

        delay(20);
        if(g_eeprom_stat.overflow_flag==1)
        {
                   g_eeprom_stat.read_start_sector=(g_eeprom_stat.last_write_sector_num+1);
        }else
        {
                g_eeprom_stat.read_start_sector=0;
        }


        //*******************************************************       
        //处理电表数据
        //*******************************************************                       
          if(g_comStat)  //如果控制器在线
                        {
                                 if(g_Address[0]>1||g_eeprom_stat.sector_cnt>0)                  //有离线保存的记录send and insert record
                                 {

                                                   LostConnection_Process();         //处理从电表发来的数据(掉电存储)

                                 }
                                 else        //没有离线保存的记录read and update data
                                 {
                                         
                                         if (SendFlag>=10)          //CS5460        转换就绪
                                         {
                                                //存储当前检测的数据
                                                SendFlag=0;                                               
                                                NewFrame();                          //打包准备数据
                                          
                                                eeprom_byte_erase(0x0000);
                                                delay(100);
                                                eeprom_data_write(EEPROM_Frame,0x0000,23);          //将数据存入eeprom
                                                g_Address[0]=0x01;       
                                                g_eeprom_stat.last_write_addr=0x00;                                                        //存储记录
                                                g_eeprom_stat.last_write_sector_num=0;
                                                g_eeprom_stat.current_send_sector_num=0;
                                                His_data_len=1;
                                                if(E_Con==800)
                                                {
                                                E_Con=0;
                                                EA = 0;                                    // 关总中断
                                                while(1)
                                                {
                                                elevar.floatvar=E_Power;
                                                write_i2c_data(0,elevar.var,4);
                                                   read_i2c_data(0,elevar.var,4);
                                                if(elevar.floatvar==E_Power)
                                                break;
                                            WDT_CONTR=0x3F;           //清狗指令
                                                delay(100000);
                                                }
//                                                x24c08_write(5,RELAY_val);                                               
                                                EA = 1;
                                                }
                                         }
                                  }
                        }
                        else          //控制器离线
                        {
               LostConnection_Process();         //处理从电表发来的数据(掉电存储)
                        }

        }

}


SHUAILONG2004
6楼-- · 2019-07-16 20:07
下面是主程序


/*************************************************************************
* Copyright (c) 2012, 元澄智能科技有限公司
* All rights reserved.
* STC12C5A16S2
* 文件名称:2send1re.c
* 文件标识:2send1re.c
* 摘要:采集电表数据,存储,然后发送给网络控制器,如果控制器在线直接发送,不在线显存储,上线后发送
* 资源配置:UART1和网络控制器通信,UART2和电表通信
* 电表波特率:1200   和网络控制器通信波特率:4800
* eeprom分配最后一个扇区存放参数,其他的存放电量数据
*
* 当前版本:1.0.03
* 作者:wenzer
* 完成日期:2013-02-26
* 修改内容:
*
* 当前版本:1.0.04
* 修改者: 张振亮
* 完成日期:2012年11月10日
*
* 当前版本:1.0.05
* 修改者:         张振亮
*修改内容:命令接收函数,发送函数
* 完成日期:2013年03月18日
* 当前版本:1.0.07
* 修改者:         张振亮
*修改内容:命令接收函数,发送函数
* 完成日期:2013年03月25日
*************************************************************************/
#include <stdio.h>
#include <intrins.h>
#include <stc12c5a60s2.h>
#include "mytypes.h"
#include "i2c.h"
#include "spi.h"
#include "2send1re.H"
#include "net_com.h"
#include "DS1302.H"
#include "EEPROM.H"


//sbit RS485EE=P4^3;                           //串口2定义485的使能脚A板
sbit RS485EE=P3^4;                           //串口2定义485的使能脚B板

sbit RELAY=P4^1;                           //RELAY3.5-4.1


sbit LED1=P3^6;                           //led1  D14
sbit LED2=P3^5;                           //led2        D15

sbit CP=P1^0;                           //CP
unsigned char RELAY_val=0xff;                                 //继电器保存的值
unsigned char  SendFlag=0;
uchar g_eeprom_sector_cnt=0;

#define OFFLINE_TIME   130             //掉线检测周期130s
#define EEPROM_SECTOR_CNT 15                //16个扇区         
#define EEPROM_FLAG  0X66                //eeprom erase
#define S2RI 0x01
#define S2TI 0x02
bit RI2;
bit TI2;

//定时,延时用

unsigned int count=0;
unsigned int timer_count=0;
unsigned int gtimer_count2=0;
unsigned int gLoopQueryCount=0;
unsigned int g_comStat=0;
unsigned char g_ComCnt=0; //统计通信次数,离线判断用

volatile unsigned int His_data_len=0;
unsigned int E_Con=0;
unsigned int re_con=0;
//操作eeprom记录用
EEPROM_STAT g_eeprom_stat;
unsigned char xdata g_Address[56]={0};          //28K56个扇区






//数据集中器通信用变量
volatile uchar g_totalRvcCnt=0;
volatile uchar g_RvcCnt=0;
volatile bit g_NetStat;
uchar g_swStat,g_slaveId;

//延时用
volatile uint g_timeCnt;


unsigned char xdata E_Frame[20]={0};
unsigned char xdata EEPROM_Frame[25]={0};        //从EEPROM中读取的数据帧
float E_Power;
volatile unsigned char xdata Elect[6]={0};                    //定义电量累计数据
unsigned char xdata UIData[6]={0};                //读取的电流和电压
unsigned char xdata N_Frame[20]={0};                //数据集中器对下发送的查询指令
typedef union
             {
                           unsigned char var[4];
                       float floatvar;
                          }float_var;
float_var elevar;

//*****************************************************************************
//函数名:                  将一个数组所有元素清0
//函数功能描述:         
//函数参数:                 数组名,长度
//函数返回值:                  无
//作者:                  wenzer
//修改人:
//修改原因:
//*****************************************************************************
void my_bzero(unsigned char *arr,unsigned int len)
{
unsigned int i;
for(i=0;i<len;i++)
        {
          arr[i]=0;
        }
}
/**************************************
                  延时程序
**************************************/
void delay(uint i)
{
        unsigned char j;
        for(i; i > 0; i--)
                for(j = 200; j > 0; j--);
}
//*****************************************************************************
//函数名:                          void save_parameter_toflash(void)
//函数功能描述:        保存参数到24c08
//函数参数:                 无
//函数返回值:                  无
//作者:                  wenzer
//修改人:
//修改原因:
//*****************************************************************************
void save_parameter_toflash(void)
{
        uint addr=0;
        uchar xdata tmp[70];
        addr=0x1fa4;
//        addr=100;
//        elevar.floatvar=E_Power;
       
        tmp[0]=(uchar)g_eeprom_stat.last_write_addr;     //eeprom操作当前地址
        tmp[1]=(uchar)g_eeprom_stat.last_write_addr>>8;     //eeprom操作当前地址
        tmp[2]=g_eeprom_stat.record_cnt;     //记录数
        tmp[3]=g_eeprom_stat.current_send_sector_num;     //已发送数据的当前扇区编号
        tmp[4]=g_eeprom_stat.sector_send_up;     //上半部分记录已发送
        tmp[5]=g_eeprom_stat.last_write_sector_num;     //最后一个扇区编号
       
        tmp[6]=g_eeprom_stat.overflow_flag;     //溢出标志
        tmp[7]=g_eeprom_stat.sector_cnt;     //扇区编号
        tmp[8]=EEPROM_FLAG;     //parameter save flag,means save ok
                                                        //
//        tmp[9]=elevar.var[0];
//        tmp[10]=elevar.var[1];
//        tmp[11]=elevar.var[2];
//        tmp[12]=elevar.var[3];                  //保存累计电量
        tmp[13]=RELAY_val;                           //保存继电器状态
        MyMemCpy(tmp+14,g_Address,56);        //加入数据段

        eeprom_data_write(tmp,addr,70);  //将数据存入eeprom
//        write_i2c_data(addr,tmp,70);
}
//*****************************************************************************
//函数名:                          void read_parameter_fromflash(void)
//函数功能描述:        从24c08读取参数
//函数参数:                 无
//函数返回值:                  无
//作者:                  wenzer
//修改人:
//修改原因:
//*****************************************************************************
void read_parameter_fromflash(void)
{
        uint addr=0;
        uchar xdata tmp[70]={0};
        addr=0x1fa4;
//        addr=100;
        eeprom_data_read(tmp,addr,70);
    eeprom_byte_erase(0x1e00);
//        Uart2Send(tmp,70);

        if(tmp[8]==EEPROM_FLAG)                           //保存过参数
        {
                g_eeprom_stat.last_write_addr=tmp[0];     //eeprom操作当前地址
                g_eeprom_stat.last_write_addr=tmp[1]*256;     //eeprom操作当前地址 左移8位
               
                g_eeprom_stat.record_cnt=tmp[2];     //记录数
                g_eeprom_stat.current_send_sector_num=tmp[3];     //已发送数据的当前扇区编号
                g_eeprom_stat.sector_send_up=tmp[4];     //上半部分记录已发送
                g_eeprom_stat.last_write_sector_num=tmp[5];     //最后一个扇区编号
               
                g_eeprom_stat.overflow_flag=tmp[6];     //溢出标志
                g_eeprom_stat.sector_cnt=tmp[7];     //扇区编号
//                elevar.var[0]=tmp[9];
//                elevar.var[1]=tmp[10];
//                elevar.var[2]=tmp[11];
//                elevar.var[3]=tmp[12];
                RELAY_val=tmp[13];       
//                E_Power=elevar.floatvar;
                MyMemCpy(g_Address,tmp+14,56);        //加入数据段

                 if(g_eeprom_stat.sector_cnt==0&&g_Address[0]==1)                  //无离线保存的记录
                {
                  His_data_len=1;
                }
                if(g_eeprom_stat.sector_cnt>0)                  //有离线保存的记录
                        {
                                His_data_len=(g_eeprom_stat.sector_cnt-1)*30;
                                His_data_len+=g_Address[g_eeprom_stat.last_write_sector_num];
                                if(g_eeprom_stat.overflow_flag==1)
                                {
                                        His_data_len=EEPROM_SECTOR_CNT*30;
                                        His_data_len+=g_Address[g_eeprom_stat.last_write_sector_num];
                                }       
                        }
        }else                   //第一次使用
        {
            EEPROM_Erase();
                delay(400);
                delay(400);
        }

}
//*****************************************************************************
//函数名:                          void poweroff_init(void)
//函数功能描述:        使能掉电检测中断
//函数参数:                 无
//函数返回值:                  无
//作者:                  wenzer
//修改人:
//修改原因:
//*****************************************************************************
void poweroff_check_init(void)
{
        P4SW&=0XBF;   //set p4.6 as lvd pin
        WAKE_CLKO=0X08; //enable lvd signal wakeup mcu
        ELVD=1;             //enable lvd interrupt
        PCON&=0XDF;
}
//*****************************************************************************
//函数名:                          void lvdint()
//函数功能描述:        掉电检测中断
//函数参数:                 无
//函数返回值:                  无
//作者:                  wenzer
//修改人:
//修改原因:
//*****************************************************************************
void lvdint() interrupt 6
{
  uchar tmp;

        PCON&=0XDF;  //clear LVD flag
        tmp=(PCON&0X20);
        if(tmp>0)  //还是1则是掉电了,否则是电源波动
        {
          elevar.floatvar=E_Power;
          write_i2c_data(0,elevar.var,4);
          save_parameter_toflash();                                //保存数据
          PCON&=0XDF;  //clear LVD flag
          ELVD=0;             //disenable lvd interrupt
          PCON&=0Xfd;
        }
}

//*****************************************************************************
//函数名:                          void exint0()
//函数功能描述:        外部0中断处理 ,读取电表累计电量
//函数参数:                 无
//函数返回值:                  无
//作者:                     szl
//修改人:
//修改原因:
//*****************************************************************************
void exint1() interrupt 2
  {
//   EA=0;
   SCAN_CS5460();
   SendFlag++;
//   EA=1;
  }

//*****************************************************************************
//函数名:                          Timer0Init(void)
//函数功能描述:        定时器0初始化,初值设定1毫秒@11.0592MHz
//函数参数:         
//函数返回值:          
//作者:                  wenzer
//修改人:
//修改原因:
//*****************************************************************************
void Timer0Init(void)                //1毫秒@11.0592MHz
{
        AUXR |= 0x80;                //定时器时钟1T模式
        TMOD &= 0xF0;                //设置定时器模式
        TMOD |= 0x01;                //设置定时器模式
        TL0 = 0xCD;                //设置定时初值
        TH0 = 0xD4;                //设置定时初值
        TF0 = 0;                //清除TF0标志
        TR0 = 1;                //定时器0开始计时
        ET0 = 1;
        count = 1;

}
//*****************************************************************************
//函数名:                         tm0_isr() interrupt 1 using 1
//函数功能描述:        定时器1中断服务函数(1s)
//函数参数:         
//函数返回值:          
//作者:                  wenzer
//修改人:
//修改原因:
//*****************************************************************************
void tm0_isr() interrupt 1 using 1                  //定时器1中断,方式1(1s)
{

        TR0=0;
        TF0=0;
        TL0 = 0xCD;                //设置定时初值
        TH0 = 0xD4;                //设置定时初值
        if (count--==0)
        {               
        count =1000;
                timer_count++;
                gLoopQueryCount++;
                gtimer_count2++;
               
        }
        TR0=1;

}
/**************************************
       数组反转倒序输出
**************************************/
void Reverse(uchar * array, uchar len)
{
        uchar i;
        for ( i = 0; i < len / 2; ++ i)
        {
                uchar temp = array[i];
                array[i] = array[len - 1 - i];
                array[len - 1 - i] = temp;
        }
}
//*****************************************************************************
//函数名:                  
//函数功能描述:
//函数参数:          
//函数返回值:          
//作者:                  wenzer
//修改人:
//修改原因:
//*****************************************************************************
/*
uchar RolData(uchar x)
{
         x = ((x<<4) & 0xf0) | ((x>>4) & 0x0f);
         x = ((x<<2) & 0xcc) | ((x>>2) & 0x33);
         x = ((x<<1) & 0xaa) | ((x>>1) & 0x55);
         return x;
}
*/
//*****************************************************************************
//函数名:                  
//函数功能描述:
//函数参数:引脚序号,0输出1输入         
//函数返回值:          
//作者:                  wenzer
//修改人:
//修改原因:
//*****************************************************************************
void Port0Set(uchar pnum,uchar stat)
{
        if(stat)
        {
                P0M1|=pnum;
                P0M0&=(~pnum);
        }
        else
        {
                P0M0|=pnum;
                P0M1&=(~pnum);
        }
}
//*****************************************************************************
//函数名:                  
//函数功能描述:
//函数参数:          
//函数返回值:          
//作者:                  wenzer
//修改人:
//修改原因:
//*****************************************************************************
void PortsInit(void)
{
        Port0Set(0xff,1);
}
//*****************************************************************************
//函数名:                  
//函数功能描述:
//函数参数:          
//函数返回值:          
//作者:                  wenzer
//修改人:
//修改原因:
//*****************************************************************************
void GetSlaveId(void)
{
        volatile uchar st;
        CP=0;
        delay(50);
        CP=1;
        delay(50);
        st=P0;  
        g_swStat=~st;
        g_slaveId=(g_swStat&0x1f);
       
}
/**************************************
            串口2波特率设置
**************************************/
unsigned char SetBaudRate(void)
{
        unsigned char Baud,BaudRate;
        Baud=(g_swStat>>5);                                //PO口前三个引脚设置波特率4800/9600/14400/19200/38400
        Baud=(Baud&0x07);
        switch(Baud)
        {
        case 1:
                        BaudRate=0xF4;                        //2400
                        break;
        case 2:
                        BaudRate=0xFA;                        //4800
                        break;
        case 3:
                        BaudRate=0xFD;                        //9600
                        break;
        case 4:
                        BaudRate=0xFE;                        //19200
                        break;
        case 5:
                        BaudRate=0xFF;                        //38400
                        break;
        case 6:
                        BaudRate=0xFF;                        //38400
                        break;          
        default:
                        break;
        }
        return BaudRate;
}
//*****************************************************************************
//函数名:                  
//函数功能描述:
//函数参数:          
//函数返回值:          
//作者:                  wenzer
//修改人:
//修改原因:
//*****************************************************************************
void UartInit(void)                //14400bps@11.0592MHz
{
//        PCON &= 0x7F;                //波特率不倍速
//        SCON = 0x50;                //8位数据,可变波特率
//        AUXR |= 0x40;                //定时器1时钟为Fosc,即1T
//        AUXR &= 0xFE;                //串口1选择定时器1为波特率发生器
//        TMOD &= 0x0F;                //清除定时器1模式位
//        TMOD |= 0x20;                //设定定时器1为8位自动重装方式
//        TL1 = 0XE8        ;
//        TH1 = 0xE8  ;
//        ET1 = 0;                //禁止定时器1中断
//        TR1 = 1;                //启动定时器1
//        ES = 1;
        PCON &= 0x7F;                //波特率不倍速
        SCON = 0x50;                //8位数据,可变波特率
        AUXR &= 0xBF;                //定时器1时钟为Fosc/12,即12T
        AUXR &= 0xFE;                //串口1选择定时器1为波特率发生器
        TMOD &= 0x0F;                //清除定时器1模式位
        TMOD |= 0x20;                //设定定时器1为8位自动重装方式
        TL1 = 0xE8;                //设定定时初值
        TH1 = 0xE8;                //设定定时器重装值
        ET1 = 0;                //禁止定时器1中断
        TR1 = 1;                //启动定时器1
        ES = 1;
}
//*****************************************************************************
//函数名:                  
//函数功能描述:
//函数参数:          
//函数返回值:          
//作者:                  wenzer
//修改人:
//修改原因:
//*****************************************************************************
void Uart2Init(void)                //1200bps@11.0592MHz
{
/*        AUXR &= 0xF7;                //波特率不倍速
        S2CON = 0xD0;                //9位数据,可变波特率
        AUXR &= 0xFB;                //独立波特率发生器时钟为Fosc/12,即12T
        BRT = 0xE8;                //设定独立波特率发生器重装值
        AUXR |= 0x10;                //启动独立波特率发生器
*/
//        S2CON = 0xD0;                      //REN=1允许串行接受状态,串口工作模式3,数据位8、停止位1。偶校验 (11.0592)
//        PCON|= 0x00;                                //不加倍
//        AUXR = 0x11;                                //BRTx12=0,独立波特率发生器每12个时钟技计数一次
//        BRT = 0xfa;                          //波特率4800

        AUXR &= 0xF7;                //波特率不倍速
        S2CON = 0x50;                //8位数据,可变波特率
        AUXR &= 0xFB;                //独立波特率发生器时钟为Fosc/12,即12T
        BRT = SetBaudRate();                    //设定独立波特率发生器重装值
        AUXR |= 0x10;                //启动独立波特率发生器
        IE2 = 0x01;         //开串口2中断  
       
}

/**************************************
            串口2发送一字节(加偶校验)
**************************************/
void SendByte2(unsigned char dat)
{
//        unsigned char S2TB8;
////        ACC=dat;
//        S2TB8=P;                                                //偶校验位(P判断ACC的奇偶特性)
//
//
//        if (S2TB8)                                                //S2TB8发送校验位判断
//        {
//                S2CON|=0x08;                       
//        }
//        else
//        {
//                S2CON&=~0x08;
//        }

        S2BUF=dat;                                        //发送一个字节
        while(!(S2CON&0x02));        //等待发送标志位
        S2CON &=~S2TI;                                //清空发送标志位

}
/**************************************
            串口2发送一字符串meter
**************************************/
void Uart2Send(uchar *dat,uchar len)
{
        uchar tmp;
        RS485EE=1;                                            //485置1发送
        _nop_();                                                //485置1等待时间
        _nop_();
        _nop_();
        _nop_();
           _nop_();
        _nop_();

        for(tmp=0;tmp<len;tmp++)
        {
                SendByte2(*dat);
                dat++;
        }
        _nop_();
        _nop_();
        _nop_();                                                //485置0等待时间
        _nop_();
        _nop_();
        RS485EE=0;                                        //485置0接收
        _nop_();
        _nop_();
        _nop_();
       
}
/**************************************
            串口1发送一字节
//**************************************/
void SendByte1(unsigned char dat1)
{
        SBUF=dat1;
        while (!TI);                                //等待发送完成
        TI=0;                                                        //清空发送标志位
}

/**************************************
            串口1发送一字符串net
**************************************/
void Uart1Send(uchar *dat,uchar len)
{
        uchar tmp;
//        RS485EE=1;                                            //485置1发送
        _nop_();                                                //485置1等待时间
        _nop_();
        _nop_();
        _nop_();


        for(tmp=0;tmp<len;tmp++)
        {
                SendByte1(*dat);
                dat++;
        }
       
        _nop_();                                                //485置0等待时间
        _nop_();
        _nop_();
//        RS485EE=0;                                        //485置0接收
        _nop_();
        _nop_();
        _nop_();
       
}
/**************************************
               清空接收缓存区
**************************************/
void ClearComDat(void)
{
        g_RvcCnt=0;
        g_totalRvcCnt=0;


}
/****************************************************
               串口2中断程序(NET)
                           与网络控制器通信
******************************************************/
void UART2_int (void) interrupt 8 using 1
{


//        TI2=S2CON & S2TI;
        RI2=S2CON & S2RI;
//        if(TI2)         {S2CON=S2CON&0xfd;}                //TI标志清除

        if(RI2)                                        //RI接受中断标志
        {
                S2CON = S2CON&=~S2RI;
                N_Frame[g_RvcCnt]= S2BUF;                  //SUBF接受/发送缓冲器

                if(g_RvcCnt<5)
                {
       
                        switch(g_RvcCnt)
                        {
                        case 0:
                                if(N_Frame[0]==0x0a)
                                g_RvcCnt++;
                                break;
                        case 1:
                                if(N_Frame[1]==0x0c)
                                  {       
                                  g_RvcCnt++;
                                  }
                                else if(N_Frame[1]==0x0a)
                                        {
                                                 N_Frame[0]=N_Frame[1];
                                                }
                                else
                                        {
                                                 g_RvcCnt=0;
                                                }
                                break;
                        case 2:
                                if(N_Frame[2]==0x0e)
                                 {
                                 g_RvcCnt++;
                                 }
                                 else
                                 {
                                 g_RvcCnt=0;
                                 }
                                break;
                        case 3:
                                g_totalRvcCnt=N_Frame[3];  //计算数据总长度
                                g_RvcCnt++;
                                break;

                        case 4:
                                if(N_Frame[4]==g_slaveId)
                                {
                                g_RvcCnt++;
                                }
                                else
                                {
                                 g_RvcCnt=0;
                                }
                                break;
                        default:
                                break;               
                         }
                  }
        else{               
                                g_RvcCnt++;
                                if((g_RvcCnt==g_totalRvcCnt)&&(N_Frame[g_RvcCnt-1]==0x46))
                                {
//                                          Uart2Send(N_Frame, g_totalRvcCnt);
                                        g_RvcCnt=0;
                                        g_totalRvcCnt=0;
                                        g_NetStat=1;
                                        g_ComCnt=1;
                                        g_comStat=1;                                   //在线
                                LED2=0;
                                    re_con=0;
                                }
                        } //end s1

                }  //end s2




}

/****************************************************
               串口1中断程序(与电表通信)
******************************************************/

//void UART1_int (void) interrupt 4 using 1
//{
//
//   if(TI == 1)    TI =0;             //TI发送中断标志       
//   if(RI == 1)                                //RI接受中断标志
//        {
//                 RI = 0;       
//                E_Frame[i] = SBUF;                  //SUBF接受/发送缓冲器
////                if (E_Frame[i-1]==0x0a)
////                    LED2=0;
//                i++;
//
//                if(i==19)
//                {
//                        if((E_Frame[i-1]==0x16))
//                    SendFlag2=1;
//                        i=0;
////          Uart1Send("Meter data rcv",14);
//                }
//
//           }
//     }

//*****************************************************************************
//函数名:                  
//函数功能描述:
//函数参数:          
//函数返回值:          
//作者:                  wenzer
//修改人:
//修改原因:
//*****************************************************************************
void RelayCtl(uchar rel)
{
        if(rel==0)
        {
                  RELAY=1;
                RELAY_val=0xff;
//                LED2=0;
        }else
        {
                RELAY=0;
                RELAY_val=0;
//                LED2=1;
        }
}
/**************************************
       取电表返回数据E_Frame中数据域处理并加入时钟nowTime组成新数组EEPROM_Frame
**************************************/
void NewFrame(void)
{
        unsigned long elect ;
        uchar xdata nowTime[7];
        EX1=0;         //关闭外部中断
        elect=E_Power;
        Elect[2]=elect;
        Elect[1]=elect>>8;
        Elect[0]=elect>>16;
        elect=E_Power;
        Elect[3]=(E_Power-elect)*100;
////        if(Elect[3]==0xff)
////        {
////          unsigned char i;
////         for(i=0;i<6;i++)
////            {
////                 Elect[i]=0;
////                 }
////        }
        Elect[4]=0x01;                                   //表示后面没有其它电量数据
        Elect[5]=0x04;                                   //电量值为四个字节
    EX1=1;    //打开外部中断

        dsReadTime(nowTime);

        Reverse(nowTime,7);
        MyMemCpy(EEPROM_Frame,nowTime,7);  
        MyMemCpy((EEPROM_Frame+7),UIData,6); ///----------------- 电流电压放入
        MyMemCpy((EEPROM_Frame+13),Elect,6);        //电量放入
        MyMemCpy((EEPROM_Frame+19),Elect,4);        //电量放入
//        Uart2Send(EEPROM_Frame,17);

}
//*****************************************************************************
//函数名:LoopQueryStat
//函数功能描述:轮询就地控制器是否在线
//函数参数:
//函数返回值:
//作者:                  wenzer
//修改人:
//修改原因:
//*****************************************************************************
void LoopQueryStat(void)                                   //轮询就地控制器是否在线
{
        if(gLoopQueryCount>OFFLINE_TIME)
        {
                gLoopQueryCount=0;
                if(g_ComCnt)          //5分钟内有通信
                {
                        g_comStat=1;                                   //在线
                        LED2=0;

                }
                else
                {
                        g_comStat=0;
                        LED2=1;
                }
                g_ComCnt=0;                 //通信次数归0
        }
}

//*****************************************************************************
//函数名:void eeprom_op_init(void)
//函数功能描述:初始化eeprom操作参数
//函数参数:
//函数返回值:
//作者:                  wenzer
//修改人:
//修改原因:
//*****************************************************************************
void eeprom_op_init(void)
{

        g_eeprom_stat.sector_cnt=0;
        g_eeprom_stat.last_write_addr=0x00;
        g_eeprom_stat.record_cnt=0;

        g_eeprom_stat.read_start_sector=0;
        g_eeprom_stat.current_send_sector_num=0;
        g_eeprom_stat.current_send_cnt=0;

        g_eeprom_stat.last_write_sector_num=0;

        g_eeprom_stat.overflow_flag=0;
        g_eeprom_stat.sector_send_up=0;
        His_data_len=0;
    g_eeprom_sector_cnt=EEPROM_SECTOR_CNT;
        my_bzero(g_Address,56);
}
//*****************************************************************************
//函数名:                        Section_data_write(unsigned char num,unsigned char address)
//函数功能描述:        若一直掉线,存满一个扇区(一个23字节的数组存入一个扇区可以存22组);从第num扇区的address地址开始写数据
//函数参数:          
//函数返回值:          
//作者:                  wenzer
//修改人:
//修改原因:
//*****************************************************************************
void Section_data_write(unsigned char num,uint address)//num:第num扇区;addr:第一扇区:0x0000;第二扇区:0x0200;第三扇区:0x0400......
{
                num = num;
                if (timer_count>OFFLINE_TIME)        //每隔5分钟写入一组数组
                {
                        timer_count=0;
                        if (SendFlag>=10)
                        {
                                SendFlag=0;
                                NewFrame();                        //时间+电表数据
                                if(g_eeprom_stat.last_write_addr==0x00&&g_Address[0]==1)           //有一条记录
                                {
                                   g_eeprom_stat.last_write_addr+=23;
                                   address=g_eeprom_stat.last_write_addr;
                                   g_eeprom_stat.sector_cnt=1;                                        //CNT=1
                                   His_data_len=1;
                                }                                                                                                                                 
                                eeprom_data_write(EEPROM_Frame,address,23);               //将数据存入eeprom
                                g_eeprom_stat.last_write_addr+=23;
                                g_Address[g_eeprom_stat.last_write_sector_num]++;                 //本扇区记录数++
                                His_data_len++;                                          //all history record count

                                if(g_Address[g_eeprom_stat.last_write_sector_num]==22)          //此扇区已写满 22*23=506
                                {                                                                                                                                                  
                                        g_eeprom_stat.sector_cnt++;                    //有数据记录的扇区数加1 0-0 1-1
                                        g_eeprom_stat.last_write_sector_num++;        //指向下一个扇区   2

                                        if(g_eeprom_stat.last_write_sector_num==EEPROM_SECTOR_CNT)          //eeprom已满,从头写入0-14
                                        {
                                                 g_eeprom_stat.sector_cnt=EEPROM_SECTOR_CNT;
                                                 g_eeprom_stat.last_write_sector_num=0;
                                                 g_eeprom_stat.last_write_addr=0x00;
                                                 g_eeprom_stat.overflow_flag=1;
                                                 eeprom_byte_erase(0x0000);                 //擦除第一个扇区
                                                 g_Address[g_eeprom_stat.last_write_sector_num]=0;
                                        }else
                                        {
                                            g_eeprom_stat.last_write_addr=g_eeprom_stat.last_write_sector_num*0x0200;
                                                g_Address[g_eeprom_stat.last_write_sector_num]=0;
                                                eeprom_byte_erase(g_eeprom_stat.last_write_addr);                 //擦除下一个扇区
                                        }                               
                                }                                                                                                 
                               
                        } //have data?
                }          //five minitus?

}
//*****************************************************************************
//函数名:                 LostConnection_Process(void)
//函数功能描述:处理从电表发来的数据(掉电存储)
//函数参数:          
//函数返回值:          
//作者:                  wenzer
//修改人:
//修改原因:
//*****************************************************************************
void LostConnection_Process(void)                           //处理从电表发来的数据(掉电存储)
{
                Section_data_write(g_eeprom_stat.last_write_sector_num,g_eeprom_stat.last_write_addr);
}
//*****************************************************************************
//函数名:                  
//函数功能描述:发送历史记录数据
//函数参数:          
//函数返回值:          
//作者:                  wenzer
//修改人:
//修改原因:
//*****************************************************************************
void LostConnection_Send(unsigned char* addrLen)                   //处理从电表发来的数据(掉电存储后发送)
{
        unsigned char sendLen;
        unsigned char surplusRecord;
        uint address,address_bk;
        unsigned char xdata tmpData[256];         //从EEPROM中读取数据存入temData

        address=g_eeprom_stat.current_send_sector_num*0x0200;
        address_bk=address;


   //将某扇区的所有记录发送出给网络控制器
   //不足10条或下半部分
        if(g_eeprom_stat.sector_send_up>0)          //current page 已经发送sector_send_up条记录
                {
                        address+=(g_eeprom_stat.sector_send_up*23);   //剩下的半部分
                 }else
                 {
                           g_eeprom_stat.current_send_cnt=0;
                 }       
        //只要记录数还没发完,进入函数就发历史数据
        if(His_data_len>1)
        {
                   surplusRecord=(addrLen[g_eeprom_stat.current_send_sector_num]-g_eeprom_stat.current_send_cnt);        //how man records left
                   if(surplusRecord<11)                 //不足11条记录全读并发送
                   {
                                        eeprom_data_read(tmpData,address,surplusRecord*23);
                                        if(His_data_len>surplusRecord||His_data_len==surplusRecord)
                                        {
                                                His_data_len-=surplusRecord;                                       
                                        }else
                                        {
                                                His_data_len=0;
                                        }
                                        sendLen=SlaveDatPack(surplusRecord*23,tmpData,SLAVE_ID,0x0108);
                                        Uart2Send(g_slaveSendBuf,sendLen);

                                        g_eeprom_stat.current_send_cnt=addrLen[g_eeprom_stat.current_send_sector_num];
                        }else  //上半部分10records
                   {
                                eeprom_data_read(tmpData,address,11*23);
                                if(His_data_len>11)
                                {
                                        His_data_len-=11;
                                }else
                                {
                                   His_data_len=0;
                                }

                                sendLen=SlaveDatPack(11*23,tmpData,SLAVE_ID,0x0108);
                                Uart2Send(g_slaveSendBuf,sendLen);

                                g_eeprom_stat.current_send_cnt+=11;
                                g_eeprom_stat.sector_send_up+=11;                //上半部分已发送
                   }

                  if(g_eeprom_stat.current_send_cnt==addrLen[g_eeprom_stat.current_send_sector_num])        //本扇区已经发完
                                {
                               
                                        g_eeprom_stat.current_send_cnt=0;
                                        g_eeprom_stat.sector_send_up=0;
                                        g_eeprom_stat.current_send_sector_num++;

                                        if((g_eeprom_stat.current_send_sector_num-g_eeprom_stat.last_write_sector_num)==1)  //读取扇区和最后写入的扇区重叠,所有扇区全部发完
                                        {                 
                                                g_eeprom_stat.current_send_sector_num=g_eeprom_stat.read_start_sector;
                                                g_eeprom_stat.current_send_cnt=0;
                                                His_data_len=0;
                                        }                               
                                }//本扇区已经发完
                                //整片都发完了       
                         if(g_eeprom_stat.current_send_sector_num==EEPROM_SECTOR_CNT)
                         {         
                                 g_eeprom_stat.current_send_sector_num=0;
                                 g_eeprom_stat.current_send_cnt=0;       
                         }
         }   
}

/*******************************************************
*******************************************************
                            主程序
*******************************************************
*******************************************************/
void main (void)
{
       
        uint sysStat=0;
        EA = 0;                                    // 关总中断
//        LED1=1;
//        LED2=0;

        P0=0XFF;
        PortsInit();  //set port0 input
        GetSlaveId();
        Uart2Init();  //1200         
//        UartInit();  //4800

        DS1302_init(); //DS1302 io初始化
//        RtcInit();   //第一次使用时初始化DS1302时间
        Timer0Init();       
        eeprom_op_init();
        delay(1000);
    WDT_CONTR=0x3F;           //清狗指令
        poweroff_check_init();         //使能掉电检测
        read_parameter_fromflash();

////        P1DIR |= 0x60;  //P15、P16定义为输出
        Init_5460(); //初始化SPI
//        Sync_5460(); //5460校准

        TR0=1;
        g_comStat=0;                           //默认不在线
//               
//        RS485E=0;        //串口2 485置接收
        RS485EE=0;        //串口1 485置接收
        LED2=1;

        read_i2c_data(0,elevar.var,4);
        E_Power=elevar.floatvar;
        RELAY=RELAY_val;
        Uart2Send(elevar.var,4);                 //芯片重启发四个零
        IT1=0;                                           //外部1中断模式1        下降沿触发0低电平触发
        EX1=1;                                           //外部1中断允许1允许中断 0禁止中断
        EA =1;                                        // 开总中断
        E_Con=0;
        if(E_Power==0)

          {
                   delay(100000);
                   read_i2c_data(0,elevar.var,4);
            E_Power=elevar.floatvar;
       }
        while(1)
   {

                sysStat++;
            WDT_CONTR=0x3F;           //清狗指令
               
                if(sysStat==120)   //灯闪一次
                {
                        E_Con++;
                        re_con++;
                           if((g_comStat==0)&&(re_con>300))                         //采集器离线
                       {
                            EA=0;
                                elevar.floatvar=E_Power;
                                write_i2c_data(0,elevar.var,4);
                            ((void (code *) (void)) 0x0000) ();
                           }
                        sysStat=0;
                    LED1=~LED1;                       
                 }

    //*******************************************************       
        //处理与主控制器的通信
        //*******************************************************
                DealCmd();                 //处理从控制器发来的命令
                LoopQueryStat(); //判断是否掉线

        delay(20);
        if(g_eeprom_stat.overflow_flag==1)
        {
                   g_eeprom_stat.read_start_sector=(g_eeprom_stat.last_write_sector_num+1);
        }else
        {
                g_eeprom_stat.read_start_sector=0;
        }


        //*******************************************************       
        //处理电表数据
        //*******************************************************                       
          if(g_comStat)  //如果控制器在线
                        {
                                 if(g_Address[0]>1||g_eeprom_stat.sector_cnt>0)                  //有离线保存的记录send and insert record
                                 {

                                                   LostConnection_Process();         //处理从电表发来的数据(掉电存储)

                                 }
                                 else        //没有离线保存的记录read and update data
                                 {
                                         
                                         if (SendFlag>=10)          //CS5460        转换就绪
                                         {
                                                //存储当前检测的数据
                                                SendFlag=0;                                               
                                                NewFrame();                          //打包准备数据
                                          
                                                eeprom_byte_erase(0x0000);
                                                delay(100);
                                                eeprom_data_write(EEPROM_Frame,0x0000,23);          //将数据存入eeprom
                                                g_Address[0]=0x01;       
                                                g_eeprom_stat.last_write_addr=0x00;                                                        //存储记录
                                                g_eeprom_stat.last_write_sector_num=0;
                                                g_eeprom_stat.current_send_sector_num=0;
                                                His_data_len=1;
                                                if(E_Con==800)
                                                {
                                                E_Con=0;
                                                EA = 0;                                    // 关总中断
                                                while(1)
                                                {
                                                elevar.floatvar=E_Power;
                                                write_i2c_data(0,elevar.var,4);
                                                   read_i2c_data(0,elevar.var,4);
                                                if(elevar.floatvar==E_Power)
                                                break;
                                            WDT_CONTR=0x3F;           //清狗指令
                                                delay(100000);
                                                }
//                                                x24c08_write(5,RELAY_val);                                               
                                                EA = 1;
                                                }
                                         }
                                  }
                        }
                        else          //控制器离线
                        {
               LostConnection_Process();         //处理从电表发来的数据(掉电存储)
                        }

        }

}

一周热门 更多>