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_RTU, MB_ASCII, MB_TCP } enum eMBRegisterMode { MB_REG_READ, MB_REG_WRITE } enum eMBErrorCode {
MB_ENOERR, MB_ENOREG, MB_EINVAL, MB_EPORTERR,
MB_ENORES, MB_EIO, MB_EILLSTATE, MB_ETIMEDOUT
}enum eMBParity { MB_PAR_NONE, MB_PAR_ODD, MB_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.c, STR71XTCP/demo.c, and WIN32TCP/demo.cpp.
Enumeration Type Documentation
enum eMBErrorCode Errorcodes used by all function in the protocol stack.
- Enumeration values:
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:
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:
enum eMBRegisterMode 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:
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.c, MCF5235TCP/demo.c, STR71XTCP/demo.c, WIN32/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.c, MCF5235TCP/demo.c, STR71XTCP/demo.c, WIN32/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.
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:
- eMBErrorCode::MB_EINVAL If the slave address was not valid. Valid slave addresses are in the range 1 - 247.
- eMBErrorCode::MB_EPORTERR IF the porting layer returned an error.
- Examples:
- AT91SAM7X_ROWLEY/demo.c, AVR/demo.c, LINUX/demo.c, MCF5235/demo.c, MSP430/demo.c, STR71X/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.
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.c, LINUX/demo.c, MCF5235/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:
- eMBErrorCode::MB_EINVAL If the slave address was not valid. Valid slave addresses are in the range 1 - 247.
- eMBErrorCode::MB_EPORTERR IF the porting layer returned an error.
- Examples:
- MCF5235TCP/demo.c, STR71XTCP/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
|
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.
|
|
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.
|
|
Callback function used if a Holding Register value is read or written by the protocol stack. The starting register address is given by
|
|
Callback function used if the value of a Input Register is required by the protocol stack. The starting register address is given by
|
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
|
If Modbus ASCII support is enabled.
|
|
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. |
|
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. |
|
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. |
|
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 |
|
If the Report Slave ID function should be enabled.
|
|
If the Read Coils function should be enabled.
|
|
If the Read Discrete Inputs function should be enabled.
|
|
If the Read Holding Registers function should be enabled.
|
|
If the Read Input Registers function should be enabled.
|
|
If the Read/Write Multiple Registers function should be enabled.
|
|
If the Write Coils function should be enabled.
|
|
If the Write Single Register function should be enabled.
|
|
If the Write Multiple Coils function should be enabled.
|
|
If the Write Multiple registers function should be enabled.
|
|
If Modbus RTU support is enabled.
|
|
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
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 fileport.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( ;; );
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. Seembconfig.h
for the value of the timeout defined byMB_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 implementingxMBPortSerialInit( 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( ;; );
}
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( ;; );
}
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( ); }
- 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 functioneMBPoll
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 pxMBFrameCBByteReceived
, pxMBFrameCBTransmitterEmpty
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.
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通