本帖最后由 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();
}
一周热门 更多>