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();
}

友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。