This is a note I got from Bill Brown at LBL a few months ago.
Apparantly there are different flavors of MODBUS. If you are using it
in ASCII or RTU mode, you should be able to implement a MODBUS
driver by using the included note and the read() and write() calls to
the tyco triver that comes with vxWorks.
We have no current MODBUS needs at that APS (that I am aware of) so I
have not really been to active in the MODBUS area.
I hope the following stuff is useful.
--John
------- Forwarded Message
Return-Path: <[email protected]>
Received: from csg.lbl.gov by phebos.aps.anl.gov (4.1/SMI-4.1)
id AA13058; Tue, 12 Jul 94 09:29:47 CDT
Received: from brownie.csg.lbl.gov.csg by csg.lbl.gov (4.1/1.39)
id AA08055; Tue, 12 Jul 94 07:29:45 PDT
Date: Tue, 12 Jul 94 07:29:45 PDT
From: [email protected] (Bill Brown)
Message-Id: <[email protected]>
To: [email protected]
Subject: Modbus
I saw the following reference to the Modicon stuff on Comp.realtime - since
I don't know if you watch that newsgroup and since it may provide a pointer
to something useful, I'm passing it on. If not, I'm sure you know what to
do with it.
- -bollcomp.realtime #74 (0 + 0 more) (1)--[1]
From: [email protected] (Neil Dunbar)
[1] Re: Modbus Protocol
Organization: Rochester Instrument Systems, Ltd.
Date: Tue Jul 12 03:34:31 PDT 1994
Lines: 175
[email protected] (Mark West) writes:
>I am looking for information about the Modbus protocol. In particular
>I am searching for information on C source code and information about
>any possible real data type extensions and how they are implemented.
G other than what I've found out via experimentation. The following
almost certainly contains errors and definitely contains omissions, so by
all means send in corrections.
There are two distinct Modbus protocols, Modbus and Modbus Plus. Modbus, in
its true form is a point-to-point protocol implemented via RS-232 at up
to 19,200 bps. The company that invented it, AEG Modicon had as their main
interest a protocol for interrogating/controlling PLCs, but as other people
(desperately seeking a common data acquisition protocol) looked at it,
they figured it could be used for various purposes, e.g. data acquisition,
system control, etc. So AEG/Modicon released the information into the public
domain. Modbus requires no special hardware to set up a network of nodes.
It is also true that many installations of 'Modbus' nodes ignore the more
stringent requirements, and end up installing 38,400 bps transmissions
hosted over an RS-422/485 multidrop cabling system.
Modbus Plus, on the other hand, is a true peer-to-peer networking system,
which requires special equipment from AEG, and they charge a fortune for
it. I know very little about this.
The Modbus protocol has two incarnations, ASCII and RTU modes. ASCII transfers
all numbers as explicit ASCII digits, e.g. number 7F hex would be
transmitted as '7' 'F'. RTU mode transmits all bytes as 8 bit bytes. Two
byte values are tranmitted as MSB:LSB pairs. The parity setting is not
defined, but if parity is enabled (Even or Odd), then 1 stop bit is used.
If parity is disabled, 2 stop bits are used. 1 start bit is used in either
case. ASCII mode defines a 7 bit data byte, RTU mode defines 8.
A Modbus network can have one node designated as a master, which means that
it alone can transmit request. All other nodes (slaves) can only respond to
requests by the master node. Nodes have unique numbers between 1 and 64. When
the master transmits to node number 0, this is taken to mean a broadcast to
all nodes. The protocol specifies that broadcasts cannot elicit responses. As
far as I know, multicasting is not supported on standard Modbus.
A Modbus packet is defined as a series of bytes, corresponding to the following
meanings -
+-------------+
| ASCII ':' | -- ASCII mode ONLY - Start of message indicator
+-------------+
| Node Number | -- 00-40h: if a request, the node that the request is
| | is addressed to, if a reply, the node that replied.
+-------------+
| Function No.| -- function number. 00-7F. Functions 01 to 24h are
| | defined by AEG as standard. Function 08, for
| | example, is the diagnostic command, which has as
| | its parameters various subfunctions designed to
| | test various aspects of the remote unit.
+-------------+
| : |
| : | -- zero or more bytes serving as data for the
| : | function defined above.
+-------------+
| LRC or CRC | -- If ASCII mode, a Longitudinal Redundancy Check is
| | used. If RTU mode, Cyclic Redundancy Check is used.
| (16 bit val)| Checked over the length of the message.
+-------------+
| ASCII CR/LF | -- ASCII mode ONLY - Carriage Return and Line Feed
| | acts as message terminator.
+-------------+
The CRC for RTU mode is generated by the following C code -
========== Start of crc.c =================================================
/* include file with arrays concerning 16 bit crc calculations */
/* table of crc values for high order byte */
static unsigned char auchCRCHi[] = {
0x00,0xc1,0x81,0x40,0x01,0xc0,0x80,0x41,0x01,0xc0,0x80,0x41,0x00,0xc1,0x81,
0x40,0x01,0xc0,0x80,0x41,0x00,0xc1,0x81,0x40,0x00,0xc1,0x81,0x40,0x01,0xc0,
0x80,0x41,0x01,0xc0,0x80,0x41,0x00,0xc1,0x81,0x40,0x00,0xc1,0x81,0x40,0x01,
0xc0,0x80,0x41,0x00,0xc1,0x81,0x40,0x01,0xc0,0x80,0x41,0x01,0xc0,0x80,0x41,
0x00,0xc1,0x81,0x40,0x01,0xc0,0x80,0x41,0x00,0xc1,0x81,0x40,0x00,0xc1,0x81,
0x40,0x01,0xc0,0x80,0x41,0x00,0xc1,0x81,0x40,0x01,0xc0,0x80,0x41,0x01,0xc0,
0x80,0x41,0x00,0xc1,0x81,0x40,0x00,0xc1,0x81,0x40,0x01,0xc0,0x80,0x41,0x01,
0xc0,0x80,0x41,0x00,0xc1,0x81,0x40,0x01,0xc0,0x80,0x41,0x00,0xc1,0x81,0x40,
0x00,0xc1,0x81,0x40,0x01,0xc0,0x80,0x41,0x01,0xc0,0x80,0x41,0x00,0xc1,0x81,
0x40,0x00,0xc1,0x81,0x40,0x01,0xc0,0x80,0x41,0x00,0xc1,0x81,0x40,0x01,0xc0,
0x80,0x41,0x01,0xc0,0x80,0x41,0x00,0xc1,0x81,0x40,0x00,0xc1,0x81,0x40,0x01,
0xc0,0x80,0x41,0x01,0xc0,0x80,0x41,0x00,0xc1,0x81,0x40,0x01,0xc0,0x80,0x41,
0x00,0xc1,0x81,0x40,0x00,0xc1,0x81,0x40,0x01,0xc0,0x80,0x41,0x00,0xc1,0x81,
0x40,0x01,0xc0,0x80,0x41,0x01,0xc0,0x80,0x41,0x00,0xc1,0x81,0x40,0x01,0xc0,
0x80,0x41,0x00,0xc1,0x81,0x40,0x00,0xc1,0x81,0x40,0x01,0xc0,0x80,0x41,0x01,
0xc0,0x80,0x41,0x00,0xc1,0x81,0x40,0x00,0xc1,0x81,0x40,0x01,0xc0,0x80,0x41,
0x00,0xc1,0x81,0x40,0x01,0xc0,0x80,0x41,0x01,0xc0,0x80,0x41,0x00,0xc1,0x81,
0x40
};
/* table of crc values for low order byte */
static char auchCRCLo[] = {
0x00,0xc0,0xc1,0x01,0xc3,0x03,0x02,0xc2,0xc6,0x06,0x07,0xc7,0x05,0xc5,0xc4,
0x04,0xcc,0x0c,0x0d,0xcd,0x0f,0xcf,0xce,0x0e,0x0a,0xca,0xcb,0x0b,0xc9,0x09,
0x08,0xc8,0xd8,0x18,0x19,0xd9,0x1b,0xdb,0xda,0x1a,0x1e,0xde,0xdf,0x1f,0xdd,
0x1d,0x1c,0xdc,0x14,0xd4,0xd5,0x15,0xd7,0x17,0x16,0xd6,0xd2,0x12,0x13,0xd3,
0x11,0xd1,0xd0,0x10,0xf0,0x30,0x31,0xf1,0x33,0xf3,0xf2,0x32,0x36,0xf6,0xf7,
0x37,0xf5,0x35,0x34,0xf4,0x3c,0xfc,0xfd,0x3d,0xff,0x3f,0x3e,0xfe,0xfa,0x3a,
0x3b,0xfb,0x39,0xf9,0xf8,0x38,0x28,0xe8,0xe9,0x29,0xeb,0x2b,0x2a,0xea,0xee,
0x2e,0x2f,0xef,0x2d,0xed,0xec,0x2c,0xe4,0x24,0x25,0xe5,0x27,0xe7,0xe6,0x26,
0x22,0xe2,0xe3,0x23,0xe1,0x21,0x20,0xe0,0xa0,0x60,0x61,0xa1,0x63,0xa3,0xa2,
0x62,0x66,0xa6,0xa7,0x67,0xa5,0x65,0x64,0xa4,0x6c,0xac,0xad,0x6d,0xaf,0x6f,
0x6e,0xae,0xaa,0x6a,0x6b,0xab,0x69,0xa9,0xa8,0x68,0x78,0xb8,0xb9,0x79,0xbb,
0x7b,0x7a,0xba,0xbe,0x7e,0x7f,0xbf,0x7d,0xbd,0xbc,0x7c,0xb4,0x74,0x75,0xb5,
0x77,0xb7,0xb6,0x76,0x72,0xb2,0xb3,0x73,0xb1,0x71,0x70,0xb0,0x50,0x90,0x91,
0x51,0x93,0x53,0x52,0x92,0x96,0x56,0x57,0x97,0x55,0x95,0x94,0x54,0x9c,0x5c,
0x5d,0x9d,0x5f,0x9f,0x9e,0x5e,0x5a,0x9a,0x9b,0x5b,0x99,0x59,0x58,0x98,0x88,
0x48,0x49,0x89,0x4b,0x8b,0x8a,0x4a,0x4e,0x8e,0x8f,0x4f,0x8d,0x4d,0x4c,0x8c,
0x44,0x84,0x85,0x45,0x87,0x47,0x46,0x86,0x82,0x42,0x43,0x83,0x41,0x81,0x80,
0x40
};
unsigned short int CRC16(unsigned char *puchMsg, unsigned int usDataLen)
/* Return a 16 bit Cyclic Redundancy check on a string of 'usDataLen' bytes */
/* starting at 'puchMsg'. This CRC is worked out via tables for speed */
{
unsigned char uchCRCHi = 0xff; /* high byte of crc initialisation */
unsigned char uchCRCLo = 0xff; /* low byte of crc initialisation */
unsigned int uIndex; /* will index into crc lookup table */
while (usDataLen--)
{
uIndex = uchCRCHi ^ *puchMsg++; /* calculate the crc */
uchCRCHi = uchCRCLo ^ auchCRCHi[uIndex];
uchCRCLo = auchCRCLo[uIndex];
}
return (uchCRCHi << 8 | uchCRCLo);
}
========================End of crc.c===========================================
A message must be preceded by a silence on the serial line of the time taken
for 3.5 characters to be transmitted. The message in RTU mode is taken to
end when a silence of 3.5 character spaces has been observed. If a silence
of 1.5 characters is observed, and other characters are then received before
the necessary 3.5 character spaces has elapsed, those characters are discarded
and the message received so far is designated as faulty.
When a response is sent to the master, the function number field simply should
echo that within the request. If, however, the top bit is set within the field,
this denotes an exception, and the first byte within the data field is the
actual exception code, which is a number 1 through 8. These exception codes
define Illegal Function, Illegal Data Address, Illegal Data Value, Slave
Device Failure, Acknowledge (used to signal that the request will be a while
in computing, so don't time out the slave), Slave Busy, Negative Acknowledge,
Memory Parity Error.
For the formal definition of all of this stuff, get document PI-MBUS-300
(Revision E) "Modicon Modbus Protocol Reference Guide" from AEG/Modicon, at
the following address :-
MODICON, Inc.,
Industrial Automation Systems,
One High Street,
North Andover,
Massachusetts 01845.
Hope some of this helps,
Neil.
------- End of Forwarded Message
- Navigate by Date:
- Prev:
MODBUS F. Gougnaud
- Next:
Re: MODBUS James F. Harrison
- Index:
<1994>
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
- Navigate by Thread:
- Prev:
MODBUS F. Gougnaud
- Next:
Re: MODBUS James F. Harrison
- Index:
<1994>
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
|