完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
本帖最后由 SHUAILONG2004 于 2013-12-24 16:22 编辑
写了个电表程序,把累计的电量值放在定义的一个浮点数中(float),一段时间后会自动清零,哪位大神知道是什么原因吗?程序在附件中,加了掉电存储和定时存入24C08,重启后读取,数值清零发生在芯片重启(可能是看门狗溢出)后,手动离线或断电,或者使看门狗启动都不会掉数据,但正常运行一段时间就会发生(E_Power)这个变量! 下面是主程序,后面是CS5460的程序 *************************************************************************/ #include #include #include #include "mytypes.h" #include "i2c.h" #include "spi.h" #include "2send1re.H" #include "net_com.h" #include "DS1302.H" #include "EEPROM.H" //***it RS485EE=P4^3; //串口2定义485的使能脚A板 ***it RS485EE=P3^4; //串口2定义485的使能脚B板 ***it RELAY=P4^1; //RELAY3.5-4.1 ***it LED1=P3^6; //led1 D14 ***it LED2=P3^5; //led2 D15 ***it 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 float power; power=E_Power; power+=ElectRMS; if((power>0)&(ElectRMS<1)) E_Power=power; } } Clear_DRDY(); } |
|
相关推荐
8个回答
|
|
|
|
|
|
|
|
|
|
本帖最后由 SHUAILONG2004 于 2013-12-24 16:22 编辑
ssssssssssssssssssssssssssssssssssssssssssssssss |
|
|
|
上面是CS5460程序,下面是主程序,主要是E_POWER这个变量
/************************************************************************* * Copyright (c) 2012, 元澄智能科技有限公司 * All rights reserved. * STC12C5A16S2 * 文件名称:2send1re.c * 文件标识:2send1re.c * 摘要:采集电表数据,存储,然后发送给网络控制器,如果控制器在线直接发送,不在线显存储,上线后发送 * 资源配置:UART1和网络控制器通信,UART2和电表通信 * 电表波特率:1200 和网络控制器通信波特率:4800 * eeprom分配最后一个扇区存放参数,其他的存放电量数据 * * 当前版本:1.0.03 * 作者:wenzer * 完成日期:2013-02-26 * 修改内容: * * 当前版本:1.0.04 * 修改者: 张振亮 * 完成日期:2012年11月10日 * * 当前版本:1.0.05 * 修改者: 张振亮 *修改内容:命令接收函数,发送函数 * 完成日期:2013年03月18日 * 当前版本:1.0.07 * 修改者: 张振亮 *修改内容:命令接收函数,发送函数 * 完成日期:2013年03月25日 *************************************************************************/ #include #include #include #include "mytypes.h" #include "i2c.h" #include "spi.h" #include "2send1re.H" #include "net_com.h" #include "DS1302.H" #include "EEPROM.H" //***it RS485EE=P4^3; //串口2定义485的使能脚A板 ***it RS485EE=P3^4; //串口2定义485的使能脚B板 ***it RELAY=P4^1; //RELAY3.5-4.1 ***it LED1=P3^6; //led1 D14 ***it LED2=P3^5; //led2 D15 ***it 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 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 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 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 #include #include #include "mytypes.h" #include "i2c.h" #include "spi.h" #include "2send1re.H" #include "net_com.h" #include "DS1302.H" #include "EEPROM.H" //***it RS485EE=P4^3; //串口2定义485的使能脚A板 ***it RS485EE=P3^4; //串口2定义485的使能脚B板 ***it RELAY=P4^1; //RELAY3.5-4.1 ***it LED1=P3^6; //led1 D14 ***it LED2=P3^5; //led2 D15 ***it 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 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 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 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 #include #include #include "mytypes.h" #include "i2c.h" #include "spi.h" #include "2send1re.H" #include "net_com.h" #include "DS1302.H" #include "EEPROM.H" //***it RS485EE=P4^3; //串口2定义485的使能脚A板 ***it RS485EE=P3^4; //串口2定义485的使能脚B板 ***it RELAY=P4^1; //RELAY3.5-4.1 ***it LED1=P3^6; //led1 D14 ***it LED2=P3^5; //led2 D15 ***it 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 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 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 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(); //处理从电表发来的数据(掉电存储) } } } |
|
|
|
|
|
|
|
调哪个延时? 好像和延时没有关系吧
|
|
|
|
你正在撰写答案
如果你是对答案或其他答案精选点评或询问,请使用“评论”功能。
751 浏览 0 评论
使用Keil建立完整的工程,并使用外部中断0触发数码管显示903
1330 浏览 0 评论
嵌入式学习-飞凌嵌入式ElfBoard ELF 1板卡-使用AHT20进行环境监测之AHT20传感器介绍
1184 浏览 0 评论
899 浏览 0 评论
947 浏览 1 评论
【youyeetoo X1 windows 开发板体验】少儿AI智能STEAM积木平台
11865 浏览 31 评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-3 11:28 , Processed in 0.700644 second(s), Total 55, Slave 48 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号