1.准备模板

打开雅特力官网,也就是带有LwIP的示例。

下载官方源码:modbus

2.移植

我这里是在这里新建两个文件夹,分别是modbus与port,这个任意,只需要将必要的文件加入项目即可。

将源码中的modbus这些都移植过来,分别是实现,头文件、以及tcp相关的文件。其余的就不需要了

port文件夹里为:源码->demo->MCF5235TCP->port。

接下来将这些文件加入工程。加入头文件

编译后,发现有12个错误

3.依次解决:

1.打开mbconfig.h

确保,我是本来就这样,所以可能就只有12个错误,如果不是这样可能之前编译的错误更多。

2.打开port.h

这里我就关闭tcp_debug了。

3.打开portevent.c

没有定义,自己定义一下,然后这里的sys_mbox_ne()这个函数定义已经发生了改变。按照途中修改,后续报警的xMailBox加上&符号,

4.打开portother.c

删掉多余的这个三个

编译,发现还有五个错误

1.打开porttcp.c

报错说没有memcpy,那么我们加入头文件

还有这个错误,我们ctrl+h寻找,发现定义在portother.c文件里

复制并放在port.h中:

2.突然又发现少个宏定义,很离谱,我之前移植的时候没有少过

是这个宏

拷贝,并放到mbconfig.h文件中:

#ifndef MB_ASCII_TIMEOUT_WAIT_BEFORE_SEND_MS
#define MB_ASCII_TIMEOUT_WAIT_BEFORE_SEND_MS    ( 0 )
#endif

不过我记得我之前没有这个问题。

再次编译:

我出现了以下五个错误

我的main.c为:

/**
  **************************************************************************
  * @file     main.c
  * @version  v2.0.6
  * @date     2022-03-11
  * @brief    main program
  **************************************************************************
  *                       Copyright notice & Disclaimer
  *
  * The software Board Support Package (BSP) that is made available to 
  * download from Artery official website is the copyrighted work of Artery. 
  * Artery authorizes customers to use, copy, and distribute the BSP 
  * software and its related documentation for the purpose of design and 
  * development in conjunction with Artery microcontrollers. Use of the 
  * software is governed by this copyright notice and the following disclaimer.
  *
  * THIS SOFTWARE IS PROVIDED ON "AS IS" BASIS WITHOUT WARRANTIES,
  * GUARANTEES OR REPRESENTATIONS OF ANY KIND. ARTERY EXPRESSLY DISCLAIMS,
  * TO THE FULLEST EXTENT PERMITTED BY LAW, ALL EXPRESS, IMPLIED OR
  * STATUTORY OR OTHER WARRANTIES, GUARANTEES OR REPRESENTATIONS,
  * INCLUDING BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
  * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
  *
  **************************************************************************
  */

#include "at32f435_437_board.h"
#include "at32f435_437_clock.h"
#include "at32_emac.h"
#include "stdio.h"
#include "FreeRTOS.h"
#include "task.h"

#include "lwip/api.h"
#include "lwip/sys.h"
/*FreeModBus*/
#include "mb.h"
#include "mbutils.h"


/* ----------------------- Defines ------------------------------------------*/
#define PROG                    "FreeModbus"

//输入寄存器起始地址
#define REG_INPUT_START       0x0000
//输入寄存器数量
#define REG_INPUT_NREGS       8
//保持寄存器起始地址
#define REG_HOLDING_START     0x0000
//保持寄存器数量
#define REG_HOLDING_NREGS     8

//线圈起始地址
#define REG_COILS_START       0x0000
//线圈数量
#define REG_COILS_SIZE        16

//开关寄存器起始地址
#define REG_DISCRETE_START    0x0000
//开关寄存器数量
#define REG_DISCRETE_SIZE     16

/* Private variables ---------------------------------------------------------*/
//输入寄存器内容
uint16_t usRegInputBuf[REG_INPUT_NREGS] = {0x1000,0x1001,0x1002,0x1003,0x1004,0x1005,0x1006,0x1007};
//输入寄存器起始地址
uint16_t usRegInputStart = REG_INPUT_START;

//保持寄存器内容
uint16_t usRegHoldingBuf[REG_HOLDING_NREGS] = {0x147b,0x3f8e,0x147b,0x400e,0x1eb8,0x4055,0x147b,0x408e};
//保持寄存器起始地址
uint16_t usRegHoldingStart = REG_HOLDING_START;

//线圈状态
uint8_t ucRegCoilsBuf[REG_COILS_SIZE / 8] = {0x0f,0x02};
//开关输入状态
uint8_t ucRegDiscreteBuf[REG_DISCRETE_SIZE / 8] = {0x0f,0x02};
/** @addtogroup UTILITIES_examples
  * @{
  */
  /*开始任务*/
TaskHandle_t StartTask_Handler;
void start_task(void *pvParameters);
/** @addtogroup FreeRTOS_demo
  * @{
  */
extern void tcpip_stack_init(void);
extern void udpecho_init(void);
extern void tcpecho_init(void);

TaskHandle_t network_handler;

/* led3 task */
void network_task_function(void *pvParameters);

/**
  * @brief  main function.
  * @param  none
  * @retval none
  */
int main(void)
{
  nvic_priority_group_config(NVIC_PRIORITY_GROUP_4);
  
  system_clock_config();
  
  /* init led2*/
  at32_led_init(LED2);
  /* init led3*/
  at32_led_init(LED3);
  /* init led4*/
  at32_led_init(LED4);
  
  /* init usart1 */
  uart_print_init(115200);
  
  /* enter critical */
  taskENTER_CRITICAL(); 

  
  if(xTaskCreate((TaskFunction_t )network_task_function,     
                 (const char*    )"Network_task",   
                 (uint16_t       )512, 
                 (void*          )NULL,
                 (UBaseType_t    )2,
                 (TaskHandle_t*  )&network_handler) != pdPASS)
  {
    printf("Network task could not be created as there was insufficient heap memory remaining.\r\n");
  }        
  else
  {
    printf("Network task was created successfully.\r\n");
  }
  
  /* exit critical */            
  taskEXIT_CRITICAL();      
              
  /* start scheduler */            
  vTaskStartScheduler(); 
  
}

static void modbustcp_thread(void *arg)
{	
	LWIP_UNUSED_ARG(arg);
	eMBErrorCode    xStatus;
	eMBTCPInit( MB_TCP_PORT_USE_DEFAULT );
	eMBEnable();
	while(1)
	{
		eMBPoll();
		vTaskDelay(5);
	}
		/* An error occured. Maybe we can restart. */
//		( void )eMBDisable(  );
//		( void )eMBClose(  );
	//}
}


void modbustcp_init(void)
{
  sys_thread_new("modbustcp_thread", modbustcp_thread, NULL, 512, 4);
}

/* led3 task function */
void network_task_function(void *pvParameters)
{
  while(emac_system_init() == ERROR);
  tcpip_stack_init();
	modbustcp_init();
  taskENTER_CRITICAL();           //进入临界区
  vTaskDelete(StartTask_Handler); //删除开始任务
  taskEXIT_CRITICAL();            //退出临界区
}

/**
  * @}
  */ 

/****************************************************************************
* 名	  称:eMBRegInputCB 
* 功    能:读取输入寄存器,对应功能码是 04 eMBFuncReadInputRegister
* 入口参数:pucRegBuffer: 数据缓存区,用于响应主机   
*						usAddress: 寄存器地址
*						usNRegs: 要读取的寄存器个数
* 出口参数:
* 注	  意:上位机发来的 帧格式是: SlaveAddr(1 Byte)+FuncCode(1 Byte)
*								+StartAddrHiByte(1 Byte)+StartAddrLoByte(1 Byte)
*								+LenAddrHiByte(1 Byte)+LenAddrLoByte(1 Byte)+
*								+CRCAddrHiByte(1 Byte)+CRCAddrLoByte(1 Byte)
*							3 区
****************************************************************************/
eMBErrorCode
eMBRegInputCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs )
{
    eMBErrorCode    eStatus = MB_ENOERR;
    int             iRegIndex;

    /* it already plus one in modbus function method. */
    usAddress--;
    if( ( usAddress >= REG_INPUT_START )
        && ( usAddress + usNRegs <= REG_INPUT_START + REG_INPUT_NREGS ) )
    {
        iRegIndex = ( int )( usAddress - usRegInputStart );
        while( usNRegs > 0 )
        {
            *pucRegBuffer++ = ( UCHAR )( usRegInputBuf[iRegIndex] >> 8 );
            *pucRegBuffer++ = ( UCHAR )( usRegInputBuf[iRegIndex] & 0xFF );
            iRegIndex++;
            usNRegs--;
        }
    }
    else
    {
        eStatus = MB_ENOREG;
    }

    return eStatus;
}

/****************************************************************************
* 名	  称:eMBRegHoldingCB 
* 功    能:对应功能码有:06 写保持寄存器 eMBFuncWriteHoldingRegister 
*													16 写多个保持寄存器 eMBFuncWriteMultipleHoldingRegister
*													03 读保持寄存器 eMBFuncReadHoldingRegister
*													23 读写多个保持寄存器 eMBFuncReadWriteMultipleHoldingRegister
* 入口参数:pucRegBuffer: 数据缓存区,用于响应主机   
*						usAddress: 寄存器地址
*						usNRegs: 要读写的寄存器个数
*						eMode: 功能码
* 出口参数:
* 注	  意:4 区
****************************************************************************/
eMBErrorCode
eMBRegHoldingCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs, eMBRegisterMode eMode )
{
	eMBErrorCode    eStatus = MB_ENOERR;
	int             iRegIndex;

    /* it already plus one in modbus function method. */
    usAddress--;
	if((usAddress >= REG_HOLDING_START)&&\
		((usAddress+usNRegs) <= (REG_HOLDING_START + REG_HOLDING_NREGS)))
	{
		iRegIndex = (int)(usAddress - usRegHoldingStart);
		switch(eMode)
		{                                       
			case MB_REG_READ://读 MB_REG_READ = 0
        while(usNRegs > 0)
				{
					*pucRegBuffer++ = (u8)(usRegHoldingBuf[iRegIndex] >> 8);            
					*pucRegBuffer++ = (u8)(usRegHoldingBuf[iRegIndex] & 0xFF); 
          iRegIndex++;
          usNRegs--;					
				}                            
        break;
			case MB_REG_WRITE://写 MB_REG_WRITE = 0
				while(usNRegs > 0)
				{         
					usRegHoldingBuf[iRegIndex] = *pucRegBuffer++ << 8;
          usRegHoldingBuf[iRegIndex] |= *pucRegBuffer++;
          iRegIndex++;
          usNRegs--;
        }				
			}
	}
	else//错误
	{
		eStatus = MB_ENOREG;
	}	
	
	return eStatus;
}

extern void xMBUtilSetBits( UCHAR * ucByteBuf, USHORT usBitOffset, UCHAR ucNBits,
                UCHAR ucValue );
extern UCHAR xMBUtilGetBits( UCHAR * ucByteBuf, USHORT usBitOffset, UCHAR ucNBits );
/****************************************************************************
* 名	  称:eMBRegCoilsCB 
* 功    能:对应功能码有:01 读线圈 eMBFuncReadCoils
*													05 写线圈 eMBFuncWriteCoil
*													15 写多个线圈 eMBFuncWriteMultipleCoils
* 入口参数:pucRegBuffer: 数据缓存区,用于响应主机   
*						usAddress: 线圈地址
*						usNCoils: 要读写的线圈个数
*						eMode: 功能码
* 出口参数:
* 注	  意:如继电器 
*						0 区
****************************************************************************/
eMBErrorCode
eMBRegCoilsCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNCoils,
              eMBRegisterMode eMode )
{
  //错误状态
  eMBErrorCode eStatus = MB_ENOERR;
  //寄存器个数
  int16_t iNCoils = ( int16_t )usNCoils;
  //寄存器偏移量
  int16_t usBitOffset;
  
    /* it already plus one in modbus function method. */
    usAddress--;
  //检查寄存器是否在指定范围内
  if( ( (int16_t)usAddress >= REG_COILS_START ) &&
     ( usAddress + usNCoils <= REG_COILS_START + REG_COILS_SIZE ) )
  {
    //计算寄存器偏移量
    usBitOffset = ( int16_t )( usAddress - REG_COILS_START );
    switch ( eMode )
    {
      //读操作
    case MB_REG_READ:
      while( iNCoils > 0 )
      {
        *pucRegBuffer++ = xMBUtilGetBits( ucRegCoilsBuf, usBitOffset,
                                         ( uint8_t )( iNCoils > 8 ? 8 : iNCoils ) );
        iNCoils -= 8;
        usBitOffset += 8;
      }
      break;
      
      //写操作
    case MB_REG_WRITE:
      while( iNCoils > 0 )
      {
        xMBUtilSetBits( ucRegCoilsBuf, usBitOffset,
                       ( uint8_t )( iNCoils > 8 ? 8 : iNCoils ),
                       *pucRegBuffer++ );
        iNCoils -= 8;
      }
      break;
    }
    
  }
  else
  {
    eStatus = MB_ENOREG;
  }
  return eStatus;
}

/****************************************************************************
* 名	  称:eMBRegDiscreteCB 
* 功    能:读取离散寄存器,对应功能码有:02 读离散寄存器 eMBFuncReadDiscreteInputs
* 入口参数:pucRegBuffer: 数据缓存区,用于响应主机   
*						usAddress: 寄存器地址
*						usNDiscrete: 要读取的寄存器个数
* 出口参数:
* 注	  意:1 区
****************************************************************************/
eMBErrorCode
eMBRegDiscreteCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNDiscrete )
{
  //错误状态
  eMBErrorCode eStatus = MB_ENOERR;
  //操作寄存器个数
  int16_t iNDiscrete = ( int16_t )usNDiscrete;
  //偏移量
  uint16_t usBitOffset;
     /* it already plus one in modbus function method. */
    usAddress--; 
  //判断寄存器时候再制定范围内
  if( ( (int16_t)usAddress >= REG_DISCRETE_START ) &&
     ( usAddress + usNDiscrete <= REG_DISCRETE_START + REG_DISCRETE_SIZE ) )
  {
    //获得偏移量
    usBitOffset = ( uint16_t )( usAddress - REG_DISCRETE_START );
    
    while( iNDiscrete > 0 )
    {
      *pucRegBuffer++ = xMBUtilGetBits( ucRegDiscreteBuf, usBitOffset,
                                       ( uint8_t)( iNDiscrete > 8 ? 8 : iNDiscrete ) );
      iNDiscrete -= 8;
      usBitOffset += 8;
    }
    
  }
  else
  {
    eStatus = MB_ENOREG;
  }
  return eStatus;
}
/**
  * @}
  */ 

    usAddress--;每一个都有这个是因为在modbus内部处理的时候,会将地址+1,从1开始。所以读数组的时候,会出现问题。

现在再次编译:

我们按照指示,打开mbutils.c

void __aeabi_assert(const char *expr, const char *file, int line) {
    // 打印断言失败信息(根据需要修改,如输出到串口、LCD等)

    // 断言失败后的处理(如停机、复位等)
    while (1);  // 死循环,防止程序继续运行
    // 或调用复位函数(根据芯片型号,如 NVIC_SystemReset())
}

加入后,编译通过,下载:

打开tcpip_stack_init();函数,发现绑定ip为172.31.96.101.我的eMBTCPInit( MB_TCP_PORT_USE_DEFAULT );为默认502.

发送数据:读取8个数据:收到回应。

更多推荐