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

📄 mbmaster.c

📁 Modbus协议主从协议栈
💻 C
字号:
/****************************************Copyright (c)**************************************************
**                                  广州致远电子有限公司
**
**                                 http://www.21cm.com.cn
**
**
**--------------File Info-------------------------------------------------------------------------------
** File name:			MBMaster.c
** Last modified Date:  2005-01-11
** Last Version:		1.0
** Descriptions:		
**
**------------------------------------------------------------------------------------------------------
** Created by:			ZhouLishan
** Created date:		2005-01-11
** Version:				1.0
** Descriptions:		
**
**------------------------------------------------------------------------------------------------------
** Modified by:
** Modified date:
** Version:
** Descriptions:
**
********************************************************************************************************/
#include "config.h"

#define ERR_ADRRESS 	0xff		// 设备地址无效
#define ERR_PARAMETER	0xfe		// 输入参数无效出错

#define ERR_TIMEOUT		0xfd		// 没应答超时出错
#define ERR_FRAME		0xfc		// 接收到的帧出错(CRC出错)
#define ERR_NON			0x00		// 正常返回


#define MB_POLL_TIMEOUT		100
#define MB_POLL_DELAY		5


extern FUNCTION_PACK_PDU FunPDUPackHanlde[MAX_FUNCTION];
extern FUNCTION_DATA_HANDLE FunParRepAndStData[MAX_FUNCTION];

uint16 Modbus_CRC16(uint8 *Buff_addr,uint16 len);
void SendResponse(uint8 *buff,uint16 len);

//*****************************************************************************
// 函数名称:
// 输入参数:
// 输出参数:
// 功能描述:
//*****************************************************************************


uint8 ADUBuffer[256];

extern g_WaitN10mS;

#ifdef UCOSII
	OS_EVENT *mb_handle_event_ptr;
	OS_EVENT *mb_reply_event_ptr;
	OS_EVENT *mb_idle_event_ptr;
#endif

MASTER_INFORMATION MB_Master;
//********************************************************************************************************
// 函数名称:MBSlaveIni
// 输入参数:无
// 输出参数:无
// 功能描述:MODBUS从机初始化
//********************************************************************************************************
void MBMasterIni(void)
{

	MB_Master.Status = MB_MASTER_IDLE;	// 主机空闲
	ADUData.Address = 0;
	ADUData.ADUBuffPtr = ADUBuffer;
	ADUData.ADULength = 0;

//	ADUData.RedundancyCheck = 0;
	ADUData.EndT15 = FALSE;
	ADUData.FrameOK = FALSE;
//	ADUData.OverTime = FALSE;
	PDUData.PDUBuffPtr = NULL;
//	PDUData.Response.ExceptionCode = 0;
#ifdef UCOSII
	mb_idle_event_ptr   = OSSemCreate(1);			// MODBUS主机空闲信号量
	mb_handle_event_ptr = OSSemCreate(0);			// MODBUS处理信号量
	mb_reply_event_ptr  = OSMboxCreate((void *)0);	// MODBUS处理应答消息
#endif
}


//******************************************************************************************
// 函数名称:ModbusPoll
// 输入参数:NodeID,节点ID(设备地址)
// 			 FunctionCode,功能代码
//			 ParameterPtr,参数入口
// 输出参数:err,指令执行状态
// 功能描述:
//******************************************************************************************

uint8 ModbusPoll(uint8 NodeID,uint8 FunctionCode,void *ParameterPtr)
{
	uint8 i,err;
	ADUData.Address = NodeID;
	

	for(i=0;i<MAX_FUNCTION;i++)							// 查打有效的功能代码			
	{	if(FunPDUPackHanlde[i].Code==FunctionCode)		// 查找功能代码处理函数
		{
		#ifdef UCOSII
			OSSemPend(mb_idle_event_ptr,0,&err);		// 等待可以操作MODBUS主机的一个信号量	
		#else
			if(MB_Master.Status!=(uint8)MB_MASTER_IDLE)
				return (uint8)MB_MASTER_BUSY;			// 无效指令返回
		#endif	
			PDUData.PDUBuffPtr = ADUData.ADUBuffPtr+1;	// 设置PDU起始指针
			FunPDUPackHanlde[i].Function(ParameterPtr);	// 调用功能代码处理函数
			PDUData.FrameOK = TRUE;						// 请求帧准备就绪
			MB_Master.ParPtr = ParameterPtr;			// 请求参数结构指针
			
		#ifdef UCOSII
			OSSemPost(mb_handle_event_ptr);				// 发报信号量,使MODBUS服务任务处理传输
			err = *(uint8 *)OSMboxPend(mb_reply_event_ptr,0,&err);	// 等待执行完成	
		#else
			do
			{
				err = IdleModbus();
			}while(MB_Master.Status==(uint8)MB_MASTER_BUSY);
		#endif		
			return err;	// 无效指令返回

		}
	}
	return (uint8)MB_FUN_NOT_DEF;
}


//******************************************************************************************
// 函数名称:ParseReponseAndStoreData
// 输入参数:无
// 输出参数:无
// 功能描述:解析应答帧,并保存数据
//******************************************************************************************
uint8 ParseReponseAndStoreData(void)
{
	uint8 i,err;
	err = MB_FUN_NOT_DEF;
	for(i=0;i<MAX_FUNCTION;i++)							
		if(FunParRepAndStData[i].Code==PDUData.FunctionCode)		// 查找功能代码处理函数
		{
			if(PDUData.PDUBuffPtr[0]&0x80)	// 异常产生
			{	err = PDUData.PDUBuffPtr[1];}
			else	
			{	err = MB_NO_ERR;
				FunParRepAndStData[i].Function(PDUData.PDUBuffPtr,MB_Master.ParPtr);	// 调用功能代码处理函数
			}
			break;
		}
	return err;// 未定义功能码
}

//******************************************************************************************
// 函数名称:CheckModbusMessage
// 输入参数:无
// 输出参数:ADU描述符
// 功能描述:检查是否有需要发送的的帧
//******************************************************************************************
ADU_CONTROL *CheckModbusMessage(void)
{
	uint16 CRC16;
	uint8 *ADUPtr;
	if(PDUData.FrameOK == TRUE)			// 请求帧的PDU是否准备就绪
	{
		PDUData.FrameOK = FALSE;		// 清PDU是否准备就绪标志,当接收到有效的PDU后将被再次置1
		ADUPtr = ADUData.ADUBuffPtr;
		ADUPtr[0] = ADUData.Address;	// 设置ADU地址(节点)
		
		CRC16 = Modbus_CRC16(ADUPtr,PDUData.PDULength+1);	// 求CRC16值
		ADUPtr[PDUData.PDULength+1] = CRC16;				// 设置CRC16值
		ADUPtr[PDUData.PDULength+2] = CRC16>>8;
		ADUData.ADULength=PDUData.PDULength+3;		// ADU长度等于PDU长度加1个地址和2个CRC字符
		ADUData.FrameOK = TRUE;						// 标记ADU请求帧准备就绪
		
		return (ADU_CONTROL *) &ADUData;			
	}
	else
		return NULL;
}








//******************************************************************************************
// 函数名称:IdleModbus
// 输入参数:无
// 输出参数:MODBUS主机状态
// 功能描述:
//******************************************************************************************
uint8 IdleModbus(void)
{
	static uint8 err;
	static uint8  modbus_state=0;
	
#ifdef	UCOSII
	OSSemPend(mb_handle_event_ptr,0,&err);
#endif	
	
	err = MB_MASTER_BUSY;
	switch ( modbus_state )
	{
      	case 0:
         	/******************************************************************/
         	/*       CHECK FOR THE NEXT MESSAGE TO SEND                       */
         	/*       检查需要发送的消息,并发送请求帧						  */
         	/******************************************************************/
        	if ( CheckModbusMessage() )
			{     
				/******************************************************************/
	         	/*       SEND THE POLL                                            */
	         	/*		发送请求帧												  */
	         	/******************************************************************/
	         	SendResponse(ADUData.ADUBuffPtr,ADUData.ADULength);// 发送帧
	        	ADUData.FrameOK = FALSE;
	        	ADUData.ADULength = 0;
   				MB_Master.Status = (uint8)MB_MASTER_BUSY;				// 设置主机忙状态
	        	Waite10mS(MB_POLL_TIMEOUT);			// 命令应答计时 
	            modbus_state++;
 				
            }
            else
            	err = MB_MASTER_IDLE;	// 没有功能代码需传输
         	break;
      	case 1:
         	/******************************************************************/
         	/*       GET THE PACKET AND MAKE SURE IT IS COMPLETE              */
         	/******************************************************************/
         	if ( PDUData.FrameOK )	// 成功接收PDU帧
            {
                /******************************************************************/
         		/*       PARSE THE RESPONSE AND STORE THE DATA                    */
         		/*       解析应等帧,并储存数据									  */
         		/******************************************************************/
         		err = ParseReponseAndStoreData();
         		PDUData.FrameOK = FALSE;
         		Waite10mS(MB_POLL_DELAY);	
    		#ifdef	UCOSII
				OSMboxPost(mb_reply_event_ptr,&err);  		   
			#endif		 
            	modbus_state++;
            	break;
            }

         	/******************************************************************/
         	/*       IF NO RESPONSE RECEIVED TIME OUT AND SEND NEXT POLL      */
         	/******************************************************************/
         	if (g_TimeEnd)
            {
            	modbus_state = 0;
            	MB_Master.Status = MB_MASTER_IDLE;	// 主机空闲
            	err = MB_RESPONSE_TIME_OUT;
 			#ifdef	UCOSII
				OSMboxPost(mb_reply_event_ptr,&err);  		   
			#endif	
            }
         	break;
      	case 2:
         	/******************************************************************/
         	/*       POLL DELAY                                               */
         	/*		轮循延时												  */
         	/******************************************************************/

         	if (g_TimeEnd)
            {
               	modbus_state=0;
          		MB_Master.Status = MB_MASTER_IDLE;	// 主机空闲
            }
      	default:
         	break;
      }
      
#ifdef	UCOSII
	if(MB_Master.Status == MB_MASTER_IDLE)
		OSSemPost(mb_idle_event_ptr);     
#endif
    return err;
}







⌨️ 快捷键说明

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