⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 work.c

📁 电力载波抄表系统里的电力载波采集器,采集数据再通过RS485向主站发送.
💻 C
📖 第 1 页 / 共 2 页
字号:
//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 + -