目录

1.摘要

2.代码移植与使用

        2.1 下载官方的FreeModbus代码

        2.2 代码移植

​编辑

3.第一步:移植层 (Port) 代码实现

        3.1事件管理 (portevent.c)

        3.2 串口驱动 (portserial.c)

        3.3 定时器驱动 (porttimer.c)

        3.4 端口通用定义 (port.h)

4. 第二步:应用层接口与数据映射

        4.1 回调函数实现 (apimodbus.c)

        4.2 apifreemodbus.h

5. 第三步:主程序调用 (main.c)


1.摘要

FreeModbus简介:

        FreeModbus是一款开源的Modbus协议栈,采用C语言编写,轻量级且跨平台,广泛用于嵌入式系统中实现Modbus通信。它支持RTU、ASCII和TCP模式,具有高可移植性,可运行于裸机或RTOS环境,适用于STM32、ARM、AVR等多种微控制器。

使用场景:

        工业自动化中连接PLC与传感器;能源管理中用于智能电表数据采集;楼宇自控系统中实现设备通信;物联网终端中作为标准通信协议;以及教学科研中用于协议学习与开发实践。

2.代码移植与使用

        2.1 下载官方的FreeModbus代码

        FreeModbus官方下载连接1  

        2.2 代码移植


我们移植的只需要其中的modbus文件里的所有所有文件(这些文件不同修改,可以直接使用)

3.第一步:移植层 (Port) 代码实现

FreeModbus 采用分层设计,我们需要实现 port 文件夹下的三个核心文件。

新建一个port文件夹,这里存放的都是需要手写的代码

        3.1事件管理 (portevent.c)


#include "mb.h"
#include "mbport.h"

/* ----------------------- static functions ---------------------------------*/
// enent type in queue
static eMBEventType eQueuedEvent;   // 队列中的事件类型
//enent queue flag, TRUE: event in queue, FALSE: no event in queue
static BOOL     xEventInQueue;     // 事件队列标志

/* ----------------------- static variables ----------------------------------*/
// 事件模块初始化

BOOL xMBPortEventInit( void )
{
    //enent queue init   
    xEventInQueue = FALSE; 
    return TRUE;
}

/**
// 发送事件到队列
 * @param  eEvent: (EV_READY, EV_FRAME_RECEIVED, EV_EXECUTE, EV_FRAME_SENT)
 */
BOOL xMBPortEventPost( eMBEventType eEvent )
{
    
    eQueuedEvent = eEvent;
    
    xEventInQueue = TRUE;
    return TRUE;
}

/**
// 从队列获取事件
 */
BOOL xMBPortEventGet( eMBEventType * eEvent )
{
    BOOL xEventHappened = FALSE;

    //check if event in queue
    if( xEventInQueue )
    {
        // 1. get event from queue
        *eEvent = eQueuedEvent;
        // 2. clear event in queue
        xEventInQueue = FALSE;
        xEventHappened = TRUE;
    }
    
    return xEventHappened;
}

        3.2 串口驱动 (portserial.c)

        这里包含了串口的初始化、使能以及中断回调函数的接口。

#include "mb.h"
#include "mbport.h"
#include "port.h"
#include "uart.h"


uart_handle_t UartHandle;
typedef enum
{
    PORT_RS232,   //0                 
    PORT_RS485,    //1                     
} MBPort;
/* uart enable or disable */
void	
vMBPortSerialEnable( BOOL xRxEnable, BOOL xTxEnable )
{

    if( xTxEnable )	//tx enable
    {
        /* Enable the USART Transmit interrupt. */
		
	}
	else	//tx disable
	{
		/* Disable the USART Transmit interrupt. */
		
    }
	if( xRxEnable )	//rx enable
	{
		/* Enable the USART Receive interrupt. */

	}
	else	//rx disable
	{
		/* Disable the USART Receive interrupt. */
	
	}

}

/*  uart init * /*/
BOOL
xMBPortSerialInit( UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits, eMBParity eParity )
{
    //仅作演示,需替换为实际硬件初始化
	u8 u8Ret = FALSE;
	u32 u32baudrate;			
	u32 u32parity;				
	
	(void)ucDataBits;	
	u32baudrate=ulBaudRate;
	u32parity=eParity;
	switch(ulBaudRate)
	{
		case 1200:
			u32baudrate = HAL_UART_BAUDRATE_1200;
			break;	
		case 1800:
			u32baudrate = HAL_UART_BAUDRATE_1800;
			break;
		case 2400:
			u32baudrate = HAL_UART_BAUDRATE_2400;
			break;		
		case 4800:
			u32baudrate = HAL_UART_BAUDRATE_4800;
			break;
		case 7200:
			u32baudrate = HAL_UART_BAUDRATE_7200;
			break;
		case 9600:
			u32baudrate = HAL_UART_BAUDRATE_9600;
			break;
		case 14400:
			u32baudrate = HAL_UART_BAUDRATE_14400;
			break;
		case 19200:
			u32baudrate = HAL_UART_BAUDRATE_19200;
			break;
		case 38400:
			u32baudrate = HAL_UART_BAUDRATE_38400;
			break;
		case 57600:
			u32baudrate = HAL_UART_BAUDRATE_57600;
			break;
		case 115200:
			u32baudrate = HAL_UART_BAUDRATE_115200;
			break;	
		case 125000:
			u32baudrate = HAL_UART_BAUDRATE_125000;
			break;			
		case 172800:
			u32baudrate = HAL_UART_BAUDRATE_172800;
			break;		
		default:
			break;
	}
	
	switch (eParity)
	{
	case MB_PAR_NONE:
			u32parity = HAL_UART_PARITY_NONE;
			break;

	case MB_PAR_ODD:
			u32parity = HAL_UART_PARITY_ODD;
			break;

	case MB_PAR_EVEN:
			u32parity = HAL_UART_PARITY_EVEN;
			break;
	}	
	
	switch(ucPORT)
	{
		case PORT_RS232:
			if(HalInitRS232(u32baudrate,u32parity,HAL_UART_STOPBITS_1)==HAL_ERR_NONE)	u8Ret=TRUE;
			break;
		case PORT_RS485:
			if(HalInitRS485(u32baudrate,u32parity,HAL_UART_STOPBITS_1)==HAL_ERR_NONE)	u8Ret=TRUE;
			break;
		default:		
			break;
	}								
	return u8Ret;
}

/* uart put byte  发送一个字节 */
BOOL
xMBPortSerialPutByte( CHAR ucByte )
{
	UartHandle.TxBuf[UartHandle.TxIndex++] = ucByte;
	huart2.Instance->DR = (uint8_t)ucByte;  
    return TRUE;
}
 /* uart get byte 接收一个字节 */
BOOL
xMBPortSerialGetByte( CHAR * pucByte )
{
    *pucByte = UartHandle.RxBuf[UartHandle.RxIndex++];
    return TRUE;
}
/* uart tx ready interrupt   串口发送中断回调 (函数名固定,由协议栈内部调用) */
void prvvUARTTxReadyISR( void )		
{
    pxMBFrameCBTransmitterEmpty(  );
}
/* uart rx interrupt  串口接收中断回调 (函数名固定)*/
void prvvUARTRxISR( void )
{
    pxMBFrameCBByteReceived(  );
}

        3.3 定时器驱动 (porttimer.c)

Modbus RTU 模式依赖定时器来检测帧间隔(3.5T)。定时时间需根据波特率计算(如 9600bps 约需 3.65ms,建议设为 4ms)。

#include "api.h"
#include "port.h"
//modbus timerout = 50us * usTim1Timerout50us
/* ----------------------- Modbus includes ----------------------------------*/
#include "mb.h"
#include "mbport.h"

/* ----------------------- static functions ---------------------------------*/
void prvvTIMERExpiredISR( void );

/* ----------------------- Start implementation -----------------------------*/
/*
timer init  定时器初始化
 */
BOOL
xMBPortTimersInit( USHORT usTim1Timerout50us )
{
    //usTim1Timerout50us set timer period, 50us * usTim1Timerout50us
    //1.timer init
    //2.timer clear
    //3.timer clear interrupt
    return TRUE;
}

/*
 timer enable  定时器使能 (开始计时)
 */
void
vMBPortTimersEnable(  )
{

    //1.timer clear    计数器请0
    //2.timer clear interrupt 中断清除
    //3.timer start //开始计时
    
}

/*
 timer disable   (停止计时)
 */
void
vMBPortTimersDisable(  )
{
    /* timer stop */
	
}

/* 
 * timer expired interrupt service routine  定时器中断服务函数 (函数名固定)
 */
void prvvTIMERExpiredISR( void )
{
    ( void )pxMBPortCBTimerExpired(  );
}

        3.4 端口通用定义 (port.h)

定义基础数据类型和临界区保护(关中断)。


#ifndef _PORT_H
#define _PORT_H
 
#include <assert.h>
#include <inttypes.h>
 
#define INLINE
#define PR_BEGIN_EXTERN_C           extern "C" {
#define PR_END_EXTERN_C             }
 
#define ENTER_CRITICAL_SECTION( ) EnterCriticalSection( )
#define EXIT_CRITICAL_SECTION( )    ExitCriticalSection( )
 /*回调函数,方便其他文件使用*/
void prvvUARTRxISR( void );         //UART Receive Interrupt Service Routine
void prvvUARTTxReadyISR( void )	;   //UART Send Ready Interrupt Service Routine
void prvvTIMERExpiredISR( void );   //TIMER Expired Interrupt Service Routine



typedef uint8_t BOOL;
 
typedef unsigned char UCHAR;
typedef char    CHAR;
 
typedef uint16_t USHORT;
typedef int16_t SHORT;
 
typedef uint32_t ULONG;
typedef int32_t LONG;
 
#ifndef TRUE
#define TRUE            1
#endif
 
#ifndef FALSE
#define FALSE           0
#endif
 
#endif
 

以上代码都是freemobus的基础代码,接下来需要些使用freemodbus的代码apifreemodbus

4. 第二步:应用层接口与数据映射

我们需要实现寄存器的读写回调函数,并将其封装供主程序调用。

        4.1 回调函数实现 (apimodbus.c)

/*
 * @Author: error: error: git config user.name & please set dead value or install git && error: git config user.email & please set dead value or install git & please set dead value or install git
 * @Date: 2026-05-09 20:10:24
 * @LastEditors: error: error: git config user.name & please set dead value or install git && error: git config user.email & please set dead value or install git & please set dead value or install git
 * @LastEditTime: 2026-05-10 20:56:52
 * @FilePath: \modbus\apifreemobus.c
 * @Description: 杩欐槸榛樿璁剧疆,璇疯缃甡customMade`, 鎵撳紑koroFileHeader鏌ョ湅閰嶇疆 杩涜璁剧疆: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 */
#include "mbport.h"
#include "mb.h"
#include <stdint.h>
#include "apifreemodbus.h"

#define USE_FREE_MODBUS				// FREEMODBUS   ENABLE

#ifdef USE_FREE_MODBUS
#define REG_INPUT_START 		1
#define REG_HOLDING_START 		1
#define REG_COILS_START 		1
#define REG_DISCRETE_START 		1
#define REG_INPUT_NREGS     500     //INPUT Register Number
#define REG_HOLDING_NREGS   500     // Holding Register Number
#define REG_COILS_NCOILS    500     // Coils Number
#define REG_DISCRETE_NREGS  500     // Discrete Input Number
/* REGISTER */
static USHORT usRegInputStart   = REG_INPUT_START;
static USHORT usRegHoldingStart = REG_HOLDING_START;
static USHORT usRegCoilsStart   = REG_COILS_START;
static USHORT usRegDiscreteStart= REG_DISCRETE_START;

/* REGISTER BUFFER */
static USHORT REG_INPUT_BUFF[REG_INPUT_NREGS] = {0};        // INPUT Register Buffer (16-bit)
static USHORT REG_HOLDING_BUFF[REG_HOLDING_NREGS] = {0};    // HOLDING Register Buffer (16-bit)
static UCHAR  REG_COILS_BUFF[REG_COILS_NCOILS] = {0};       // COILS Buffer (bit-level)
static UCHAR  REG_DISCRETE_BUFF[REG_DISCRETE_NREGS] = {0};  // DISCRETE Input Buffer (bit-level)

/* -------------------------------------------------------------------------- */
/* INPUT Register Callback 输入寄存器回调函数(函数名固定) */
/* -------------------------------------------------------------------------- */
eMBErrorCode	
eMBRegInputCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs )
{
    eMBErrorCode    eStatus = MB_ENOERR;
    int             iRegIndex;

    if( ( usAddress >= REG_INPUT_START )
        && ( usAddress + usNRegs <= REG_INPUT_START + REG_INPUT_NREGS ) )
    {
        iRegIndex = ( int )( usAddress - usRegInputStart );			
        while( usNRegs > 0 )
        {
            *pucRegBuffer++ = ( unsigned char )( REG_INPUT_BUFF[iRegIndex] >> 8 );
            *pucRegBuffer++ = ( unsigned char )( REG_INPUT_BUFF[iRegIndex] & 0xFF );
            iRegIndex++;
            usNRegs--;
        }
    }
    else
    {
        eStatus = MB_ENOREG;
    }
    return eStatus;
}

/* -------------------------------------------------------------------------- */
/* REGHOLDING Register Callback(保持寄存器回调函数(函数名固定) */
/* -------------------------------------------------------------------------- */
eMBErrorCode
eMBRegHoldingCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNRegs, eMBRegisterMode eMode )
{
	eMBErrorCode    eStatus = MB_ENOERR;
	int             iRegIndex;


    if( ( usAddress >= REG_HOLDING_START ) &&
        ( usAddress + usNRegs <= REG_HOLDING_START + REG_HOLDING_NREGS ) )
    {
        iRegIndex = ( int )( usAddress - usRegHoldingStart );
        switch ( eMode )
        {
            /* Pass current register values to the protocol stack. */
        case MB_REG_READ:   /*master read register values from the protocol stack. */
            while( usNRegs > 0 )
            {
                *pucRegBuffer++ = ( UCHAR ) ( REG_HOLDING_BUFF[iRegIndex] >> 8 );   //high byte
                *pucRegBuffer++ = ( UCHAR ) ( REG_HOLDING_BUFF[iRegIndex] & 0xFF ); //low byte
                iRegIndex++;
                usNRegs--;
            }
            break;

            /* Update current register values with new values from the
             * protocol stack. */
        case MB_REG_WRITE:    /*master write register values to the protocol stack. */
            while( usNRegs > 0 )
            {
                REG_HOLDING_BUFF[iRegIndex] = *pucRegBuffer++ << 8; //high byte
                REG_HOLDING_BUFF[iRegIndex] |= *pucRegBuffer++;     //low byte
                iRegIndex++;
                usNRegs--;
            }
        }
    }
    else
    {
        eStatus = MB_ENOREG;
    }
    return eStatus;
}

/* -------------------------------------------------------------------------- */
/* COILS Register Callback 线圈回调函数(函数名固定)*/
/* -------------------------------------------------------------------------- */
eMBErrorCode
eMBRegCoilsCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNCoils, eMBRegisterMode eMode )
{
    eMBErrorCode eStatus = MB_ENOERR;
    int iRegIndex;

    if( (usAddress >= REG_COILS_START) && 
        (usAddress + usNCoils <= REG_COILS_START + REG_COILS_NCOILS) )
    {
        iRegIndex = (int)(usAddress - usRegCoilsStart);
        switch( eMode )
        {
            case MB_REG_READ:
                while( usNCoils > 0 )
                {
                    UCHAR ucResult = 0;
                    for( UCHAR i = 0; i < 8 && usNCoils > 0; i++, usNCoils-- )
                    {
                        if( REG_COILS_BUFF[iRegIndex] )
                            ucResult |= (1 << i);
                        iRegIndex++;
                    }
                    *pucRegBuffer++ = ucResult;
                }
                break;

            case MB_REG_WRITE:
                while( usNCoils > 0 )
                {
                    UCHAR ucByte = *pucRegBuffer++;
                    for( UCHAR i = 0; i < 8 && usNCoils > 0; i++, usNCoils-- )
                    {
                        REG_COILS_BUFF[iRegIndex] = (ucByte & (1 << i)) ? 1 : 0;
                        iRegIndex++;
                    }
                }
                break;
        }
    }
    else
    {
        eStatus = MB_ENOREG;
    }
    return eStatus;
}
/* -------------------------------------------------------------------------- */
/* DISCRETE Input Register Callback离散线圈回调函数(函数名固定) */
/* -------------------------------------------------------------------------- */
eMBErrorCode
eMBRegDiscreteCB( UCHAR * pucRegBuffer, USHORT usAddress, USHORT usNDiscrete )
{
eMBErrorCode eStatus = MB_ENOERR;
    int iRegIndex;

    if( (usAddress >= REG_DISCRETE_START) && 
        (usAddress + usNDiscrete <= REG_DISCRETE_START + REG_DISCRETE_NREGS) )
    {
        iRegIndex = (int)(usAddress - usRegDiscreteStart);
        while( usNDiscrete > 0 )
        {
            UCHAR ucResult = 0;
            for( UCHAR i = 0; i < 8 && usNDiscrete > 0; i++, usNDiscrete-- )
            {
                if( REG_DISCRETE_BUFF[iRegIndex] )
                    ucResult |= (1 << i);
                iRegIndex++;
            }
            *pucRegBuffer++ = ucResult;
        }
    }
    else
    {
        eStatus = MB_ENOREG;
    }
    return eStatus;
}

#endif
/* ==================== Modbus Free Modbus Library - FreeModbus.org ==================== */
typedef uint8_t  u8;
typedef uint16_t u16;

/* Swap Endian 16 (2 bytes) ,this not is a standard function  大小端转换,不需要*/
void SwapEndian16(u8* pData, u16 u16ByteLen)
{
    if (!pData || (u16ByteLen & 1)) return; /* Length must be even */
    for (u16 i = 0; i < u16ByteLen; i += 2)
    {
        u8 tmp = pData[i];
        pData[i]   = pData[i+1];
        pData[i+1] = tmp;
    }
}
/*=============================封装函数============================*/
/**
 * @brief  register hold register encapsulation function
 * 
 * @param  pu8RegBuffer: data buffer for holding register, the data is in big-endian format, which means the high byte is stored first followed by the low byte.
 * @param  u16Address:   Modbus holding register address, 1-based address.
 * @param  u16NRegs:     Number of holding registers, each register is 16 bits (2 bytes).
 * @param  u8Mode:       operation mode
 *         - 0: MB_REG_READ   read holding register values and pass to protocol stack.
 *         - 1: MB_REG_WRITE  update holding register values with new values from protocol stack.
 * @return error code, MB_ENOERR=0 means success.
 */
u8 Modbus_RegHold(u8* pu8RegBuffer, u16 u16Address, u16 u16NRegs, u8 u8Mode)
{
#ifdef USE_FREE_MODBUS
    return (u8)eMBRegHoldingCB((UCHAR *)pu8RegBuffer, (USHORT)u16Address, (USHORT)u16NRegs, (eMBRegisterMode)u8Mode);
#else
    return 0; 
#endif
}


/**
 * @brief  register input register encapsulation function
 * 
 * @param  pu8RegBuffer: data buffer for input register, the data is in big-endian format, which means the high byte is stored first followed by the low byte.
 * @param  u16Address:   Modbus input register address, 1-based address.
 * @param  u16NRegs:     Number of input registers, each register is 16 bits (2 bytes).
 * @return error code, MB_ENOERR=0 means success.
 */
u8 Modbus_RegInput(u8* pu8RegBuffer, u16 u16Address, u16 u16NRegs)
{
#ifdef USE_FREE_MODBUS
    return (u8)eMBRegInputCB((UCHAR *)pu8RegBuffer, (USHORT)u16Address, (USHORT)u16NRegs);
#else
    return 0;
#endif
}
/**
 * @brief  register coil encapsulation function
 * 
 * @param  pu8RegBuffer: data buffer for coil register, the data is in big-endian format, which means the high byte is stored first followed by the low byte.
 * @param  u16Address:   Modbus coil register address, 1-based address.
 * @param  u16NCoils:    Number of coil registers, each register is 1 bit.
 * @param  u8Mode:       operation mode
 *         - 0: MB_REG_READ   read coil register values and pass to protocol stack.
 *         - 1: MB_REG_WRITE  update coil register values with new values from protocol stack.
 * @return error code, MB_ENOERR=0 means success.
 * 
 * 使用场景:
 *   - 控制开关量输出(继电器、指示灯等)
 *   - MCGS(主站)通过 01/05/15 功能码读写线圈
 * 
 */
u8 Modbus_RegCoil(u8* pu8RegBuffer, u16 u16Address, u16 u16NCoils, u8 u8Mode)
{
#ifdef USE_FREE_MODBUS
    return (u8)eMBRegCoilsCB((UCHAR *)pu8RegBuffer, (USHORT)u16Address, (USHORT)u16NCoils, (eMBRegisterMode)u8Mode);
#else
    return 0;
#endif
}
/**
 * @brief  register discrete input encapsulation function
 * 
 * @param  pu8RegBuffer: data buffer for discrete input register, the data is in big-endian format, which means the high byte is stored first followed by the low byte.
 * @param  u16Address:   Modbus discrete input register address, 1-based address.
 * @param  u16NDiscrete: Number of discrete input registers, each register is 1 bit.
 * @return error code, MB_ENOERR=0 means success.
 * 
 */
u8 Modbus_RegDiscrete(u8* pu8RegBuffer, u16 u16Address, u16 u16NDiscrete)
{
#ifdef USE_FREE_MODBUS
    return (u8)eMBRegDiscreteCB((UCHAR *)pu8RegBuffer, (USHORT)u16Address, (USHORT)u16NDiscrete);
#else
    return 0;
#endif
}

        4.2 apifreemodbus.h

/*
 * @Author: error: error: git config user.name & please set dead value or install git && error: git config user.email & please set dead value or install git & please set dead value or install git
 * @Date: 2026-05-09 22:14:46
 * @LastEditors: error: error: git config user.name & please set dead value or install git && error: git config user.email & please set dead value or install git & please set dead value or install git
 * @LastEditTime: 2026-05-10 19:21:46
 * @FilePath: \modbus\apifreemodbus.h
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 */
#ifndef __APIFREEMODBUS_H__
#define __APIFREEMODBUS_H__

#include <stdint.h>

/* 类型定义(若全局已有可删除) */
typedef uint8_t  u8;
typedef uint16_t u16;

/* 封装接口声明 */
u8 Modbus_RegHold(u8* pu8RegBuffer, u16 u16Address, u16 u16NRegs, u8 u8Mode);
u8 Modbus_RegInput(u8* pu8RegBuffer, u16 u16Address, u16 u16NRegs);
u8 Modbus_RegCoil(u8* pu8RegBuffer, u16 u16Address, u16 u16NCoils, u8 u8Mode);
u8 Modbus_RegDiscrete(u8* pu8RegBuffer, u16 u16Address, u16 u16NDiscrete);
void SwapEndian16(u8* pData, u16 u16ByteLen);//big-endian <-> little-endian,this is not a standard function, just for modbus register data format conversion.   

#endif /* __APIFREEMODBUS_H__ */

5. 第三步:主程序调用 (main.c)

#include "mb.h"
#include "mbport.h"
#include "apifreemodbus.h"
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
//数据需要通过网络发送、写入文件、或与外部硬件/协议交互(如 Modbus、USB、SPI Flash、TCP/IP 包头)。
// 定义一个测试结构体 (例如时间信息)
#pragma pack(push, 1)   // 设置结构体字节对齐
typedef struct {
    u16 year;      // 2 bytes
    u8 month;      // 1 byte
    u8 day;        // 1 byte
    u8 hour;       // 1 byte
    u8 minute;     // 1 byte
    u8 second;     // 1 byte
    u8 reserved;   // 1 byte (Padding for alignment to 16-bit Modbus register)
} time_t;
#pragma pack(pop)


time_t time;

#define MB_TIME_ADDRESS 0x0000 
int main(void)
{
    //  HAL 库初始化 (时钟、串口、LED等)
    HAL_Init();
    SystemClock_Config();

    //  Modbus协议栈初始化
    // 参数: MB_RTU, 从机地址,串口端口(类型), 波特率,校验位
    //如果已经硬件初始化,关于串口的参数可以随意写(最好一样)
    eMBErrorCode eStatus = eMBInit( MB_RTU, 0x01, PORT_RS232, 115200, MB_PAR_EVEN );//已包含硬件初始化
    
    // 设置从机 ID 信息 (你在 mbconfig.h 开启了 REP_SLAVEID)
    //不调用没有太大影响(主机发送17功能码,从机依然会回复主机,不会死机或返回异常码(从机会回复一段默认的空数据(或者长度为 0 的数据段))
    UCHAR ucSlaveID[] = { 'S', 'T', 'M', '3', '2', '-', 'F', 'R', 'E', 'E', 'M', 'O', 'D', 'B', 'U', 'S' };
    eMBSetSlaveID( 0x01, TRUE, ucSlaveID, sizeof(ucSlaveID) );//单片机作为主机时不调用

    //  启动 Modbus
    eMBEnable();

    while (1)
    {
                // 这个函数内部会处理所有收发逻辑
        eMBPoll();  
        Modbus_RegHold(&time,MB_TIME_ADDRESS,(sizeof(time)/2),MB_REG_WRITE);//主机写时间信息
        // 可以在这里放其他的用户代码
    }
    
}

完整代码

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐