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

📄 protocol.c

📁 电力载波抄表系统里的电力载波采集器,采集数据再通过RS485向主站发送.
💻 C
📖 第 1 页 / 共 2 页
字号:
					putStrRTClow(0x03, BuffPLC+c_OffsetData+4, 0x04);	//0x03,时钟芯片周次地址
					v_FrameC	= 0x84;
					v_FrameL	= 0x00;
					goto	BuffPLCCheckEnd;
				}
				else if((v_DI0 == 0x11) && (v_FrameL == 0x09))
				{
					//设置时钟(ssmmhh)
					v_ExtRunFlag	= c_putStrRTC;
					putStrRTClow(0x00, BuffPLC+c_OffsetData+4, 0x03);	//0x0,时钟芯片时间
					v_FrameC	= 0x84;
					v_FrameL	= 0x00;
					goto	BuffPLCCheckEnd;
				}
			}
			v_FrameC	= 0xc4;
		}
		else if(0x09 == v_FrameC)				//删除表号
		{
			if(0 == v_FrameL)
			{
				v_ExtRunFlag	= c_FMSet;
				FMSet(a_MeterID, 0xff, 192);	//表号全部删除!!

				v_FrameC	= 0x89;
				v_FrameL	= 0x00;
				goto	BuffPLCCheckEnd;
			}
		}
		else if(0x0d == v_FrameC)				//
		{
			if(0 == v_FrameL)
			{
				//恢复默认
				v_ExtRunFlag	= c_FMInit;
				FMInit();						//恢复默认参数值!!!

				v_ExtRunFlag	= c_FMSet;
				FMSet(a_MeterID, 0xff, 192);	//表号全部删除!!

				v_FrameC	= 0x8d;
				v_FrameL	= 0x00;
				goto	BuffPLCCheckEnd;
			}
		}

		v_FrameL				= 0x01;
		BuffPLC[c_OffsetDI0]	= 0x02;						//非法数据标识
		goto	BuffPLCCheckEnd;
	}

BuffPLCCheckEnd:
	ReturnFrameSet();
	ei();
	return;
	
BuffPLCCheckErr:
	BuffPLCMark.Sta	= c_Free;
	BuffPLCMark.ptr	= BuffPLC;
	ei();									//使能中断!!!
	Nop();
}
// ********** 广播指令处理 ***********
// Return _TRUE		:需要返回帧
// Return _FALSE	:不需要返回帧
// ***********************************
unsigned char BroadDispose(void)
{
	if(0x01 == v_FrameC)
	{
		if(0x02 == v_FrameL)
		{
			if((v_DI0 == 0x32) && (v_DI1 == 0xc0))		//广播读地址不响应
			{
				return	_FALSE;
			}
		}
	}
	
	if(0x0A == v_FrameC)
	{
		if(0x06 == v_FrameL)
		{
			//设置采集器红外地址
			if(_Set	== 1)	return	_FALSE;

			v_ExtRunFlag	= c_putStrFM;
			putStrFMlow(a_CollecterID, BuffPLC+c_OffsetDI0, 0x06);
		
			lowmemcpy(BuffPLC+1, BuffPLC + c_OffsetDI0, 0x06);
			
			v_FrameC	= 0x8A;
			v_FrameL	= 0x00;
			return	_TRUE;
		}
		else if(0x01 == v_FrameL)
		{
			//广播读地址,只有红外可以68 99 99 99 99 99 99 68 0A 01 01 CS 16
			if(0x01 != BuffPLC[c_OffsetL])	return	_FALSE;
			
			//判断按键
			if(_Set	== 1)	return	_FALSE;
			
			//返回帧: 68 11 01 00 00 00 00 68 8A 02 34 34 D6 16
			getStrFMlow(BuffPLC+1, a_CollecterID, 0x06);
			v_FrameC	= 0x8A;
			v_FrameL	= 0x02;
			v_DI0		= 0x01;				//未加33
			v_DI1		= 0x01;				//未加33
			
			return	_TRUE;
		}
	}
	
	else if(0x08 == v_FrameC)
	{
		//广播校时68 99 .. 68 08 06 ss mm hh dd mm yy cs 16
		if(0x06	== v_FrameL)
		{
			//设置秒分时
			v_ExtRunFlag	= c_putStrRTC;
			putStrRTClow(0x00, BuffPLC+c_OffsetDI0, 0x03);
			
			//设置日月年
			v_ExtRunFlag	= c_putStrRTC;
			putStrRTClow(0x04, BuffPLC+c_OffsetData+1, 0x03);
			
			//指令广播到485总线
//			memcpyl2h(Buff485, BuffPLC, v_FrameL + 12);
			
			//enable485send;
//			v_DI0485	= Buff485[c_OffsetDI0];
//			v_DI1485	= Buff485[c_OffsetDI1];
//			v_FrameC485 = 0x08;
//			v_FrameL485	= 0x06;
//			highmemset(tempBuff1, 0x99, 6);
//			Buff485Mark.feCont	= 2;
//			FrameSet485(tempBuff1);
		}
	}
	else if(0x12 == v_FrameC)
	{
		//冻结相关
		if(0x01 == v_FrameL)			//冻结时,仅设置冻结时间
		{
			v_ExtRunFlag	= c_putStrFM;
			putStrFMlow(a_FreezeTime, BuffPLC+c_OffsetDI0, 1);
		}
		else if(0x02 == v_FrameL)		//冻结日时
		{
			v_ExtRunFlag = c_putStrFM;
			putStrFMlow(a_FreezeTime, BuffPLC+c_OffsetDI0, 2);
		}
		else if(0x00 == v_FrameL)		//马上冻结
		{
			v_hhTask		= timerBuff[hh];
			v_hhTask		= bytebcdtohex(v_hhTask);
			v_FreezeTask	= timerBuff[dd];
		}
	}
	//指令广播到485总线
	memcpyl2h(Buff485, BuffPLC, v_FrameL + 12);	

	//enable485send;
	v_DI0485	= Buff485[c_OffsetDI0];
	v_DI1485	= Buff485[c_OffsetDI1];
	v_FrameC485 = Buff485[c_OffsetC];
	v_FrameL485	= Buff485[c_OffsetL];
	highmemset(tempBuff1, 0x99, 6);
	Buff485Mark.feCont	= 2;
	FrameSet485(tempBuff1);
	
	return	_FALSE;						//广播指令不需回应,特意设置为错误
}

//组织回应帧(载波或者红外)
void ReturnFrameSet(void)
{
	unsigned char len;
	unsigned char cs;

	BuffPLC[0]				= 0x68;
	memcpyh2l(BuffPLC+1, CollectorID, 6);
	BuffPLC[c_Offset68_2]	= 0x68;
	BuffPLC[c_OffsetC] 		= v_FrameC;
	BuffPLC[c_OffsetL]	 	= v_FrameL;
	
	if(v_FrameL > 8)						//DI0+DI1+表号
	{
		BuffPLC[c_OffsetDI0]	= v_DI0;
		BuffPLC[c_OffsetDI1]	= v_DI1;
	}
	
	BuffPLCMark.len		= v_FrameL + 12;	//帧长=L + 12,包括CS 16

	//数据域加33
	p_BuffPLC			= BuffPLC + c_OffsetData - 2;
	len					= v_FrameL;
	while(len--)
	{
		*p_BuffPLC	+= 0x33;
		p_BuffPLC++;
	}

	//计算CS
	p_BuffPLC	= BuffPLC;
	cs			= 0;
	len			= v_FrameL + 10;	//需要计算CS的个不算CS 0x16
	while(len--)
	{
		cs		+= *p_BuffPLC;
		p_BuffPLC++;
	}
	
	*p_BuffPLC++	= cs;
	*p_BuffPLC		= 0x16;
	
	//设置返回参数
	BuffPLCMark.ptr		= BuffPLC;
	BuffPLCMark.Sta		= c_Send;

	//发送一个FE
    if(v_RecPort == c_Port_Irf)
	{
		putCharIrf(0xfe);
	}
	else
	{
		putCharPLC(0xfe);
	}
}

//[]============================================================
//功能: 指令对象确认
//输出:	  _TRUE 针对采集器,_FALSE针对485表
//说明: 长度<6肯定针对采集器
//		 长度>6,但对象是采集器的指令有(设置类带密码)
//		 C038, C010(L=0x0A采集器, L = 0x0A+6 针对表),C011(L=0x09), C117(L=0x08)
//[]============================================================
unsigned char CommObjCheck(void)
{
	if(v_FrameL < 6)
	{
		return	_TRUE;						//指令针对采集器
	}

	//长度大于6的指令,只有部分设置类指令(0x04)是针对采集器
	if(v_FrameC != 0x04)
	{
		if(v_FrameC == 0x01)
		{
			if((v_DI1 == 0xc0) && (v_DI0 == 0x38) && (0x08 == v_FrameL))
			return	_TRUE;					//读取电表特征字
		}
		return	_FALSE;						//长度大于6的非设置类指令针对电表
	}
	
	if(0xc0 == v_DI1)
	{
		if((0x10 == v_DI0) && (0x0a == v_FrameL))	//C010 + 0a 采集器日期周次+4字节密码
		{
			return	_TRUE;
		}
		else if((0x11 == v_DI0) && (0x09 == v_FrameL))//C010 + 09 采集器时钟
		{
			return	_TRUE;
		}
		else if((0x38 == v_DI0) && (0x07 == v_FrameL))//c038 + 07 采集间隔
		{
			return	_TRUE;
		}
	}
	else if((0xc1 == v_DI1) && (0x17 == v_DI0))		//C117 + 08 自动抄表日时(冻结)
	{
		if(0x08 == v_FrameL)
		{
				return	_TRUE;
		}
	}
	
	return	_FALSE;
}

//************* 获取电表数量
//前提必须保证meterBuff,中存放正确表号
unsigned char getMeterAmount(void)
{
	unsigned char loop1;
    unsigned char loop2		= 0;				//8次读取=32只表
	unsigned char amount	= 0;
	bank2 unsigned char *p_data;

	while(loop2 < 8)
	{
    	//获取4只电表表号
    	getStrFM(tempBuff, a_MeterID+loop2*24, 24);//一次4只表
    	p_data		= tempBuff;
    	
    	loop1		= 4;
    	while(loop1--)
    	{
    	    if(_TRUE == MeterIDCheck(p_data))
    	    {
				amount++;
			}
    	    p_data += 6;
    	}
    	
    	loop2++;
    }

	return	amount;
}

//表号有效性判断
//全零和带有0xff的均为非法表号
unsigned char MeterIDCheck(bank2 unsigned char *p)
{
	unsigned char cnt0=0, cntff=0, i;
	unsigned char j;
	for(i=6; i>0; i--)
	{
		j = *p++;
		
		if(j == 0xff)
		{
			cntff++;
		}
		else if(j == 0)
		{
			cnt0++;
		}
	}
	
	if((cnt0 == 6u) || (cntff > 0))		//全零,或者有一个以上的ff均为非法
	{
		return	_FALSE;
	}
	return	_TRUE;
}

//645帧格式判断,要求输入帧起始地址
unsigned char frame645Check(bank2 unsigned char *p_comm)
{
	unsigned char len, cs;
	bank2 unsigned char *p_data;

	p_data		= p_comm + c_OffsetDI0;	//数据域-33时用
	
	//判第一个68
	if(0x68 != *p_comm)
	{
		return	(_FALSE);
	}
	//第二个68
	if(0x68 != *(p_comm + c_Offset68_2))
	{
		return	(_FALSE);
	}

	//获取长度
	len		= *(p_comm + c_OffsetL);

	//判断16结束符:c_DefaltLen = 645规约除了数据域以外所有字节长度,包括CS 16
	if(0x16 != *(p_comm + len + c_DefaltLen - 1))
	{
		return	(_FALSE);
	}

	//计算CS
	len		+= c_DefaltLen - 2;		//需要计算CS的字节数
	cs		= 0;
	while(len --)
	{
		cs	+= *p_comm++;			//计算完成p_comm指向CS	
	}

	//判断CS
	if(cs != *p_comm)				//p_comm指向CS
	{
		return	(_FALSE);
	}
	//数据域减33
	len		= *(p_data - 1);
	while(len--)
	{
		*p_data++ -= 0x33;
	}
	return	(_TRUE);
}

unsigned char frame645Checklow(unsigned char *p_comm)
{
	unsigned char len, cs;
	unsigned char *p_data;

	p_data		= p_comm + c_OffsetDI0;	//数据域-33时用
	
	//判第一个68
	if(0x68 != *p_comm)
	{
		return	(_FALSE);
	}
	//第二个68
	if(0x68 != *(p_comm + c_Offset68_2))
	{
		return	(_FALSE);
	}

	//获取长度
	len		= *(p_comm + c_OffsetL);

	//判断16结束符:c_DefaltLen = 645规约除了数据域以外所有字节长度,包括CS 16
	if(0x16 != *(p_comm + len + c_DefaltLen - 1))
	{
		return	(_FALSE);
	}

	//计算CS
	len		+= c_DefaltLen - 2;		//需要计算CS的字节数
	cs		= 0;
	while(len --)
	{
		cs	+= *p_comm++;			//计算完成p_comm指向CS	
	}

	//判断CS
	if(cs != *p_comm)				//p_comm指向CS
	{
		return	(_FALSE);
	}
	//数据域减33
	len		= *(p_data - 1);
	while(len--)
	{
		*p_data++ -= 0x33;
	}
	return	(_TRUE);
}
/*************************************
*	返回所有电表地址
*	帧较长特殊处理,直接返回红外
**************************************/
void ReturnAllMeterID(void)
{
	unsigned char temp;
	unsigned char loop;
	unsigned char serial;
	unsigned char CS;
	unsigned char *p_data;
	//1、控制字 C
	BuffPLC[c_OffsetC]	= 0x81;

	//2、长度	L
	temp				= getMeterAmount();
    BuffPLC[c_OffsetL]	= 6*temp + 3;			//+DI0 DI1 表数量

	//3、控制字	DI0, DI1 + 33
	BuffPLC[c_OffsetDI0]	+= 0x33;
	BuffPLC[c_OffsetDI1]	+= 0x33;

	//4、表数量+33
	temp					+= 0x33;
	BuffPLC[c_OffsetData]	= temp;

	//5、发送表号之前的数据
	CS		= 0;
    loop	= 13;				//68 xx xx xx xx xx xx 68 C L DI0 DI1 N
	p_data	= BuffPLC;
	while(loop--)
	{
		temp	= *p_data;
		CS		+= temp;
		putCharIrf(temp);
		p_data++;
	}
	
	//发送表号
	for(serial=0; serial<32; serial++)
	{
		if(_TRUE == getMeterID(tempBuff, serial))
		{
			for(loop=0; loop<6; loop++)
			{
				temp	= tempBuff[loop] + 0x33;
				CS		+= temp;
				putCharIrf(temp);
			}
		}
	}
    
	//发送CS, 16
	putCharIrf(CS);
	putCharIrf(0x16);
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -