基于Freertos与lwip移植FreeModbusTcp协议_freertos+modbustcp-程序员宅基地

技术标签: LWIP  Freertos  arm开发  Freemodbus  

前言:

        本文是在已移植Freertos与lwip的基础项目上对FreeModbusTcp协议的移植步骤讲解,本文不涉及Modbus Tcp相关协议讲解,软硬件开发环境与lwip的移植步骤可参考我之前的一篇文章:基于FreeRTOS的N32G457VEL7之LWIP网络协议栈移植-程序员宅基地


1、获取FreeModbus源码包

下载路径:【免费】freemodbusV1.5&V1.6资源-CSDN文库

本例程是使用了freemodbusV1.6版本

2、将源码拷贝至项目文件夹目录下

①在项目文件夹下新建 freemodbus 文件夹,并在freemodbus 文件夹下新建 port文件夹;

②并将freemodbus源码目录下的modbus文件夹拷贝到freemodbus文件夹下。

3、将freemodbus-v1.6\demo\MCF5235TCP\port下的相关文件拷贝至port文件夹下。由于在上一步中移植的freemodbus\modbus\include文件夹下已存在mbconfig.h文件,所以此处的mbconfig.h文件可以不移植到项目中。

4、将freemodbus-v1.6\demo\MCF5235TCP下的demo.c文件拷贝至freemodbus\modbus下,并修改为mb_callback_tcp.c,同时新建mb_callback_tcp.h文件。

5、在工程中新建FREEMODBUS_TCP分组,并将相关文件添加到工程中。

6、添加freeModbus Tcp头文件到工程中

7、相应修改源代码
①在mbconfig.h中,使能Modbus Tcp,失能ASCII与RTU,同时失能线圈寄存器函数与分离寄存器函数(本例中只实现了输入寄存器函数与保持寄存器函数,所以将未实现的线圈寄存器函数与分离寄存器函数失能)。
/*! \brief If Modbus ASCII support is enabled. */
#define MB_ASCII_ENABLED                        (  0 )

/*! \brief If Modbus RTU support is enabled. */
#define MB_RTU_ENABLED                          (  0 )

/*! \brief If Modbus TCP support is enabled. */
#define MB_TCP_ENABLED                          (  1 )
/*! \brief If the <em>Read Coils</em> function should be enabled. */
#define MB_FUNC_READ_COILS_ENABLED              (  0 )

/*! \brief If the <em>Write Coils</em> function should be enabled. */
#define MB_FUNC_WRITE_COIL_ENABLED              (  0 )

/*! \brief If the <em>Write Multiple Coils</em> function should be enabled. */
#define MB_FUNC_WRITE_MULTIPLE_COILS_ENABLED    (  0 )

/*! \brief If the <em>Read Discrete Inputs</em> function should be enabled. */
#define MB_FUNC_READ_DISCRETE_INPUTS_ENABLED    (  0 )
②在mbport.h中,添加port.h头文件,并声明xMBTCPPortEventInit,vMBTCPPortEventClose,xMBTCPPortEventPost,xMBTCPPortEventGet这些函数。
#include "port.h"

#ifndef _MB_PORT_H
#define _MB_PORT_H

#ifdef __cplusplus
PR_BEGIN_EXTERN_C
#endif
/* ----------------------- Supporting functions -----------------------------*/
BOOL            xMBPortEventInit( void );

BOOL            xMBPortEventPost( eMBEventType eEvent );

BOOL            xMBPortEventGet(  /*@out@ */ eMBEventType * eEvent );

BOOL 			xMBTCPPortEventInit( void );

void 			vMBTCPPortEventClose( void );

BOOL 			xMBTCPPortEventPost( eMBEventType eEvent );

BOOL 			xMBTCPPortEventGet( eMBEventType *eEvent );
③、在port.h中声明接收发送ETH帧时的打印函数prvvMBTCPLogFrame,与临界区函数vMBPortEnterCritical,vMBPortExitCritical。
#define MB_TCP_DEBUG            1       /* Debug output in TCP module. */

#define ENTER_CRITICAL_SECTION( )   vMBPortEnterCritical()
#define EXIT_CRITICAL_SECTION( )    vMBPortExitCritical()
/* ----------------------- Type definitions ---------------------------------*/
/* ----------------------- Function prototypes ------------------------------*/
#ifdef MB_TCP_DEBUG
void            vMBPortLog( eMBPortLogLevel eLevel, const CHAR * szModule,
                            const CHAR * szFmt, ... );
void            prvvMBTCPLogFrame( UCHAR * pucMsg, UCHAR * pucFrame, USHORT usFrameLen );
#endif

void            vMBPortEnterCritical( void );
void            vMBPortExitCritical( void );
④、修改portevent.c文件如下,主要是实现了第②步中那些函数,同时删除了一些用不到的头文件。
/*
 * FreeModbus Libary: BARE Port
 * Copyright (C) 2006 Christian Walter <[email protected]>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 * File: $Id: portevent.c,v 1.1 2006/08/22 21:35:13 wolti Exp $
 */

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

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

static eMBEventType eTCPQueuedEvent ;
static BOOL         xTCPEventInQueue= FALSE ;

/* ----------------------- 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;
}



BOOL
xMBTCPPortEventInit( void )
{
    xTCPEventInQueue = FALSE;
    return TRUE ;
}

void
vMBTCPPortEventClose( void )
{
    xTCPEventInQueue = FALSE;
}

BOOL
xMBTCPPortEventPost( eMBEventType eEvent )
{
    xTCPEventInQueue = TRUE;
    eTCPQueuedEvent = eEvent;
    return TRUE;
}

BOOL
xMBTCPPortEventGet( eMBEventType *eEvent )
{
     if( xTCPEventInQueue )
        {
          *eEvent = eTCPQueuedEvent;
          xTCPEventInQueue = FALSE;
          return TRUE;
        }
    else
        {
           return FALSE  ;
        }
}
⑤、修改portother.c文件如下,主要是实现了第③步中的帧打印函数与临界区函数。
/*
 * FreeModbus Libary: lwIP Port
 * Copyright (C) 2006 Christian Walter <[email protected]>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 * File: $Id$
 */

/* ----------------------- System includes ----------------------------------*/
#include <stdio.h>
#include <stdarg.h>
#include <string.h>

#include "port.h"
#include <FreeRTOS.h>
#include <task.h>
/* ----------------------- Defines ------------------------------------------*/
#define MB_FRAME_LOG_BUFSIZE    512

/* ----------------------- Start implementation -----------------------------*/

#ifdef MB_TCP_DEBUG
void
prvvMBTCPLogFrame( UCHAR * pucMsg, UCHAR * pucFrame, USHORT usFrameLen )
{
    int             i;
    int             res = 0;
    int             iBufPos = 0;
    size_t          iBufLeft = MB_FRAME_LOG_BUFSIZE;
    static CHAR     arcBuffer[MB_FRAME_LOG_BUFSIZE];

    assert( pucFrame != NULL );

    for( i = 0; i < usFrameLen; i++ )
    {
        /* Print some additional frame information. */
        switch ( i )
        {
        case 0:
            /* TID = Transaction Identifier. */
            res = snprintf( &arcBuffer[iBufPos], iBufLeft, "| TID = " );
            break;
        case 2:
            /* PID = Protocol Identifier. */
            res = snprintf( &arcBuffer[iBufPos], iBufLeft, " | PID = " );
            break;
        case 4:
            /* Length */
            res = snprintf( &arcBuffer[iBufPos], iBufLeft, " | LEN = " );
            break;
        case 6:
            /* UID = Unit Identifier. */
            res = snprintf( &arcBuffer[iBufPos], iBufLeft, " | UID = " );
            break;
        case 7:
            /* MB Function Code. */
            res = snprintf( &arcBuffer[iBufPos], iBufLeft, "|| FUNC = " );
            break;
        case 8:
            /* MB PDU rest. */
            res = snprintf( &arcBuffer[iBufPos], iBufLeft, " | DATA = " );
            break;
        default:
            res = 0;
            break;
        }
        if( res == -1 )
        {
            break;
        }
        else
        {
            iBufPos += res;
            iBufLeft -= res;
        }

        /* Print the data. */
        res = snprintf( &arcBuffer[iBufPos], iBufLeft, "%02X", pucFrame[i] );
        if( res == -1 )
        {
            break;
        }
        else
        {
            iBufPos += res;
            iBufLeft -= res;
        }
    }

    if( res != -1 )
    {
        /* Append an end of frame string. */
        res = snprintf( &arcBuffer[iBufPos], iBufLeft, " |\r\n" );
        if( res != -1 )
        {
            vMBPortLog( MB_LOG_DEBUG, (CHAR *)pucMsg, "%s", arcBuffer );
        }
    }
}
#endif

void
vMBPortLog( eMBPortLogLevel eLevel, const CHAR * szModule, const CHAR * szFmt, ... )
{
    va_list         args;
    static const char *arszLevel2Str[] = { "DEBUG", "INFO", "WARN", "ERROR" };

    ( void )printf( "%s: %s: ", arszLevel2Str[eLevel], szModule );
    va_start( args, szFmt );
    vprintf( szFmt, args );
    va_end( args );
}

void
vMBPortEnterCritical( void )
{
    taskENTER_CRITICAL(  );
}

void
vMBPortExitCritical( void )
{
    taskEXIT_CRITICAL(  );
}
⑥在porttcp.c中添加string.h头文件,修改vMBPortEventClose为vMBTCPPortEventClose。
/* ----------------------- System includes ----------------------------------*/
#include <stdio.h>
#include "string.h"
#include "port.h"
/* ----------------------- Prototypes ---------------------------------------*/
void            vMBTCPPortEventClose( void );
void            vMBPortLog( eMBPortLogLevel eLevel, const CHAR * szModule,
                            const CHAR * szFmt, ... );
void
vMBTCPPortClose(  )
{
    /* Shutdown any open client sockets. */
    prvvMBPortReleaseClient( pxPCBClient );

    /* Shutdown or listening socket. */
    prvvMBPortReleaseClient( pxPCBListen );

    /* Release resources for the event queue. */
    vMBTCPPortEventClose( );
}
⑦、修改mb_callback_tcp.c文件如下,该文件主要是实现了输入寄存器与保持寄存器的具体实现。
/* ------------------------ System includes ------------------------------- */
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <assert.h>

/* ------------------------ FreeModbus includes --------------------------- */
#include "mb.h"

/* ------------------------ Project includes ------------------------------ */
#include "mb_callback_tcp.h"


/* ----------------------- Static variables ------------------------------- */
static USHORT   usRegInputStart = S_REG_INPUT_START;
static USHORT   usRegInputBuf[S_REG_INPUT_NREGS];
static USHORT   usRegHoldingStart = S_REG_HOLDING_START;
static USHORT   usRegHoldingBuf[S_REG_HOLDING_NREGS];

static USHORT TempPara[10];
/* ------------------------ Static functions ------------------------------ */
/**
 * The callback method of the input function.
 * @param reg_addr Offset of the register address relative to the start address		
 * @return none
 */
static void  RegInputReadCallBack(uint16_t reg_addr)
{
	switch(reg_addr)
	{
        case 0:usRegInputBuf[reg_addr] = 0		;break;		
		case 1:usRegInputBuf[reg_addr] = 1		;break;		
        case 2:usRegInputBuf[reg_addr] = 2		;break;		
        case 3:usRegInputBuf[reg_addr] = 3		;break;		
        case 4:usRegInputBuf[reg_addr] = 4		;break;		
		case 5:usRegInputBuf[reg_addr] = 5		;break;		
		case 6:usRegInputBuf[reg_addr] = 6		;break;
        case 7:usRegInputBuf[reg_addr] = 7		;break;
        case 8:usRegInputBuf[reg_addr] = 8		;break;		
		case 9:usRegInputBuf[reg_addr] = 9		;break;		     	
        default:break;
	}
}

/**
 * The callback method of the read hold function.
 * @param reg_addr Offset of the register address relative to the start address		
 * @return none
 */
static void  RegHoldReadCallBack(uint16_t reg_addr)
{
	switch(reg_addr)
	{
        case 0:usRegHoldingBuf[reg_addr] = TempPara[0]		;break;		
		case 1:usRegHoldingBuf[reg_addr] = TempPara[1]		;break;		
        case 2:usRegHoldingBuf[reg_addr] = TempPara[2]		;break;		
        case 3:usRegHoldingBuf[reg_addr] = TempPara[3]	    ;break;		
        case 4:usRegHoldingBuf[reg_addr] = TempPara[4]		;break;		
		case 5:usRegHoldingBuf[reg_addr] = TempPara[5]		;break;		
		case 6:usRegHoldingBuf[reg_addr] = TempPara[6]		;break;
        case 7:usRegHoldingBuf[reg_addr] = TempPara[7]		;break;		
		case 8:usRegHoldingBuf[reg_addr] = TempPara[8]		;break;		
        case 9:usRegHoldingBuf[reg_addr] = TempPara[9]		;break;	     	
        default:break;
	}
}

/**
 * The callback method of the write hold function.
 * @param reg_addr Offset of the register address relative to the start address		
 * @return none
 */
static void  RegHoldWriteCallBack(uint16_t reg_addr)
{
	switch(reg_addr)
	{
        case 0:TempPara[0] = usRegHoldingBuf[reg_addr]      ;printf("TempPara[0] = %d\r\n",TempPara[0]);break;		
		case 1:TempPara[1] = usRegHoldingBuf[reg_addr]		;printf("TempPara[1] = %d\r\n",TempPara[1]);break;	
        case 2:TempPara[2] = usRegHoldingBuf[reg_addr]		;printf("TempPara[2] = %d\r\n",TempPara[2]);break;	
        case 3:TempPara[3] = usRegHoldingBuf[reg_addr]	    ;printf("TempPara[3] = %d\r\n",TempPara[3]);break;	
        case 4:TempPara[4] = usRegHoldingBuf[reg_addr]		;printf("TempPara[4] = %d\r\n",TempPara[4]);break;	
		case 5:TempPara[5] = usRegHoldingBuf[reg_addr]		;printf("TempPara[5] = %d\r\n",TempPara[5]);break;	
		case 6:TempPara[6] = usRegHoldingBuf[reg_addr]		;printf("TempPara[6] = %d\r\n",TempPara[6]);break;
        case 7:TempPara[7] = usRegHoldingBuf[reg_addr]		;printf("TempPara[7] = %d\r\n",TempPara[7]);break;	
		case 8:TempPara[8] = usRegHoldingBuf[reg_addr]		;printf("TempPara[8] = %d\r\n",TempPara[8]);break;	
        case 9:TempPara[9] = usRegHoldingBuf[reg_addr]		;printf("TempPara[9] = %d\r\n",TempPara[9]);break;    	
        default:break;
	}
}


/* ------------------------ Implementation -------------------------------- */
/**
 * Modbus slave input register callback function.
 * @param pucRegBuffer input register buffer	
 * @param usAddress input register address		
 * @param usNRegs input register number			
 * @return result
 */
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 >= S_REG_INPUT_START )
        && ( usAddress + usNRegs <= S_REG_INPUT_START + S_REG_INPUT_NREGS ) )
    {
        iRegIndex = ( int )( usAddress - usRegInputStart );
        while( usNRegs > 0 )
        {
            RegInputReadCallBack(iRegIndex);
            *pucRegBuffer++ = ( unsigned char )( usRegInputBuf[iRegIndex] >> 8 );
            *pucRegBuffer++ = ( unsigned char )( usRegInputBuf[iRegIndex] & 0xFF );
            iRegIndex++;
            usNRegs--;
        }
    }
    else
    {
        eStatus = MB_ENOREG;
    }
    return eStatus;
}

/**
 * Modbus slave holding register callback function.	
 * @param pucRegBuffer holding register buffer	
 * @param usAddress holding register address	
 * @param usNRegs holding register number		
 * @param eMode read or write					
 * @return result
 */
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 >= S_REG_HOLDING_START ) &&
        ( usAddress + usNRegs <= S_REG_HOLDING_START + S_REG_HOLDING_NREGS ) )
    {
        iRegIndex = ( int )( usAddress - usRegHoldingStart );
        switch ( eMode )
        {
            /* Pass current register values to the protocol stack. */
        case MB_REG_READ:
            while( usNRegs > 0 )
            {
                RegHoldReadCallBack(iRegIndex);
                *pucRegBuffer++ = ( UCHAR ) ( usRegHoldingBuf[iRegIndex] >> 8 );
                *pucRegBuffer++ = ( UCHAR ) ( usRegHoldingBuf[iRegIndex] & 0xFF );
                iRegIndex++;
                usNRegs--;
            }
            break;

            /* Update current register values with new values from the
             * protocol stack. */
        case MB_REG_WRITE:
            while( usNRegs > 0 )
            {
                usRegHoldingBuf[iRegIndex] = *pucRegBuffer++ << 8;
                usRegHoldingBuf[iRegIndex] |= *pucRegBuffer++;
                RegHoldWriteCallBack(iRegIndex);
                iRegIndex++;
                usNRegs--;
            }
            break;
        }
    }
    else
    {
        eStatus = MB_ENOREG;
    }
    return eStatus;
}

eMBErrorCode
eMBRegCoilsCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNCoils, eMBRegisterMode eMode )
{
    return MB_ENOREG;
}

eMBErrorCode
eMBRegDiscreteCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNDiscrete )
{
    return MB_ENOREG;
}




⑧、修改mb_callback_tcp.h文件如下。
#ifndef    	USER_APP
#define 	USER_APP
/* ------------------------ FreeModbus includes --------------------------- */
#include "mb.h"


/* ------------------------ Defines --------------------------------------- */
#define S_COIL_START                  0         /*线圈寄存器起始地址*/
#define S_COIL_NCOILS                 10        /*线圈寄存器数量*/

#define S_DISCRETE_INPUT_START        10000		/*离散寄存器起始地址*/
#define S_DISCRETE_INPUT_NDISCRETES   10        /*离散寄存器数量*/

#define S_REG_INPUT_START             30000		/*输入寄存器起始地址*/
#define S_REG_INPUT_NREGS             10		/*输入寄存器数量*/

#define S_REG_HOLDING_START           40000		/*保持寄存器起始地址*/
#define S_REG_HOLDING_NREGS           10		/*保持寄存器数量*/


 eMBErrorCode    eMBRegInputCB( UCHAR * pucRegBuffer, USHORT usAddress,USHORT usNRegs );
 eMBErrorCode    eMBRegHoldingCB(UCHAR * pucRegBuffer,USHORT usAddress,USHORT usNRegs,eMBRegisterMode eMode);
 eMBErrorCode    eMBRegCoilsCB(UCHAR * pucRegBuffer,USHORT usAddress,USHORT usNCoils,eMBRegisterMode eMode);
 eMBErrorCode    eMBRegDiscreteCB( UCHAR * pucRegBuffer, USHORT usAddress,USHORT usNDiscrete );

#endif

⑨、修改main.c如下,板子IP为192.168.12.247,端口为502,电脑IP为192.168.12.245。

/*****************************************************************************
 * Copyright (c) 2019, Nations Technologies Inc.
 *
 * All rights reserved.
 * ****************************************************************************
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * - Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the disclaimer below.
 *
 * Nations' name may not be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY NATIONS "AS IS" AND ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
 * DISCLAIMED. IN NO EVENT SHALL NATIONS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * ****************************************************************************/

/**
 * @file main.c
 * @author Nations
 * @version v1.0.0
 *
 * @copyright Copyright (c) 2019, Nations Technologies Inc. All rights reserved.
 */
#include <stdio.h>
#include "drv_log.h"
#include "drv_rcc.h"
#include "drv_log_segger.h"

#include "FreeRTOS.h"
#include "cmsis_os.h"
#include "task.h"
#include "misc.h"

#include "lwip/netif.h"
#include "lwip/api.h"
#include "lwip/sockets.h"
#include "lwipopts.h"
#include "lwip_port.h"
#include "mb.h"

/** @addtogroup N32G45X_StdPeriph_Examples
 * @{
 */
int errno ;
void vApplicationStackOverflowHook(TaskHandle_t xTask, char* pcTaskName)
{
    printf("stack overflow\n");
}

void vApplicationMallocFailedHook(void)
{
    printf("malloc failed\n");
}
/** @addtogroup USART_Printf
 * @{
 */

/***********************************task init**********************************/
#define START_TASK_PRIO         osPriority_5      
#define START_STK_SIZE          ((unsigned short)128)      
TaskHandle_t StartThread_Handler;           
static void StartThread(void const * argument);     

#define LED_TASK_PRIO           osPriority_10         
#define LED_STK_SIZE            ((unsigned short)128)     
TaskHandle_t LedThread_Handler; 
static void LedThread(void const * argument);  

#define LWIP_DMEO_TASK_PRIO     osPriority_10         
#define LWIP_DMEO_STK_SIZE      ((unsigned short)2*128)     
TaskHandle_t LwipThread_Handler;
static void LwipThread(void const * argument);   
/***********************************task end***********************************/
//uint32_t PreviousWakeTime;

/**
 * @brief  Main program
 */
extern void test_tcp_server_init(void);
extern void test_tcp_client_init(void);
int main(void)
{
	//drv_SysClockInit_144MHZ();
    RCC_ClocksType clks;
	
	drv_log_init();
	drv_log_segger_Init();

    /* Output a message on Hyperterminal using printf function */
    RCC_GetClocksFreqValue(&clks);
    log_info("SYSCLK: %d\r\n", clks.SysclkFreq);
    log_info("HCLK: %d\r\n", clks.HclkFreq); 
    log_info("PCLK1: %d\r\n", clks.Pclk1Freq);
    log_info("PCLK2: %d\r\n", clks.Pclk2Freq);
    log_info("AdcPllClkFreq: %d\r\n", clks.AdcPllClkFreq);	
    log_info("AdcHclkFreq: %d\r\n", clks.AdcHclkFreq);
	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
	/* Initialize all configured peripherals */
    osThreadDef(Start_Thread, StartThread, START_TASK_PRIO, 0, START_STK_SIZE);
    StartThread_Handler  = osThreadCreate(osThread(Start_Thread), NULL);

    /* Start scheduler */
	osKernelStart();	
		
    while (1){}
}

static void StartThread(void const * argument)
{	
	uint16_t u16Val = 0;
	UBaseType_t uxHighWaterMark;
	uxHighWaterMark = uxTaskGetStackHighWaterMark( NULL );  
	log_info("1---StartThread: uxHighWaterMark:%ld\r\n",uxHighWaterMark);	
		
	
	for(int i=0;i<5;i++)
	{
		osDelay(500);
		log_info("StartThread\r\n");
	}
	
	/* Initialize all configured peripherals */
	osThreadDef(Led_Thread, LedThread, LED_TASK_PRIO, 0, LED_STK_SIZE);
    LedThread_Handler  = osThreadCreate(osThread(Led_Thread), NULL);
	
    osThreadDef(Lwip_Thread, LwipThread, LWIP_DMEO_TASK_PRIO, 0, LWIP_DMEO_STK_SIZE);
    LwipThread_Handler  = osThreadCreate(osThread(Lwip_Thread), NULL);	
		
	u16Val = uxTaskGetNumberOfTasks();
	log_info("In all tasks:%d\r\n",u16Val);

	uxHighWaterMark = uxTaskGetStackHighWaterMark( LedThread_Handler );  
	log_info("1---LwipThread: uxHighWaterMark:%ld\r\n",uxHighWaterMark);
	
	uxHighWaterMark = uxTaskGetStackHighWaterMark( LwipThread_Handler );  
	log_info("2---LwipThread: uxHighWaterMark:%ld\r\n",uxHighWaterMark);

	uxHighWaterMark = uxTaskGetStackHighWaterMark( NULL );  
	log_info("0---StartThread: uxHighWaterMark:%ld\r\n",uxHighWaterMark);		
	
	vTaskDelete(xTaskGetCurrentTaskHandle());
}	

static void LedThread(void const * argument)
{
	for(int i=0;i<10;i++)
	{
		osDelay(1100);
		printf("LedThread is running\r\n");
		print_log("LedThread is running\r\n");
	}
	while(1){osDelay(1000);}	
}

static void LwipThread(void const * argument)
{	
    RCC_EnableAPB2PeriphClk(  RCC_APB2_PERIPH_AFIO  | RCC_APB2_PERIPH_GPIOA | RCC_APB2_PERIPH_GPIOB | RCC_APB2_PERIPH_GPIOC
                            | RCC_APB2_PERIPH_GPIOD | RCC_APB2_PERIPH_GPIOE | RCC_APB2_PERIPH_GPIOF
                            | RCC_APB2_PERIPH_GPIOG ,
                            ENABLE);
    RCC_EnableAHBPeriphClk(RCC_AHB_PERIPH_ETHMAC, ENABLE);
    if (lwip_port_init())
    {
        printf("LWIP Init Falied!\n");
        while (1)
            ;
    }
	
    log_info("LWIP Init Success!\n");
    //test_tcp_server_init();    
    //test_tcp_client_init();
	eMBTCPInit(0);
	eMBEnable();
    log_info("TCP Task Success!\n");	
	while(1)
	{
		eMBPoll();
		osDelay(50);
	}
}


8、编译下载测试:

在40005保持寄存器写入15

在40003保持寄存器写入13

读保持寄存器

读输入寄存器


至此移植测试完毕,通讯成功。后续我整理出该工程后,分享给大家。

本例程移植参考链接:

freemodbus modbus TCP 学习笔记_freemodbustcp-程序员宅基地

STM32F407ZET7+ETH+LWIP移植modbusTCP测试通过(带软件和freemodbusv1.6包)_stm32f407ETH资源-CSDN文库

STM32F407+LAN8720+LWIP移植freemodbusTCP.zip_freemodbustcp移植资源-CSDN文库

STM32F103移植FreeModbus同时实现ModbusRTU和ModbusTCP.zip_freemodbustcp移植资源-CSDN文库

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/Dd_456456/article/details/136447080

智能推荐

linux devkmem 源码,linux dev/mem dev/kmem实现访问物理/虚拟内存-程序员宅基地

文章浏览阅读451次。dev/mem: 物理内存的全镜像。可以用来访问物理内存。/dev/kmem: kernel看到的虚拟内存的全镜像。可以用来访问kernel的内容。调试嵌入式Linux内核时,可能需要查看某个内核变量的值。/dev/kmem正好提供了访问内核虚拟内存的途径。现在的内核大都默认禁用了/dev/kmem,打开的方法是在 make menuconfig中选中 device drivers --> ..._dev/mem 源码实现

vxe-table 小众但功能齐全的vue表格组件-程序员宅基地

文章浏览阅读7.1k次,点赞2次,收藏19次。vxe-table,一个小众但功能齐全并支持excel操作的vue表格组件_vxe-table

(开发)bable - es6转码-程序员宅基地

文章浏览阅读62次。参考:http://www.ruanyifeng.com/blog/2016/01/babel.htmlBabelBabel是一个广泛使用的转码器,可以将ES6代码转为ES5代码,从而在现有环境执行// 转码前input.map(item => item + 1);// 转码后input.map(function (item) { return item..._让开发环境支持bable

FPGA 视频处理 FIFO 的典型应用_fpga 频分复用 视频-程序员宅基地

文章浏览阅读2.8k次,点赞6次,收藏29次。摘要:FPGA视频处理FIFO的典型应用,视频输入FIFO的作用,视频输出FIFO的作用,视频数据跨时钟域FIFO,视频缩放FIFO的作用_fpga 频分复用 视频

R语言:设置工作路径为当前文件存储路径_r语言设置工作目录到目标文件夹-程序员宅基地

文章浏览阅读575次。【代码】R语言:设置工作路径为当前文件存储路径。_r语言设置工作目录到目标文件夹

background 线性渐变-程序员宅基地

文章浏览阅读452次。格式:background: linear-gradient(direction, color-stop1, color-stop2, ...);<linear-gradient> = linear-gradient([ [ <angle> | to <side-or-corner>] ,]? &l..._background线性渐变

随便推点

【蓝桥杯省赛真题39】python输出最大的数 中小学青少年组蓝桥杯比赛 算法思维python编程省赛真题解析-程序员宅基地

文章浏览阅读1k次,点赞26次,收藏8次。第十三届蓝桥杯青少年组python编程省赛真题一、题目要求(注:input()输入函数的括号中不允许添加任何信息)1、编程实现给定一个正整数N,输出正整数N中各数位最大的那个数字。例如:N=132,则输出3。2、输入输出输入描述:只有一行,输入一个正整数N输出描述:只有一行,输出正整数N中各数位最大的那个数字输入样例:

网络协议的三要素-程序员宅基地

文章浏览阅读2.2k次。一个网络协议主要由以下三个要素组成:1.语法数据与控制信息的结构或格式,包括数据的组织方式、编码方式、信号电平的表示方式等。2.语义即需要发出何种控制信息,完成何种动作,以及做出何种应答,以实现数据交换的协调和差错处理。3.时序即事件实现顺序的详细说明,以实现速率匹配和排序。不完整理解:语法表示长什么样,语义表示能干什么,时序表示排序。转载于:https://blog.51cto.com/98..._网络协议三要素csdn

The Log: What every software engineer should know about real-time data's unifying abstraction-程序员宅基地

文章浏览阅读153次。主要的思想,将所有的系统都可以看作两部分,真正的数据log系统和各种各样的query engine所有的一致性由log系统来保证,其他各种query engine不需要考虑一致性,安全性,只需要不停的从log系统来同步数据,如果数据丢失或crash可以从log系统replay来恢复可以看出kafka系统在linkedin中的重要地位,不光是d..._the log: what every software engineer should know about real-time data's uni

《伟大是熬出来的》冯仑与年轻人闲话人生之一-程序员宅基地

文章浏览阅读746次。伟大是熬出来的  目录  前言  引言 时间熬成伟大:领导者要像狼一样坚忍   第一章 内圣外王——领导者的心态修炼  1. 天纵英才的自信心  2. 上天揽月的企图心  3. 誓不回头的决心  4. 宠辱不惊的平常心  5. 换位思考的同理心  6. 激情四射的热心  第二章 日清日高——领导者的高效能修炼  7. 积极主动,想到做到  8. 合理掌控自己的时间和生命  9. 制定目标,马..._当狼拖着受伤的右腿逃生时,右腿会成为前进的阻碍,它会毫不犹豫撕咬断自己的腿, 以

有源光缆AOC知识百科汇总-程序员宅基地

文章浏览阅读285次。在当今的大数据时代,人们对高速度和高带宽的需求越来越大,迫切希望有一种新型产品来作为高性能计算和数据中心的主要传输媒质,所以有源光缆(AOC)在这种环境下诞生了。有源光缆究竟是什么呢?应用在哪些领域,有什么优势呢?易天将为您解答!有源光缆(Active Optical Cables,简称AOC)是两端装有光收发器件的光纤线缆,主要构成部件分为光路和电路两部分。作为一种高性能计..._aoc 光缆

浏览器代理服务器自动配置脚本设置方法-程序员宅基地

文章浏览阅读2.2k次。在“桌面”上按快捷键“Ctrl+R”,调出“运行”窗口。接着,在“打开”后的输入框中输入“Gpedit.msc”。并按“确定”按钮。如下图 找到“用户配置”下的“Windows设置”下的“Internet Explorer 维护”的“连接”,双击选择“自动浏览器配置”。如下图 选择“自动启动配置”,并在下面的“自动代理URL”中填写相应的PAC文件地址。如下..._設置proxy腳本