MODBUS的API接口

FreeModbus 1.6

Introduction

The latest version of this document is available on http://freemodbus.berlios.de/api.

FreeModbus is a Modbus ASCII/RTU and Modbus TCP implementation for embedded systems. It provides an implementation of the Modbus Application Protocol v1.1a and supports the RTU/ASCII transmission modes defined in the Modbus over serial line specification 1.0. Since version 0.7 FreeModbus also supports Modbus/TCP. Version 0.9 added the first Modbus/TCP port for embedded systems using the lwIP TCP/IP stack.

Ports

Cortex M3 devices:
  • Atmel AT91SAM3S.
ARM devices:
  • STR71X with FreeRTOS/GCC. See STR71X/simple2.c for an example.
  • STR71TCP with FreeRTOS/lwIP/GCC. This port includes FreeRTOS, lwIP and a fully working PPP stack. The lwIP, PPP and FreeRTOS part is generic and therefore can be used for other ports ( or other projects ).
  • LPC214X with Keil. See LPC214X/demo.c for an example. This port uses the Keil ARM Compiler 2.41.
  • AT91SAM7X with FreeRTOS/Rowley. See AT91SAM7X_ROWLEY/demo.c for an example.
AVR devices:
  • ATMega8/16/32/128/168/169 with WinAVR. See AVR/demo.c for an example.
Coldfire devices:
  • MCF5235 with GCC. See MCF5235/demo.c for an example.
  • MCF5235 with CodeWarrior and FreeRTOS port for ColdFire. See MCF5235CW/demo.c for an example.
  • MCF5235/TCP with GCC. This port features FreeRTOS and the lwIP stack. The lwIP part is generic and therefore it should be used as a basis for other lwIP ports.
MSP430 devices
  • MSP430F169 with Rowley Crossworks. See MSP430/demo.c for an example.
  • MSP430F169 with GCC. See MSP430/demo.c for an example.
Z8Encore devices
  • Z8F6422 and Z8F1622 port. See Z8ENCORE/demo.c for an example. The port uses ZDS II - Z8 Encore! 4.10.1 as development environment.
Win32:
  • A Win32 Modbus RTU/ASCII Port.
  • A Win32 Modbus/TCP Port.
Linux:
  • A Linux (uCLinux or other distributions) Modbus RTU/ASCII Port.

FreeModbus Modules

Here is a list of all modules:

Modbus


Detailed Description

 #include "mb.h" 

This module defines the interface for the application. It contains the basic functions and types required to use the Modbus protocol stack. A typical application will want to call eMBInit() first. If the device is ready to answer network requests it must then call eMBEnable() to activate the protocol stack. In the main loop the function eMBPoll() must be called periodically. The time interval between pooling depends on the configured Modbus timeout. If an RTOS is available a separate task should be created and the task should always call the function eMBPoll().

 

 // Initialize protocol stack in RTU mode for a slave with address 10 = 0x0A
 eMBInit( MB_RTU, 0x0A, 38400, MB_PAR_EVEN );
 // Enable the Modbus Protocol Stack.
 eMBEnable(  );
 for( ;; )
 {
     // Call the main polling loop of the Modbus protocol stack.
     eMBPoll(  );
     ...
 }
 

Defines

#define  MB_TCP_PORT_USE_DEFAULT   0

Enumerations

enum   eMBMode { MB_RTUMB_ASCIIMB_TCP }
enum   eMBRegisterMode { MB_REG_READMB_REG_WRITE }
enum   eMBErrorCode {
  MB_ENOERRMB_ENOREGMB_EINVALMB_EPORTERR,
  MB_ENORESMB_EIOMB_EILLSTATEMB_ETIMEDOUT
}
enum   eMBParity { MB_PAR_NONEMB_PAR_ODDMB_PAR_EVEN }

Functions

eMBErrorCode  eMBInit (eMBMode eMode, UCHAR ucSlaveAddress, UCHAR ucPort, ULONG ulBaudRate, eMBParity eParity)
eMBErrorCode  eMBTCPInit (USHORT usTCPPort)
eMBErrorCode  eMBClose (void)
eMBErrorCode  eMBEnable (void)
eMBErrorCode  eMBDisable (void)
eMBErrorCode  eMBPoll (void)
eMBErrorCode  eMBSetSlaveID (UCHAR ucSlaveID, BOOL xIsRunning, UCHAR const *pucAdditional, USHORT usAdditionalLen)
eMBErrorCode  eMBRegisterCB (UCHAR ucFunctionCode, pxMBFunctionHandler pxHandler)

Define Documentation

#define MB_TCP_PORT_USE_DEFAULT   0
 

Use the default Modbus TCP port (502).

 

Examples:
MCF5235TCP/demo.cSTR71XTCP/demo.c, and WIN32TCP/demo.cpp.

Enumeration Type Documentation

enum eMBErrorCode

 

Errorcodes used by all function in the protocol stack.

 

Enumeration values:
MB_ENOERR  no error.
MB_ENOREG  illegal register address.
MB_EINVAL  illegal argument.
MB_EPORTERR  porting layer error.
MB_ENORES  insufficient resources.
MB_EIO  I/O error.
MB_EILLSTATE  protocol stack in illegal state.
MB_ETIMEDOUT  timeout error occurred.
Examples:
AT91SAM7X_ROWLEY/demo.cAVR/demo.cLINUX/demo.cMCF5235/demo.cMCF5235TCP/demo.cMSP430/demo.cSTR71X/simple2.cSTR71XTCP/demo.cWIN32/demo.cpp, and WIN32TCP/demo.cpp.
enum eMBMode

 

Modbus serial transmission modes (RTU/ASCII).

Modbus serial supports two transmission modes. Either ASCII or RTU. RTU is faster but has more hardware requirements and requires a network with a low jitter. ASCII is slower and more reliable on slower links (E.g. modems)

Enumeration values:
MB_RTU  RTU transmission mode.
MB_ASCII  ASCII transmission mode.
MB_TCP  TCP mode.
enum eMBParity

 

Parity used for characters in serial mode.

The parity which should be applied to the characters sent over the serial link. Please note that this values are actually passed to the porting layer and therefore not all parity modes might be available.

Enumeration values:
MB_PAR_NONE  No parity.
MB_PAR_ODD  Odd parity.
MB_PAR_EVEN  Even parity.
 

If register should be written or read.

This value is passed to the callback functions which support either reading or writing register values. Writing means that the application registers should be updated and reading means that the modbus protocol stack needs to know the current register values.

 

See also:
eMBRegHoldingCB( )eMBRegCoilsCB( )eMBRegDiscreteCB( ) and eMBRegInputCB( ).
Enumeration values:
MB_REG_READ  Read register values and pass to protocol stack.
MB_REG_WRITE  Update register values.
Examples:
AT91SAM7X_ROWLEY/demo.cAVR/demo.cLINUX/demo.cMCF5235/demo.cMCF5235TCP/demo.cMSP430/demo.cSTR71X/simple2.cSTR71XTCP/demo.cWIN32/demo.cpp, and WIN32TCP/demo.cpp.

Function Documentation

eMBErrorCode eMBClose void     )   

 

Release resources used by the protocol stack.

This function disables the Modbus protocol stack and release all hardware resources. It must only be called when the protocol stack is disabled.

 

Note:
Note all ports implement this function. A port which wants to get an callback must define the macro MB_PORT_HAS_CLOSE to 1.
Returns:
If the resources where released it return eMBErrorCode::MB_ENOERR. If the protocol stack is not in the disabled state it returns eMBErrorCode::MB_EILLSTATE.
Examples:
LINUX/demo.cMCF5235TCP/demo.cSTR71XTCP/demo.cWIN32/demo.cpp, and WIN32TCP/demo.cpp.
eMBErrorCode eMBDisable void     )   

 

Disable the Modbus protocol stack.

This function disables processing of Modbus frames.

 

Returns:
If the protocol stack has been disabled it returns eMBErrorCode::MB_ENOERR. If it was not in the enabled state it returns eMBErrorCode::MB_EILLSTATE.
Examples:
LINUX/demo.cMCF5235TCP/demo.cSTR71XTCP/demo.cWIN32/demo.cpp, and WIN32TCP/demo.cpp.
eMBErrorCode eMBEnable void     )   

 

Enable the Modbus protocol stack.

This function enables processing of Modbus frames. Enabling the protocol stack is only possible if it is in the disabled state.

 

Returns:
If the protocol stack is now in the state enabled it returns eMBErrorCode::MB_ENOERR. If it was not in the disabled state it return eMBErrorCode::MB_EILLSTATE.
Examples:
AT91SAM7X_ROWLEY/demo.cAVR/demo.cLINUX/demo.cMCF5235/demo.cMCF5235TCP/demo.cMSP430/demo.cSTR71X/simple2.cSTR71XTCP/demo.cWIN32/demo.cpp, and WIN32TCP/demo.cpp.
eMBErrorCode eMBInit eMBMode  eMode,
    UCHAR  ucSlaveAddress,
    UCHAR  ucPort,
    ULONG  ulBaudRate,
    eMBParity  eParity
   

 

Initialize the Modbus protocol stack.

This functions initializes the ASCII or RTU module and calls the init functions of the porting layer to prepare the hardware. Please note that the receiver is still disabled and no Modbus frames are processed until eMBEnable( ) has been called.

 

Parameters:
  eMode  If ASCII or RTU mode should be used.
  ucSlaveAddress  The slave address. Only frames sent to this address or to the broadcast address are processed.
  ucPort  The port to use. E.g. 1 for COM1 on windows. This value is platform dependent and some ports simply choose to ignore it.
  ulBaudRate  The baudrate. E.g. 19200. Supported baudrates depend on the porting layer.
  eParity  Parity used for serial transmission.
Returns:
If no error occurs the function returns eMBErrorCode::MB_ENOERR. The protocol is then in the disabled state and ready for activation by calling eMBEnable( ). Otherwise one of the following error codes is returned:
Examples:
AT91SAM7X_ROWLEY/demo.cAVR/demo.cLINUX/demo.cMCF5235/demo.cMSP430/demo.cSTR71X/simple2.c, and WIN32/demo.cpp.
eMBErrorCode eMBPoll void     )   

 

The main pooling loop of the Modbus protocol stack.

This function must be called periodically. The timer interval required is given by the application dependent Modbus slave timeout. Internally the function calls xMBPortEventGet() and waits for an event from the receiver or transmitter state machines.

 

Returns:
If the protocol stack is not in the enabled state the function returns eMBErrorCode::MB_EILLSTATE. Otherwise it returns eMBErrorCode::MB_ENOERR.
Examples:
AT91SAM7X_ROWLEY/demo.cAVR/demo.cLINUX/demo.cMCF5235/demo.cMCF5235TCP/demo.cMSP430/demo.cSTR71X/simple2.cSTR71XTCP/demo.cWIN32/demo.cpp, and WIN32TCP/demo.cpp.
eMBErrorCode eMBRegisterCB UCHAR  ucFunctionCode,
    pxMBFunctionHandler  pxHandler
   

 

Registers a callback handler for a given function code.

This function registers a new callback handler for a given function code. The callback handler supplied is responsible for interpreting the Modbus PDU and the creation of an appropriate response. In case of an error it should return one of the possible Modbus exceptions which results in a Modbus exception frame sent by the protocol stack.

 

Parameters:
  ucFunctionCode  The Modbus function code for which this handler should be registers. Valid function codes are in the range 1 to 127.
  pxHandler  The function handler which should be called in case such a frame is received. If NULL a previously registered function handler for this function code is removed.
Returns:
eMBErrorCode::MB_ENOERR if the handler has been installed. If no more resources are available it returns eMBErrorCode::MB_ENORES. In this case the values in mbconfig.h should be adjusted. If the argument was not valid it returns eMBErrorCode::MB_EINVAL.
eMBErrorCode eMBSetSlaveID UCHAR  ucSlaveID,
    BOOL  xIsRunning,
    UCHAR const *  pucAdditional,
    USHORT  usAdditionalLen
   

 

Configure the slave id of the device.

This function should be called when the Modbus function Report Slave ID is enabled ( By defining MB_FUNC_OTHER_REP_SLAVEID_ENABLED in mbconfig.h ).

 

Parameters:
  ucSlaveID  Values is returned in the Slave ID byte of the Report Slave ID response.
  xIsRunning  If TRUE the Run Indicator Status byte is set to 0xFF. otherwise the Run Indicator Status is 0x00.
  pucAdditional  Values which should be returned in the Additional bytes of the Report Slave ID response.
  usAdditionalLen  Length of the buffer pucAdditonal.
Returns:
If the static buffer defined by MB_FUNC_OTHER_REP_SLAVEID_BUF in mbconfig.h is to small it returns eMBErrorCode::MB_ENORES. Otherwise it returns eMBErrorCode::MB_ENOERR.
Examples:
AVR/demo.cLINUX/demo.cMCF5235/demo.c, and WIN32/demo.cpp.
eMBErrorCode eMBTCPInit USHORT  usTCPPort  )   
 

Initialize the Modbus protocol stack for Modbus TCP.

This function initializes the Modbus TCP Module. Please note that frame processing is still disabled until eMBEnable( ) is called.

 

Parameters:
  usTCPPort  The TCP port to listen on.
Returns:
If the protocol stack has been initialized correctly the function returns eMBErrorCode::MB_ENOERR. Otherwise one of the following error codes is returned:
Examples:
MCF5235TCP/demo.cSTR71XTCP/demo.c, and WIN32TCP/demo.cpp.

Modbus Registers


Detailed Description

 #include "mb.h" 

       The protocol stack does not internally allocate any memory for the registers. This makes the protocol stack very small and also usable on low end targets. In addition the values don't have to be in the memory and could for example be stored in a flash.

       Whenever the protocol stack requires a value it calls one of the callback function with the register address and the number of registers to read as an argument. The application should then read the actual register values (for example the ADC voltage) and should store the result in the supplied buffer.
  If the protocol stack wants to update a register value because a write register function was received a buffer with the new register values is passed to the callback function. The function should then use these values to update the application register values.

 

 

Functions

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)

Function Documentation

eMBErrorCode eMBRegCoilsCB UCHAR *  pucRegBuffer,
    USHORT  usAddress,
    USHORT  usNCoils,
    eMBRegisterMode  eMode
   

 

Callback function used if a Coil Register value is read or written by the protocol stack. If you are going to use this function you might use the functions xMBUtilSetBits( ) and xMBUtilGetBits( ) for working with bitfields.

 

Parameters:
  pucRegBuffer  The bits are packed in bytes where the first coil starting at address usAddress is stored in the LSB of the first byte in the buffer pucRegBuffer. If the buffer should be written by the callback function unused coil values (I.e. if not a multiple of eight coils is used) should be set to zero.
  usAddress  The first coil number.
  usNCoils  Number of coil values requested.
  eMode  If eMBRegisterMode::MB_REG_WRITE the application values should be updated from the values supplied in the buffer pucRegBuffer. If eMBRegisterMode::MB_REG_READ the application should store the current values in the buffer pucRegBuffer.
Returns:
The function must return one of the following error codes:
  • eMBErrorCode::MB_ENOERR If no error occurred. In this case a normal Modbus response is sent.
  • eMBErrorCode::MB_ENOREG If the application does not map an coils within the requested address range. In this case a ILLEGAL DATA ADDRESS is sent as a response.
  • eMBErrorCode::MB_ETIMEDOUT If the requested register block is currently not available and the application dependent response timeout would be violated. In this case a SLAVE DEVICE BUSY exception is sent as a response.
  • eMBErrorCode::MB_EIO If an unrecoverable error occurred. In this case a SLAVE DEVICE FAILURE exception is sent as a response.
Examples:
AT91SAM7X_ROWLEY/demo.cAVR/demo.cLINUX/demo.cMCF5235/demo.cMCF5235TCP/demo.cMSP430/demo.cSTR71X/simple2.cSTR71XTCP/demo.cWIN32/demo.cpp, and WIN32TCP/demo.cpp.
eMBErrorCode eMBRegDiscreteCB UCHAR *  pucRegBuffer,
    USHORT  usAddress,
    USHORT  usNDiscrete
   

 

Callback function used if a Input Discrete Register value is read by the protocol stack.

If you are going to use his function you might use the functions xMBUtilSetBits( ) and xMBUtilGetBits( ) for working with bitfields.

 

Parameters:
  pucRegBuffer  The buffer should be updated with the current coil values. The first discrete input starting at usAddress must be stored at the LSB of the first byte in the buffer. If the requested number is not a multiple of eight the remaining bits should be set to zero.
  usAddress  The starting address of the first discrete input.
  usNDiscrete  Number of discrete input values.
Returns:
The function must return one of the following error codes:
  • eMBErrorCode::MB_ENOERR If no error occurred. In this case a normal Modbus response is sent.
  • eMBErrorCode::MB_ENOREG If no such discrete inputs exists. In this case a ILLEGAL DATA ADDRESS exception frame is sent as a response.
  • eMBErrorCode::MB_ETIMEDOUT If the requested register block is currently not available and the application dependent response timeout would be violated. In this case a SLAVE DEVICE BUSY exception is sent as a response.
  • eMBErrorCode::MB_EIO If an unrecoverable error occurred. In this case a SLAVE DEVICE FAILURE exception is sent as a response.
Examples:
AT91SAM7X_ROWLEY/demo.cAVR/demo.cLINUX/demo.cMCF5235/demo.cMCF5235TCP/demo.cMSP430/demo.cSTR71X/simple2.cSTR71XTCP/demo.cWIN32/demo.cpp, and WIN32TCP/demo.cpp.
eMBErrorCode eMBRegHoldingCB UCHAR *  pucRegBuffer,
    USHORT  usAddress,
    USHORT  usNRegs,
    eMBRegisterMode  eMode
   

 

Callback function used if a Holding Register value is read or written by the protocol stack. The starting register address is given by usAddress and the last register is given by usAddress + usNRegs - 1.

 

Parameters:
  pucRegBuffer  If the application registers values should be updated the buffer points to the new registers values. If the protocol stack needs to now the current values the callback function should write them into this buffer.
  usAddress  The starting address of the register.
  usNRegs  Number of registers to read or write.
  eMode  If eMBRegisterMode::MB_REG_WRITE the application register values should be updated from the values in the buffer. For example this would be the case when the Modbus master has issued an WRITE SINGLE REGISTER command. If the value eMBRegisterMode::MB_REG_READ the application should copy the current values into the buffer pucRegBuffer.
Returns:
The function must return one of the following error codes:
  • eMBErrorCode::MB_ENOERR If no error occurred. In this case a normal Modbus response is sent.
  • eMBErrorCode::MB_ENOREG If the application can not supply values for registers within this range. In this case a ILLEGAL DATA ADDRESS exception frame is sent as a response.
  • eMBErrorCode::MB_ETIMEDOUT If the requested register block is currently not available and the application dependent response timeout would be violated. In this case a SLAVE DEVICE BUSY exception is sent as a response.
  • eMBErrorCode::MB_EIO If an unrecoverable error occurred. In this case a SLAVE DEVICE FAILURE exception is sent as a response.
Examples:
AT91SAM7X_ROWLEY/demo.cAVR/demo.cLINUX/demo.cMCF5235/demo.cMCF5235TCP/demo.cMSP430/demo.cSTR71X/simple2.cSTR71XTCP/demo.cWIN32/demo.cpp, and WIN32TCP/demo.cpp.
eMBErrorCode eMBRegInputCB UCHAR *  pucRegBuffer,
    USHORT  usAddress,
    USHORT  usNRegs
   
 

Callback function used if the value of a Input Register is required by the protocol stack. The starting register address is given by usAddress and the last register is given by usAddress + usNRegs - 1.

 

Parameters:
  pucRegBuffer  A buffer where the callback function should write the current value of the modbus registers to.
  usAddress  The starting address of the register. Input registers are in the range 1 - 65535.
  usNRegs  Number of registers the callback function must supply.
Returns:
The function must return one of the following error codes:
  • eMBErrorCode::MB_ENOERR If no error occurred. In this case a normal Modbus response is sent.
  • eMBErrorCode::MB_ENOREG If the application can not supply values for registers within this range. In this case a ILLEGAL DATA ADDRESS exception frame is sent as a response.
  • eMBErrorCode::MB_ETIMEDOUT If the requested register block is currently not available and the application dependent response timeout would be violated. In this case a SLAVE DEVICE BUSY exception is sent as a response.
  • eMBErrorCode::MB_EIO If an unrecoverable error occurred. In this case a SLAVE DEVICE FAILURE exception is sent as a response.
Examples:
AT91SAM7X_ROWLEY/demo.cAVR/demo.cLINUX/demo.cMCF5235/demo.cMCF5235TCP/demo.cMSP430/demo.cSTR71X/simple2.cSTR71XTCP/demo.cWIN32/demo.cpp, and WIN32TCP/demo.cpp.

 

Modbus Configuration


Detailed Description

Most modules in the protocol stack are completly optional and can be excluded. This is specially important if target resources are very small and program memory space should be saved.

All of these settings are available in the file mbconfig.h

 

Defines

#define  MB_ASCII_ENABLED   ( 1 )
#define  MB_RTU_ENABLED   ( 1 )
#define  MB_TCP_ENABLED   ( 0 )
#define  MB_ASCII_TIMEOUT_SEC   ( 1 )
#define  MB_ASCII_TIMEOUT_WAIT_BEFORE_SEND_MS   ( 0 )
#define  MB_FUNC_HANDLERS_MAX   ( 16 )
#define  MB_FUNC_OTHER_REP_SLAVEID_BUF   ( 32 )
#define  MB_FUNC_OTHER_REP_SLAVEID_ENABLED   ( 1 )
#define  MB_FUNC_READ_INPUT_ENABLED   ( 1 )
#define  MB_FUNC_READ_HOLDING_ENABLED   ( 1 )
#define  MB_FUNC_WRITE_HOLDING_ENABLED   ( 1 )
#define  MB_FUNC_WRITE_MULTIPLE_HOLDING_ENABLED   ( 1 )
#define  MB_FUNC_READ_COILS_ENABLED   ( 1 )
#define  MB_FUNC_WRITE_COIL_ENABLED   ( 1 )
#define  MB_FUNC_WRITE_MULTIPLE_COILS_ENABLED   ( 1 )
#define  MB_FUNC_READ_DISCRETE_INPUTS_ENABLED   ( 1 )
#define  MB_FUNC_READWRITE_HOLDING_ENABLED   ( 1 )

Define Documentation

#define MB_ASCII_ENABLED   ( 1 )

 

If Modbus ASCII support is enabled.

 

#define MB_ASCII_TIMEOUT_SEC   ( 1 )

 

The character timeout value for Modbus ASCII.

The character timeout value is not fixed for Modbus ASCII and is therefore a configuration option. It should be set to the maximum expected delay time of the network.

#define MB_ASCII_TIMEOUT_WAIT_BEFORE_SEND_MS   ( 0 )

 

Timeout to wait in ASCII prior to enabling transmitter.

If defined the function calls vMBPortSerialDelay with the argument MB_ASCII_TIMEOUT_WAIT_BEFORE_SEND_MS to allow for a delay before the serial transmitter is enabled. This is required because some targets are so fast that there is no time between receiving and transmitting the frame. If the master is to slow with enabling its receiver then he will not receive the response correctly.

#define MB_FUNC_HANDLERS_MAX   ( 16 )

 

Maximum number of Modbus functions codes the protocol stack should support.

The maximum number of supported Modbus functions must be greater than the sum of all enabled functions in this file and custom function handlers. If set to small adding more functions will fail.

#define MB_FUNC_OTHER_REP_SLAVEID_BUF   ( 32 )

 

Number of bytes which should be allocated for the Report Slave ID command.

This number limits the maximum size of the additional segment in the report slave id function. See eMBSetSlaveID( ) for more information on how to set this value. It is only used if MB_FUNC_OTHER_REP_SLAVEID_ENABLED is set to 1.

#define MB_FUNC_OTHER_REP_SLAVEID_ENABLED   ( 1 )

 

If the Report Slave ID function should be enabled.

 

#define MB_FUNC_READ_COILS_ENABLED   ( 1 )

 

If the Read Coils function should be enabled.

 

#define MB_FUNC_READ_DISCRETE_INPUTS_ENABLED   ( 1 )

 

If the Read Discrete Inputs function should be enabled.

 

#define MB_FUNC_READ_HOLDING_ENABLED   ( 1 )

 

If the Read Holding Registers function should be enabled.

 

#define MB_FUNC_READ_INPUT_ENABLED   ( 1 )

 

If the Read Input Registers function should be enabled.

 

#define MB_FUNC_READWRITE_HOLDING_ENABLED   ( 1 )

 

If the Read/Write Multiple Registers function should be enabled.

 

#define MB_FUNC_WRITE_COIL_ENABLED   ( 1 )

 

If the Write Coils function should be enabled.

 

#define MB_FUNC_WRITE_HOLDING_ENABLED   ( 1 )

 

If the Write Single Register function should be enabled.

 

#define MB_FUNC_WRITE_MULTIPLE_COILS_ENABLED   ( 1 )

 

If the Write Multiple Coils function should be enabled.

 

#define MB_FUNC_WRITE_MULTIPLE_HOLDING_ENABLED   ( 1 )

 

If the Write Multiple registers function should be enabled.

 

#define MB_RTU_ENABLED   ( 1 )

 

If Modbus RTU support is enabled.

 

#define MB_TCP_ENABLED   ( 0 )
 

If Modbus TCP support is enabled.

 

 

Porting for RTU/ASCII

The first steps should always be to create a new directory for the port. The recommended layout is to create a top level directory, e.g. demo/PLATFORM which hold the application and project files. In addition a subdirectory port should be created for the port specific files.
demo/PLATFORM/Makefile
demo/PLATFORM/main.c
demo/PLATFORM/port/portserial.c
demo/PLATFORM/port/porttimer.c
demo/PLATFORM/port/portother.c
demo/PLATFORM/port/port.h
You can use demo/BARE as a starting point. Simply copy the directory and rename it to a name of your choice.

Platform specifics (port.h)

You should first check the file port.h and check the if the examples are already suitable for your platform. You must at least define the macros for enabling ENTER_CRITICAL_SECTION and disabling EXIT_CRITICAL_SECTION interrupts.

Implementation of the timer functions (porttimer.c)

The Modbus protocol stacks needs a timer to detect the end of the frame. The timers should have a resolution of half the time of a serial character. For example for 38400 baud the character time is approx. 280us assuming 11bits for a single character. The smallest timeout used by the protocol stack is 3.5 times the character timeout.

You should start by implementing the function xMBPortTimersInit( USHORT usTim1Timerout50us ) and vMBPortTimersEnable( ). Test the function with the following sample code:

xMBPortTimersInit( 20 );
vMBPortTimersEnable( );
for( ;; );
Place a breakpoint or toggle an LED in the interrupt handler which calls pxMBPortCBTimerExpired. The ISR should occur approx. 1ms after the call to vMBPortTimersEnable(). You should also check that vMBPortTimersDisable( ) works as expected.
Note:
If you use Modbus ASCII the timers are in the range of seconds because the timeouts are much larger there. Make sure you can handle a value of 20000 for usTim1Timerout50us which corresponds to an one second timeout. See mbconfig.h for the value of the timeout defined by MB_ASCII_TIMEOUT_SEC.

Porting for RTU/ASCII

The serial porting layer must be capable of initializing the UART, disabling and enabling the receiver and transmitter components as well as performing callbacks if a character has been received or can be transmitted. You should start by implementing xMBPortSerialInit( UCHAR ucPORT, ULONG ulBaudRate, UCHAR ucDataBits, eMBParity eParity ) and vMBPortSerialEnable( BOOL xRxEnable, BOOL xTxEnable ). In addition you need to create two interrupt service routines for you communication devices. It is usually simpler to start with the receive interrupt.

Create an interrupt handler for the receive interrupt, set a breakpoint there and check if xMBPortSerialGetByte( CHAR * pucByte ) correctly returns the character. This can be tested by the following code:

/* Initialize COM device 0 with 38400 baud, 8 data bits and no parity. */
if( xMBPortSerialInit( 0, 38400, 8, MB_PAR_NONE ) == FALSE )
{
  fprintf(stderr, "error: com init failed");
}
else
{
  /* Enable the receiver. */ 
  vMBPortSerialEnable( TRUE, FALSE );
  /* Now block. Any character received should cause an interrupt now. */
  for( ;; );
}
And your serial character received ISR should look like:
static void prvvUARTTxReadyISR( void )
{
    CHAR cByte;
    ( void )xMBPortSerialGetByte( &cByte );
    /* Now cByte should contain the character received. */
}

Next you should check that the transmitter part is actually working as expected. Open a terminal program and simply call xMBPortSerialPutByte( 'a' ) in the transmit buffer empty ISR. If you use the sample code from below exactly 10 characters should be received.

/* Initialize COM device 0 with 38400 baud, 8 data bits and no parity. */
if( xMBPortSerialInit( 0, 38400, 8, MB_PAR_NONE ) == FALSE )
{
  fprintf(stderr, "error: com init failed");
}
else
{
  /* Enable the transmitter. */ 
  vMBPortSerialEnable( FALSE, TRUE );
  /* Now block. Any character received should cause an interrupt now. */
  for( ;; );
}
And you serial transmit buffer empty ISR should look like:
static unsigned int uiCnt = 0;

void prvvUARTTxReadyISR( void )
{
    if( uiCnt++ < 10 )
    {
        ( void )xMBPortSerialPutByte( 'a' );
    }
    else
    {
        vMBPortSerialEnable( FALSE, FALSE );
    }
}

If you are sure everything works correctly change the interrupt routines back to the examples shown in portserial.c

Implementing the event queue (portevent.c)

If you are not using an operating system the port is already finished and the demo application should work as expected. If you in the luck of having an operating system usage of the FreeModbus protocol stack differs in the following way:

 

  • Create another task at startup which calls eMBPoll( ) in a loop. This should look like:
    for( ;; )
    {
        ( void )eMBPoll(  );
    }
    
    See the STR71x port for an FreeRTOS example.

 

  • Change the function xMBPortEventPost to post an event to a queue. Note that this function will be called from an ISR so check your RTOS documentation for that.

 

  • Change the xMBPortEventGet to retrieve an event from that queue. The function eMBPoll periodically calls it. The function should block until an event has been posted to the queue.

In addition the serial and timer interrupt function must be modified. Whenever the protocol handler callback functions pxMBFrameCBByteReceivedpxMBFrameCBTransmitterEmpty and pxMBPortCBTimerExpired return TRUE a context switch should be made after exiting the ISR because an event has been posted to the queue. Forgetting to do this will result in slow performance of the protocol stack.

Tips

This page provides some tips for using the FreeModbus protocol stack.

Reducing memory requirements

The memory requirements of FreeModbus can be tuned in the following way. These are basic tricks and can easily be done:

 

  • Decided if you need RTU, ASCII and TCP at the same time. If not disable them in the file mbconfig.h by settings the respective options MB_RTU_ENABLED, MB_ASCII_ENABLED and MB_TCP_ENABLED to zero.
  • If you don't need all Modbus functions disable them in the file mbconfig.h. This will reduce code requirements.
  • Set the variable MB_FUNC_HANDLERS_MAX in mbconfig.h to the number of functions codes you want to support.

If you have stronger limits you can also try the following options. Note that this options have an impact on the features of the protocol stack.

 

  • Use some compiler directive to put the mapping of function codes to handler functions into the flash memory of you CPU. You can find this table in the file mb.c at the top of the file. The static variable is named xFuncHandlers.

 

  • Reduce the size of the RTU buffer. In this case longer frames will result in an error (Your device will drop all these frames). This is possible if you will never get read/write requests with that number of registers or your total amount of registers is small anyway.

 

  • You could also remove some function pointers which make the protocol stack configurable and replace them by the functions itself. For example if you only want to use RTU remove the callback functions from the porting layer and fill in the appropriate calls. This will save the space for all function pointers.
posted @   溪风_不忘初心  阅读(355)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
点击右上角即可分享
微信分享提示