📄 rscomm.c
字号:
TFlag = PsWdCHK(RS_DataPtr); //密码检查
if((TFlag==0x10)&&(RS_CmdH==0xC1)&&(RS_CmdL==0x19)) //清零密码+电表清零指令
{
//编程允许+清零次数
TFlag=0x00;
if(Prog_Flag==1) TFlag = 0x03; //编程允许后有2次机会
else
{
Addr[0] = 0xA0;
Addr[1] = 0xBE;
Len[1] = 0x02;
do
{
ReadData(Temp);
} while((Temp[0]!=~Temp[1])&&(Addr[0]<=0xA4));
if((Temp[0]==~Temp[1])&&(Temp[0]<0x03)) TFlag = Temp[0]; //清零次数
}
if(TFlag<3) ArrayInit(&ComBuf[RS_CmdPtr+6],16);
else
{
if( BCDCHK(&ComBuf[RS_CmdPtr+6],16)==0 ) TFlag = 0x00;
}
if( TFlag!=0x00 )
{
ArrayInit(&ComBuf[RS_CmdPtr+6],16);
for(i=0;i<5;i++)
{
j= 4*i;
//小数清零
EryTmp[i] = ComBuf[RS_CmdPtr+6+j];
Temp[0] = EryTmp[i];
Temp[1] =~EryTmp[i];
Addr[0] = 0xA0;
Addr[1] = Ptr[i];
Len[1] = 0x02;
WriteEPMData(Temp);
//整数校验和
ComBuf[RS_CmdPtr+6+j]=SumCHK(&ComBuf[RS_CmdPtr+6+j+1],3);
}
EryTmp[5]=SumCHK(EryTmp,5);//小数检验和
//有功电量整数清零
Addr[0] = 0xA0;
Addr[1] = 0xC0;
Len[1] = 0x10;
WriteEPMData(&ComBuf[RS_CmdPtr+6]);
//ArrayInit(&ComBuf[RS_CmdPtr+6],16);
//有功电量整数低字节清零
Addr[0] = 0xA0;
Addr[1] = 0xA0;
Len[1] = 0x0A;
WriteEPMData(&ComBuf[RS_CmdPtr+6]);
//反向电量整数清零
Addr[0] = 0xA0;
Addr[1] = 0xD0;
Len[1] = 0x04;
WriteEPMData(&ComBuf[RS_CmdPtr+6]);
//****
//反向累计总时间
Addr[0] = 0xA0;
Addr[1] = 0x30;
Len[1] = 0x10;
WriteEPMData(&ComBuf[RS_CmdPtr+6]);
//最近一次反向起始时间
Addr[0] = 0xA0;
Addr[1] = 0xAA;
Len[1] = 0x05;
WriteEPMData(&ComBuf[RS_CmdPtr+6]);
EryRev = 0; //电能反向标志清零(060302)
//****
//清零次数回写
TFlag--;
Temp[0] = TFlag;
Temp[1] = ~TFlag;
Addr[0] = 0xA0;
Addr[1] = 0xBE;
Len[1] = 0x02;
WriteEPMData(Temp);
ArrayInit(PulseTmp,6);//剩余脉冲清零
}
else Flag &= ~0x0A;
}
else if(TFlag==0x11) //编程密码
{
if(RS_CmdH==0xC0)
{
if( (RS_CmdL==0x10)&&(Prog_Flag==1) )//日期编程+编程允许
{
if((ComBuf[RS_CmdPtr+6]<0x07)&&(DateCHK(&ComBuf[RS_CmdPtr+7])==1))
{
//周日月年
RTC_Set(0x30,&ComBuf[RS_CmdPtr+6],0x04);
TimeAdj = 1;//校时时间
//********
EryBln_Flag = 1;
}
}
else if((RS_CmdL==0x11)&&(TimeTerm()==1))//时间编程
{
RTC_Set(0x00,&ComBuf[RS_CmdPtr+6],0x03);
AdjTime = 0;//校时条件满足
TimeAdj = 1;//校时时间
Fee_Flag= 1;//费率检查
}
else if(((RS_CmdL==0x32)||(RS_CmdL==0x33))&&(Prog_Flag==1))
{
Addr[0] = 0xA0;
Addr[1] = 0xF0; //局编号
if(RS_CmdL==0x32) Addr[1] = 0xF8; //出厂编号
//else Addr[1] = 0xF0; //局编号
Len[1] = 0x07;
ComBuf[RS_CmdPtr+6+6]=SumCHK(&ComBuf[RS_CmdPtr+6],6);
WriteEPMData(&ComBuf[RS_CmdPtr+6]);
}
else Flag &= ~0x0A;
}
//else if((RS_CmdH==0xC1)&&(RS_CmdL==0x15)&&(Prog_Flag==1))//显示选择
else if((RS_CmdH==0xC1)&&(RS_CmdL==0x15)) //显示选择
{
DspTime = ComBuf[RS_CmdPtr+6+0];
DspCtrl2 = ComBuf[RS_CmdPtr+6+1];
DspCtrl1 = ComBuf[RS_CmdPtr+6+2]|0x1C;
if(DspTime>0x30||DspTime<0x02)DspTime=0x10;
DspParaCHK = ~(DspCtrl1+DspCtrl2+DspTime);
Addr[0] = 0xA0;
Addr[1] = 0xDC;
Len[1] = 0x04;
WriteEPMData(DspPara);
DspSec = BCD2HEX(DspTime);
DspPtr = 0xFF;
}
else if((RS_CmdH==0xC1)&&(RS_CmdL==0x17)&&(Prog_Flag==1))//自动抄表日期
{
ComBuf[RS_CmdPtr+6+2]=~(ComBuf[RS_CmdPtr+6+0]+ComBuf[RS_CmdPtr+6+1]);//~SumCHK(&ComBuf[RS_CmdPtr+6],2);
Addr[0] = 0xA0;
Addr[1] = 0xD4;
Len[1] = 0x03;
WriteEPMData(&ComBuf[RS_CmdPtr+6]);
}
else if((RS_CmdH==0xC3)&&(RS_CmdL==0x3F)&&(Prog_Flag==1))//时段表
{
//时段表数据分析
TFlag=0x00;
i=RS_CmdPtr+6;//两位命令符+4位密码
j=RS_CmdPtr+RS_Len;
//一个时段单位数据检查
do
{
//费率
if((ComBuf[i]<0x02)||(ComBuf[i]>0x04)) TFlag |= 0x01;
//分
i++;
if((ComBuf[i]!=0x00)&&(ComBuf[i]!=0x30)) TFlag |= 0x01;
//时
i++;
if(((ComBuf[i]&0x0F)>0x09)||(ComBuf[i]>0x23)) TFlag |= 0x01;
i++;
}while((TFlag==0x00)&&(i<j));
if(TFlag==0x00)//数据正确
{
Temp[0] = (RS_Len/3)-2; //有效时段数
j -= 3;
do//时段表排序算法(冒泡)
{
k=1;
for(i=RS_CmdPtr+6;i<j;)
{
//基于小时量的比较
if(ComBuf[i+2]>ComBuf[i+5])
{
//费率
Temp[1] = ComBuf[i];
ComBuf[i] = ComBuf[i+3];
ComBuf[i+3] = Temp[1];
//分
Temp[1] = ComBuf[i+1];
ComBuf[i+1] = ComBuf[i+4];
ComBuf[i+4] = Temp[1];
//时
Temp[1] = ComBuf[i+2];
ComBuf[i+2] = ComBuf[i+5];
ComBuf[i+5] = Temp[1];
}
else if(ComBuf[i+2]==ComBuf[i+5])
{
if(ComBuf[i+1]>ComBuf[i+4])//分比较
{
//费率
Temp[1] = ComBuf[i];
ComBuf[i] = ComBuf[i+3];
ComBuf[i+3] = Temp[1];
//分
Temp[1] = ComBuf[i+1];
ComBuf[i+1] = ComBuf[i+4];
ComBuf[i+4] = Temp[1];
}
else if((ComBuf[i+1]==ComBuf[i+4])&& //同时段,费率不同错误
( ComBuf[i]!=ComBuf[i+3])) TFlag =0x01;
else k++;
}
else k++;
i += 0x03;
}
}while(k<Temp[0]);
if(TFlag==0x00)
{
Fee_Flag = 1;
i = RS_Len-6;
RS_CRC = ~SumCHK(&ComBuf[RS_CmdPtr+6],i);//时段费率检验和反码
//有效时段数
Temp[1] = ~Temp[0];
Addr[0] = 0xA2;
Addr[1] = 0xCE;
Len[1] = 0x02;
WriteEPMData(Temp);
if(Temp[0]<6)
{
Addr[0] = 0xA2;
Addr[1] = 0xD0;
Len[1] = i+1;
WriteEPMData(&ComBuf[RS_CmdPtr+6]);
}
else if(Temp[0]>10)
{
Addr[0] = 0xA2;
Addr[1] = 0xD0;
Len[1] = 0x10;
WriteEPMData(&ComBuf[RS_CmdPtr+6]);
Addr[0] = 0xA2;
Addr[1] = 0xE0;
WriteEPMData(&ComBuf[RS_CmdPtr+6+16]);
Addr[0] = 0xA2;
Addr[1] = 0xF0;
Len[1] = i-32+1;
WriteEPMData(&ComBuf[RS_CmdPtr+6+32]);
}
else
{
Addr[0] = 0xA2;
Addr[1] = 0xD0;
Len[1] = 0x10;
WriteEPMData(&ComBuf[RS_CmdPtr+6]);
Addr[0] = 0xA2;
Addr[1] = 0xE0;
Len[1] = i-16+1;
WriteEPMData(&ComBuf[RS_CmdPtr+6+16]);
}
}
else Flag &= ~0x0A;
}
else Flag &= ~0x0A;
}
else Flag &= ~0x0A;
}
else Flag &= ~0x0A;
}
//**********************************************************
//名称:
//功能:
//说明:
//**********************************************************
uchar RxdCheck(void)
{
uchar Address[6];
//帧长度、帧结构检查
if( ComPtr<RS_MinSize || RS_Head!=0x68 || RS_Head0!=0x68 || RS_End!=0x16 ) return 0x00;
//校验错误
if( RS_CRC!=SumCHK(ComBuf,RS_CmdPtr+RS_Len)) return 0x00;
Addr[0] = 0xA0;
Addr[1] = 0xF0; //局编号地址
Len[1] = 0x06;
ReadData(Address);
if( RS_Addr0==0x99 && RS_Addr1==0x99 && RS_Addr2==0x99 &&
RS_Addr3==0x99 && RS_Addr4==0x99 && RS_Addr5==0x99 )
{
if( RS_Ctrl==RS_CTRL_Time ) return 0x10; //广播校时
else if( RS_Ctrl==RS_CTRL_MetID && Prog_Flag==1 ) return 0x11; //广播设置电表号
//※※※※※※※※
//else if( RS_Ctrl==0xAA && Prog_Flag==1 ) return 0x12; //自定义命令集
//※※※※※※※※
else return 0x00; //广播命令码错误
}
//局号符合(包含缩位寻址)
else if( (RS_Addr0==Address[0]||RS_Addr0==0xAA) && (RS_Addr1==Address[1]||RS_Addr1==0xAA) &&
(RS_Addr2==Address[2]||RS_Addr2==0xAA) && (RS_Addr3==Address[3]||RS_Addr3==0xAA) &&
(RS_Addr4==Address[4]||RS_Addr4==0xAA) && (RS_Addr5==Address[5]||RS_Addr5==0xAA) )
{
RS_Addr0 = Address[0];
RS_Addr1 = Address[1];
RS_Addr2 = Address[2];
RS_Addr3 = Address[3];
RS_Addr4 = Address[4];
RS_Addr5 = Address[5];
if( RS_Ctrl==RS_CTRL_Pswd ) return 0x20; //修改密码
else if( RS_Ctrl==RS_CTRL_Read ) return 0x21; //读数据
else if( RS_Ctrl==RS_CTRL_Write ) return 0x22; //写数据
else return 0x00;
}
else return 0x00; //地址身份不符合,错误不响应
}
//**********************************************************
//名称:
//功能:
//说明:
//**********************************************************
uchar PsWdCHK(uchar PsWdPtr)
{
uchar Temp;
uchar PassWord[4];
if(ComBuf[PsWdPtr]>0x01) return 0x00; //权限错误
else
{
Addr[0] = 0xA0;
Addr[1] = 0xEC; //编程密码地址
if(ComBuf[PsWdPtr]==0x00) Addr[1] = 0xE8; //清零密码地址
Len[1] = 0x04;
//密码读取和检查
do
{
ReadData(PassWord);
Temp = PassWord[0]+PassWord[1]+PassWord[2];//SumCHK(PassWord,3);
}while((PassWord[3]!=~Temp)&&(Addr[0]<=0xA4));
//默认密码
if( PassWord[3]!=~Temp )
{
PassWord[0]=0x56;
PassWord[1]=0x34;
PassWord[2]=0x12;
PassWord[3]=0x63;
}
//密码出错修正
ErrorModify(0xA4,PassWord);
//密码比较
if( ComBuf[PsWdPtr+1]==PassWord[0] && ComBuf[PsWdPtr+2]==PassWord[1] && ComBuf[PsWdPtr+3]==PassWord[2] )
{
if(ComBuf[PsWdPtr]==0x00) return 0x10; //清零密码
else return 0x11; //编程密码
}
else return 0x00; //密码错误
}
}
//**********************************************************
//名称:TimeTerm()
//功能:时间条件检查
//说明:
//**********************************************************
bit TimeTerm(void)
{
uchar MinSum1;
uchar MinSum2;
//时间数据正确性检查
if( TimeCHK(&ComBuf[RS_CmdPtr+6])==0 ) return(0);
//25天判断
AdjDate = DateTerm();
//编程条件检查
if( Prog_Flag==1 ) return(1); //编程允许
else
{
if( AdjDate==1 ) //25天判断
{
//========================================
//不允许跨日校时
//========================================
if((Hour==0x00 && ComBuf[RS_CmdPtr+6+2]==0x23)||
(Hour==0x23 && ComBuf[RS_CmdPtr+6+2]==0x00)) return(0);
//时间误差计算
if(abs(BCD2HEX(Hour)-BCD2HEX(ComBuf[RS_CmdPtr+6+2]))>1) //小时条件检查
{
AdjTime = 1; //时钟异常
return(0);
}
else
{
//相差1小时之内
MinSum1 = BCD2HEX(Min);
MinSum2 = BCD2HEX(ComBuf[RS_CmdPtr+6+1]);
if(Hour>ComBuf[RS_CmdPtr+6+2]) MinSum1 += 60;
if(Hour<ComBuf[RS_CmdPtr+6+2]) MinSum2 += 60;
if( abs(MinSum1-MinSum2)>=TimeErrorTerm )//大于时间条件
{
AdjTime = 1; //时钟异常
return(0);
}
else
{
AdjDate=0; //?????????
return(1); //满足校时误差条件
}
}
}
else return(0);
}
}
//**********************************************************
//名称:ReadMeterData()
//功能:从EEPROM中读取数据
//说明:
//**********************************************************
void ReadMeterData(uchar addr,uchar saddr,uchar DataLen)
{
Addr[0] = addr; //页地址
Addr[1] = saddr; //页内子地址
Len[1] = DataLen; //数据长度
ReadData(&ComBuf[RS_DataPtr]);
}
//**********************************************************
//名称:Proc33()
//功能:加减0x33H处理
//说明:
//**********************************************************
void Proc33(uchar procdata)
{
uchar i;
i=0x00;
do
{
ComBuf[RS_CmdPtr+i] += procdata;
i++;
}while(i<RS_Len);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -