[HAL library] STM32CubeMX development----STM32F407----LAN8720A----transplant FreeModbus to realize ModbusTCP


foreword

In this experiment, the STM32F407VET6 chip is used as the MCU, and a 25MHz external clock source is used.
The Ethernet PHY layer chip is LAN8720A, and FreeModbus is transplanted to realize ModbusTCP network port communication.
Refer to the article for specific content: [HAL library] STM32CubeMX development----STM32F407----ETH+LAN8720A+LWIP----ping

This time transplant the TCP function in FreeModbus, as a client (slave), and realize the network port TCP-Modbus communication.

1. FreeModbus source code download

FreeModbus source code download link: https://www.embedded-experts.at/en/freemodbus-downloads/

click to download
insert image description here

The source code package is as follows:

insert image description here

2. Transplant FreeModbus source code----create new TCP function file

In this experiment, to realize the TCP function of FreeModbus, create a new FreeModbus_TCP folder, and transplant all the required files. The specific files are as follows:

step 1

Open the freemodbus-v1.6 folder and click the modbus folder.

insert image description here

step 2

Migrate all the files in the modbus folder to the newly created FreeModbus_TCP folder.
insert image description here

step 3

Transplant the port file in freemodbus-v1.6\demo\STR71XTCP to the newly created FreeModbus_TCP folder.

insert image description here

step 4

The final result of transplantation, the content of the newly created FreeModbus_TCP folder is as follows:

insert image description here

3. Transplant FreeModbus source code ---- TCP function files are transplanted into STM32 project files.

This time, the STM32F407 project that can achieve Ethernet ping is used.
Project source code: STM32F407-ETH+LAN8720A+LWIP-no operating system-ping----program source code

step 1

Copy the FreeModbus_TCP folder to the project file.

insert image description here

step 2

Use keil5 to open the project and import the files in the FreeModbus_TCP folder.

insert image description here

Select all .c files in the functions folder in the FreeModbus_TCP folder.

insert image description here

Select all .c files of the port folder in the FreeModbus_TCP folder.

insert image description here
Select all .c files of the tcp folder in the FreeModbus_TCP folder. Select the mb.c file in the FreeModbus_TCP folder.
insert image description here

insert image description here

The final result is as follows

insert image description here
insert image description here

step 3

Click the magic wand , select C/C++ , and add the file path .

insert image description here

add file path

insert image description here

Add the result as follows

insert image description here
Compile the program, there will be some errors, edit the program below to eliminate the errors.

4. Transplant FreeModbus source code----editing program

Step 1: Modify mbconfig.h

Turn off MB_ASCII and MB_RTU, and turn on MB_TCP .

insert image description here

Step 2: Modify port.h

Comment out line 27: #include "71x_type.h" .
Open the comments from line 39 to line 46.
The specific code is as follows:

insert image description here

Step 3: Modify portevent.c

Replace the original program with the following program.

/* ----------------------- Modbus includes ----------------------------------*/
#include "mb.h"
#include "mbport.h"

/* ----------------------- Variables ----------------------------------------*/
static eMBEventType eQueuedEvent;
static BOOL     xEventInQueue;

/* ----------------------- Start implementation -----------------------------*/
BOOL
xMBPortEventInit( void )
{
    
    
    xEventInQueue = FALSE;
    return TRUE;
}

BOOL
xMBPortEventPost( eMBEventType eEvent )
{
    
    
    xEventInQueue = TRUE;
    eQueuedEvent = eEvent;
    return TRUE;
}

BOOL
xMBPortEventGet( eMBEventType * eEvent )
{
    
    
    BOOL            xEventHappened = FALSE;

    if( xEventInQueue )
    {
    
    
        *eEvent = eQueuedEvent;
        xEventInQueue = FALSE;
        xEventHappened = TRUE;
    }
    return xEventHappened;
}

Step 4: Modify porttcp.c

On line 24, add #include "string.h" .
On line 43, add #define NETCONN_COPY 0x01 .

insert image description here

Comment out vPortEnterCritical( ); on lines 120 and 135 .

insert image description here
Comment out vMBPortEventClose( ); on line 148 .
insert image description here

Step 5: Modify mb.c

Comment out ENTER_CRITICAL_SECTION( ); on line 232 . Comment out EXIT_CRITICAL_SECTION( );
on line 261 .

insert image description here

Step 6: Create a new file

User_modbus_TCP.c file

#include <stdio.h>
#include <string.h>
#include "User_modbus_TCP.h"
#include "mb.h"
#include "mbutils.h"

void ModbusTCPInit(void)
{
    
    
    eMBTCPInit(MODBUS_TCP_PORT);
    eMBEnable();
}

void ModbusTCPDeInit(void)
{
    
    
    eMBDisable();
    eMBClose();
}

void ModbusTCPMain(void)
{
    
    
    if (MB_ENOERR != eMBPoll())
    {
    
    
        ModbusTCPDeInit();
        ModbusTCPInit();
    }
}

//线圈
#define REG_Coils_START   1
#define REG_Coils_SIZE    10

uint8_t  Coils_Data[REG_Coils_SIZE] = {
    
    1,1,0,1,0,0,1,1,1,0};

/**
 * @brief: 读线圈---01,写线圈---05
 *
 * @param pucRegBuffer  缓存指针
 * @param usAddress     起始地址
 * @param usNCoils      线圈数量
 * @param eMode         读写模式
 * @return eMBErrorCode 错误码
 */
eMBErrorCode eMBRegCoilsCB(UCHAR *pucRegBuffer, USHORT usAddress, USHORT usNCoils, eMBRegisterMode eMode)
{
    
    
    uint16_t i = 0,byteOffset=0,bitOffset=0,RegIndex = usAddress - REG_Coils_START-1;
    if ((usAddress >= REG_Coils_START)&&(usAddress + usNCoils <= REG_Coils_START + REG_Coils_SIZE+1))
    {
    
    
        if (MB_REG_READ == eMode)
        {
    
    
          for(i=0;i<usNCoils;i++)
          {
    
    
              byteOffset = i / 8;
              bitOffset = i % 8;
              xMBUtilSetBits(&pucRegBuffer[byteOffset], bitOffset, 1, Coils_Data[RegIndex+i]);
          }
        }
        else
        {
    
    
          for(i=0;i<usNCoils;i++)
          {
    
    
              byteOffset = i / 8;
              bitOffset = i % 8;
              Coils_Data[RegIndex+i]=xMBUtilGetBits(&pucRegBuffer[byteOffset], bitOffset, 1);
          }
        }
    }
    else
    {
    
    
        return MB_ENOREG;
    }
    
    return MB_ENOERR;
}

 //离散寄存器
#define REG_DISCRETE_START   10
#define REG_DISCRETE_SIZE    20

uint8_t  Discrete_Data[REG_DISCRETE_SIZE] = {
    
    1,1,0,1,0,0,1,1,1,0,1,0,0,1};

/**
 * @brief:读离散寄存器---02
 *
 * @param pucRegBuffer  缓存指针
 * @param usAddress     起始地址
 * @param usNDiscrete   寄存器个数
 * @return eMBErrorCode 返回错误码
 */
eMBErrorCode eMBRegDiscreteCB(UCHAR *pucRegBuffer, USHORT usAddress, USHORT usNDiscrete)
{
    
    
    uint16_t i = 0,byteOffset=0,bitOffset=0,RegIndex = usAddress - REG_DISCRETE_START-1;
  
    if ((usAddress >= REG_DISCRETE_START)&&(usAddress + usNDiscrete <= REG_DISCRETE_START + REG_DISCRETE_SIZE+1))
    {
    
    
      for(i=0;i<usNDiscrete;i++)
      {
    
    
          byteOffset = i / 8;
          bitOffset = i % 8;
          xMBUtilSetBits(&pucRegBuffer[byteOffset], bitOffset, 1, Discrete_Data[RegIndex+i]);
      }
    }
    else
    {
    
    
        return MB_ENOREG;
    }

    return MB_ENOERR;
}

//保持寄存器
#define REG_HOLDING_REGISTER_START   10
#define REG_HOLDING_REGISTER_SIZE    30

uint16_t  Holding_Data[REG_HOLDING_REGISTER_SIZE] = 
{
    
    0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F,0x10,0x11,0x12};

/**
 * @brief: 读保持寄存器---03,写保持寄存器---06
 *
 * @param pucRegBuffer  缓存指针
 * @param usAddress     起始地址
 * @param usNRegs       寄存器个数
 * @param eMode         读写模式
 * @return eMBErrorCode 返回错误码
 */

eMBErrorCode eMBRegHoldingCB(UCHAR *pucRegBuffer, USHORT usAddress, USHORT usNRegs, eMBRegisterMode eMode)
{
    
    
    uint16_t i = 0,RegIndex = usAddress - REG_HOLDING_REGISTER_START-1;
  
    if ((usAddress >= REG_HOLDING_REGISTER_START )&&(usAddress + usNRegs <= REG_HOLDING_REGISTER_START  + REG_HOLDING_REGISTER_SIZE+1))
    {
    
    
        if (MB_REG_READ == eMode)//读
        {
    
    
          for(i=0;i<usNRegs;i++)
          {
    
    
            pucRegBuffer[i*2] = (UCHAR)(Holding_Data[RegIndex+i]>>8);
            pucRegBuffer[i*2+1] = (UCHAR)Holding_Data[RegIndex+i];
          }
        }
        else//写
        {
    
    
          for(i=0;i<usNRegs;i++)
          {
    
    
            Holding_Data[RegIndex+i]=(pucRegBuffer[i*2]<<8)|(pucRegBuffer[i*2+1]);
          }
        }
    }
    else
    {
    
    
        return MB_ENOREG;
    }

    return MB_ENOERR;
}

//输入寄存器
#define REG_INPUT_REGISTER_START    1
#define REG_INPUT_REGISTER_SIZE    20

uint16_t  Input_Data[REG_DISCRETE_SIZE] = 
{
    
    100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119};
/**
 * @brief: 读输入寄存器---04
 *
 * @param pucRegBuffer  缓存指针
 * @param usAddress     起始地址
 * @param usNRegs       寄存器个数
 * @return eMBErrorCode 返回错误码
 */
eMBErrorCode eMBRegInputCB(UCHAR *pucRegBuffer, USHORT usAddress, USHORT usNRegs)
{
    
    
    uint16_t i = 0,RegIndex = usAddress - REG_INPUT_REGISTER_START-1;
    if ((usAddress >= REG_INPUT_REGISTER_START)&&(usAddress + usNRegs <= REG_INPUT_REGISTER_START + REG_INPUT_REGISTER_SIZE+1))
    {
    
    
        for(i=0;i<usNRegs;i++)
        {
    
    
          pucRegBuffer[i*2] = (UCHAR)(Input_Data[RegIndex+i]>>8);
          pucRegBuffer[i*2+1] = (UCHAR)Input_Data[RegIndex+i];
        }
    }
    else
    {
    
    
        return MB_ENOREG;
    }
    
    return MB_ENOERR;
}

/**********************printf重定向****************************/
//取消ARM的半主机工作模式
#pragma import(__use_no_semihosting)//标准库需要的支持函数                 
struct __FILE 
{
    
     
    int handle; 
}; 
FILE __stdout;       
void _sys_exit(int x) //定义_sys_exit()以避免使用半主机模式
{
    
     
    x = x; 
} 

int fputc(int ch, FILE *f)
{
    
      
    return ch;
}

Need to add printf redirection ( article about printf redirection ), if not added, the program will freeze, I don’t know why, whoever knows, you can comment, thank you very much.

User_modbus_TCP.h file

#ifndef __User_modbbus_TCP_H__
#define	__User_modbbus_TCP_H__

#include "main.h"

#define MODBUS_TCP_PORT 4002

extern void ModbusTCPInit(void);
extern void ModbusTCPMain(void);

#endif

Step 7: Call ModbusTCP in the main function

In the main function initialization, call ModbusTCPInit();
in the main function while running, call ModbusTCPMain();

insert image description here

5. Transplant FreeModbus source code----test verification

Use Modbus Poll software to test the ModbusTCP function.
Modbus Poll Software----Download and Install

Step 1: Open the Modbus Poll software

insert image description here

Step 2: Open the connection configuration window and configure the connection

Click on the menu bar "Connection"->"Connect..." (or press the shortcut key F3) to pop up the connection configuration window.

insert image description here
Select ModbusTCP/IP , then configure the IP address , then select the port , the other times are default values, and then click OK .

insert image description here

Step 3: Configure window information

Click "Setup" -> "Read/Write Definition...", or press the shortcut key F8.

insert image description here

Set the slave address, function code, start address, number of registers and other information, and then click OK.

insert image description here

Step 4: Test Results

Function code 01, read the coil, the test result is consistent with the program.

insert image description here

Function code 02, read discrete register, the test result is consistent with the program.

insert image description here

Function code 03, read the holding register, the test result is consistent with the program.

insert image description here

Function code 04, read the input register, the test result is consistent with the program.

insert image description here


Guess you like

Origin blog.csdn.net/MQ0522/article/details/132011066