📄 work.c
字号:
//work
//1.设置采集器地址不需长按按键
//2.
//任务定制,任务优先级:实时任务->抄表->测试
void AmrTaskSet(void)
{
if(c_Free != Buff485Mark.Sta) return; //485缓冲区不空闲,退出
if(c_TaskRun == RtTask.Sta) //是否有实时任务需要执行
{
RtTask.Sta = c_TaskFree;
//设定透传任务指令
Buff485Mark.goal= c_DirReturn; //设定485缓冲区目前用于透传
v_FrameC485 = RtTask.Ctr;
v_FrameL485 = RtTask.len; //实时任务长度必 >= 2
v_DI0485 = RtTask.DI0;
v_DI1485 = RtTask.DI1;
//数据域拷贝到485缓冲区数据域
highmemcpy(Buff485+c_OffsetDI0, RtData+1, RtTask.len);
Buff485Mark.feCont = RtTask.FeCont;
FrameSet485(RtMeterID); //组织指令帧
return;
}
//*************** 定时抄表
else if(c_TaskFree != AmrTask.start) //开始自动抄表任务
{
if(c_TaskFree == AmrTask.Sta) //该序号电表还没有抄读
{
if(c_TaskAllStart == AmrTask.start) //抄读所有电表任务需要按序号设置,以下数据
{
if(AmrTask.serial >= c_MaxMeterAmount)
{
//抄表完成
AmrTask.start = c_TaskFree;//停止自动抄表
Buff485Mark.goal = c_Free; //必须,防止485主动上传
Buff485Mark.Sta = c_Free;
return;
}
//获取表号
if(_FALSE == getMeterID(AmrMeterID, AmrTask.serial))
{
AmrTask.serial++; //地址无效
return;
}
//获取特征字
getStrFMlow(&AmrTask.MeterMark, a_MeterMark + c_OneSize*AmrTask.serial, 1);
if(MeterMarkCheck(AmrTask.MeterMark) == _FALSE)//判断有效性
{
//该表未测试不抄读,需要测试
if(c_TaskFree == TestTask.start)
{
TestTask.start = c_TaskAllStart; //测试必须针对所有表
TestTask.reCont = 0; //失败次数
TestTask.serial = AmrTask.serial;
}
AmrTask.serial++;
return;
}
}
//设置抄读状态
AmrTask.Sta = c_TaskOneStart;
//按特征字设置抄读项
AmrTask.ReadItem = AmrTask.MeterMark & 0b11111100;
AmrTask.p_consume = Consume + 1; //0 放长度
Consume[0] = 0; //数据长度置零!!!
AmrTask.reCont = 0; // 失败次数
//组织645帧开始抄表
v_FrameC485 = 0x01;
v_FrameL485 = 0x02;
setDataMark485(AmrTask.MeterMark);
AmrTask.DI0 = v_DI0485;
AmrTask.DI1 = v_DI1485;
FrameSet485(AmrMeterID);
Buff485Mark.goal = c_AMR; //485缓冲区目前用于抄表
AmrTask.reCont = 0; //抄读失败次数
Buff485Mark.feCont = AmrTask.MeterMark & 0b00000011;//前导符个数
return;
}
}
//************* 测试电表类型
else if(c_TaskFree != TestTask.start)
{
if(c_TaskFree == TestTask.Sta) //没有测试中的单表
{
//测试全部电表,
if(c_TaskAllStart == TestTask.start)
{
//判断是否全部测试完成
if(TestTask.serial >= c_MaxMeterAmount)
{
//抄表完成
TestTask.start = c_TaskFree; //停止自动抄表
TestTask.Sta = c_TaskFree;
return;
}
//获取表号
if(_FALSE == getMeterID(TestMeterID, TestTask.serial))
{
TestTask.serial++; //地址无效
return;
}
//获取特征字
getStrFMlow(&TestTask.MeterMark, a_MeterMark + c_OneSize*TestTask.serial, 1);
if(MeterMarkCheck(TestTask.MeterMark) == _TRUE)
{
TestTask.serial++; //特征字有效无需测试
return;
}
TestTask.MeterMarkSr = 0; //特征字序号
}
TestTask.Sta = c_TaskOneStart; //测试状态
if(TestTask.MeterMarkSr >= c_MarkAmount)
{
TestTask.MeterMarkSr = 0; //特征字序号
}
TestTask.MeterMark = RomMeterMark[TestTask.MeterMarkSr];
TestTask.ReadItem = TestTask.MeterMark & 0b11111100;
//组织645帧开始测试
v_FrameC485 = 0x01;
v_FrameL485 = 0x02;
setDataMark485(TestTask.ReadItem); //设置DI0,DI1
TestTask.DI0 = v_DI0485;
TestTask.DI1 = v_DI1485;
FrameSet485(TestMeterID); //组织测试帧
//
TestTask.reCont = 0; //失败次数
Buff485Mark.feCont = TestTask.MeterMark & 0b00000011; //fe 个数
Buff485Mark.goal = c_Test; //485缓冲区目前用于表类型测试
return;
}
}
}
//*****************************
//任务处理,处理485缓冲区的数据
//*****************************
void AmrTaskDispose(void)
{
unsigned char temp;
//485接收完成否?或者接收错误?
if((c_RecEnd != Buff485Mark.Sta) && (c_RecOutT != Buff485Mark.Sta))
{
return; //没有数据需要处理
}
//********** 透传数据
if(c_DirReturn == Buff485Mark.goal)
{
if((c_RecEnd == Buff485Mark.Sta) && (_FALSE != frame645Check(Buff485)))
{
//***********透传数据,组织回应帧用
v_FrameC = Buff485[c_OffsetC];
v_FrameL = Buff485[c_OffsetL]; //还没有加表号长度
v_DI0 = Buff485[c_OffsetDI0];
v_DI1 = Buff485[c_OffsetDI1];
//判断485数据标示和实时任务中标示是否一致,只有抄读类判断
if((v_FrameC == 0x81)||(v_FrameC == 0x91))
{
if((v_DI0 != RtTask.DI0) || (v_DI1 != RtTask.DI1))
{
Buff485Mark.Sta = c_Free;
return;
}
//只有抄读类备份实时数据
v_RetCback = v_FrameC;
RtData[0] = c_UpData; //首字节方向标示
RtData[1] = v_FrameL; //第二字节数据域长度,包括DI0,DI1
highmemcpy(RtData+2, Buff485+c_OffsetDI0, v_FrameL); //3字节开始存放数据
}
else
{
lastCommBack[0] = 0; //指令备份失效
}
//数据域转移到上行指令存储区(载波或者红外),包括DI0,DI1
memcpyh2l(BuffPLC+c_OffsetDI0, Buff485+c_OffsetDI0, v_FrameL);
//表号添加到数据域末尾
memcpyh2l(BuffPLC+c_OffsetDI0 + v_FrameL, RtMeterID, 6);
v_FrameL += 0x06u; //加表号长度
v_RecPort = RtTask.Port; //回应端口
ReturnFrameSet(); //上行回应数据组织
v_DirRetCont = 0; //数据有效期计数器清零
}
else
{
//错误处理,破坏指令备份和数据备份
lowmemset(lastCommBack, 0xff, 4);
}
Buff485Mark.Sta = c_Free; //空闲
Buff485Mark.goal = c_Free;
return;
}
//***********自动抄表
else if(c_AMR == Buff485Mark.goal)
{
//判断超时,和数据有效性,地址,DI0 DI1!!
if((c_RecOutT == Buff485Mark.Sta) || (_FALSE == amrFrameCheck()))
{
Buff485Mark.Sta = c_Free; //必须设置
//重复
if(AmrTask.reCont++ < (c_AmrReCont-1))
{
//不到失败次数,重新测试该项
v_DI0485 = AmrTask.DI0;
v_DI1485 = AmrTask.DI1;
v_FrameC485 = 0x01;
v_FrameL485 = 0x02;
FrameSet485(AmrMeterID);
Buff485Mark.feCont = AmrTask.MeterMark & 0b00000011; //前导符个数
return;
}
//重复多次不成功,失败次数+1
//获取失败次数
getStrFM(tempBuff, a_FalseNO + c_OneSize*AmrTask.serial, 1);
temp = tempBuff[0]+1;
if(temp >= c_FalseCont)
{
//连续失败次数过多删除该表
delOneMeter(AmrTask.serial);
}
else
{
//失败次数+1
tempBuff[0] = temp;
v_ExtRunFlag = c_putStrFM;
putStrFM(a_FalseNO + c_OneSize*AmrTask.serial, tempBuff, 1);
}
//开始下一只电表抄读
AmrTask.serial++;
AmrTask.Sta = c_TaskFree;
return;
}
//接收数据无误,数据处理
else
{
Buff485Mark.Sta = c_Free; //必须设置
//按长度保存电量到电量缓冲区
temp = Buff485[c_OffsetL] - 2; //数据域长度
temp -= temp%4; //滤除多余0xaa
Consume[0] += temp; //电量数据长度
highmemcpy(AmrTask.p_consume, Buff485 + c_OffsetData, temp);
AmrTask.p_consume += temp;
bcfMarkbit(&AmrTask.ReadItem, AmrTask.DI0); //清除抄表完成位
//判断是否全部抄读项都完成
if(0 == (AmrTask.ReadItem & 0b11111100))
{
//*****存储电量
if(Consume[0] > sizeof(Consume)-1)
{
Consume[0] = sizeof(Consume) - 1; //防止出错太大写错存储器
}
v_ExtRunFlag = c_putStrFM;
putStrFM(a_Consume + c_OneSize*AmrTask.serial, Consume, Consume[0]+1);//+1长度
//抄读失败次数清零
v_ExtRunFlag = c_FMSet;
FMSet(a_FalseNO + c_OneSize*AmrTask.serial, 0, 1);
//开始下一表的抄读任务
AmrTask.Sta = c_TaskFree;
AmrTask.serial++;
return;
}
else
{
//还有分项未抄读
setDataMark485(AmrTask.ReadItem); //设置DI0,DI1
AmrTask.DI0 = v_DI0485;
AmrTask.DI1 = v_DI1485;
v_FrameC485 = 0x01;
v_FrameL485 = 0x02;
FrameSet485(AmrMeterID); //组织发送帧
AmrTask.reCont = 0; //失败重复次数
Buff485Mark.feCont = AmrTask.MeterMark & 0b00000011; //fe 个数
Buff485Mark.goal = c_AMR;
return;
}
}
}
//*********** 表类型测试
//测试流程:首先按表类型序号设置好特征字,抄读项=特征字屏蔽长度位
// 一次抄读成功,置零抄度项相应位,直到抄读
// 项为零测试完成
else if(c_Test == Buff485Mark.goal)
{
//判断超时,和帧格式
if((c_RecOutT == Buff485Mark.Sta) || _FALSE == testFrameCheck())
{
//超时需要重复
if(++TestTask.reCont < c_FalseCont)
{
//不到失败次数,重新测试该项
v_DI0485 = TestTask.DI0;
v_DI1485 = TestTask.DI1;
v_FrameC485 = 0x01;
v_FrameL485 = 0x02;
FrameSet485(TestMeterID);
Buff485Mark.feCont = TestTask.MeterMark & 0b00000011; //前导符个数
return;
}
//重复多次不成功,清除此项标志位
bcfMarkbit(&TestTask.MeterMark, TestTask.DI0); //清除特征字标志位
}
Buff485Mark.Sta = c_Free;
bcfMarkbit(&TestTask.ReadItem, TestTask.DI0); //该位已经测试完,清除
if(0 == (TestTask.ReadItem & 0b11111100)) //判断是否所有位都测试完
{
//单只表测试完成,判断有效性
if(MeterMarkCheck(TestTask.MeterMark) == _FALSE)
{
//特征字无效!!!判断是否到最大特征字序号
if(TestTask.MeterMarkSr >= c_MarkAmount-1)
{
delOneMeter(TestTask.serial); //删除一只电表
TestTask.Sta = c_TaskFree; //单表测试结束
TestTask.serial++; //表序号++
return;
}
//开始下一表类型的测试
TestTask.MeterMarkSr++; //表特征字序号++
TestTask.MeterMark = RomMeterMark[TestTask.MeterMarkSr];
TestTask.ReadItem = TestTask.MeterMark & 0b11111100;
setDataMark485(TestTask.ReadItem);
TestTask.DI0 = v_DI0485;
TestTask.DI1 = v_DI1485;
v_FrameC485 = 0x01;
v_FrameL485 = 0x02;
FrameSet485(TestMeterID); //组织测试帧
TestTask.reCont = 0; //失败次数
Buff485Mark.feCont = TestTask.MeterMark & 0b00000011; //fe 个数
Buff485Mark.goal = c_Test; //485缓冲区目前用于表类型测试
return;
}
//保存特征字
v_ExtRunFlag = c_putStrFM;
putStrFMlow(a_MeterMark + c_OneSize*TestTask.serial, &TestTask.MeterMark, 1);
//设置测试任务状态
TestTask.Sta = c_TaskFree; //单表测试结束
TestTask.serial++; //表序号++
if(c_TaskOneStart == TestTask.start)
{
TestTask.start = c_TaskFree; //如果测试单表,全部测试完成
}
//没有抄表任务,则开始抄读此表
if(c_TaskFree == AmrTask.start)
{
AmrTask.start = c_TaskAllStart; //开始全部抄读任务
AmrTask.serial = TestTask.serial - 1; //电表序号
AmrTask.MeterMark = TestTask.MeterMark; //设置特征字
highmemcpy(AmrMeterID, TestMeterID, 6);
return;
}
}
else
{
//分项测试未完成,继续
if((TestTask.MeterMark & 0b01000000) == 0) //判断9010位
{
//不支持9010,没有有必要测试其它项
TestTask.MeterMarkSr++; //表特征字序号++
if(TestTask.MeterMarkSr >= c_MarkAmount)
{
delOneMeter(TestTask.serial); //删除一只电表
TestTask.Sta = c_TaskFree; //单表测试结束
TestTask.serial++; //表序号++
return;
}
TestTask.MeterMark = RomMeterMark[TestTask.MeterMarkSr];
TestTask.ReadItem = TestTask.MeterMark & 0b11111100;
}
setDataMark485(TestTask.ReadItem); //设置DI0,DI1
TestTask.DI0 = v_DI0485;
TestTask.DI1 = v_DI1485;
v_FrameC485 = 0x01;
v_FrameL485 = 0x02;
FrameSet485(TestMeterID); //组织测试帧
TestTask.reCont = 0; //失败重复次数
Buff485Mark.feCont = TestTask.MeterMark & 0b00000011; //fe 个数
Buff485Mark.goal = c_Test; //485缓冲区目前用于表类型测试
}
return;
}
Buff485Mark.Sta = c_Free;
}
//*****************************
//分钟任务处理,转存数据
//*****************************
void minTaskDispose(void)
{
unsigned char serial;
unsigned char temp;
unsigned int addr;
//判断抄表任务是否完成,没有完成不能转存
if(AmrTask.start != c_TaskFree) return;
//判断小时任务标志
if(v_hhTask > 23)
{
return; //没有小时任务,肯定不会有冻结任务
}
//确定写入小时电量地址
getStrFM(tempBuff1, a_24ConMark, 2); //分别代表两个存储区的日期
if(tempBuff1[0] == timerBuff[dd]) //和当前日比较
{
addr = a_24Consume0;
}
else if(tempBuff1[1] == timerBuff[dd])
{
addr = a_24Consume1;
}
else
{
//跨天当前日期减一
highmemcpy(tempBuff, &timerBuff[dd], 3);
DateDec(tempBuff); //tempBuff[0], 日
if(tempBuff1[0] == tempBuff[0])
{
tempBuff1[1] = timerBuff[dd]; //当前日写入另一区域
addr = a_24Consume1; //写另一个缓冲区
for(serial=0; serial<c_MaxMeterAmount; serial++)
{
v_ExtRunFlag = c_FMSet;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -