MODBUS/RTU slave
Does anyone have ideas about how to implement a slave using the MODBUS/RTU protocol?
I have been using for some time a MODBUS/ASCII slave I implemented. I'd like to implement MODBUS/RTU for compatibility with other devices that don't understand MODBUS/ASCII. But a MODBUS/RTU implementation is required to detect gaps between characters of more than 3.5 character times, because this is what delimits a message, unlike MODBUS/ASCII which uses specific characters. Since my controller has other things to do, it may not get back to checking the character input buffer before the gap has elapsed and some other slave has started to reply. It therefore would get out of sync and miss messages.
If only the UART virtual peripheral could detect and mark these gaps...
I suspect is isn't possible. Looking for ideas... Thanks.
Derry
I have been using for some time a MODBUS/ASCII slave I implemented. I'd like to implement MODBUS/RTU for compatibility with other devices that don't understand MODBUS/ASCII. But a MODBUS/RTU implementation is required to detect gaps between characters of more than 3.5 character times, because this is what delimits a message, unlike MODBUS/ASCII which uses specific characters. Since my controller has other things to do, it may not get back to checking the character input buffer before the gap has elapsed and some other slave has started to reply. It therefore would get out of sync and miss messages.
If only the UART virtual peripheral could detect and mark these gaps...
I suspect is isn't possible. Looking for ideas... Thanks.
Derry
Comments
static final int rxpin = CPU.pin0;
static Uart rxmod = new Uart(Uart.dirReceive,rxpin,Uart.dontInvert,Uart.speed1200,Uart.stop1);
in true mode, the idle pin level is high (true)
to await a gap, wait for a high period of 3.5*bytetime = 3.5*10*bittime = 35*bittime
= 35/baudrate = 35/1200 = 0.02917sec = 3360.215*8.68usec
So you need to detect a high period of at least 3360 ticks (at 1200 baud)
int n·= CPU.pulseIn(3360,rxpin,true); //checkout pulseIn command
if (n == -1) { //pulse>timeout so gap detected
· //copy receive buffer to message·buffer
· //process·message
}
Normally it is not adviced to access pins used in a VP also using other commands,
but since the pin direction does not change it may work.
regards peter
Another idea I had: I do have control of the master on the bus, so I could put larger gaps between messages, large enough to guarantee that the Javelin stamp slave will check the Uart sometime within that gap and see an empty buffer. Some of the problems with this are (a) the gap would probably have to be 100 ms or more, which would seriously degrade performance; (b) I don't have control of the other slaves, which would probably transmit replies too soon for the Javelin Stamp to see them as separate messages; and (c) I would not be able to use standard Modbus programs such as monitoring tools.
Still another idea I had, this one pretty ugly: Go ahead and use MODBUS/RTU for the devices that need it, and MODBUS/ASCII for the Javelin stamp. It is likely, though not guaranteed, that the messages that are not understood will be considered to be garbage and thrown away, though some devices might be disturbed by all the errors.
Derry
gap. The problem is receiving. If you would happen to know the value of the first byte(s) of the
message (eg. header) then it wouldn't matter that subsequent messages are received after a gap
because you could calculate the message end based on the RTU format, if that is possible.
If a message end can only be detected by·using the gap, then you must indeed poll the receive
frequently enough so you·do not miss it. If you use RTU for sending control commands only
(eg. you don't request values, so you don't really need to receive data) then the received RTU
message could be ignored. Are ascii and RTU messages mixed on the same bus?
That would·complicate things even more, especially if reesponses are out of order with
transmitted commands.
regards peter
http://www.protocessor.com/techsupport/Free_Modbus_RTU_Source_Code.asp
I suspect that source uses an interrupt to monitor for a gap, but perhaps not.
And since C is almost javelin java it may give some ideas that would also
work on the javelin.
regards peter
one master -- will be at different times a PC, a programmable RS485-Ethernet gateway, or a home automation processor. In any of these cases it can speak either MODBUS/RTU or MODBUS/ASCII, and it is custom-programmed.
multiple slaves
* one is my controller based on Javelin stamp, which responds to both set-data and get-data commands, which speaks MODBUS/ASCII today
* others are manufacturered devices; all can speak MODBUS/RTU but some cannot speak MODBUS/ASCII, and I have no control over the programming
My choices are:
1. Use MODBUS/RTU exclusively, if I can get the Javelin stamp to reliably use this protocol. It would have to both receive and reply. One challenge for receiving is that it must process and ignore messages directed to other devices.
2. Attempt to use MODBUS/RTU and MODBUS/ASCII on the same network, the latter for the Javelin stamp and the former for everything else. As I mentioned this MIGHT work but is not pretty.
3. Give up and use two different RS485 networks, one for MODBUS/RTU and one for MODBUS/ASCII. Less desirable because it requires more connections to the computers, an extra programmable gateway, extra wiring, etc.
I think that some RTU implementations do process the message as it is received to know where the frame ends. The message does have enough information to do this, but it isn't simple like a length field; I believe it requires full knowledge of the message formats down at a software level where it doesn't belong. But I think that is the approach I'll pursue to see if it can work. One challenge is that if there is an error it may take a long time to resynchronize. There is no way I know of to detect the beginning of a message; there's no fixed header.
The PIC code you sent is interesting. It's not clear to me how it works, since I don't see where it is doing any timing.
Derry
http://www.lammertbies.nl/comm/info/modbus.html
ascii and rtu cannot be mixed. So your option 2 is not possible.
I think option 1 is not possible either because the javelin cannot
detect gaps frequently enough.
If the PIC source does not show any timing, then I am convinced
the idle times are calculated in the interrupt routine, which would consist
of a simple counter and a boolean value set if that counter reaches a value
corresponding to 3.5 charactertime. (much like my pulseIn example,
but executed more frequently and independant of the main program).
Which leaves option 3, where the javelin is connected to the ascii bus.
A 4th option would be to implement a RTU/ascii converter using a microcontroller
like SX28/48,·PIC, AVR etc. and use its ascii output to commicate with the javelin.
Or use a readymade RTU/ascii converter.
That way you only need·one network (RTU).
regards peter