Our full technical support staff does not monitor this forum. If you need assistance from a member of our staff, please submit your question from the Ask a Question page.

Log in or register to post/reply in the forum.

experience with the modbus protocol

smile Jan 2, 2013 10:50 AM

Dear All, Happy new 2013

I want to acquire experience with the modbus protocol,
also by simulation, in our office of a system of virtual installation
(i.e. SCADA management of a wind farm) through free or evaluation SW,
and integrate in this system, a CR1000 datalogger.
Does anyone have suggestions?




Sam Jan 21, 2013 01:53 AM

the cr1000 supports modbus rtu, ascii(os 26), and modbus tcp.
I have used the following software during my desktop testing.



smile Jan 22, 2013 06:14 AM

Dear Sam

I try it now, too. many thanks


willB Jan 25, 2013 04:19 PM


Here is a decent reference guide. It has more information than what you need. However, it presents the transmission modes and framing of the packets which should help you learn the protocol.



smile Feb 19, 2013 08:15 AM

Dear all,

for have date and time of the events of maximum, minimum, and other, I used an array of string to 50 characters in the array of locations modbus, if the normal locations will use two registers 40000, with these strings how many records will be used and how?
I suspect that the strings can be not used.
If so, how do I get variables with at least the hour and minute of the various events, since the datatable is every 10 minutes ( with getrecord and splitstring I copy last 10 min datatable in the array for modbus)

In the help list these possibilities for VarDataType.
0-Default; 32-bit float or Long with no reversal of the byte order (ABCD)

1-If the ModBus variable array is defined as a Long, variables are treated as 16-bit signed integers

2-If the ModBus variable array is defined as a 32-bit float or a Long, the standard ordering of the 2 byte registers are reversed (CDAB)




Sam Feb 20, 2013 06:21 AM

I think there are a variety of ways to do this.

Convey the minimum time as seconds since 1990. If you used the following, your Modbus master device or software (capabilities willing) could query Modbus holding registers 1-6 (three 4-byte values) and then interpret registers 3 & 4 as a single 4-byte long representing seconds since 1990.

Public PTemp, batt_volt
Public MBReg(3) As Float
Public MBCoil(2) As Boolean

DataTable (test,1,1000)
DataInterval (0,30,Sec,10)
Minimum (1,batt_volt,FP2,0,True)
Sample (1,PTemp,FP2)

ModBusSlave (502,115200,1,MBReg(),MBCoil(),2)
Scan (1,Sec,0,0)
PanelTemp (PTemp,250)
Battery (batt_volt)
CallTable test
If Test.Output Then
MBReg(1) = Test.batt_volt_min(1,1)
MoveBytes (MBReg(2),0,Test.batt_volt_TMn(1,1),0,4)
MBReg(3) = Test.PTemp(1,1)


2) Like (1) above, convey the minimum time as seconds since 1990 but also force all of your other variable to long (4 byte signed integers). For example,

Public PTemp, batt_volt
Public MBReg(3) As Long
Public MBCoil(2) As Boolean

DataTable (test,1,1000)
DataInterval (0,30,Sec,10)
'mult by 10 to preserve 1st digit after decimal
Minimum (1,batt_volt*10,Long,0,True)
Sample (1,PTemp*10,Long)

ModBusSlave (502,115200,1,MBReg(),MBCoil(),2)
Scan (1,Sec,0,0)
PanelTemp (PTemp,250)
Battery (batt_volt)
CallTable test
If Test.Output Then
GetRecord (MBReg,test,1)

3) Yes, you can transfer strings via modbus. Remember a string is just a collection / array of bytes. And each register in modbus can contain 2 bytes. This isn't the most efficient way you could do this. And you would need to see if your modbus master can reassemble the registers into a string on the other end for you. You need to be careful about registry management and allocation. But here is a simplified example where I have allocated registers 1-2 for a floating point measurement, 3-20 for my string variable, and 21-22 for the next measurement.

Public StringMsg As String = "I am a string"
Public MBReg(11) As Float
Public MBCoil(2) As Boolean

ModBusSlave (502,115200,1,MBReg(),MBCoil(),2)
Scan (1,Sec,0,0)

' might be a battery voltage
MBReg(1) = 13.1

'initialize string registers to 0's
Move (MBReg(2),9,0,1)

'transfer string into registers
MoveBytes (MBReg(2),0,StringMsg,0,Len(StringMsg))

'maybe another measurement
MBReg(11) = 100


And there have to be a half dozen other ways to get done what you want with a little imagination.

smile Feb 21, 2013 05:52 AM

Many thanks Sam,
your message has stimulated my fantasy.

In order to not complicate the situation because of my little experience, I thought to transform the time of the events in HHMM,SS. Since, however, having outputs 10 minutes with 1 sec scan, the year, month and day are repeated continuously. So to provide the tag list to the scada system, I must to associate in pairs the register 40000 for all locations numeric floating-point I declared the array of modbuslave.
modln(1)= 40001&40002 = battVolt
modln(2)=40003&40004 = airtemp
From other tread
"Therefore, the first register corresponding to any array location X is holding register 40000+2X-1. For example, to retrieve array value number 3, you would ask for two registers starting with 40005."

modln(x)= 40000+2x-1 = min airTemp Time (HHMM,S)




Sam Feb 21, 2013 11:54 PM

The string "HHMM,SS" is 8 bytes long.
7 bytes for the items of interest and 1 for the terminating null character.
8 bytes requires 4 modbus registers.

Public myTime as string = "2400,00"
MoveBytes (MBReg(1),0,myTime,0,8)

puts this string into registers 1-4 (each register contains 2 bytes)

MoveBytes (MBReg(5),0,myTime,0,8)
puts the string into registers 11-14

smile Feb 22, 2013 04:53 AM

Hi Sam

Sorry but the comma caused a misunderstanding, in fact it would be correct to write HHMM.SS, because I want to create for the time of the events normal floating-point locations like other measurements. So a time event loc is 513.45 means the 5AM 13 minutes and 45 sec or if is 2254.35 means 10PM 54 minutes and 35 seconds. So is always the rule 2 modbus registers for each location.
However, thanks to your last description I understand the relationship between bytes, strings and Modbus register.
Thanks again

Sam Feb 22, 2013 10:43 PM

That is the general rule.
Generally folks are dealing with the FLOAT or LONG data type.
And each of these occupy 4-bytes of memory.
Since the registers are only 2-bytes, the FLOAT or LONG data occupy 2 registers.

Benjamin.vial Feb 14, 2017 05:09 PM


I think I have find want I'm looking for (in part). Is this a modbus TCP or RTU ? The 502 could be the port, so it's TCP.

Can I use your program examples sam, for a CR200X, which communicate in RTU ?

But I'm afraid I just can't understand all your actions ...

Thank you,


MattPerry Feb 14, 2017 10:36 PM

Our products support both Modbus TCP/IP (default Port 502) and Modbus RTU.  See below for Modbus master example program and Modbus slave program example, in both cases is Modbus RTU. We offer a system configuration app called ShortCut that can be used to configure our dataloggers for Modbus (https://www.campbellsci.com/scwin). For Modbus TCP/IP use 502 instead of RS-232 in program examples below.

CR300 Example:

ModbusMaster Example

The following is an example program using the ModbusMaster instruction to set up a datalogger to read the holding registers of a Modbus slave device.

This program was written for a CR1000, but other dataloggers can use similar code (voltage ranges, channel numbers, or other parameters may need to be changed to reflect the specifications of the datalogger).


'Declare Public Variables

Public PTemp, batt_volt,ModbusData(20),Result


'Define Data Tables

DataTable (Test,1,-1)

    DataInterval (0,15,Sec,10)

    Minimum (1,batt_volt,FP2,0,False)

    Sample (1,PTemp,FP2)

    Sample (1,ModbusData(),FP2)



'Main Program


    Scan (1,Sec,0,0)

      PanelTemp (PTemp,60)

      Battery (Batt_volt)


      'Retrieve Modbus Data

      ModbusMaster (Result,COMRS232,115200,3,3,ModbusData(),1,10,3,100)


      'Enter other measurement instructions

      'Call Output Tables

      CallTable Test




ModbusSlave Example


Public PTemp, batt_volt, ModResult,I

Public ModIn(80)


'Main Program


ModbusSlave (ComRS232,9600,1,ModIn(),0)


  Scan (2,Sec,0,0)

    PanelTemp (PTemp,60)

    Battery (Batt_volt)


    ModIn(1) = batt_volt

    ModIn(2) = PTemp

    ModIn(3) = ModResult




Benjamin.vial Feb 15, 2017 12:50 PM


thanks a lot for your answer. If the CR300 program very interess me (since few month we prefer this datalogger), it remains a problem : what about the CR200X ? Is this datalogger can be in modbus TCP or only RTU ?

I will try the CR300 program in few days (one of them come back of the field).

I have tried use this program on CR200X but with adaptation, and now I can see some value in register with a windows RTU software (first time, youhou)!

Now I'm trying to read the same thing with a pyton program (minimalmodbus). When I will successfully read a value and make a clean table, I will probably come again and ask some program improvement, because I'm not a specialist of CR Basic...



Benjamin.vial Feb 15, 2017 01:21 PM

Hello again,

so, good new, I can reach the CR200X with my python program. But there is a strange thing : I'm asking th reads from the register 1 to 4 (16 bit reading) and have a response but I don't understand the values. And when I'm trying to read registers 3000X or 4000X, I can't.

Have I miss something ?


Benjamin.vial Feb 16, 2017 02:16 PM


I have tried a lot of way, but CR200X denied request farther than register addresse 12. All request on 30001 or 40001 are denied ans the response is "illegal data address", like the CR200X don't recognize my register request. I'm pretty sure that's not a python program problem.

Have you an idea ?

Maybe there is missing somethine in the CR200X program ?

Thanks, bye.

MattPerry Feb 16, 2017 03:39 PM

Can you post the CR200X program?

Benjamin.vial Feb 16, 2017 03:51 PM

of course, here it is :

'CR200/CR200X Series

'Declare Variables and Units
Public BattV
Public SEVolt
Public Rain_mm
Public Moddata(80)
Public ModResult

Units BattV=Volts
Units SEVolt=mV
Units Rain_mm=mm

'Define Data Tables


'Main Program
  ModBusSlave (2,9600,1,Moddata(),0,0,0)
    'Main Scan
        'Default CR200 Series Datalogger Battery Voltage measurement 'BattV'
        'Generic Single-Ended Voltage measurement 'SEVolt'
        '52202/52203 Rain Gage (CSL) measurement 'Rain_mm'
        'Call Data Tables and Store Data


        CallTable Table1
        CallTable Table2


I precize that no sensor is connected on for the moment.


MattPerry Feb 16, 2017 04:00 PM

if you're asking the slave for 16-bit, then you need to configure the CR200X for 16-bit. Edit the last parameter in your ModbusSlave instruction for the right data type:


ModbusOption      ModbusOption is an optional parameter that is used to specify the data type of the Modbus variables.

Code          Description

0                Default; 32-bit float or Long, the standard ordering of the 2 byte registers are reversed (CDAB)

1                If the Modbus variable array is defined as a Long, variables are treated as 16-bit signed integers

2                If the Modbus variable array is defined as a 32-bit float or a Long, with no reversal of the byte order (ABCD)

3                If the Modbus variable array is defined as a Long, variables are treated as 16-bit unsigned integers

10               Modbus ASCII, 4 bytes, CDAB

11               Modbus ASCII, 2 bytes, signed

12               Modbus ASCII, 4 bytes, ABCD

13               Modbus ASCII, 2 bytes, unsigned

Benjamin.vial Feb 16, 2017 04:21 PM

Effectively, i'm asking a 16-bit response from the registers but where in the function can I set this parameter ?

ModbusSlave (COMPortMB,Baudrate,ModbusAddress,ModbusVariable,ModbusBooleanVar,ByteOrder,OffsetMB)

Because in CRBasic editor I can't see the "ModbusOption" parameter type (only for the CR300).

But I have test the 1 option at the end of the function (write as "offsetMB"), just in case, it doen't work.

But thank you for your answer.

MattPerry Feb 16, 2017 04:31 PM

Sorry, I keep thinking of the CR300. For the CR200 you must have special OS:

CR200 MODBUS OS v.10 (1.97 MB) 09-08-2010

Special operating system that supports ModBus communication and SDI-12 sensors .  Also included is the Compiler and CRBasic Editor support files for the CR2xx dataloggers.

Use of this file will update the datalogger compiler and CRBasic Editor support files.

Note: Not to be used with the CR200X series.

Includes: MODBUS Instructions, SDI12Sensor, WindVector

please download from the Downloads section on this page:


here is more information about modbusslave in CR200X:



For the CR200, this instruction is supported only in a special operating system version M. You must have this special operating system loaded in your datalogger, and the datalogger program must be compiled with an alternate precompiler that supports this instruction. 

No special operating system is needed for the CR200X.

The ModBusSlave instruction sets up a datalogger as a ModBus slave device.


ModBusSlave ( ComPort, BaudRate, ModBusAddr, ModBusVariable, BooleanVariable, ByteOrder [optional], Offset [optional] )


This instruction sets up a ModBus slave device to respond to the data request of a ModBus master. Supported ModBus functions are 01, 02, 03, 04, 05, 15, and 16. See the ModBusMaster help for details on these functions.

This instruction may be placed outside the main program scan. It only needs to be executed once.

ComPort               The ComPort parameter specifies the communication port and mode that will be used for this instruction.

Alphanumeric Code           Description

0  RS232 ModBus/PakBus

1                                        RF Port

2                                        RS232 Port

3                                        COM1, Datalogger's control ports C1 (TX) and C2 (RX)

  Option 0, ModBus/PakBus, uses the PakBus Datagram protocol with an application ID of 502 that will allow ModBus packets to be routed via PakBus on the RS232 port.

BaudRate              The BaudRate parameter is used to set the rate, in bps, for communication. The options are 1200 and 9600. Selecting one of these options fixes the baud rate at that rate of communication. This parameter is ignored if RF Port ComPort option is selected.

                            The datalogger uses 8 data bits and no parity for ModBus communication.

ModBusAddr        The ModBusAddr parameter is used to assign an address to the ModBusSlave. Valid ranges are 1 - 127 for ModBus, or 1 - 247 for ModBus/PakBus.

ModBusVariable    The ModBusVariable parameter is used to specify the variable array that is used as the source of data for the ModBusMaster, or the variable array that is used as the destination for data received from the ModBusMaster. The maximum size allowed for this variable is 15 elements. The datalogger does not differentiate between holding and input registers. The only difference is the address offset. The specified array will be used for requests of input (address offset of 30000) or holding (address offset of 40000) registers.

                            Floating point variables take two ModBus registers. The ModBus input registers are offset by 30000; ModBus holding registers are offset by 40000. Therefore, the first register corresponding to any array location X is holding register 40000+2X-1. For example, to retrieve array value number 3, you would ask for two registers starting with 40005.

BooleanVariable    The BooleanVariable parameter is a variable or variable array that is used to hold the result if the master sends one of the discrete on/off commands to the slave (i.e., 01 Read Coil/Port Status, 02 Read Input Status, 05 Force Single Coil/Port, 15 Force Multiple Coils/Ports). Each element in the variable array maps to one Boolean value. The array size determines the number of Boolean values; the maximum size of the array is 16 elements.   

                            If a 0 is entered for this parameter, then the discrete commands are mapped to control ports C1 and C2 instead. Note that if 0 is entered for this parameter, there will be a conflict if  ComPort is configured for option 3, COM 1.

ByteOrder             ByteOrder is an optional parameter that indicates the byte order of the floating point value. If this parameter is not used or is set to 0, no inverse on float values is used. Any value greater than 0 indicates that inverse order for float values will be used.

Offset                   Offset is an optional parameter that specifies the offset for the starting register. 


The datalogger communicates in RTU mode (not ASCII mode) to other ModBus devices. The communications port, baud rate, data bits, stop bits, and parity are set in the ModBus driver for PC-based software or on the PLC.

A datalogger acting as a ModBus slave returns a ModBus exception code 01 (Illegal Function) if a query is invalid, and an exception code of 02 (Illegal data address) if data values beyond the size of an array are requested. 

Some ModBus devices (e.g., some RTUs made by Bailey Controls that use less common CPUs) require reverse word order (MSW/LSW versus LSW/MSW) in the floating point format. Some software packages have a setting to work with this original ModBus format. For example, the “Modicon 32-bit floating point order (0123 vs. 3201)” advanced option must be enabled for the ModBus object in National Instruments’ Lookout.

Benjamin.vial Feb 17, 2017 04:22 PM

Hello Matt,

thank for your answer. So I have a CR200X, no special OS needed, as you said.

Thank you to have copy the CRBasic function help but, as you can see, there is not the parameter type "ModbusOption" in ModbusSlave for CR200X.

So I remains stuck, I don't find a solution to set the datalogger to 16bit communication for the moment.

But maybe it's another problem. What do you think about this ?


JDavis Feb 17, 2017 11:56 PM

The CR200X only supports the equilavent of ModbusOption set to 0. 

Log in or register to post/reply in the forum.