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

📄 mm_rab.lib

📁 modbus 运用事例
💻 LIB
📖 第 1 页 / 共 4 页
字号:
			{
				// incomplete response
				nErr = MM_TIMEOUT;
				abort;
			}
			if(!(pcHex = strchr(acHex, nByte)))
			{
				// illegal character
				nErr = MM_GARBAGE;
				abort;
			}
			*pcRep++ += (pcHex - acHex);
		}

		if(nByte != '\r')
		{
			// look for ASCII response's terminal CR
			nByte = -1;	// protect against immediate time out
			waitfor(DelayMs(MM_ERTO) || ((nByte = mmRecv()) != -1));
			if(nByte == -1)
			{
				// incomplete response
				nErr = MM_TIMEOUT;
				abort;
			}
			else if(nByte != '\r')
			{
				// response doesn't fit in buffer
				nErr = MM_TOOLONG;
				abort;
			}
		}

		// look for ASCII response's terminal LF
		nByte = -1;	// protect against immediate time out
		waitfor(DelayMs(MM_ERTO) || ((nByte = mmRecv()) != -1));
		if(nByte == -1)
		{
			// incomplete response
			nErr = MM_TIMEOUT;
		}
		else if(nByte != '\n')
		{
			// illegal character
			nErr = MM_GARBAGE;
		}
		else if(mmLRC(acMMRep, pcRep - acMMRep))
		{
			// bad LRC in ASCII response
			nErr = MM_BADXRC;
		}
		else if(acMMCmd[0] != acMMRep[0])
		{
			// response is not from queried slave!
			nErr = MM_BADID;
		}
		else if(acMMCmd[1] == acMMRep[1])
		{
			// normal response to query
			nErr = MM_OK;
		}
		else if(acMMCmd[1] != (acMMRep[1] & 0x7F))
		{
			// not a response to query
			nErr = MM_BADCODE;
		}
		else
		{
			// return slave's exception response, except zero (MM_BUSY)
			nErr = (acMMRep[2] == 0) ? MM_RESCODE : ((int) acMMRep[2] & 0xFF);
		}
	}
	return nErr;
}

/*=========================================================================*\
	Initialize MODBus ASCII Driver
\*=========================================================================*/

/* START FUNCTION DESCRIPTION *****************************************
mmaInit                       <MM_RAB.LIB>

NOTE: MM_RAB.LIB functions are generally not reentrant.

SYNTAX: void mmaInit()

DESCRIPTION: Responsible for inclusion of Modbus ASCII mmLRC() and
mmExec() functions. The standard 1 second end reply time out may be
overridden by an optional user defined milliseconds value (MM_ERTO,
cast to long). The standard 1 second begin reply (query end to response
begin) time out may also be overridden by an optional user defined
milliseconds value (MM_BRTO, cast to long). This function is normally
called only by the user supplied or library function which initializes
the Modbus Master communication port.

RETURN VALUE: None.
END DESCRIPTION ******************************************************/

nodebug
void mmaInit()
{
}

/***************************************************************************\
	MODBus RTU Master Packet Processing
\***************************************************************************/

/*** BeginHeader mmrInit */
void mmrInit(unsigned long);

// additional function prototypes for Modbus RTU
unsigned mmCRC(unsigned char *,unsigned);
int mmExec();

extern long mmrEndTimeOutMS;
/*** EndHeader */

/*=========================================================================*\
	Compute Cyclic Redundancy Check
\*=========================================================================*/

const unsigned char acMMRHi[] ={
	0x00,0xC1,0x81,0x40,	0x01,0xC0,0x80,0x41,	0x01,0xC0,0x80,0x41,	0x00,0xC1,0x81,0x40,
	0x01,0xC0,0x80,0x41,	0x00,0xC1,0x81,0x40,	0x00,0xC1,0x81,0x40,	0x01,0xC0,0x80,0x41,
	0x01,0xC0,0x80,0x41,	0x00,0xC1,0x81,0x40,	0x00,0xC1,0x81,0x40,	0x01,0xC0,0x80,0x41,
	0x00,0xC1,0x81,0x40,	0x01,0xC0,0x80,0x41,	0x01,0xC0,0x80,0x41,	0x00,0xC1,0x81,0x40,
	0x01,0xC0,0x80,0x41,	0x00,0xC1,0x81,0x40,	0x00,0xC1,0x81,0x40,	0x01,0xC0,0x80,0x41,
	0x00,0xC1,0x81,0x40,	0x01,0xC0,0x80,0x41,	0x01,0xC0,0x80,0x41,	0x00,0xC1,0x81,0x40,
	0x00,0xC1,0x81,0x40,	0x01,0xC0,0x80,0x41,	0x01,0xC0,0x80,0x41,	0x00,0xC1,0x81,0x40,
	0x01,0xC0,0x80,0x41,	0x00,0xC1,0x81,0x40, 0x00,0xC1,0x81,0x40,	0x01,0xC0,0x80,0x41,
	0x01,0xC0,0x80,0x41,	0x00,0xC1,0x81,0x40,	0x00,0xC1,0x81,0x40,	0x01,0xC0,0x80,0x41,
	0x00,0xC1,0x81,0x40,	0x01,0xC0,0x80,0x41,	0x01,0xC0,0x80,0x41,	0x00,0xC1,0x81,0x40,
	0x00,0xC1,0x81,0x40,	0x01,0xC0,0x80,0x41,	0x01,0xC0,0x80,0x41,	0x00,0xC1,0x81,0x40,
	0x01,0xC0,0x80,0x41,	0x00,0xC1,0x81,0x40,	0x00,0xC1,0x81,0x40,	0x01,0xC0,0x80,0x41,
	0x00,0xC1,0x81,0x40,	0x01,0xC0,0x80,0x41,	0x01,0xC0,0x80,0x41,	0x00,0xC1,0x81,0x40,
	0x01,0xC0,0x80,0x41,	0x00,0xC1,0x81,0x40,	0x00,0xC1,0x81,0x40,	0x01,0xC0,0x80,0x41,
	0x01,0xC0,0x80,0x41,	0x00,0xC1,0x81,0x40,	0x00,0xC1,0x81,0x40,	0x01,0xC0,0x80,0x41,
	0x00,0xC1,0x81,0x40,	0x01,0xC0,0x80,0x41,	0x01,0xC0,0x80,0x41,	0x00,0xC1,0x81,0x40
};

const unsigned char acMMRLo[] ={
   0x00,0xC0,0xC1,0x01, 0xC3,0x03,0x02,0xC2,	0xC6,0x06,0x07,0xC7,	0x05,0xC5,0xC4,0x04,
   0xCC,0x0C,0x0D,0xCD,	0x0F,0xCF,0xCE,0x0E, 0x0A,0xCA,0xCB,0x0B,	0xC9,0x09,0x08,0xC8,
   0xD8,0x18,0x19,0xD9, 0x1B,0xDB,0xDA,0x1A,	0x1E,0xDE,0xDF,0x1F, 0xDD,0x1D,0x1C,0xDC,
   0x14,0xD4,0xD5,0x15,	0xD7,0x17,0x16,0xD6, 0xD2,0x12,0x13,0xD3,	0x11,0xD1,0xD0,0x10,
   0xF0,0x30,0x31,0xF1,	0x33,0xF3,0xF2,0x32,	0x36,0xF6,0xF7,0x37,	0xF5,0x35,0x34,0xF4,
	0x3C,0xFC,0xFD,0x3D,	0xFF,0x3F,0x3E,0xFE,	0xFA,0x3A,0x3B,0xFB,	0x39,0xF9,0xF8,0x38,
	0x28,0xE8,0xE9,0x29,	0xEB,0x2B,0x2A,0xEA,	0xEE,0x2E,0x2F,0xEF,	0x2D,0xED,0xEC,0x2C,
	0xE4,0x24,0x25,0xE5,	0x27,0xE7,0xE6,0x26,	0x22,0xE2,0xE3,0x23,	0xE1,0x21,0x20,0xE0,
	0xA0,0x60,0x61,0xA1,	0x63,0xA3,0xA2,0x62,	0x66,0xA6,0xA7,0x67,	0xA5,0x65,0x64,0xA4,
	0x6C,0xAC,0xAD,0x6D,	0xAF,0x6F,0x6E,0xAE,	0xAA,0x6A,0x6B,0xAB,	0x69,0xA9,0xA8,0x68,
	0x78,0xB8,0xB9,0x79,	0xBB,0x7B,0x7A,0xBA,	0xBE,0x7E,0x7F,0xBF,	0x7D,0xBD,0xBC,0x7C,
	0xB4,0x74,0x75,0xB5,	0x77,0xB7,0xB6,0x76,	0x72,0xB2,0xB3,0x73,	0xB1,0x71,0x70,0xB0,
	0x50,0x90,0x91,0x51,	0x93,0x53,0x52,0x92,	0x96,0x56,0x57,0x97,	0x55,0x95,0x94,0x54,
	0x9C,0x5C,0x5D,0x9D,	0x5F,0x9F,0x9E,0x5E,	0x5A,0x9A,0x9B,0x5B,	0x99,0x59,0x58,0x98,
	0x88,0x48,0x49,0x89,	0x4B,0x8B,0x8A,0x4A,	0x4E,0x8E,0x8F,0x4F,	0x8D,0x4D,0x4C,0x8C,
	0x44,0x84,0x85,0x45,	0x87,0x47,0x46,0x86,	0x82,0x42,0x43,0x83,	0x41,0x81,0x80,0x40
};

nodebug
unsigned mmCRC(unsigned char *pcMess, unsigned wLen)
{
	auto unsigned char cHi,cLo;			//	CRC Accumulators (MSB & LSB)
	auto unsigned w;							//	CRC Shift In Index

	cHi = cLo = 0xFF;							//	Init CRC
	while(wLen--)
	{												//	For Each Byte   
		w = cHi ^ *pcMess++;						//	Next Table Index
		cHi = cLo ^ acMMRHi[w];					//	Next CRC
		cLo = acMMRLo[w];
	}
	return ((unsigned) cHi << 8) | cLo;				//	Return Composite
}

/*=========================================================================*\
	Assemble MODBus RTU Packet & Process when Done
\*=========================================================================*/

#ifndef MM_BRTO
#define MM_BRTO 100L	// arbitrary default RTU Begin Reply Time Out (mS)
#endif

nodebug
int mmExec()
{
	static unsigned char *pcRep;
	auto unsigned wCRC;
	static unsigned wCnt;
	static int nByte;
	auto int nErr;

	nErr = MM_BUSY;

	costate
	{
		wCRC = mmCRC(acMMCmd, pcMMCmd - acMMCmd);		// get RTU CRC
		mmCmdWord(wCRC);										// add CRC to RTU query
		
		while(mmRecv() != -1);								// clean out receive buffer
		mmSend(NULL, 0);										// clean out transmit buffer
		waitfor(mmSend(acMMCmd, pcMMCmd - acMMCmd));	// send Modbus RTU query

		// clear out response buffer (extra time for response to begin)
		memset(acMMRep, 0, sizeof(acMMRep));

		if(acMMCmd[0] == 0x00)
		{
			// broadcast command, no slave response expected
			nErr = MM_OK;
			abort;
		}
		
		// look for RTU response's initial byte (slave ID)
		pcRep = acMMRep;
		nByte = -1;	// protect against immediate time out
		waitfor(DelayMs(MM_BRTO) || ((nByte = mmRecv()) != -1));
		if(nByte == -1){
			nErr = MM_TIMEOUT;
			abort;
		}
		*pcRep++ = nByte;

		// collect RTU response bytes until a time out
		for(wCnt = 1; wCnt < sizeof(acMMRep); wCnt++)
		{
			nByte = -1;	// protect against immediate time out
			waitfor(DelayMs(mmrEndTimeOutMS) || ((nByte = mmRecv()) != -1));
			if(nByte == -1)
			{
				// end of RTU response
				break;
			}
			*pcRep++ = nByte;
		}

		// check excessive response length
		if(wCnt == sizeof(acMMRep))
		{
			// look for RTU response's time out
			nByte = -1;	// protect against immediate time out
			waitfor(DelayMs(mmrEndTimeOutMS) || ((nByte = mmRecv()) != -1));
			if(nByte != -1)
			{
				// response doesn't fit in buffer
				nErr = MM_TOOLONG;
				abort;
			}
		}

		// check minimum response length (ID + Function + loCRC + hiCRC)
		if(wCnt < 4)
		{
			// incomplete response
			nErr = MM_TIMEOUT;
		}
		else if(wCnt -= 2, mmCRC(acMMRep,wCnt) != mmRepWord(wCnt))
		{
			// bad CRC in RTU response
			nErr = MM_BADXRC;
		}
		else if(acMMCmd[0] != acMMRep[0])
		{
			// response is not from queried slave!
			nErr = MM_BADID;
		}
		else if(acMMCmd[1] == acMMRep[1])
		{
			// normal response to query
			nErr = MM_OK;
		}
		else if(acMMCmd[1] != (acMMRep[1] & 0x7F))
		{
			// not a response to query
			nErr = MM_BADCODE;
		}
		else
		{
			// return slave's exception response, except zero (MM_BUSY)
			nErr = (acMMRep[2] == 0) ? MM_RESCODE : ((int) acMMRep[2] & 0xFF);
		}
	}

	return nErr;
}

/*=========================================================================*\
	Initialize MODBus RTU Driver
\*=========================================================================*/

/* START FUNCTION DESCRIPTION *****************************************
mmrInit                       <MM_RAB.LIB>

NOTE: MM_RAB.LIB functions are generally not reentrant.

SYNTAX: void mmrInit(unsigned long qBaud)

DESCRIPTION: Responsible for inclusion of Modbus RTU mmCRC() and
mmExec() functions. Initializes the end reply time out gap to the
standard 3.5 character-times, unless overridden by an optional user
defined milliseconds value (MM_ERTO, cast to long). The arbitrary 100
milliseconds begin reply (query end to response begin) time out may
also be overridden by an optional user defined milliseconds value
(MM_BRTO, cast to long). This function is normally called only by the
user supplied or library function which initializes the Modbus Master
communication port.


PARAMETER1: baud rate (bits per second).

RETURN VALUE: None.
END DESCRIPTION ******************************************************/

long mmrEndTimeOutMS;

nodebug
void mmrInit(unsigned long qBaud)
{
	// check/set user defined vs. default Modbus RTU end time out gap value
	// NB: Modbus RTU default end time out gap depends on communication rate.

#ifdef	MM_ERTO
	mmrEndTimeOutMS = (long) MM_ERTO;
#else
	// NB: This formula assumes 11 bits (start1+data8+stop2) per transmitted
	//     character, then adds 1 mS "round up" time.
	//
	//          (3.5 char/gap) * (11 bits/char) * (1000 mS/sec)
	// mS/gap = ----------------------------------------------- + (1 mS/gap)
	//                          (qBaud bits/sec)
	mmrEndTimeOutMS = 38500L / qBaud + 1L;
#endif
}

/*** BeginHeader */
#endif
/*** EndHeader */

⌨️ 快捷键说明

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