本帖最后由 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();
}
a
b
/*************************************************************************
* 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(); //处理从电表发来的数据(掉电存储)
}
}
}
/*************************************************************************
* 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(); //处理从电表发来的数据(掉电存储)
}
}
}
/*************************************************************************
* 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(); //处理从电表发来的数据(掉电存储)
}
}
}
一周热门 更多>