Project - Master/Slave Modbus (RTU/TCP) Library for NETMF and Windows

For Modbus RTU you can try this: http://www.plcsimulator.org/
It`s absolutely free.

Or

Also I recommended Terring Modbus Tools - it’s Russian program includes English language. You can download it from my One Drive, because official site “terring.ru” is dead :frowning:

https://onedrive.live.com/redir?resid=265FBEC72091C5A9!2694

Interesting advice!

But what about continuous streaming data, for example, using an auxiliary device/slave such as a temperature sensor that would constantly send back data over RTU to the master.

Is this a possibility with Modbus?

Your sensor device can act as a slave on Modbus and you simply encode your sensor data into suitable Modbus registers.

You’ll need a Master device to poll and read the registers. The slave does not send without the master requesting its data,

It would allow you to have more than 1 sensor slave on the bus as each one would have its own Modbus address.

It would not be a continuous stream as such as Modbus has inherent delays to detect start and end of messages but it should be pretty fast if only dealing with a few Modbus registers.

If you wanted a streaming system with lots of fast data consider CAN bus for this instead. Its multi-master so each slave can send any time it wants on the bus (within limitations of the priority of course but would be faster than Modbus in most cases)

No.
Each communication starts with a request by the master.
This is also a must, because there can only be one device that is sending on RS485, because there is no collision detection.
By this no slave can send data on it’s own.
I’m not sure if there is some kind of extension for this on Modbus TCP, but I’d guess not.

In fact, Modbus was designed for “simple” IO devices.
I have some Modbus TCP Devices, which I poll easily with 1kHz.
Modbus RTU is slower of course, depends on the Baudrate.

1 Like

I have a another question around Modbus Master emulators.
I have tried everything I can including ones that have been posted in this thread and they all pretty ,much only look and the coil, discrete and register function codes. What I haven’t see are ones that test all Modbus Function codes.

Does anyone know of any that do that do all function codes? would perfer free but would pay a reasonable cost for one

I have a bit of a different project in mind.
I’m building a controller for my observatory to control, LED Recticles, Fans, Main Power, domes, roll of roofs and a slew of other types of equipment.

I was working on a domain specific language for it but thought MODBUS, it’s a control language why not for telescopes?

One other question I have if you dont mind a general C# question
If I have one class which inside it defines a public variable. then in another class I use it. I keep getting variable can not be used in this context. I know it’s something simple I’m not doing but am not sure.

basic summary is a gadgeteer device that in the program class creates the variable then in a separate class I user it.

The coil and register Function codes are more or less all you need for general IO.
Most of the others are for diagnostic, device identification, …
Most of the Modbus slaves on the market does not support them anyway.

Could you poste some code and the exact error you get?
Normally a public variable (I assume you mean a field, or is it a property?) should be usable from anywhere with a view exceptions.
You can’t use properties as ref or out parameters. Not sure about fields for that.

In the Gadgeteer Part of the program I am after the led_strip and it is declared this way


namespace MODBUSled {
    using Gadgeteer;
    using GTM = Gadgeteer.Modules;
  
    public partial class Program : Gadgeteer.Program {
         /// <summary>The LED Strip module using socket 1 of the mainboard.</summary>
        public Gadgeteer.Modules.GHIElectronics.LED_Strip led_Strip;

later in create a class for the my modbus slave I have


   public class ModbusSlave : ModbusDevice
        {
            public ModbusSlave(IModbusInterface intf, byte deviceAddress, object syncObject = null)
                : base(intf, deviceAddress, syncObject)
            {

            }
...
            protected override ModbusErrorCode OnWriteSingleCoil(bool isBroadcast, ushort address, bool value)
            {
                switch (address)
                {
                    case 4000:
                        if (value == false)
                        {
                            Debug.Print("OnWriteSingleRegister address=4000 value=false");
                            led_Strip.SetLED(1, false);
                        }

The error I get is

[quote]Error 1 The name ‘led_Strip’ does not exist in the current context C:\Users\Sandra\Google Drive\FEZ\Cobra II\ModbusLib\ModbusLib\MODBUSled\Program.cs
[/quote]

it is either something really simple or really dumb.

I understand that most MODBUS devices don’t do these the identification and diagnostics but mine needs to. I am not building a typical modbus device.
I am building a astronomic set of devices that the driver on a control PC will need to know what it attached on it’s network of devices, Focuser Controller, Dome Controller, Temperature devices and others. They need to identify what they are and I need to be able to run diagnostics on some of them. Hence my desire for something that does this already.

@ smgvbest - The led_Strip field is only known directly inside the Program class.
From any other class you need a reference to the Program class.

You could create an static property that points to the Program class, so you can access it from anywhere in your program.
This will work here, since there is always only one instance of the program class.
You can do this as follows.

public partial class Program : Gadgeteer.Program {
    /// <summary>The LED Strip module using socket 1 of the mainboard.</summary>
   public Gadgeteer.Modules.GHIElectronics.LED_Strip led_Strip;

   // static property to access singleton instance of program from anywhere
   public static Program Instance { get; private set; }

   // constrcutor
   public Program()
   {
      // assign this Program to property Instance
      Instance = this;
   }

Then you can access led_Strip like this:

case 4000:
                         if (value == false)
                         {
                             Debug.Print("OnWriteSingleRegister address=4000 value=false");
                             Program.Instance.led_Strip.SetLED(1, false);
                         }

For testing more Modbus functions, you could use the Windows version of my library in master mode.
Just create a simple win forms or WPF application, initialize a Modbus master and test the functions on your device with it.

Thank you, that worked.

To add to another comment I do get CRC and Timeout errors both in debug and release versions especially at higher speeds (highest I ran was 256Kb serial).
I’m using a 1000ms timeout and a 10ms poll, tried changing them with some effect but even at a 2000ms timeout and a 50ms poll i still get both.

@ smgvbest - So I couldn’t test the slave mode too much.
May be the Receiver code Needs a bit mor tweaking.

@ Reinhard Ostermeier
FWIW, at <115200 I don’t seem to have an issue, it’s speeds over 115200 that I seem to have4 the problem, for my application I would like to go at 256000Kbaud

if you could point me to where you think the problem might be I could try to get it to work

I will also pass this on and hopefully I am correct in this
in the ModbusDevice.cs I changed the ReadInputRegisters to pass the registerCount to the OnReadInputRegisters and changed the OnReadInputRegisters to accept the additional Parm


var err = OnReadInputRegisters(isBroadcast, startAddress, registers);

to


var err = OnReadInputRegisters(isBroadcast, startAddress, registerCount, registers);

and here is the small change to the OnReadInputRegisters


        /// <summary>
        /// Is called when a ReadInputRegisters request comes in.
        /// </summary>
        /// <param name="isBroadcast">true if the message is a broadcast. For broadcast messages no reponse is sent.</param>
        /// <param name="startAddress">Start address: 0x0000 .. 0xFFFF</param>
        /// <param name="registerCount">The number of Registers to read</param>
        /// <param name="registers">Array in which the read register values must be written.</param>
        /// <returns>Returns <see cref="ModbusErrorCode.NoError"/> on success or any other <see cref="ModbusErrorCode"/> on errors.</returns>
        /// <remarks>
        /// Look at <see cref="http://www.modbus.org/docs/Modbus_Application_Protocol_V1_1b3.pdf"/> for more details.
        /// </remarks>
        protected virtual ModbusErrorCode OnReadInputRegisters(bool isBroadcast, ushort startAddress,ushort registerCount, ushort[] registers)
        {
            return ModbusErrorCode.IllegalFunction;
        }

@ smgvbest - I can imagine two soureces of the Problems at high baud rate:

1st: Your wiring is not good enough for high baud rates, and you get corrupted Messages:
Make sure you have twisted pair cables, shielding and Termination resistors in place, and also a straight line, no T or even star shaped topology.

2nd: If ist in my Software, then it’s most likely here
Modbus/Interface/ModbusRtuInterface.cs
public bool ReceiveTelegram(byte[] buffer, short desiredDataLength, int timeout, out short telegramLength)

about the additional Parameter:
You aslo get the number of Registers by the length of the registers Array:
so: Registers.Length is the same as registerCount.

I do not think it my wiring, it does work with other devices at the same speed. in my case this is a usb to serial adapter. FTDI chip based. 12" cable run total into the Cobra II. @ 256k its continuous errors. @ 115K its around 70% errors. at 19200 its ok. in the code I notice at that speed it switches to a constant value of 500us i think for 11920+. seems interesting to me thats where it happens for me.

Ill use the length as you mention but for those of us not masters of c# passing parms is allot more clear.

I am working on a Master Client for windows now instead that does all function codes. based of the modbuspoll.exe app

I don’t think this is related to the Modbus driver. I have major issues getting a Cobra 2 to work at 115200 baud with a GSM modem. Far too many errors. Up to 19200 us OK but anything above this is just not stable.

I have finally added the 2nd version of the library to CodeShare.

  • Added Gateway functionality
  • Added optional digital output pin to ModbusRtuInterface to control read/write mode
  • Improved TCP code
  • Added Sandcastle Help project

Thanks a lot for sharing your code!

A quick question:

How do you switch the RS485 transceiver from receive to send (and back)? Is this something must be solved at “hardware” level?

Most transceivers have an additional Pin for controlling this… Is it possible to control this in software via GPIO (then we must know when the uart buffer is empty and all bytes have been sent)?

You can simply use this constructor of RtuInterface:

/// <summary>
/// Creates a new Modbus RTU interface using an existing and fully initialized <see cref="SerialPort"/>.
/// This interface can be used with <see cref="ModbusMaster"/> or <see cref="ModbusDevice"/>.
/// </summary>
/// <param name="serial">Fully initialized <see cref="SerialPort"/>.</param>
/// <param name="writePin">Pin for select read/write mode. Set <see cref="Cpu.Pin.GPIO_NONE"/> for an automatic switching transceiver.</param>
/// <param name="writeState">State of writePin to set for writing.</param>
/// <param name="maxDataLength">Maximum number of data bytes</param>
/// <remarks>
/// This overload allows to specify a digital output pin by which read/write is selected.
/// For writing the value of writeState is set, For reading !writeState is set.
/// The pin is held at state read for all the time except in the short write phase.
/// </remarks>
public ModbusRtuInterface(SerialPort serial, Cpu.Pin writePin, bool writeState, short maxDataLength = 252)

writePin specifies the pin you use for read/write mode.
If the pin needs to be set to true (high) for writing, then you set writeState to true. in pin needs to be low for writing you set writeState to false.
I use this al the time. Internally the pin is kept at read state all the time, except for the time when data is sent. To make sure all data is written, SerialFlush is called before the pin is set back to read mode.

Thanks will try. Which hardware do you use for RS485?

Can you suggest a ready to use module?

At work we use custom PCB’s which use a MAX48 chip.
At home I use the GHI RS485 module, which does not need the read/write pin.

Thanks for the information.

Do you know, if it is possible to adjust the delay from switching from Send to Receive in the GHI module?
or is it implemented in hardware.

I ask, because I had some hardware, where I had to tune the delay to get communication without errors in another project…