FreeModbus線圈

線圈的訪問屬性爲讀寫

對線圈的操作包括:讀線圈(0x01)、寫單個線圈(0x05)、寫多個線圈(0x0F)

 

讀線圈(0x01)

在一個遠程設備中,使用該功能碼讀取線圈的1 至2000 連續狀態。請求PDU 詳細說明了起始地址,即指定的第一個線圈地址和線圈編號。從零開始尋址線圈。因此尋址線圈1-16 爲0-15。根據數據域的每個比特將響應報文中的線圈分成爲一個線圈。指示狀態爲1= ON 和0= OFF。第一個數據字節的LSB(最低有效位)包括在詢問中尋址的輸出。其它線圈依次類推,一直到這個字節的高位端爲止,並在後續字節中從低位到高位的順序。

如果返回的輸出數量不是八的倍數,將用零填充最後數據字節中的剩餘比特(一直到字節的高位端)。字節數量域說明了數據的完整字節數。

讀線圈狀態圖

/* 讀線圈 */
eMBException eMBFuncReadCoils(UCHAR *pucFrame, USHORT *usLen)
{
	USHORT usRegAddress;
	USHORT usCoilCount;
	UCHAR ucNBytes;
	UCHAR *pucFrameCur;
	eMBException eStatus = MB_EX_NONE;
	eMBErrorCode eRegStatus;

	/* 校驗PDU長度是否合理 */
	if(*usLen == (MB_PDU_FUNC_READ_SIZE + MB_PDU_SIZE_MIN))
	{
		/* 線圈地址 */
		usRegAddress = (USHORT)(pucFrame[MB_PDU_FUNC_READ_ADDR_OFF] << 8);
		usRegAddress |= (USHORT)(pucFrame[MB_PDU_FUNC_READ_ADDR_OFF + 1]);
		/* 第1個線圈尋址爲0,所以地址加一 */
		usRegAddress++;

		/* 線圈數量 */
		usCoilCount = (USHORT)(pucFrame[MB_PDU_FUNC_READ_COILCNT_OFF] << 8);
		usCoilCount |= (USHORT)(pucFrame[MB_PDU_FUNC_READ_COILCNT_OFF + 1]);

		/* 檢查線圈數量是否合理 */
		if((usCoilCount >= 1) &&
			 (usCoilCount < MB_PDU_FUNC_READ_COILCNT_MAX))
		{
			/* 構建響應 */
			
			/* PDU指針 */
			pucFrameCur = &pucFrame[MB_PDU_FUNC_OFF];
			/* PDU長度初始化爲0 */
			*usLen = MB_PDU_FUNC_OFF;

			/* 功能碼 */
			*pucFrameCur++ = MB_FUNC_READ_COILS;
			*usLen += 1;

			/* 字節數 */
			if((usCoilCount & 0x0007) != 0)
			{
				ucNBytes = (UCHAR)(usCoilCount / 8 + 1);
			}
			else
			{
				ucNBytes = (UCHAR)(usCoilCount / 8);
			}
			*pucFrameCur++ = ucNBytes;
			*usLen += 1;

			/* 讀取線圈值 */
			eRegStatus = eMBRegCoilsCB(pucFrameCur, usRegAddress, usCoilCount, MB_REG_READ);
			/* 產生異常 */
			if(eRegStatus != MB_ENOERR)
			{
				/* 錯誤轉化爲異常碼 */
				eStatus = prveMBError2Exception(eRegStatus);
			}
			/* 未產生異常 */
			else
			{
				/* 數據長度 */
				*usLen += ucNBytes;;
			}
		}
		/* 線圈數量不合理 */
		else
		{
			/* 非法數據值 */
			eStatus = MB_EX_ILLEGAL_DATA_VALUE;
		}
	}
	/* PDU長度不對 */
	else
	{
		/* 非法數據值 */
		eStatus = MB_EX_ILLEGAL_DATA_VALUE;
	}

	return eStatus;
}

 

寫單個線圈(0x05)

在一個遠程設備上,使用該功能碼寫單個輸出爲ON 或OFF。請求數據域中的常量說明請求的ON/OFF狀態。十六進制值FF 00請求輸出爲ON。十六進制值00 00 請求輸出爲OFF。其它所有值均是非法的,並且對輸出不起作用。請求PDU說明了強制的線圈地址。從零開始尋址線圈。因此,尋址線圈1 爲0。線圈值域的常量說明請求的ON/OFF 狀態。十六進制值0XFF00請求線圈爲ON。十六進制值0X0000請求線圈爲OFF。其它所有值均爲非法的,並且對線圈不起作用。

正常響應是請求的應答,在寫入線圈狀態之後返回這個正常響應。

寫單個線圈狀態圖

/* 寫單個線圈 */
eMBException eMBFuncWriteCoil(UCHAR *pucFrame, USHORT *usLen)
{
	USHORT usRegAddress;
	UCHAR ucBuf[2];
	eMBException eStatus = MB_EX_NONE;
	eMBErrorCode eRegStatus;

	/* 校驗PDU長度是否合理 */
	if(*usLen == (MB_PDU_FUNC_WRITE_SIZE + MB_PDU_SIZE_MIN))
	{
		/* 線圈地址 */
		usRegAddress = (USHORT)(pucFrame[MB_PDU_FUNC_WRITE_ADDR_OFF] << 8);
		usRegAddress |= (USHORT)(pucFrame[MB_PDU_FUNC_WRITE_ADDR_OFF + 1]);
		/* 第1個線圈尋址爲0,所以地址加一 */
		usRegAddress++;

		/* 判斷值是否合法,ON:0xFF00 OFF:0x0000 */
		if((pucFrame[MB_PDU_FUNC_WRITE_VALUE_OFF + 1] == 0x00) &&
			 ((pucFrame[MB_PDU_FUNC_WRITE_VALUE_OFF] == 0xFF) ||
				(pucFrame[MB_PDU_FUNC_WRITE_VALUE_OFF] == 0x00)))
		{
			/* 將ON/OFF轉換爲位1/0 */
			ucBuf[1] = 0;
			if(pucFrame[MB_PDU_FUNC_WRITE_VALUE_OFF] == 0xFF)
			{
				ucBuf[0] = 1;
			}
			else
			{
				ucBuf[0] = 0;
			}
			/* 寫入線圈值 */
			eRegStatus = eMBRegCoilsCB(&ucBuf[0], usRegAddress, 1, MB_REG_WRITE);
			/* 產生異常 */
			if(eRegStatus != MB_ENOERR)
			{
				/* 錯誤轉化爲異常碼 */
				eStatus = prveMBError2Exception(eRegStatus);
			}
		}
		/* 狀態值錯誤 */
		else
		{
			/* 非法數據值 */
			eStatus = MB_EX_ILLEGAL_DATA_VALUE;
		}
	}
	/* PDU長度不對 */
	else
	{
		/* 非法數據值 */
		eStatus = MB_EX_ILLEGAL_DATA_VALUE;
	}

	return eStatus;
}

 

寫多個線圈(0x0F)

在一個遠程設備中,使用該功能碼強制線圈序列中的每個線圈爲ON 或OFF。請求PDU說明了強制的線圈參考。從零開始尋址線圈。因此,尋址線圈1 爲0。請求數據域的內容說明了被請求的ON/OFF 狀態。域比特位置中的邏輯“1”請求相應輸出爲ON。域比特位置中的邏輯“0”請求相應輸出爲OFF。

正常響應返回功能碼、起始地址和強制的線圈數量。

寫多個線圈狀態圖

/* 寫多個線圈 */
eMBException eMBFuncWriteMultipleCoils(UCHAR *pucFrame, USHORT *usLen)
{
	USHORT usRegAddress;
	USHORT usCoilCnt;
	UCHAR ucByteCount;
	UCHAR ucByteCountVerify;
	eMBException eStatus = MB_EX_NONE;
	eMBErrorCode eRegStatus;

	/* 校驗PDU長度是否合理 */
	if(*usLen > (MB_PDU_FUNC_WRITE_SIZE + MB_PDU_SIZE_MIN))
	{
		/* 線圈地址 */
		usRegAddress = (USHORT)(pucFrame[MB_PDU_FUNC_WRITE_MUL_ADDR_OFF] << 8);
		usRegAddress |= (USHORT)(pucFrame[MB_PDU_FUNC_WRITE_MUL_ADDR_OFF + 1]);
		/* 第1個線圈尋址爲0,所以地址加一 */
		usRegAddress++;

		/* 線圈數量 */
		usCoilCnt = (USHORT)(pucFrame[MB_PDU_FUNC_WRITE_MUL_COILCNT_OFF] << 8);
		usCoilCnt |= (USHORT)(pucFrame[MB_PDU_FUNC_WRITE_MUL_COILCNT_OFF + 1]);

		/* 字節數 */
		ucByteCount = pucFrame[MB_PDU_FUNC_WRITE_MUL_BYTECNT_OFF];

		/* 計算字節數 */
		if((usCoilCnt & 0x0007) != 0)
		{
			ucByteCountVerify = (UCHAR)(usCoilCnt / 8 + 1);
		}
		else
		{
			ucByteCountVerify = (UCHAR)(usCoilCnt / 8);
		}

		/* 檢查線圈數量和字節數是否合理 */
		if((usCoilCnt >= 1) &&
			 (usCoilCnt <= MB_PDU_FUNC_WRITE_MUL_COILCNT_MAX) &&
			 (ucByteCountVerify == ucByteCount))
		{
			/* 寫入線圈值 */
			eRegStatus = eMBRegCoilsCB(&pucFrame[MB_PDU_FUNC_WRITE_MUL_VALUES_OFF],
																 usRegAddress, usCoilCnt, MB_REG_WRITE);
			/* 產生異常 */
			if(eRegStatus != MB_ENOERR)
			{
				/* 錯誤轉化爲異常碼 */
				eStatus = prveMBError2Exception(eRegStatus);
			}
			/* 未產生異常 */
			else
			{
				/* 數據長度 */
				*usLen = MB_PDU_FUNC_WRITE_MUL_BYTECNT_OFF;
			}
		}
		/* 線圈數量或字節數不合理 */
		else
		{
			/* 非法數據值 */
			eStatus = MB_EX_ILLEGAL_DATA_VALUE;
		}
	}
	/* PDU長度不對 */
	else
	{
		/* 非法數據值 */
		eStatus = MB_EX_ILLEGAL_DATA_VALUE;
	}

	return eStatus;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章