Modbus Master ——关于“木蓝创智”的Modbus Master库在STM32上的移植修改和测试

       如题,首先要感谢一下“木蓝创智”在博客中分享他的Modbus Master的库,他的博文地址是:http://www.cnblogs.com/foxclever/p/7441384.html

        最近需要搞一下关于Modbus主从一体的设备,之前只弄过一个Modbus从站设备,是移植FreeModbus的,个人比较懒,网上有现成的一般我也就不想细究了。所以到现在对Modbus协议本身还不是很精通,弄主站设备时就有一种茫然的感觉。在这里就不得不感谢一下互联网了,在我的耐心寻找下就找到了上面所说的那篇博文。

        话不多说了,我立马就把别人写好的代码给下下来了,打开一看,我又要感慨一下了,注释很详尽,还有一个函数开发功能文档。这对于一个懒人来说真是太好了。随后我就把他放到我的工程里,编译下载一切都很顺利。

        但是在测试的时候出现问题了,我使用的是主站功能,但是从站总是会返回03的错误码,检查一看是主站数据发错了,又开始仔细的看代码,然后发现博主不小心留了几个错误给我,另外我也在这个基础上稍微改了几个地方,现在把它们贴出来吧

1、头文件修改

mbpdu.h

原文:

/*作为RTU主站(TCP客户端)时,生成读写RTU从站(TCP服务器)对象的命令*/
uint16_t GenerateReadWriteCommand(ObjAccessInfo objInfo,bool *statusList,uint16_t *registerList,uint8_t commandBytes[]); 

改成

/*作为RTU主站(TCP客户端)时,生成读写RTU从站(TCP服务器)对象的命令*/
uint16_t GenerateReadWriteCommand(ObjAccessInfo *objInfo,bool *statusList,uint16_t *registerList,uint8_t commandBytes[]);

mbrtu.h

原文

/*生成读写从站数据对象的命令,命令长度包括2个校验字节*/
uint16_t SyntheticReadWriteSlaveCommand(ObjAccessInfo slaveInfo,bool *statusList,uint16_t *registerList,uint8_t *commandBytes);

改成

/*生成读写从站数据对象的命令,命令长度包括2个校验字节*/
uint16_t SyntheticReadWriteSlaveCommand(ObjAccessInfo *slaveInfo,bool *statusList,uint16_t *registerList,uint8_t *commandBytes);

mbrtumaster.h

原文

/*生成访问服务器的命令*/
uint16_t CreateAccessSlaveCommand(ObjAccessInfo objInfo,void *dataList,uint8_t *commandBytes);

/*解析收到的服务器相应信息*/
void ParsingSlaveRespondMessage(uint8_t *recievedMessage,uint8_t *command);

改成

/*生成访问服务器的命令*/
uint16_t CreateAccessSlaveCommand(ObjAccessInfo *objInfo,void *dataList,uint8_t *commandBytes);

/*解析收到的服务器相应信息*/
void ParsingSlaveRespondMessage(uint8_t *recievedMessage,uint8_t *command, uint16_t length);

mbtcp.h

原文

//生成读写服务器对象的命令
uint16_t SyntheticReadWriteTCPServerCommand(ObjAccessInfo objInfo,bool *statusList,uint16_t *registerList,uint8_t *commandBytes);

改成

//生成读写服务器对象的命令
uint16_t SyntheticReadWriteTCPServerCommand(ObjAccessInfo *objInfo,bool *statusList,uint16_t *registerList,uint8_t *commandBytes);

mbtcpclient.h

原文

/*生成访问服务器的命令*/
uint16_t CreateAccessServerCommand(ObjAccessInfo objInfo,void *dataList,uint8_t *commandBytes);

改成

/*生成访问服务器的命令*/
uint16_t CreateAccessServerCommand(ObjAccessInfo *objInfo,void *dataList,uint8_t *commandBytes);

2、源文件修改

mbpdu.c

原文

/*作为RTU主站(TCP客户端)时,生成读写RTU从站(TCP服务器)对象的命令*/
uint16_t GenerateReadWriteCommand(ObjAccessInfo objInfo,bool *statusList,uint16_t *registerList,uint8_t *commandBytes)
{
  uint16_t index=0;
  commandBytes[index++]=objInfo.unitID;                 //从站地址
  commandBytes[index++]=objInfo.functionCode;           //功能码
  commandBytes[index++]=objInfo.startingAddress>>8;     //起始地址高字节
  commandBytes[index++]=objInfo.startingAddress;        //起始地址低字节
  
  /*读从站对象*/
  if((objInfo.functionCode>=ReadCoilStatus)&&(objInfo.functionCode <= ReadInputStatus))
  {
    commandBytes[index++]=objInfo.quantity>>8;
    commandBytes[index++]=objInfo.quantity;
  }
  
  /*写单个线圈数据对象*/
  if((WriteSingleCoil==objInfo.functionCode)&&(statusList!=NULL))
  {
    commandBytes[index++]=(*statusList)?0xFF:0x00;
    commandBytes[index++]=0x00;
  }
  
  /*写单个寄存器数据对象*/
  if((objInfo.functionCode==WriteSingleRegister)&&(registerList!=NULL))
  {
    commandBytes[index++]=(*registerList)>>8;
    commandBytes[index++]=(*registerList);
  }
  
  /*写多个线圈*/
  if((objInfo.functionCode==WriteMultipleCoil)&&(statusList!=NULL))
  {
    commandBytes[index++]=objInfo.quantity>>8;
    commandBytes[index++]=objInfo.quantity;
    uint8_t byteArray[250];
    uint16_t bytesCount=ConvertBoolArrayToMBByteArray(statusList,objInfo.quantity,byteArray);
    commandBytes[index++]=bytesCount;
    for(int i=0;i<bytesCount;i++)
    {
      commandBytes[index++]=byteArray[i];
    }
  }
  
  /*写多个寄存器*/
  if((objInfo.functionCode==WriteMultipleRegister)&&(registerList!=NULL))
  {
    commandBytes[index++]=objInfo.quantity>>8;		//数量高字节
    commandBytes[index++]=objInfo.quantity;             //数量低字节
    uint8_t byteArray[250];
    uint16_t bytesCount=ConvertRegisterArrayToMBByteArray(registerList,objInfo.quantity,byteArray);
    commandBytes[index++]=bytesCount;		//字节数量
    for(int i=0;i<bytesCount;i++)
    {
      commandBytes[index++]=byteArray[i];
    }
  }
  return index;
}

改成

/*作为RTU主站(TCP客户端)时,生成读写RTU从站(TCP服务器)对象的命令*/
uint16_t GenerateReadWriteCommand(ObjAccessInfo *objInfo,bool *statusList,uint16_t *registerList,uint8_t *commandBytes)
{
  uint16_t index=0;
  commandBytes[index++]=objInfo->unitID;                 //从站地址
  commandBytes[index++]=objInfo->functionCode;           //功能码
  commandBytes[index++]=objInfo->startingAddress>>8;     //起始地址高字节
  commandBytes[index++]=objInfo->startingAddress;        //起始地址低字节
  
  /*读从站对象*/
  if((objInfo->functionCode>=ReadCoilStatus)&&(objInfo->functionCode <= ReadInputRegister))
  {
    commandBytes[index++]=objInfo->quantity>>8;
    commandBytes[index++]=objInfo->quantity;
  }
  
  /*写单个线圈数据对象*/
  if((WriteSingleCoil==objInfo->functionCode)&&(statusList!=NULL))
  {
    commandBytes[index++]=(*statusList)?0xFF:0x00;
    commandBytes[index++]=0x00;
  }
  
  /*写单个寄存器数据对象*/
  if((objInfo->functionCode==WriteSingleRegister)&&(registerList!=NULL))
  {
    commandBytes[index++]=(*registerList)>>8;
    commandBytes[index++]=(*registerList);
  }
  
  /*写多个线圈*/
  if((objInfo->functionCode==WriteMultipleCoil)&&(statusList!=NULL))
  {
    commandBytes[index++]=objInfo->quantity>>8;
    commandBytes[index++]=objInfo->quantity;
    uint8_t byteArray[250];
    uint16_t bytesCount=ConvertBoolArrayToMBByteArray(statusList,objInfo->quantity,byteArray);
    commandBytes[index++]=bytesCount;
    for(int i=0;i<bytesCount;i++)
    {
      commandBytes[index++]=byteArray[i];
    }
  }
  
  /*写多个寄存器*/
  if((objInfo->functionCode==WriteMultipleRegister)&&(registerList!=NULL))
  {
    commandBytes[index++]=objInfo->quantity>>8;		//数量高字节
    commandBytes[index++]=objInfo->quantity;             //数量低字节
    uint8_t byteArray[250];
    uint16_t bytesCount=ConvertRegisterArrayToMBByteArray(registerList,objInfo->quantity,byteArray);
    commandBytes[index++]=bytesCount;		//字节数量
    for(int i=0;i<bytesCount;i++)
    {
      commandBytes[index++]=byteArray[i];
    }
  }
  return index;
}

mbrtu.c

原文

/*生成读写从站数据对象的命令,命令长度包括2个校验字节*/
uint16_t SyntheticReadWriteSlaveCommand(ObjAccessInfo slaveInfo,bool *statusList,uint16_t *registerList,uint8_t *commandBytes)

改成

/*生成读写从站数据对象的命令,命令长度包括2个校验字节*/
uint16_t SyntheticReadWriteSlaveCommand(ObjAccessInfo *slaveInfo,bool *statusList,uint16_t *registerList,uint8_t *commandBytes)

mbrtumaster.c

原文

/*处理读从站状态量返回信息,读线圈状态位0x012功能码*/
static void HandleReadCoilStatusRespond(uint8_t *receivedMesasage,uint16_t startAddress,uint16_t quantity);
/*处理读从站状态量返回信息,读输入状态位0x02功能码*/
static void HandleReadInputStatusRespond(uint8_t *receivedMesasage,uint16_t startAddress,uint16_t quantity);
/*处理读从站寄存器值的返回信息,读保持寄存器0x03功能码)*/
static void HandleReadHoldingRegisterRespond(uint8_t *receivedMesasage,uint16_t startAddress,uint16_t quantity);
/*处理读从站寄存器值的返回信息,读输入寄存器0x04功能码*/
static void HandleReadInputRegisterRespond(uint8_t *receivedMesasage,uint16_t startAddress,uint16_t quantity);
/*判断接收到的信息是否是发送命令的返回信息*/
static bool CheckMessageAgreeWithCommand(uint8_t *recievedMessage,uint8_t *command);

void (*HandleSlaveRespond[])(uint8_t *,uint16_t,uint16_t)={HandleReadCoilStatusRespond,
                                                           HandleReadInputStatusRespond,
                                                           HandleReadHoldingRegisterRespond,
                                                           HandleReadInputRegisterRespond};

改为

/*处理读从站状态量返回信息,读线圈状态位0x012功能码*/
static void HandleReadCoilStatusRespond(uint8_t *receivedMesasage, uint8_t slaveID, uint16_t startAddress, uint16_t quantity);
/*处理读从站状态量返回信息,读输入状态位0x02功能码*/
static void HandleReadInputStatusRespond(uint8_t *receivedMesasage, uint8_t slaveID, uint16_t startAddress, uint16_t quantity);
/*处理读从站寄存器值的返回信息,读保持寄存器0x03功能码)*/
static void HandleReadHoldingRegisterRespond(uint8_t *receivedMesasage, uint8_t slaveID, uint16_t startAddress, uint16_t quantity);
/*处理读从站寄存器值的返回信息,读输入寄存器0x04功能码*/
static void HandleReadInputRegisterRespond(uint8_t *receivedMesasage, uint8_t slaveID, uint16_t startAddress, uint16_t quantity);
/*判断接收到的信息是否是发送命令的返回信息*/
static bool CheckMessageAgreeWithCommand(uint8_t *recievedMessage,uint8_t *command);

void (*HandleSlaveRespond[])(uint8_t *,uint8_t, uint16_t,uint16_t)={HandleReadCoilStatusRespond,
								    HandleReadInputStatusRespond,
								    HandleReadHoldingRegisterRespond,
								    HandleReadInputRegisterRespond};

原文

/*生成访问服务器的命令*/
uint16_t CreateAccessSlaveCommand(ObjAccessInfo objInfo,void *dataList,uint8_t *commandBytes)
{
  uint16_t commandLength=0;
  /*生成读服务器对象的命令,功能码0x01、0x02、0x03、0x04,命令长度12个字节*/
  if((objInfo.functionCode>=ReadCoilStatus)&&(objInfo.functionCode <= ReadInputStatus))
  {
    commandLength=SyntheticReadWriteSlaveCommand(objInfo,NULL,NULL,commandBytes);
    
    AddCommandBytesToList(commandBytes);        /*记录发送的读命令*/
  }

  /*生成预置服务器对象的命令,功能码0x05,0x0F,命令长度随发送数据而变*/
  if((objInfo.functionCode==WriteSingleCoil)&&(objInfo.functionCode==WriteMultipleCoil))
  {
    bool *statusList=(bool*)dataList;
    commandLength=SyntheticReadWriteSlaveCommand(objInfo,statusList,NULL,commandBytes);
  }
  
  /*生成预置服务器对象的命令,功能码0x06,0x10,命令长度随发送数据而变*/
  if((objInfo.functionCode==WriteSingleRegister)&&(objInfo.functionCode==WriteMultipleRegister))
  {
    uint16_t *registerList=(uint16_t*)dataList;
    commandLength=SyntheticReadWriteSlaveCommand(objInfo,NULL,registerList,commandBytes);
  }

  return commandLength;
}

改为

/*生成访问服务器的命令*/
uint16_t CreateAccessSlaveCommand(ObjAccessInfo *objInfo,void *dataList,uint8_t *commandBytes)
{
  uint16_t commandLength=0;
  /*生成读服务器对象的命令,功能码0x01、0x02、0x03、0x04,命令长度12个字节*/
  if((objInfo->functionCode>=ReadCoilStatus)&&(objInfo->functionCode <= ReadInputRegister))
  {
    commandLength=SyntheticReadWriteSlaveCommand(objInfo,NULL,NULL,commandBytes);
    
    AddCommandBytesToList(commandBytes);        /*记录发送的读命令*/
  }

  /*生成预置服务器对象的命令,功能码0x05,0x0F,命令长度随发送数据而变*/
  if((objInfo->functionCode==WriteSingleCoil)&&(objInfo->functionCode==WriteMultipleCoil))
  {
    bool *statusList=(bool*)dataList;
    commandLength=SyntheticReadWriteSlaveCommand(objInfo,statusList,NULL,commandBytes);
  }
  
  /*生成预置服务器对象的命令,功能码0x06,0x10,命令长度随发送数据而变*/
  if((objInfo->functionCode==WriteSingleRegister)&&(objInfo->functionCode==WriteMultipleRegister))
  {
    uint16_t *registerList=(uint16_t*)dataList;
    commandLength=SyntheticReadWriteSlaveCommand(objInfo,NULL,registerList,commandBytes);
  }

  return commandLength;
}

原文

/*解析收到的服务器相应信息*/
void ParsingSlaveRespondMessage(uint8_t *recievedMessage,uint8_t *command)
{
  /*如果不是读操作的反回信息不需要处理*/
  if(recievedMessage[1]>0x04)
  {
    return;
  }

  if(command==NULL)
  {
    /*判断接收到的信息是否有相应的命令*/
    int cmdIndex=FindCommandForRecievedMessage(recievedMessage);
  
    if((cmdIndex<0))
    {
      return;
    }
    command=commandMasterList[cmdIndex];
  }
  
  FunctionCode fuctionCode=(FunctionCode)recievedMessage[1];
  uint16_t startAddress=(uint16_t)command[2];
  startAddress=(startAddress<<8)+(uint16_t)command[3];
  uint16_t quantity=(uint16_t)command[4];
  quantity=(quantity<<8)+(uint16_t)command[5];
  
  if((fuctionCode>=ReadCoilStatus)&&(fuctionCode<=ReadInputRegister))
  {
    HandleSlaveRespond[fuctionCode-1](recievedMessage,startAddress,quantity);
  }
}

改为

/*解析收到的服务器相应信息*/
void ParsingSlaveRespondMessage(uint8_t *recievedMessage,uint8_t *command, uint16_t length)
{
  /*如果不是读操作的反回信息不需要处理*/
  if(recievedMessage[1] > 0x04)return;
	if(CheckRTUMessageIntegrity(recievedMessage,length) == false)return;
  if(command==NULL)
  {
    /*判断接收到的信息是否有相应的命令*/
    int cmdIndex=FindCommandForRecievedMessage(recievedMessage);
  
    if((cmdIndex<0))
    {
      return;
    }
    command=commandMasterList[cmdIndex];
  }
  
  uint8_t slaveID = recievedMessage[0];
  FunctionCode fuctionCode=(FunctionCode)recievedMessage[1];
  uint16_t startAddress=(uint16_t)command[2];
  startAddress=(startAddress<<8)+(uint16_t)command[3];
  uint16_t quantity=(uint16_t)command[4];
  quantity=(quantity<<8)+(uint16_t)command[5];
  
  if((fuctionCode>=ReadCoilStatus)&&(fuctionCode<=ReadInputRegister))
  {
    HandleSlaveRespond[fuctionCode-1](recievedMessage, slaveID, startAddress, quantity);
  }
}

原文

/*处理读从站状态量返回信息,读线圈状态位0x012功能码*/
static void HandleReadCoilStatusRespond(uint8_t *receivedMessage,uint16_t startAddress,uint16_t quantity)
{
  bool coilStatus[256];
  
  TransformClientReceivedData(receivedMessage,quantity,coilStatus,NULL);
  
  UpdateCoilStatus(startAddress,quantity,coilStatus);
}

/*处理读从站状态量返回信息,读输入状态位0x02功能码*/
static void HandleReadInputStatusRespond(uint8_t *receivedMessage,uint16_t startAddress,uint16_t quantity)
{
  bool inputStatus[256];
  
  TransformClientReceivedData(receivedMessage,quantity,inputStatus,NULL);
  
  UpdateInputStatus(startAddress,quantity,inputStatus);
}

/*处理读从站寄存器值的返回信息,读保持寄存器0x03功能码)*/
static void HandleReadHoldingRegisterRespond(uint8_t *receivedMessage,uint16_t startAddress,uint16_t quantity)
{
  uint16_t holdingRegister[125];
  
  TransformClientReceivedData(receivedMessage,quantity,NULL,holdingRegister);
  
  UpdateHoldingRegister(startAddress,quantity,holdingRegister);
}

/*处理读从站寄存器值的返回信息,读输入寄存器0x04功能码*/
static void HandleReadInputRegisterRespond(uint8_t *receivedMessage,uint16_t startAddress,uint16_t quantity)
{
  uint16_t inputRegister[125];
  
  TransformClientReceivedData(receivedMessage,quantity,NULL,inputRegister);
  
  UpdateInputResgister(startAddress,quantity,inputRegister);
}

改为

/*处理读从站状态量返回信息,读线圈状态位0x012功能码*/
static void HandleReadCoilStatusRespond(uint8_t *receivedMessage, uint8_t slaveID, uint16_t startAddress,uint16_t quantity)
{
  bool coilStatus[256];
  
  TransformClientReceivedData(receivedMessage,quantity,coilStatus,NULL);
  
  UpdateCoilStatus(startAddress,quantity,coilStatus);
}

/*处理读从站状态量返回信息,读输入状态位0x02功能码*/
static void HandleReadInputStatusRespond(uint8_t *receivedMessage, uint8_t slaveID, uint16_t startAddress,uint16_t quantity)
{
  bool inputStatus[256];
  
  TransformClientReceivedData(receivedMessage,quantity,inputStatus,NULL);
  
  UpdateInputStatus(startAddress,quantity,inputStatus);
}

/*处理读从站寄存器值的返回信息,读保持寄存器0x03功能码)*/
static void HandleReadHoldingRegisterRespond(uint8_t *receivedMessage, uint8_t slaveID, uint16_t startAddress, uint16_t quantity)
{
  uint16_t holdingRegister[125];
  
  TransformClientReceivedData(receivedMessage,quantity,NULL,holdingRegister);
  
  UpdateHoldingRegister(startAddress,quantity,holdingRegister);
}

/*处理读从站寄存器值的返回信息,读输入寄存器0x04功能码*/
static void HandleReadInputRegisterRespond(uint8_t *receivedMessage, uint8_t slaveID, uint16_t startAddress, uint16_t quantity)
{
  uint16_t inputRegister[125];
  
  TransformClientReceivedData(receivedMessage,quantity,NULL,inputRegister);
  
  UpdateInputResgister(startAddress,quantity,inputRegister);
}

mbtcp.c

原文

/*生成读写服务器对象的命令*/
uint16_t SyntheticReadWriteTCPServerCommand(ObjAccessInfo objInfo,bool *statusList,uint16_t *registerList,uint8_t *commandBytes)

改为

/*生成读写服务器对象的命令*/
uint16_t SyntheticReadWriteTCPServerCommand(ObjAccessInfo *objInfo,bool *statusList,uint16_t *registerList,uint8_t *commandBytes)

mbtcpclient.c

原文

/*生成访问服务器的命令*/
uint16_t CreateAccessServerCommand(ObjAccessInfo objInfo,void *dataList,uint8_t *commandBytes)
{
  uint16_t commandLength=0;
  /*生成读服务器对象的命令,功能码0x01、0x02、0x03、0x04,命令长度12个字节*/
  if((objInfo.functionCode>=ReadCoilStatus)&&(objInfo.functionCode <= ReadInputStatus))
  {
    commandLength=SyntheticReadWriteTCPServerCommand(objInfo,NULL,NULL,commandBytes);
    
    AddCommandBytesToList(commandBytes);        /*记录发送的读命令*/
  }

  /*生成预置服务器对象的命令,功能码0x05,0x0F,命令长度随发送数据而变*/
  if((objInfo.functionCode==WriteSingleCoil)&&(objInfo.functionCode==WriteMultipleCoil))
  {
    bool *statusList=(bool*)dataList;
    commandLength=SyntheticReadWriteTCPServerCommand(objInfo,statusList,NULL,commandBytes);
  }
  
  /*生成预置服务器对象的命令,功能码0x06,0x10,命令长度随发送数据而变*/
  if((objInfo.functionCode==WriteSingleRegister)&&(objInfo.functionCode==WriteMultipleRegister))
  {
    uint16_t *registerList=(uint16_t*)dataList;
    commandLength=SyntheticReadWriteTCPServerCommand(objInfo,NULL,registerList,commandBytes);
  }

  return commandLength;
}

改为

/*生成访问服务器的命令*/
uint16_t CreateAccessServerCommand(ObjAccessInfo *objInfo,void *dataList,uint8_t *commandBytes)
{
  uint16_t commandLength=0;
  /*生成读服务器对象的命令,功能码0x01、0x02、0x03、0x04,命令长度12个字节*/
  if((objInfo->functionCode>=ReadCoilStatus)&&(objInfo->functionCode <= ReadInputStatus))
  {
    commandLength=SyntheticReadWriteTCPServerCommand(objInfo,NULL,NULL,commandBytes);
    
    AddCommandBytesToList(commandBytes);        /*记录发送的读命令*/
  }

  /*生成预置服务器对象的命令,功能码0x05,0x0F,命令长度随发送数据而变*/
  if((objInfo->functionCode==WriteSingleCoil)&&(objInfo->functionCode==WriteMultipleCoil))
  {
    bool *statusList=(bool*)dataList;
    commandLength=SyntheticReadWriteTCPServerCommand(objInfo,statusList,NULL,commandBytes);
  }
  
  /*生成预置服务器对象的命令,功能码0x06,0x10,命令长度随发送数据而变*/
  if((objInfo->functionCode==WriteSingleRegister)&&(objInfo->functionCode==WriteMultipleRegister))
  {
    uint16_t *registerList=(uint16_t*)dataList;
    commandLength=SyntheticReadWriteTCPServerCommand(objInfo,NULL,registerList,commandBytes);
  }

  return commandLength;
}

至此库文件改完了。我再主程序里创建了一个任务来跑主站代码,如下

bspmodbus.c

#include "bsp_modbus.h"
#include "bsp_init.h"

Modbus_Rev_Type Modbus_Rev_Info;

void Bsp_Modbus_Send(uint8_t *pdata, uint16_t len)
{
	while(len--)
	{
		while((HAL_USART_Modbus.Instance->ISR & UART_FLAG_TC) == 0);
		HAL_USART_Modbus.Instance->TDR = (*pdata++ & (uint8_t)0xFF);
	}
}

#if MB_RTU_MASTER_ENABLED

/*************************************************
 * @author: mark.zhu
 * @param:
 * @function: This function requires timing (100ms) to be called 
*************************************************/
void Bsp_ModbusRTUMaster_Poll(void)
{
	uint16_t adu_len = 0;
	uint8_t  adu_buf[255];
	ObjAccessInfo objInfo;
	
	objInfo.unitID = 1; 
	objInfo.functionCode = ReadHoldingRegister;
	objInfo.startingAddress = 0;
	objInfo.quantity = 4;
	
	adu_len = CreateAccessSlaveCommand(&objInfo, NULL, adu_buf);
	Bsp_Modbus_Send(adu_buf, adu_len);
}

#endif

bsp_modbus.h

#ifndef __BSP_MODBUS_H__
#define __BSP_MODBUS_H__

/*************************************************
 * @author: mark.zhu
 * @param: include file
 * @function: config modbus params
*************************************************/
#include "mbconfig.h"

typedef struct
{
	uint8_t Buffer[255];
	uint16_t Count;
	uint8_t BaseTime;
}Modbus_Rev_Type;

extern Modbus_Rev_Type Modbus_Rev_Info;

void Bsp_ModbusRTUMaster_Poll(void);

#endif

bsp_isr.c

#include "bsp_init.h"
#include "bsp_modbus.h"

/*************************************************
 * @author: mark.zhu
 * @param: null
 * @function: Period elapsed callback in non blocking mode
*************************************************/
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
	if(Modbus_Rev_Info.BaseTime)
	{
		Modbus_Rev_Info.BaseTime--;
		if(Modbus_Rev_Info.BaseTime == 0)
		{
			ParsingSlaveRespondMessage(Modbus_Rev_Info.Buffer, NULL, Modbus_Rev_Info.Count);
			Modbus_Rev_Info.Count = 0;
		}
	}
}

/*************************************************
 * @author: mark.zhu
 * @param: null
 * @function: Rx Transfer completed callback
*************************************************/
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	uint8_t rev;
	if(__HAL_UART_GET_FLAG(&HAL_USART_Modbus,UART_FLAG_ORE))
	{
		rev = HAL_USART_Modbus.Instance->RDR;
		__HAL_UART_CLEAR_FLAG(&HAL_USART_Modbus,UART_FLAG_ORE);
	}
	if(__HAL_UART_GET_FLAG(&HAL_USART_Modbus, UART_FLAG_RXNE)!= RESET) 
	{
		rev = HAL_USART_Modbus.Instance->RDR;
		Modbus_Rev_Info.Buffer[Modbus_Rev_Info.Count++] = rev;
		Modbus_Rev_Info.BaseTime = 3;
	}
}	

main.c

/* Includes ------------------------------------------------------------------*/
#include "bsp_init.h"
#include "bsp_modbus.h"
#include "cmsis_os.h"

/* Private variables ---------------------------------------------------------*/
osThreadId ModbusPollTaskHandle;

/* Private function prototypes -----------------------------------------------*/
void StartModbusPollTask(void const * argument);

int main(void)
{
  /* MCU Configuration----------------------------------------------------------*/
	Bsp_Peripherals_Init();
	
  /* add mutexes, ... */

  /* add semaphores, ... */

  /* start timers, add new ones, ... */

  /* Create the thread(s) */
  /* definition and creation of defaultTask */
  osThreadDef(ModbusPollTask, StartModbusPollTask, osPriorityNormal, 0, 128);
  ModbusPollTaskHandle = osThreadCreate(osThread(ModbusPollTask), NULL);

  /* USER CODE BEGIN RTOS_THREADS */
  /* add threads, ... */
  /* USER CODE END RTOS_THREADS */

  /* USER CODE BEGIN RTOS_QUEUES */
  /* add queues, ... */
  /* USER CODE END RTOS_QUEUES */
 

  /* Start scheduler */
  osKernelStart();
  
  /* We should never get here as control is now taken by the scheduler */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
  /* USER CODE END WHILE */

  /* USER CODE BEGIN 3 */

  }
  /* USER CODE END 3 */

}

/* StartModbusPollTask function */
void StartModbusPollTask(void const * argument)
{
  /* USER CODE BEGIN 5 */
  /* Infinite loop */
  for(;;)
  {
    Bsp_ModbusRTUMaster_Poll();
    osDelay(300);
  }
  /* USER CODE END 5 */ 
}

/**
  * @brief  This function is executed in case of error occurrence.
  * @param  None
  * @retval None
  */
void _Error_Handler(char * file, int line)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */
  while(1) 
  {
  }
  /* USER CODE END Error_Handler_Debug */ 
}

#ifdef USE_FULL_ASSERT

/**
   * @brief Reports the name of the source file and the source line number
   * where the assert_param error has occurred.
   * @param file: pointer to the source file name
   * @param line: assert_param error line source number
   * @retval None
   */
void assert_failed(uint8_t* file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
    ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */

}

#endif

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

另外mbconfig.h的配置如下

/******************************************************************************/
/** 模块名称:Modbus通讯                                                     **/
/** 文件名称:mbconfig.h                                                     **/
/** 版    本:V1.0.0                                                         **/
/** 简    介:用于配置Modbus协议栈使用的相关定义                             **/
/**--------------------------------------------------------------------------**/
/** 修改记录:                                                               **/
/**     版本      日期              作者              说明                   **/
/**     V1.0.0  2015-07-18          尹家军            创建文件               **/
/**                                                                          **/
/******************************************************************************/ 


#ifndef _MB_CONFIG_H
#define _MB_CONFIG_H

/*定义是否使能RTU主站功能,0为禁用,1为使能*/
#define MB_RTU_MASTER_ENABLED		(1)

/*定义是否使能RTU从站功能,0为禁用,1为使能*/
#define MB_RTU_SLAVE_ENABLED		(1)

/*定义是否使能ASCII主站功能,0为禁用,1为使能*/
#define MB_ACSII_MASTER_ENABLED		(0)

/*定义是否使能ASCII从站功能,0为禁用,1为使能*/
#define MB_ASCII_SLAVE_ENABLED		(0)

/*定义是否使能TCP服务器功能,0为禁用,1为使能*/
#define MB_TCP_SERVER_ENABLED		(0)

/*定义是否使能TCP客户端功能,0为禁用,1为使能*/
#define MB_TCP_CLIENT_ENABLED		(0)

#if MB_RTU_MASTER_ENABLED > (0)
#include "mbrtumaster.h"
#endif

#if MB_RTU_SLAVE_ENABLED > (0)
#include "mbrtuslave.h"
#endif

#if MB_TCP_CLIENT_ENABLED > (0)
#include "mbtcpclient.h"
#endif

#if MB_TCP_SERVER_ENABLED > (0)
#include "mbtcpserver.h"
#endif

#include "mbcommon.h"

#endif
/*********** (C) COPYRIGHT 1999-2016 Moonan Technology *********END OF FILE****/

猜你喜欢

转载自blog.csdn.net/zhushengbing_csdn/article/details/80838473