/********************************************************* Hardware : EVB9S08DZ60 Board Author : WBR Version : V1.0 Begin Time: 2011.5.30 **********************************************************/ #include <hidef.h> /* for EnableInterrupts macro */ #include "derivative.h" /* include peripheral declarations */ #include "1302.h" //#include "lcd.h" //#include "mscan.h" //#include "KEY.h" /****************************************************** IO说明: 1:四路AD输入通道 ADP19(AD1) ADP11(AD2) ADP3(AD3) ADP4(AD4) 2:485通信 DE (PTE2) TXD1(PTE0) RXD1(PTE1) 3:四路光耦输入 DI1(PTG2) DI2 (PTE5) DI3 (PTE4) DI4(PTE3) 4:DS1302 SCL(PTF2) SDA (PTF3) RST (PTG4) 5:继电器控制 PTA6 PTB5 PTA5 PTC4 PTB6 6:按键(输入) PTC0 PTB0 PTC1 PTA0 PTC2(SW1~SW5) 7:CAN TX(PTE6) RX(PTE7) 8:LCD RW(PTG3) RS(PTF0) E(PTF1) RST(PTF7) 背光(PTG5) DATA(PTD0~PTD7) ************************************************************/ #define DI1 PTGD_PTGD2 //外触发1----->PG2 #define DI2 PTED_PTED5 //外触发2----->PE5 #define DI3 PTED_PTED4 //外触发3----->PE4 #define DI4 PTED_PTED3 //外触发4----->PE3 //********以上为输入IO********// #define JDQ1 PTCD_PTCD4 //继电器1----->PC4 #define JDQ2 PTAD_PTAD5 //继电器2----->PA5 #define JDQ3 PTBD_PTBD5 //继电器3----->PB5 #define JDQ4 PTAD_PTAD6 //继电器4----->PA6 #define JDQ5 PTBD_PTBD6 //继电器5----->PB6 #define DE485 PTED_PTED2 //485 T R切换----->PE2 //#define ID_TX 0x0001 //自定义的CAN发送标识符 //#define ID_RX 0x0002 //自定义的CAN接收标识符 //Bool can_send_enable = FALSE; //CAN发送标志位,暂定RTC0.5秒发送一次 #define Baud 19200 //串口波特率9600 #define N 51 #define T 1800 //运算电量的时间单位1800是半个小时(1800秒) extern byte time_buf1[8]; //1302时钟寄存器 byte ReadTimeFlag = 0; //定时器每0.5秒读1302时间的标志位 byte ADSET = 0; //发送电流电压功率等数值到显示屏标志位 /*********************变量和函数定义****************************/ word ADCbuffer1[N] = 0; //AD转换缓冲 word ADC1,ADC2,ADC3,ADC4; //AD转换缓冲 byte ADC1L,ADC1H,ADC2L,ADC2H,ADC3L,ADC3H,ADC4L,ADC4H; byte MW4L,MW4H,MW5L,MW5H,MW6L,MW6H,MW7L,MW7H,MW8L,MW8H,MW9L,MW9H; byte MW21L,MW21H,MW22L,MW22H,MW25L,MW25H,MW26L,MW26H; //历史充电电量记录 byte MW29L,MW29H,MW30L,MW30H,MW33L,MW33H,MW34L,MW34H; //历史放电电量记录 byte Buffer[15]; //串口接收缓冲 byte ADch_s; //AD通道选择 byte ADcount; //byte Key_value=0; //按键 //byte CANbuffer[8]; //接收到的CAN内容缓冲区数组 word sum=0; long P,P1,P2,P3,Premain,Pup,Pdown,Psum; //实时充电功率,实时放电功率,历史充电功率,历史放电记录 word PL,PH; //拆分P byte P0L,P0H,P1L,P1H; //拆分PH,PL byte RR = 1; //RR = 1;读屏的19号地址;RR = 2读屏的20号地址开始的时间; byte PAGE8; //进入设置时间页面和电量页面设置计数; byte T20 =0; word TENT; byte *p; //================================ //中值滤波程序 //================================ void filter() { static byte count,i,j; word value_buf[N]; word temp; sum=0; for(count=0;count<N;count++) { value_buf[count] = ADCbuffer1[count];; } for (j=0;j<N-1;j++) { for (i=0;i<N-j;i++) { if ( value_buf[i]>value_buf[i+1] ) { temp = value_buf[i]; value_buf[i] = value_buf[i+1]; value_buf[i+1] = temp; } } } for(count=1;count<N-1;count++) sum += value_buf[count]; } //=================================== //函数名:MCU_INIT //作用: 初始化MCU时钟 晶振16M总线频率8M //==================================== void MCU_INIT(void) { MCGC1=0x04; //选择内部时钟 MCGC2=0x40; //时钟源二分频 MCGTRM=0xa8;//内部时钟微调 } //=================================== //函数名: IO_INIT //作用: 初始化IO 输入输出 //==================================== void IO_INIT(void) { PTADD = 0xe6; //数据方向 1为输出,0为输入 PTBDD = 0x76; PTCDD = 0xb0; //PTDDD = 0xff; PTEDD = 0x45; PTFDD = 0xff; PTGDD = 0x38; PTAD = 0 ; //初始状态IO全为0 PTBD = 0; PTCD = 0; PTDD = 0; PTED = 0; PTFD = 0; PTGD = 0; } //=================================== //函数名: ADC_INIT //作用: 初始化ADC 总线时钟8M //=================================== void ADC_INIT(void) { ADCCFG = 0xf9; //低功耗模式,10位精度,ADCK=总线频率/8/2=500K ADCSC2 = 0x00; //0x00:软件触发,比较功能禁止 APCTL1 = 0x14; //通道引脚使能: 使用通道为AD19 AD11 AD3 AD4 APCTL2 = 0x08; APCTL3 = 0x08; ADch_s = 19; //选择19通道开始 ADCSC1 = 0x73; //0x53:中断使能,单次转换,选择19通道启动转换. } //=================================== //函数名:SCI_INIT //作用: 初始化SCI1 //==================================== void SCI_INIT(void) { SCI1BD = 8000000/16/Baud; SCI1C1 = 0x00; SCI1C2 = 0x2c; //使能接受中断 } //=================================== //串口发送 //=================================== void SCI1send (byte x) { while(SCI1S1_TDRE==0); SCI1D = x; } //=================================== //定时器1初始化 //=================================== void TPM1_Init(void) //定时器1初始化 { TPM1MODH=0x3d; // TPM1MODL=0x09; //250MS TPM1SC=0x4F; //TPM1时钟源为总线时钟;分频系数为128;溢出中断使能 } //=================================== //延时 //=================================== void Delay(Word time) { Word i,j; for(i=0;i<time;i++) { __RESET_WATCHDOG(); for(j=0;j<500;j++); } } void WEEP() { FCMD=0x20; FSTAT_FCBEF=1; asm{ NOP NOP NOP NOP } while(FSTAT_FCCF==0); if(FSTAT_FACCERR==1) FSTAT_FACCERR=1; } /*********************主函数************************************/ void main(void) { static byte MonthF1,DateF1,MonthF2,DateF2,MonthF3,DateF3,MonthC1,DateC1,MonthC2,DateC2,MonthC3,DateC3; //充电放电历史记录的两次时间变量及缓存变量 static byte FBETW0L,FBETW0H,FBETW1L,FBETW1H,CBETW0L,CBETW0H,CBETW1L,CBETW1H; static word PupCount,PdownCount; byte Pchange = 0 ; //充电0XFF 放电0X00转换标志 byte Failure; //故障信息指示MW17.0 = 1过压 MW17.1 = 1过流 word BetweenH,BetweenL; long a,b; byte SendSum; MCU_INIT(); IO_INIT(); Ds1302_Init(); ADC_INIT(); TPM1_Init(); SCI_INIT(); DE485 = 1; //485发送使能; PTED_PTED6 = 1; Ds1302_Read_Time(); //先读取一次时间用于判断历史时间 if(!DI1) //DI1 = 0 { Pchange = 0x01; //充电 } if(!DI2) //DI2 = 0 { //放电 Pchange = 0x02; } if(DI1&&DI2) //DI1,DI2都 为高电平 { Pchange = 0; } FCDIV = 39; //设置FLASH分频 8M总线时钟分频数39;FLASH读写200KH asm(nop); //**************读取记录的充电的历史记录************************ //************前1次的前1次得充电记录 p=(byte *)(0x1401); // MonthC1= *p; p=(byte *)(0x1402); //时间 DateC1= *p; p=(byte *)(0x1403); //电量的最低位 MW21L= *p; p=(byte *)(0x1404); // MW21H= *p; p=(byte *)(0x1405); // MW22L= *p; p=(byte *)(0x1406); // MW22H= *p; if(MonthC1>12) { MonthC1 = 0; DateC1= 0; MW21L = 0; MW21H = 0; MW22L = 0; MW22H = 0; } //*************前1次的充电记录********************************* p=(byte *)(0x1411); // MonthC2= *p; p=(byte *)(0x1412); //时间 DateC2= *p; p=(byte *)(0x1413); //电量的最低位 MW25L= *p; p=(byte *)(0x1414); // MW25H= *p; p=(byte *)(0x1415); // MW26L= *p; p=(byte *)(0x1416); // MW26H= *p; // if(MonthC2>12) //如果日期错误,清零 { MonthC2 = 0; DateC2= 0; MW25L = 0; MW25H = 0; MW26L = 0; MW26H = 0; } //***************缓存的充电记录,用于比较计算****************** p=(byte *)(0x1421); // MonthC3= *p; p=(byte *)(0x1422); //时间 DateC3= *p; p=(byte *)(0x1423); //电量的最低位 CBETW0L= *p; p=(byte *)(0x1424); // CBETW0H= *p; p=(byte *)(0x1425); // CBETW1L= *p; p=(byte *)(0x1426); // CBETW1H= *p; if(MonthC3>12) // { MonthC3 = 0; DateC3= 0; CBETW0L = 0; CBETW0H = 0; CBETW1L = 0; CBETW1H = 0; } //**************读取记录的放电的历史记录************************** //************前1次的前1次的放电记录 p=(byte *)(0x1501); // MonthF1= *p; p=(byte *)(0x1502); //时间 DateF1= *p; p=(byte *)(0x1503); //电量的最低位 MW29L= *p; p=(byte *)(0x1504); // MW29H= *p; p=(byte *)(0x1505); // MW30L= *p; p=(byte *)(0x1506); // MW30H= *p; if(MonthF1>12) { MonthF1 = 0; DateF1= 0; MW29L = 0; MW29H = 0; MW30L = 0; MW30H = 0; } //*************前1次的放电记录********************************* p=(byte *)(0x1511); // MonthF2= *p; p=(byte *)(0x1512); //时间 DateF2= *p; p=(byte *)(0x1513); //电量的最低位 MW33L= *p; p=(byte *)(0x1514); // MW33H= *p; p=(byte *)(0x1515); // MW34L= *p; p=(byte *)(0x1516); // MW34H= *p; if(MonthF2>12) // { MonthF2 = 0; DateF2= 0; MW33L = 0; MW33H = 0; MW34L = 0; MW34H = 0; } //***************缓存的放电记录,用于比较计算****************** p=(byte *)(0x1521); // MonthF3= *p; p=(byte *)(0x1522); //时间 DateF3= *p; p=(byte *)(0x1523); //电量的最低位 FBETW0L= *p; p=(byte *)(0x1524); // FBETW0H= *p; p=(byte *)(0x1525); // FBETW1L= *p; p=(byte *)(0x1526); // FBETW1H= *p; if(MonthF3>12) // { MonthF3 = 0; DateF3= 0; FBETW0L = 0; FBETW0H = 0; FBETW1L = 0; FBETW1H = 0; } p=(byte *)(0x1601); // MW8L= *p; p=(byte *)(0x1602); //时间 MW8H= *p; p=(byte *)(0x1603); //电量的最低位 MW9L= *p; p=(byte *)(0x1604); // MW9H= *p; if((MW8L==0xff)&&(MW8H==0xff)&&(MW9L==0xff)&&(MW9H==0xff)) //第一次上电 { MW8L = 0; MW8H = 0; MW9L = 0; MW9H = 0; P2 = 0; } else{ Premain = MW9L+(MW9H<<8); P2= (Premain<<16)+ (MW8L+(MW8H<<8)); P2 = P2*3600*1000; } if(Pchange==0x01) //充电时比较 { if((time_buf1[2] == MonthC3)&& (time_buf1[3] == DateC3)) { MW4L = CBETW0L; MW4H = CBETW0H; MW5L = CBETW1L; MW5H = CBETW1H; Premain = MW5L+(MW5H<<8); P3= (Premain<<16)+ (MW4L+(MW4H<<8)); P3 = P3*3600; } else { MW4L = 0; MW4H = 0; MW5L = 0; MW5H = 0; P3 = 0; } } if(Pchange==0x02) //放电时比较 { if((time_buf1[2] == MonthF3)&& (time_buf1[3] == DateF3)) { MW6L = FBETW0L; MW6H = FBETW0H; MW7L = FBETW1L; MW7H = FBETW1H; Premain = MW7L+(MW7H<<8); P1= (Premain<<16)+ (MW6L+(MW6H<<8)); P1 = P1*3600; } else { MW6L = 0; MW6H = 0; MW7L = 0; MW7H = 0; P1 = 0; } } EnableInterrupts; //开中断 for(;;) { __RESET_WATCHDOG(); //喂内部看门狗 if(!DI1) { //充电 Pchange = 0x01; } //放电 if(!DI2) { Pchange = 0x02; } if(DI1&&DI2) { Pchange = 0; //停机状态 } if(Pchange==0x02) { if((time_buf1[2] != MonthF3)|| (time_buf1[3] != DateF3)) //只要是 时间不等,就要把当前记录写入EEPROM,开始新的计算 { p=( unsigned char *)(0x1500); //指定地址 缓存的时间写入前1天,前一天的时间写入前1天前1天 *p=0x01; FCMD=0x40; //擦除命令 FSTAT_FCBEF=1; //启动命令 Delay(1); while(FSTAT_FCCF==0); //等待完成 if(FSTAT_FACCERR==1) FSTAT_FACCERR=1; p=(byte *)(0x1500); //指定地址 *p = 0x01; WEEP(); p=(byte *)(0x1501); *p = MonthF2; WEEP(); p=(byte *)(0x1502); *p = DateF2; WEEP(); p=(byte *)(0x1503); *p = MW33L; WEEP(); p=(byte *)(0x1504); *p = MW33H; WEEP(); p=(byte *)(0x1505); *p = MW34L; WEEP(); p=(byte *)(0x1506); *p = MW34H; WEEP(); p=( unsigned char *)(0x1510); //指定地址 //缓存的时间写入前1天,前一天的时间写入前1天前1天 *p=0x01; FCMD=0x40; //擦除命令 FSTAT_FCBEF=1; //启动命令 Delay(1); while(FSTAT_FCCF==0); //等待完成 if(FSTAT_FACCERR==1) FSTAT_FACCERR=1; p=(byte *)(0x1510); //指定地址 *p = 0x01; WEEP(); p=(byte *)(0x1511); //如果时间变了,原缓存存入前一天的内存 *p = MonthF3; WEEP(); p=(byte *)(0x1512); *p = DateF3; WEEP(); p=(byte *)(0x1513); *p = FBETW0L; WEEP(); p=(byte *)(0x1514); *p = FBETW0H; WEEP(); p=(byte *)(0x1515); *p = FBETW1L; WEEP(); p=(byte *)(0x1516); *p = FBETW1H; WEEP(); P1 = 0; MW29L = MW33L; MW29H = MW33H; MW30L = MW34L; MW30H = MW34H; MonthF1 = MonthF2; DateF1 = DateF2; MW33L = FBETW0L; MW33H = FBETW0H; MW34L = FBETW1L; MW34H = FBETW1H; MonthF2 = MonthF3; DateF2 = DateF3; asm(nop); MonthF3 =time_buf1[2]; //当前时间送入缓存 DateF3= time_buf1[3]; //MonthF3 = time_buf1[2]; //DateF3 = time_buf1[3]; FBETW0L = MW6L; FBETW0H = MW6H; FBETW1L = MW7L; FBETW1H = MW7H; p=( unsigned char *)(0x1520); //指定地址 *p=0x01; FCMD=0x40; //擦除命令 FSTAT_FCBEF=1; //启动命令 Delay(1); while(FSTAT_FCCF==0); //等待完成 if(FSTAT_FACCERR==1) FSTAT_FACCERR=1; p=(byte *)(0x1520); //指定地址 *p = 0x01; WEEP(); p=(byte *)(0x1521); *p = time_buf1[2]; WEEP(); p=(byte *)(0x1522); *p = time_buf1[3]; WEEP(); p=(byte *)(0x1523); *p = MW6L; WEEP(); p=(byte *)(0x1524); *p = MW6H; WEEP(); p=(byte *)(0x1525); *p = MW7L; WEEP(); p=(byte *)(0x1526); *p = MW7H; WEEP(); } } if(Pchange == 0x01) //充电的时候 { if((time_buf1[2] != MonthC3)|| (time_buf1[3] != DateC3)) //只要时间不等,开始新的计算 { p=( unsigned char *)(0x1400); //指定地址 缓存的时间写入前1天,前一天的时间写入前1天前1天 *p=0x01; FCMD=0x40; //擦除命令 FSTAT_FCBEF=1; //启动命令 Delay(1); while(FSTAT_FCCF==0); //等待完成 if(FSTAT_FACCERR==1) FSTAT_FACCERR=1; p=(byte *)(0x1400); //指定地址 *p = 0x01; WEEP(); p=(byte *)(0x1401); *p = MonthC2; WEEP(); p=(byte *)(0x1402); *p = DateC2; WEEP(); p=(byte *)(0x1403); *p = MW25L; WEEP(); p=(byte *)(0x1404); *p = MW25H; WEEP(); p=(byte *)(0x1405); *p = MW26L; WEEP(); p=(byte *)(0x1406); *p = MW26H; WEEP(); p=( unsigned char *)(0x1410); //指定地址 缓存的时间写入前1天,前一天的时间写入前1天前1天 *p=0x01; FCMD=0x40; //擦除命令 FSTAT_FCBEF=1; //启动命令 Delay(1); while(FSTAT_FCCF==0); //等待完成 if(FSTAT_FACCERR==1) FSTAT_FACCERR=1; p=(byte *)(0x1410); //指定地址 *p = 0x01; WEEP(); p=(byte *)(0x1411); *p = MonthC3; WEEP(); p=(byte *)(0x1412); *p = DateC3; WEEP(); p=(byte *)(0x1413); *p = CBETW0L; WEEP(); p=(byte *)(0x1414); *p = CBETW0H; WEEP(); p=(byte *)(0x1415); *p = CBETW1L; WEEP(); p=(byte *)(0x1416); *p = CBETW1H; WEEP(); MW21L = MW25L; MW21H = MW25H; MW22L = MW26L; MW22H = MW26H; MonthC1 = MonthC2; DateC1 = DateC2; MW25L = CBETW0L; MW25H = CBETW0H; MW26L = CBETW1L; MW26H = CBETW1H; MonthC2 = MonthC3; DateC2 = DateC3; P3 = 0; MonthC3 =time_buf1[2]; //当前时间送入缓存 DateC3= time_buf1[3]; //MonthC3 = time_buf1[2]; //DateC3 = time_buf1[3]; CBETW0L = MW4L; CBETW0H = MW4H; CBETW1L = MW5L; CBETW1H = MW5H; p=( unsigned char *)(0x1420); //指定地址 *p=0x01; FCMD=0x40; //擦除命令 FSTAT_FCBEF=1; //启动命令 Delay(1); while(FSTAT_FCCF==0); //等待完成 if(FSTAT_FACCERR==1) FSTAT_FACCERR=1; p=(byte *)(0x1420); //指定地址 *p = 0x01; WEEP(); p=(byte *)(0x1421); *p = time_buf1[2]; WEEP(); p=(byte *)(0x1422); *p = time_buf1[3]; WEEP(); p=(byte *)(0x1423); *p = MW4L; WEEP(); p=(byte *)(0x1424); *p = MW4H; WEEP(); p=(byte *)(0x1425); *p = MW5L; WEEP(); p=(byte *)(0x1426); *p = MW5H; WEEP(); } } if(!RR) { Ds1302_Write_Time(); Delay(10); T20 = 1; } if(T20) //切换到2界面 { T20 = 0; TENT = 0; DE485 = 1; //保证切换到发射 Delay(200); SCI1send (0x01); //站号 SCI1send (0x57); //写命令 SCI1send (0x12); //18号地址跳转页面指令,跳转到1界面 SCI1send (0x01); //1个长度 SCI1send (0x00); //18号地址 SCI1send (0x01); SCI1send (0x6c); Delay(100); //需加一段长延时 SCI1send (0x01); //站号 SCI1send (0x57); //写命令 SCI1send (0x12); //18号地址跳转页面指令,跳转到2界面 SCI1send (0x01); //1个长度 SCI1send (0x00); //18号地址 SCI1send (0x02); SCI1send (0x6d); Delay(200); //必须加段延时确保数据发送出去 RR = 1; //1分钟内ENT没有按下,转回正常模式 asm(nop); } if(ADSET) //处理AD; { ADSET = 0; if(ADcount == 1) { filter(); ADC1= (sum/(N-2)); if(ADC1<7){ ADC1 = 0; //屏蔽掉待机状态时的不干净的初值 } if (ADC1>163) { Failure = Failure|0x01; //置过压标志 } else Failure = Failure&0xfe; //清过压标志 //b = 750*50; //b = b/255; b = (long)7500*ADC1; //放大10倍,为了送显示 //ADC1 = b*ADC1; //ADC1 = ADC1/5; ADC1 = b>>10; //除以1024 ADC1H = ADC1>>8; ADC1L = ADC1&255; ADch_s = 11; ADCSC1=0x6b; } if(ADcount == 2) { filter(); ADC2= (sum/(N-2)); if(ADC2<7) { ADC2 = 0; } if (ADC2>191) //过流 { Failure = Failure|0x02; //置过流标志 } else Failure = Failure&0xfd; //清过流标志 //a= 400*50; //a= a/255; a = (long)4000*ADC2; //ADC2 = a*ADC2; //转换成电压值 ,取小数点后一位,所以先扩大50倍 //ADC2 = ADC2/5; //10倍电流送显示,用于显示小数点 ADC2 = a>>10; ADC2H = ADC2>>8; ADC2L = ADC2&255; ADC1 = ADC1/10; ADC2 = ADC2/10; P =(long)ADC1*ADC2; PH = P>>16; PL = P&0xffff; P1H = PH>>8; P1L = PH&255; P0H = PL>>8; P0L = PL&255; if(Pchange==0x02) //如果放电 { PdownCount++; //秒累加 P2 = P2+P; //一直累积的放电电量 Psum=(long)(P2/3600/1000); BetweenH = Psum>>16; BetweenL = Psum&0xffff; MW9H = BetweenH>>8; MW9L = BetweenH&255; MW8H = BetweenL>>8; MW8L = BetweenL&255; P1 = P1+P; //秒功率累加 Pdown = (long)P1/3600; //实际放电功率,按小时计算 BetweenH = Pdown>>16; BetweenL = Pdown&0xffff; MW7H = BetweenH>>8; MW7L = BetweenH&255; MW6H = BetweenL>>8; MW6L = BetweenL&255; if(PdownCount > T) //超过半个小时开始写入EEPROM { PdownCount = 0; p=( unsigned char *)(0x1600); //指定地址 *p=0x01; FCMD=0x40; //擦除命令 FSTAT_FCBEF=1; //启动命令 Delay(1); while(FSTAT_FCCF==0); //等待完成 if(FSTAT_FACCERR==1) FSTAT_FACCERR=1; p=(byte *)(0x1600); //指定地址 *p = 0x01; WEEP(); p=(byte *)(0x1601); //总放电量写入EEPROM *p = MW8L; WEEP(); p=(byte *)(0x1602); *p = MW8H; WEEP(); p=(byte *)(0x1603); *p = MW9L; WEEP(); p=(byte *)(0x1604); *p = MW9H; WEEP(); asm(nop); if((time_buf1[2] == MonthF3)&& (time_buf1[3] == DateF3)) //当前时间等于缓存时间,继续写入缓存 { MonthF3 = time_buf1[2]; DateF3 = time_buf1[3]; FBETW0L = MW6L; FBETW0H = MW6H; FBETW1L = MW7L; FBETW1H = MW7H; p=( unsigned char *)(0x1520); //指定地址 *p=0x01; FCMD=0x40; //擦除命令 FSTAT_FCBEF=1; //启动命令 Delay(1); while(FSTAT_FCCF==0); //等待完成 if(FSTAT_FACCERR==1) FSTAT_FACCERR=1; p=(byte *)(0x1520); //指定地址 *p = 0x01; WEEP(); p=(byte *)(0x1521); *p = time_buf1[2]; WEEP(); p=(byte *)(0x1522); *p = time_buf1[3]; WEEP(); p=(byte *)(0x1523); *p = MW6L; WEEP(); p=(byte *)(0x1524); *p = MW6H; WEEP(); p=(byte *)(0x1525); *p = MW7L; WEEP(); p=(byte *)(0x1526); *p = MW7H; WEEP(); } } } if(Pchange == 0x01) //如果充电 { PupCount++; //秒累加 P3 =P3+P; //秒功率累加 Pup = (long)P3/3600; //实际放电功率,按小时计算 BetweenH = Pup>>16; BetweenL = Pup&0xffff; MW5H = BetweenH>>8; MW5L = BetweenH&255; MW4H = BetweenL>>8; MW4L = BetweenL&255; if(PupCount >T) { PupCount = 0; //超过半个小时开始写入EEPROM if((time_buf1[2] == MonthC3)&& (time_buf1[3] == DateC3)) //当前时间等于缓存时间,继续写入缓存 { MonthC3 = time_buf1[2]; DateC3 = time_buf1[3]; CBETW0L = MW4L; CBETW0H = MW4H; CBETW1L = MW5L; CBETW1H = MW5H; p=( unsigned char *)(0x1420); //指定地址 *p=0x01; FCMD=0x40; //擦除命令 FSTAT_FCBEF=1; //启动命令 Delay(1); while(FSTAT_FCCF==0); //等待完成 if(FSTAT_FACCERR==1) FSTAT_FACCERR=1; p=(byte *)(0x1420); //指定地址 *p = 0x01; WEEP(); p=(byte *)(0x1421); *p = time_buf1[2]; WEEP(); p=(byte *)(0x1422); *p = time_buf1[3]; WEEP(); p=(byte *)(0x1423); *p = MW4L; WEEP(); p=(byte *)(0x1424); *p = MW4H; WEEP(); p=(byte *)(0x1425); *p = MW5L; WEEP(); p=(byte *)(0x1426); *p = MW5H; WEEP(); //如果相等则认为是当前时间,继续 } } } asm(nop); ADch_s = 3; ADCSC1=0x63; } if(ADcount == 3) { filter(); ADC3= (sum/(N-2)); ADC3H = (sum/(N-2))>>8; ADC3L = (sum/(N-2))&255; ADch_s = 4; ADCSC1=0x64; } if(ADcount == 4) { filter(); ADC4= (sum/(N-2)); ADC4H = (sum/(N-2))>>8; ADC4L = (sum/(N-2))&255; ADch_s = 19; ADCSC1=0x73; } if(RR ==2) { DE485 = 1; Delay(2); SCI1send (0x01); //站号 SCI1send (0x52); //读命令 SCI1send (0x14); //20号地址判断ENT键状态 SCI1send (0x01); //1个地址 SCI1send (0x68); Delay(1); //必须加段延时确保数据发送出去 DE485 = 0; //485切换到接收状态 asm(nop); } if(RR ==3) { DE485 = 1; Delay(2); SCI1send (0x01); //站号 SCI1send (0x57); //写命令 SCI1send (0x14); //20号地址清零 SCI1send (0x01); //1个长度 SCI1send (0x00); //18号地址 SCI1send (0x00); SCI1send (0x6D); Delay(50); RR =4; } if(RR ==4) //读时间 { DE485 = 1; Delay(5); SCI1send (0x01); //站号 SCI1send (0x52); //读命令 SCI1send (0x0B); //11号地址 SCI1send (0x06); //6个地址 SCI1send (0x64); Delay(1); //必须加段延时确保数据发送出去 DE485 = 0; //485切换到接收状态 //asm(nop); } } if(ReadTimeFlag) { ReadTimeFlag = 0; if(RR ==1) { Delay(10); DE485 = 1; Ds1302_Read_Time(); asm(nop); SendSum = (0x6a+Pchange+Failure+ADC1L+ADC1H+ADC2L+ADC2H+P0H+P0L+P1H+P1L+ time_buf1[1]+time_buf1[2]+time_buf1[3]+time_buf1[4]+time_buf1[5]+time_buf1[6]+ MW4L+MW4H+MW5L+MW5H+MW6L+MW6H+MW7L+MW7H+MW8L+MW8H+MW9L+MW9H); //累加和 SCI1send (0x01); //站号 SCI1send (0x57); //写命令 SCI1send (0x00); //首地址 SCI1send (0x12); //18个地址 SCI1send (ADC1H); //MW0高位 电压 SCI1send (ADC1L); //MW0低位 SCI1send (ADC2H); //MW1 电流 SCI1send (ADC2L); SCI1send (P0H); //MW2 实时功率 SCI1send (P0L); SCI1send (P1H); //MW3 SCI1send (P1L); SCI1send (MW4H); //MW4 SCI1send (MW4L); SCI1send (MW5H); //MW5 当前充电电量(一天累计) SCI1send (MW5L); SCI1send (MW6H); //MW6 SCI1send (MW6L); SCI1send (MW7H); //MW7 当前放电电量(一次累计) SCI1send (MW7L); SCI1send (MW8H); //MW8 当前放电电量(一次累计) SCI1send (MW8L); SCI1send (MW9H); //MW9 当前放电电量(一次累计) SCI1send (MW9L); SCI1send (0x00); //MW10 充放电指示00:放电;FF:充电 SCI1send (Pchange); SCI1send (0x00); //MW11开始为时间 SCI1send (time_buf1[1]); SCI1send (0x00); SCI1send (time_buf1[2]); SCI1send (0x00); SCI1send (time_buf1[3]); SCI1send (0x00); SCI1send (time_buf1[4]); SCI1send (0x00); SCI1send (time_buf1[5]); SCI1send (0x00); SCI1send (time_buf1[6]); SCI1send (0x00); //MW17 过压过流指示 SCI1send (Failure); SCI1send (SendSum); asm(nop); Delay(100); SendSum = 0x7d+MW21H+MW21L+MW22H+MW22L+MonthC1+DateC1+MW25H+MW25L+MW26L+MW26H+MonthC2+DateC2 +MW29H+MW29L+MW30H+MW30L+MonthF1+DateF1+MW33L+MW33H+MW34H+MW34L+MonthF2+DateF2; SCI1send (0x01); //站号 SCI1send (0x57); //写命令 SCI1send (0x15); //21号地址 SCI1send (0x10); //16个地址 SCI1send (MW21H); //MW21高位 SCI1send (MW21L); //MW21低位 SCI1send (MW22H); //MW22 SCI1send (MW22L); SCI1send (0x00); //月 MW23 SCI1send (MonthC1); SCI1send (0x00); //日 MW24 SCI1send (DateC1); SCI1send (MW25H); //MW25 SCI1send (MW25L); SCI1send (MW26H); //MW26 SCI1send (MW26L); SCI1send (0x00); //MW27 SCI1send (MonthC2); SCI1send (0x00); //MW28 SCI1send (DateC2); SCI1send (MW29H); //MW29 SCI1send (MW29L); SCI1send (MW30H); //MW30 SCI1send (MW30L); SCI1send (0x00); //MW31 SCI1send (MonthF1); SCI1send (0x00); //MW32 SCI1send (DateF1); SCI1send (MW33H); //MW33 SCI1send (MW33L); SCI1send (MW34H); //MW34 SCI1send (MW34L); SCI1send (0x00); //MW35 SCI1send (MonthF2); SCI1send (0x00); //MW36 SCI1send (DateF2); SCI1send (SendSum); //累加和 asm(nop); Delay(10); SCI1send (0x01); //站号 SCI1send (0x52); //读命令 SCI1send (0x13); //19号地址判断在哪个页面 SCI1send (0x01); //1个地址 SCI1send (0x67); Delay(1); //必须加段延时确保数据发送出去 DE485 = 0; //485切换到接收状态 asm(nop); } } } } //========================================== //定时器1中断函数 中断向量号11 250毫秒定时 //========================================== void interrupt 11 TPM1_ISR(void) { static byte i,j,k; if((TPM1SC & 0x80)==0x80) { TPM1SC_TOF=0; ADSET = 1; } i++; if(!PAGE8) // { j = 0; } else { j++; if(j>PAGE8) //大于5秒 { j = 0; RR = 2; //转判断ENT键是否按下程序 PAGE8 = 0; } } if(!TENT) { k = 0; } else { k++; if(k>TENT) { k = 0; T20 = 1; //如果ENT键1分钟内没有按下则跳转到2界面(显示电压,电流) TENT = 0; } } if(i>3) { i = 0; ReadTimeFlag = 1; } } //========================================== //串口接收中断 VectorNumber_Vsci1rx 中断向量号17 //========================================== interrupt VectorNumber_Vsci1rx void SCI_RE(void) { static byte j; static byte i; byte Rcv; if(SCI1S1_RDRF) //串口接收中断标志位 { //清标志位 SCI1S1_RDRF = 0; //接收数据送缓存 Rcv = SCI1D; //*********************读页面数值***************************** if(RR == 1) { if(Rcv == 0x13) { j = 1; Buffer[0]=Rcv; } else { if(j < 5) //5个字节 { Buffer[j] = Rcv; j++; } } if((Buffer[3]==0x08)&&(Buffer[4]==0x1d)) //如果检测到是第8页面则处理数据 { PAGE8 =20; //如果停在8页面设置一个计数器,5秒时间内如果还在则认为在修改时间 TENT = 240; //2分钟内ENT键没有按下,则跳转到2页面; } if(Buffer[3]!=0x08) //如果跳转到别的界面,马上清零 { PAGE8 = 0; TENT = 0; RR = 1; //回到正常状态 } } //****************判断ENT键按下与否******************************* ENT键按下的话20站号变成1 if(RR ==2) { if(Rcv == 0x14) { j = 1; Buffer[0]=Rcv; } else { if(j < 5) //5个字节 { Buffer[j] = Rcv; j++; } } if((Buffer[3]==0x01)&&(Buffer[4]==0x17)) //ENT键已经按下 { RR = 3; } } //******************************读取要修改的时间******************************* if(RR ==4) //此时ENT已经清零 { Buffer[j]=Rcv; if(!i) { if(Buffer[j]== 0x0b) //接收到11 { Buffer[0] =0x0b; j=1; //才开始类加 } if(Buffer[1]== 0x06) { i = 1; } } if(i) { if(j< 15) { Buffer[j] = Rcv; j++; } } if(j==15) { i = 0; } if(Buffer[14]==(Buffer[3]+Buffer[5]+Buffer[7]+Buffer[9]+Buffer[11]+Buffer[13]+0x12)) { RR = 0; time_buf1[1] = Buffer[3] ; //年 time_buf1[2] = Buffer[5] ; //月 time_buf1[3] = Buffer[7] ; //日 time_buf1[4] = Buffer[9] ; //时 time_buf1[5] = Buffer[11]; //分 time_buf1[6] = Buffer[13]; //秒 } } } } //========================================== //ADC转换完成中断服务程序 VectorNumber_Vadc中断向量号23 //========================================== interrupt VectorNumber_Vadc void ADC_ISR(void) { static byte count; switch(ADch_s) { case 19: ADCbuffer1[count]=ADCR; count++; if (count > N-1){ count = 0; ADCSC1=0x00; ADcount = 1; } break; case 11: ADCbuffer1[count]=ADCR; count++; if (count > N-1){ count = 0; ADCSC1=0x00; ADcount = 2; } break; case 3: ADCbuffer1[count]=ADCR; count++; if (count > N-1){ count = 0; ADCSC1=0x00; ADcount = 3; } break; case 4: ADCbuffer1[count]=ADCR; count++; if (count > N-1){ count = 0; ADCSC1=0x00; ADcount = 4; } break; default:break; } asm(nop); //在此设置一个断点,观测ad_h和ad_l的变化 }