FreeMODBUS - A Modbus ASCII/RTU and TCP implementation

latest release v1.5 - 6 June 2010
This is a simple example showing how to use the Modbus protocol stack. It is nearly the same as the example simple2.c for the FreeRTOS/STR71x demo application with some parts removed for presentation purposes. In this example we map four 16bit input registers at the register address 1000. The first register counts the number of times the main polling loop was cycled. The second and third registers hold the current RTOS ticks counter and the fourth register holds a constant.
/* ----------------------- Defines ------------------------------------------*/
#define REG_INPUT_START 1000

/* ----------------------- Static variables ---------------------------------*/
static unsigned short     usRegInputStart = REG_INPUT_START;
static unsigned short     usRegInputBuf[REG_INPUT_NREGS];


static void
vModbusTask( void *pvParameters )
    portTickType    xLastWakeTime;

    /* Select either ASCII or RTU Mode. */
    ( void )eMBInit( MB_RTU, 0x0A, 38400, MB_PAR_EVEN );

    /* Enable the Modbus Protocol Stack. */
    ( void )eMBEnable(  );
    for( ;; )
        /* Call the main polling loop of the Modbus protocol stack. */
        ( void )eMBPoll(  );
        /* Application specific actions. Count the number of poll cycles. */
        /* Hold the current FreeRTOS ticks. */
        xLastWakeTime = xTaskGetTickCount(  );
        usRegInputBuf[1] = ( unsigned portSHORT )( xLastWakeTime >> 16UL );
        usRegInputBuf[2] = ( unsigned portSHORT )( xLastWakeTime & 0xFFFFUL );
        /* The constant value. */
        usRegInputBuf[3] = 33;

Most of the work is done in the main polling loop. Internally it works by waiting for an event posted to a queue (See footnote [1]). Such a event is for example the reception of a Modbus frame. These events are posted to the event queue by the interrupt driven receiver and transmitter state machines. After a frame is received the FRAME_RECEIVED event is posted and one loop iteration is executed. Following the receive event an EXECUTION event is created internally. Because there is such a special event for the time after frame reception and before the response is sent the current register values can be updated. After execution the resulting frame is transmitted and a FRAME_SENT event is raised.
But where does the Modbus stack hold the actual register values? In this case the actual buffer is provided by the callback function eMBRegInputCB. Again the implementation of such a function is quite simple.
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 )( usRegInputBuf[iRegIndex] >> 8 );
            *pucRegBuffer++ =
                ( unsigned char )( usRegInputBuf[iRegIndex] & 0xFF );
        eStatus = MB_ENOREG;

    return eStatus;
Using this code and a Modbus test utility we get the following output in a console window:
Z:\home\wolti\devel\privat\arm\freemodbus\tools>modpoll.exe -m rtu -a 10 -r 10
00 -c 4 -t 3 -b 38400 -d 8 -p even  COM4
modpoll - FieldTalk(tm) Modbus(R) Polling Utility
Copyright (c) 2002-2004 FOCUS Software Engineering Pty Ltd
Getopt Library Copyright (C) 1987-1997  Free Software Foundation, Inc.
Protocol configuration: Modbus ASCII
Slave configuration: Address = 10, start reference = 1000, count = 4
Serial port configuration: COM4, 9600, 7, 1, even
Data type: 16-bit register, input register table

Protocol opened successfully.
Polling slave (Ctrl-C to stop) ...
[1000]: 467
[1001]: 3
[1002]: 18547
[1003]: 33
Polling slave (Ctrl-C to stop) ...
[1000]: 470
[1001]: 3
[1002]: 19544
[1003]: 33
Polling slave (Ctrl-C to stop) ...

[1]: Without an operating systems there are normally no queues available. In this case the application would look like our example and the queue receiving and sending functions would be implemented by simple global variables which are set if events are posted to the queue. The queue receive function would check the state of the variables and would return TRUE if a event was posted. The return value would then be checked by the main loop and if TRUE eMBPool would be called. Otherwise other functions can be executed.

FreeMODBUS library and web page maintained by Christian Walter [wolti at sil dot at]
BerliOS Logo
FreeMODBUS is sponsored and provided by embedded solutions embedded solutions
Low on development resources? Try freelancer and find new skilled people for your projects. IT Projekte und Freelancer

Valid HTML 4.01 Strict