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

📄 modbus.c

📁 自己编写的mod bus 协议源代码。基于keilc51开发。主要使用回调函数
💻 C
📖 第 1 页 / 共 2 页
字号:
/*
*********************************************************************************************************
*                                          Modbus Protocol Module
*
*                        (c) Copyright 2006-08-01, XXXXXXXXXXXXXXXXXXXX Corp., ltd, 
*                                           All Rights Reserved
*
*                                                  V1.00
*
* File : modbus.c
* By   : kevin zhu
*********************************************************************************************************
*/
#define MOD_GLOBALS
#define CRC_TBL
#include "modbus.h"


#define ESTST		1
#if ESTST
INT16U cnt=0;
sbit RUNFLG  = P1^1;
sbit DO1  = P1^0;
#endif
/*
*********************************************************************************************************
*                                         hardware layer functions
*********************************************************************************************************
*/
//串口寄存器初始化
void InitUart()
{
	RCAP2H=BAUDH;
	RCAP2L=BAUDL;
	T2CON=0x34;       								/*启动T2,选择T2作波特率发生器*/
	T2MOD=0;
    SCON=0x50;//0x52
	PCON=0x00;
	PS = 1;
	ES = 1;											/*the interrupt enable*/
}
//定时器0寄存器初始化
void InitTimer0()
{
	TMOD |= 0x01;									/*set timer 1ms when cpu at 11.0592MHz*/
	TH0 = Timer0H;										
	TL0 = Timer0L;
	TR0 = 1;										/*TR0 is set*/
	ET0 = 1;										/*the interrupt enable*/
}
//串口中断服务函数
ComIntISR() interrupt 4 using 1
{
	EA = 0;
	ModBusComDrv();
	EA = 1;
}
//定时器0中断服务函数
Timer0IntISR() interrupt 1 using 2
{
	ModBusTimer0Drv();
#if ESTST
	if(cnt > 0)cnt--;
#endif
}
/*
*********************************************************************************************************
*                                         Communication control layer functions
*********************************************************************************************************
*/
//通信中断处理函数
void ModBusComDrv(void)using 1
{
	COM xdata *pCOM;
	pCOM = &COM1;
    if(TI)
	{
	 	TI = 0;
		if(pCOM->TrCnt >= pCOM->TrLen)
		{
			pCOM->TrCnt = 0;
			pCOM->TrOk = 1;
		}
		else
	 	{
			SBUF = pCOM->pTrBuf[pCOM->TrCnt++];		/*发送下一个字节*/
		}
    }
#if REC_TIMEOUT_MOD
    if(RI)
	{
		RI = 0;
		pCOM->pRecBuf[pCOM->RecCnt++] = SBUF;						      
		pCOM->RecTimeOutCnt = 0;					/*清超时计数器*/
		pCOM->RecFstFlg = 1;						/*接收到起始字符时,开始计数超时时间*/
    }
#else
    if(RI)
	{
		RI = 0;
		switch (pCOM->RecStateMachine)
		{
			case 0:
				if(SBUF == PtcData.Dev)
				{
					pCOM->pRecBuf[0] = SBUF;
					pCOM->RecCnt = 0;
					pCOM->RecFstFlg = 1;   			/*启动接收超时计数器*/
					pCOM->RecStateMachine = 1;
				}
				break;
			case 1:
				pCOM->pRecBuf[1 + pCOM->RecCnt++] = SBUF;
				if(7 == pCOM->RecCnt)
				{
					if(pCOM->pRecBuf[1] != 0x10)
					{
						pCOM->RecFstFlg = 0;	 		/*清接收超时计数器*/
						pCOM->RecTimeOutCnt = 0;
						pCOM->RecLen = pCOM->RecCnt + 1;
						pCOM->RecOk = 1;				/*收到一个完整帧*/
						pCOM->RecStateMachine = 0;		/*接收状态归零*/	
					}
					else
					{					  				/*如果为0x10命令则继续收*/
						pCOM->RecCnt = 0;
						pCOM->RecStateMachine = 2;
					}
				}
				break;
			case 2:
				pCOM->pRecBuf[8 + pCOM->RecCnt++] = SBUF;
				if(pCOM->RecCnt == pCOM->pRecBuf[6] + 1)
				{
					pCOM->RecFstFlg = 0;	 		/*清接收超时计数器*/
					pCOM->RecTimeOutCnt = 0;
					pCOM->RecLen = pCOM->RecCnt + 8;
					pCOM->RecOk = 1;				/*收到一个完整帧*/
					pCOM->RecStateMachine = 0;		/*接收状态归零*/	
				}
				break;
			default:
				break;
		}
	}		
#endif
}
//定时器0中断处理函数
void ModBusTimer0Drv(void) using 2
{
	COM xdata *pCOM;;
	TH0=Timer0H;
	TL0=Timer0L;									/*重置定时器*/

	pCOM = &COM1;
#if REC_TIMEOUT_MOD
	if(pCOM->RecFstFlg)								/*COM1 口接收超时处理*/
	{
		if(++pCOM->RecTimeOutCnt >= TMROUT_9600BPS) /*此处取接收超时为6ms,在波特率为9600bps时*/
		{						 
			pCOM->RecTimeOutCnt = 0;   
			pCOM->RecFstFlg = 0;
			pCOM->RecLen = pCOM->RecCnt;
			pCOM->RecCnt = 0;
			pCOM->RecOk = 1; 
		}
	}
#else
	if(pCOM->RecFstFlg)
	{
		if(++pCOM->RecTimeOutCnt >= REC_MAX_TMROUT) 
		{
			pCOM->RecTimeOutCnt = 0; 
			pCOM->RecFstFlg = 0;
			pCOM->RecStateMachine = 0;				/*接收状态归零*/
		}
	}
#endif
}

//串口缓冲区初始化
void InitCom(void)							
{
	COM xdata *pCOM;
	pCOM = &COM1;
	pCOM->pRecBuf = RecBuf;
	pCOM->RecCnt = 0;
	pCOM->RecLen = 0;
	pCOM->RecFstFlg = 0;
	pCOM->RecTimeOutCnt = 0;
	pCOM->pTrBuf = TrBuf;
	pCOM->TrLen = 0;
	pCOM->TrCnt = 0;
	pCOM->RecOk = 0;
	pCOM->RecStateMachine = 0;

	memset(&pCOM->pRecBuf[0],0,MAX_REC_LEN);
	memset(&pCOM->pTrBuf[0],0,MAX_SEND_LEN);
	pCOM->RecOk = 0;
	pCOM->TrOk = 0;
}
//从串口获取数据
INT8S RdCom(COM xdata *pCOM,INT8U xdata* RBuf,INT8U* NumOfDataRecv)
{
	if((pCOM->RecOk == 1) && (pCOM->TrCnt == 0))
	{
		pCOM->RecOk = 0;
		*NumOfDataRecv=0;
		*NumOfDataRecv=pCOM->RecLen;
		memcpy(RBuf,&RecBuf[0],pCOM->RecLen);
		return 0;
	}
	else return -1;
}
//写数据到串口
void WrCom(COM  *pCOM,INT8U xdata* WBuf,INT8U NumOfDataTrans)
{
	while(pCOM->TrCnt != 0);							//等待上一次发送完
	memcpy(pCOM->pTrBuf,WBuf,NumOfDataTrans);
	pCOM->TrLen = NumOfDataTrans;
	pCOM->TrCnt = 1;
	SBUF = pCOM->pTrBuf[0];
}
/*
*********************************************************************************************************
*                                         Protocol layer functions
*********************************************************************************************************
*/
/*
*  [MODBUS协议数据格式]
*  +----------------------------------------+
*  | 地址码 | 功能码 | 数据区 | CRC错误校检 |
*  +----------------------------------------+
*/

//初始化协议控制层
/*
*********************************************************************************************************
*                                     INIT MODBUS PROTOCOL CONTROL LAYER
*
* Description : This function is used to initialize Modbus protocol control layer data
* Arguments   : DevAddr,		device address
*			  : pDO, 			DO table start address
*			  : pDI, 			DI table start address	
*			  : pAI, 			AI table start address	
*			  : nSizeOfDOTbl, 	the size of DO table
*			  : nSizeOfDITbl, 	the size of DI table	
*			  : nSizeOfAITbl, 	the size of AI table	
*			  : void (code *DOSet)(INT8U n,BOOLEAN State), DO channal control function defined by user
*			  : void (code *AOSet)(INT8U n,INT16U Data), AO channal control function defined by user
*			  : void (code *MultAOSet)(INT8U n,INT16U len), MAO channal control function defined by user
* Returns     : None.
*********************************************************************************************************
*/
void ModBusPtcInit(INT8U DevAddr,												/*设备地址*/
				   INT8U xdata *pDO,											/*DO表首地址*/
				   INT8U xdata *pDI,											/*DI表首地址*/
				   INT8U xdata *pAI,											/*AI表首地址*/
				   INT16U nSizeOfDOTbl,											/*DO表大小*/
				   INT16U nSizeOfDITbl,											/*DI表大小*/
				   INT16U nSizeOfAITbl,											/*AI表大小*/
																				/*用户自定义的DO控制函数*/
				   void (code *DOSet)(INT8U n,BOOLEAN State),
																				/*用户自定义的AO控制函数*/
				   void (code *AOSet)(INT8U n,INT16U Data),
																				/*用户自定义的多路AO控制函数*/
				   void (code *MultAOCtrl)(INT16U *p,INT16U len)
				  )
{
	DTBL xdata *pDTbl;

	InitCom();
	pDTbl = &PtcData;
	pDTbl->Dev = DevAddr;
	pDTbl->pDOTbl = pDO;
	pDTbl->pDITbl = pDI;
	pDTbl->pAITbl = pAI;
	pDTbl->nSizeOfDOTbl = nSizeOfDOTbl;
	pDTbl->nSizeOfDITbl = nSizeOfDITbl;
	pDTbl->nSizeOfAITbl = nSizeOfAITbl;

	DOCfgFnct(DOSet);
	AOCfgFnct(AOSet);
	MultAOCfgFnct(MultAOCtrl);
}

//计算CRC校验和
INT16U CRC16(INT8U xdata * puchMsg,INT16U usDataLen)
{
	INT8U uchCRCHi = 0xff;
	INT8U uchCRCLo = 0xff;
	INT8U uIndex;
	while(usDataLen--)
	{
		uIndex = uchCRCHi ^ *puchMsg++;
		uchCRCHi = uchCRCLo ^ auchCRCHi[uIndex];
		uchCRCLo = auchCRCLo[uIndex];

⌨️ 快捷键说明

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