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

📄 modbus.c

📁 自己编写的mod bus 协议源代码。基于keilc51开发。主要使用回调函数
💻 C
📖 第 1 页 / 共 2 页
字号:
	}
	return(uchCRCHi << 8 | uchCRCLo);
}
//接收数据报校验
INT8S RecPakChk(INT8U xdata *buf,INT8U LenOfRecPak)
{
	INT16U ChkSum;
	ChkSum = (INT16U)buf[LenOfRecPak-2] * 256 + (INT16U)buf[LenOfRecPak - 1];
	if(CRC16(buf,LenOfRecPak-2) == ChkSum)return 0;
	else return -1;
}
//发送数据报校验
void TrPakChk(INT8U xdata *buf,INT8U LenOfTrPak)
{
	buf[LenOfTrPak-2] = (CRC16(buf,(LenOfTrPak-2))) >> 8;
	buf[LenOfTrPak-1] = CRC16(buf,(LenOfTrPak-2));
}
//返回异常数据报
void RetExpPak(INT8U FntCode,INT8U ExpCode)
{
	INT8U xdata buf[5];
	buf[0] = PtcData.Dev;							/*设备地址*/
	buf[1] = 0x80|FntCode;							/*功能码*/
	buf[2] = ExpCode;								/*异常码*/
	TrPakChk(buf,5);
	WrCom(&COM1,buf,5);
}
//写数据到MODBUS协议控制层
/*
*********************************************************************************************************
*                                     SEND PROTOCOL DATA
*
* Description : This function write data to protocol control layer
* Arguments   : FncCode,	set function code
*			  : pData, 		set protocol data	
*			  : DataByteLen,set the sizeof data 
* Returns     : None.
*********************************************************************************************************
*/
void WriteDataToPtcLayer(INT8U FncCode,				/*设置功能码*/
		                 INT8U xdata *pData,		/*设置数据项*/
						 INT8U DataByteLen)			/*设置数据项大小*/
{
	INT8U xdata tbuf[512];
	tbuf[0] = PtcData.Dev;							/*设备地址*/
	tbuf[1] = FncCode;								/*功能码*/
	tbuf[2] = DataByteLen;							/*数据字节长度*/
	memcpy(&tbuf[3],pData,DataByteLen);
	TrPakChk(tbuf,5 + DataByteLen);
	WrCom(&COM1,tbuf,5 + DataByteLen);	
}
//从MODBUS协议控制层读取数据
/*
*********************************************************************************************************
*                                     RECEIVE PROTOCOL DATA
*
* Description : This function write data to protocol control layer
* Arguments   : FncCode,		return function code
*			  : pDataStartAddr,	return protocol data address
*			  : pData,			return protocol data	
* Returns     : return the result of operate.
*********************************************************************************************************
*/
INT8S ReadDataFromPtcLayer(INT8U *pFncCode,			                            /*返回功能码*/
						   INT16U *pDataStartAddr,	                            /*返回数据地址*/
						   INT16U *pData)			                            /*返回数据项*/
{
	INT8U xdata rbuf[10];
	INT8U rlen;
	if(RdCom(&COM1,rbuf,&rlen) == 0)				                            /*从串口获取数据*/
	{
		if(rbuf[0] == PtcData.Dev)							                    /*校验设备地址*/
		{
			if(RecPakChk(rbuf,rlen) == 0)										/*CRC校验*/
			{
				INT16U i = (INT16U)rbuf[2] * 256 + rbuf[3];
				INT16U j = (INT16U)rbuf[4] * 256 + rbuf[5];
				*pFncCode = rbuf[1];									         /*返回功能码*/
				*pDataStartAddr = i;
				*pData = j;
				switch (rbuf[1])
				{
					case READ_COIL_STATUS:										 /*读线圈状态*/
						if(i > 3/*遥控通道数18*/)	                             /*返回地址异常码*/
							RetExpPak(READ_COIL_STATUS,ILLEGAL_DATA_ADDRESS);
																				 /*返回数据异常码*/
						if((j == 0) || ((i + (j - 1) / 8 + 1) > PtcData.nSizeOfDOTbl))
							RetExpPak(READ_COIL_STATUS,ILLEGAL_DATA_VALUE);	
						break;
					case READ_INPUT_STATUS:										 /*读开关输入状态量*/
						if(i > 3/*DI通道数24*/)									 /*返回地址异常码*/
							RetExpPak(READ_COIL_STATUS,ILLEGAL_DATA_ADDRESS);	
																				 /*返回数据异常码*/
						if((j == 0) || ((i + (j - 1) / 8 + 1) > PtcData.nSizeOfDITbl))
							RetExpPak(READ_COIL_STATUS,ILLEGAL_DATA_VALUE);	
						break;
					case READ_HOLDING_REGISTERS:    							  /*读保持寄存器*/
						if(i > 48/*AI通道数24*/)								  /*返回地址异常码*/
							RetExpPak(READ_COIL_STATUS,ILLEGAL_DATA_ADDRESS);
													                              /*返回数据异常码*/
						if((j == 0) || ((i + j * 2) > PtcData.nSizeOfAITbl))
							RetExpPak(READ_COIL_STATUS,ILLEGAL_DATA_VALUE);	
						break;
					case READ_INPUT_REGISTERS:      							  /*读输入寄存器*/
						if(i > 48/*AI通道数24*/)								  /*返回地址异常码*/
							RetExpPak(READ_COIL_STATUS,ILLEGAL_DATA_ADDRESS);
																				  /*返回数据异常码*/
						if((j == 0) || ((i + j * 2) > PtcData.nSizeOfAITbl))
							RetExpPak(READ_COIL_STATUS,ILLEGAL_DATA_VALUE);	
						break;
					case FORCE_SINGLE_COIL:         							   /*写单路开关量输出*/
						if(i > 18/*DO通道数18*/)								   /*返回地址异常码*/
							RetExpPak(READ_COIL_STATUS,ILLEGAL_DATA_ADDRESS);
						else if((j != 0)&&(j != 0xff00))						   /*返回数据异常码*/
							RetExpPak(READ_COIL_STATUS,ILLEGAL_DATA_VALUE);	
						else
						{
							if(j == 0xff00)j = 0xff;
							else j = 0;
							PtcData.DOCtrl((INT8U)i,(BOOLEAN)j);
							WrCom(&COM1,rbuf,rlen);
						}
						break;
					case PRESET_SINGLE_REGISTER:    							   /*写单路寄存器*/
						if(i > 18/*AO通道数18*/)								   /*返回地址异常码*/
							RetExpPak(READ_COIL_STATUS,ILLEGAL_DATA_ADDRESS);
						else
						{
							PtcData.AOCtrl((INT8U)i,(INT16U)j);
							WrCom(&COM1,rbuf,rlen);
						}
						break;
					case PRESET_MULTIPLE_REGISTERS:    							   /*写多路寄存器*/
						if(i > 0x8000/*AO通道数*/)								   /*返回地址异常码*/
							RetExpPak(READ_COIL_STATUS,ILLEGAL_DATA_ADDRESS);
						else
						{
							INT16U  xdata buf[100];
							memcpy(buf,&rbuf[7],rbuf[6]);
							PtcData.MultAOCtrl(buf,rbuf[6]);
							TrPakChk(rbuf,8);
							WrCom(&COM1,rbuf,8);
						}
						break;
					default:
						RetExpPak(READ_COIL_STATUS,ILLEGAL_FUNCTION);	
						break;
				}
				return 0;
			}
		}
	}
	return -1;
}

//配置DO通道事件触发函数(当DO触发事件发生时,执行此函数关联的用户定义函数)
void DOCfgFnct(void (code *DOSet)(INT8U n,BOOLEAN State))
{
	PtcData.DOCtrl = DOSet;
} 
//配置寄存器写事件触发函数(当寄存器写事件发生时,执行此函数关联的用户定义函数)
void AOCfgFnct(void (code *AOSet)(INT8U n,INT16U Data))
{
	PtcData.AOCtrl = AOSet;
} 
//配置多路寄存器写事件触发函数(当寄存器写事件发生时,执行此函数关联的用户定义函数)
void MultAOCfgFnct(void (code *MultAOSet)(INT16U xdata *pBuf,INT16U l))
{
	PtcData.MultAOCtrl = MultAOSet;
} 

/*
*********************************************************************************************************
*                                         Application layer functions
*********************************************************************************************************
*/
//系统硬件资源初始化
void InitHardWare(void)
{
	EA = 0;
	InitUart();										/*串口初始化*/
	InitTimer0();									/*定时器0初始化*/
	EA = 1;											/*开中断*/
}
//MODBUS协议处理任务
/*
*********************************************************************************************************
*                                     MODBUS PROTOCOL PROCESS TASK
*
* Description : This function is mainly analyse and process MODBUS protocol command.
* Arguments   : None.
* Returns     : None
*********************************************************************************************************
*/
void ModBusPtcProcTask()
{
	INT8U byFncCode;
	INT16U nAddr;
	INT16U nData;
	if(ReadDataFromPtcLayer(&byFncCode,&nAddr,&nData) == 0)
	{
		switch (byFncCode)		
		{
			case READ_COIL_STATUS:					/*DO*/
				WriteDataToPtcLayer(READ_COIL_STATUS,PtcData.pDOTbl,(nData - 1)/8 + 1);
				break;
			case READ_INPUT_STATUS:					/*DI*/
				WriteDataToPtcLayer(READ_INPUT_STATUS,PtcData.pDITbl,(nData - 1)/8 + 1);
				break;
			case READ_HOLDING_REGISTERS:			/*AI*/
				WriteDataToPtcLayer(READ_HOLDING_REGISTERS,&PtcData.pAITbl[nAddr],nData*2);
				break;
			case READ_INPUT_REGISTERS:				/*AI*/
				WriteDataToPtcLayer(READ_INPUT_REGISTERS,&PtcData.pAITbl[nAddr],nData*2);
				break;
			case FORCE_SINGLE_COIL:					/*通道控制功能,驱动层已处理*/
				break;
			default:
				break;
		}
	}
}
/*
*********************************************************************************************************
*                                         Main Entry
*********************************************************************************************************
*/
#if ESTST
void estst()
{
	memset((INT8U volatile xdata *)0x3000,0x55,10);
	memset((INT8U volatile xdata *)0x2000,0xAA,3);
	memset((INT8U volatile xdata *)0x1000,0x00,3);
	if(!cnt)
	{
		RUNFLG=~RUNFLG;
		cnt = 1000;
	}
} 
#endif

void AR30DOSet(INT8U n,BOOLEAN state)
{
	n = n;
	if(state == 0xff)DO1 = 1;
	else DO1 = 0;
}
void dopusle(INT8U id,INT16U dly)  reentrant
{
	id = 0x55;;
	id = 0x55;;
	id = 0x55;;
	dly++;
}
void AR30AOSet(INT8U n,INT16U Data)
{
	n = n;
	XBYTE[0x4000] = Data >> 8;
	XBYTE[0x4001] = Data;
	dopusle(n,Data);
}
void AR30MultAOSet(INT16U xdata *p,INT16U l)reentrant
{
	INT16U v;
	l = l;
	v = *p++;
	v = *p++;
}


void main(void)
{
	InitHardWare();
	ModBusPtcInit(1,								/*设备地址*/
				  (INT8U volatile xdata *) 0x1000,	/*DO表首地址*/
				  (INT8U volatile xdata *) 0x2000,	/*DI表首地址*/
				  (INT8U volatile xdata *) 0x3000,	/*AI表首地址*/
				  1,								/*DO表大小*/
				  2,								/*DI表大小*/
				  24,								/*AI表大小*/
				  AR30DOSet,						/*用户自定义的DO控制函数*/
				  AR30AOSet,						/*用户自定义的AO控制函数*/
				  AR30MultAOSet					    /*用户自定义的多路AO控制函数*/
				  );

	for(;;)
	{
		ModBusPtcProcTask();
#if ESTST
		estst();
#endif
	}
}


⌨️ 快捷键说明

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