|
|
|
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
|
|
|
|
<html xmlns="http://www.w3.org/1999/xhtml">
|
|
|
|
|
<head>
|
|
|
|
|
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
|
|
|
|
|
<meta http-equiv="X-UA-Compatible" content="IE=9"/>
|
|
|
|
|
<meta name="generator" content="Doxygen 1.8.11"/>
|
|
|
|
|
<title>modbus-arduino: Abstract</title>
|
|
|
|
|
<link href="tabs.css" rel="stylesheet" type="text/css"/>
|
|
|
|
|
<script type="text/javascript" src="jquery.js"></script>
|
|
|
|
|
<script type="text/javascript" src="dynsections.js"></script>
|
|
|
|
|
<link href="navtree.css" rel="stylesheet" type="text/css"/>
|
|
|
|
|
<script type="text/javascript" src="resize.js"></script>
|
|
|
|
|
<script type="text/javascript" src="navtreedata.js"></script>
|
|
|
|
|
<script type="text/javascript" src="navtree.js"></script>
|
|
|
|
|
<script type="text/javascript">
|
|
|
|
|
$(document).ready(initResizable);
|
|
|
|
|
$(window).load(resizeHeight);
|
|
|
|
|
</script>
|
|
|
|
|
<link href="search/search.css" rel="stylesheet" type="text/css"/>
|
|
|
|
|
<script type="text/javascript" src="search/searchdata.js"></script>
|
|
|
|
|
<script type="text/javascript" src="search/search.js"></script>
|
|
|
|
|
<script type="text/javascript">
|
|
|
|
|
$(document).ready(function() { init_search(); });
|
|
|
|
|
</script>
|
|
|
|
|
<link href="doxygen.css" rel="stylesheet" type="text/css" />
|
|
|
|
|
</head>
|
|
|
|
|
<body>
|
|
|
|
|
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
|
|
|
|
|
<div id="titlearea">
|
|
|
|
|
<table cellspacing="0" cellpadding="0">
|
|
|
|
|
<tbody>
|
|
|
|
|
<tr style="height: 56px;">
|
|
|
|
|
<td id="projectlogo"><img alt="Logo" src="modbus.png"/></td>
|
|
|
|
|
<td id="projectalign" style="padding-left: 0.5em;">
|
|
|
|
|
<div id="projectname">modbus-arduino
|
|
|
|
|
 <span id="projectnumber">1.0.0</span>
|
|
|
|
|
</div>
|
|
|
|
|
<div id="projectbrief">Modbus library for Arduino</div>
|
|
|
|
|
</td>
|
|
|
|
|
</tr>
|
|
|
|
|
</tbody>
|
|
|
|
|
</table>
|
|
|
|
|
</div>
|
|
|
|
|
<!-- end header part -->
|
|
|
|
|
<!-- Generated by Doxygen 1.8.11 -->
|
|
|
|
|
<script type="text/javascript">
|
|
|
|
|
var searchBox = new SearchBox("searchBox", "search",false,'Search');
|
|
|
|
|
</script>
|
|
|
|
|
<div id="navrow1" class="tabs">
|
|
|
|
|
<ul class="tablist">
|
|
|
|
|
<li class="current"><a href="index.html"><span>Main Page</span></a></li>
|
|
|
|
|
<li><a href="annotated.html"><span>Classes</span></a></li>
|
|
|
|
|
<li>
|
|
|
|
|
<div id="MSearchBox" class="MSearchBoxInactive">
|
|
|
|
|
<span class="left">
|
|
|
|
|
<img id="MSearchSelect" src="search/mag_sel.png"
|
|
|
|
|
onmouseover="return searchBox.OnSearchSelectShow()"
|
|
|
|
|
onmouseout="return searchBox.OnSearchSelectHide()"
|
|
|
|
|
alt=""/>
|
|
|
|
|
<input type="text" id="MSearchField" value="Search" accesskey="S"
|
|
|
|
|
onfocus="searchBox.OnSearchFieldFocus(true)"
|
|
|
|
|
onblur="searchBox.OnSearchFieldFocus(false)"
|
|
|
|
|
onkeyup="searchBox.OnSearchFieldChange(event)"/>
|
|
|
|
|
</span><span class="right">
|
|
|
|
|
<a id="MSearchClose" href="javascript:searchBox.CloseResultsWindow()"><img id="MSearchCloseImg" border="0" src="search/close.png" alt=""/></a>
|
|
|
|
|
</span>
|
|
|
|
|
</div>
|
|
|
|
|
</li>
|
|
|
|
|
</ul>
|
|
|
|
|
</div>
|
|
|
|
|
</div><!-- top -->
|
|
|
|
|
<div id="side-nav" class="ui-resizable side-nav-resizable">
|
|
|
|
|
<div id="nav-tree">
|
|
|
|
|
<div id="nav-tree-contents">
|
|
|
|
|
<div id="nav-sync" class="sync"></div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div id="splitbar" style="-moz-user-select:none;"
|
|
|
|
|
class="ui-resizable-handle">
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<script type="text/javascript">
|
|
|
|
|
$(document).ready(function(){initNavTree('index.html','');});
|
|
|
|
|
</script>
|
|
|
|
|
<div id="doc-content">
|
|
|
|
|
<!-- window showing the filter options -->
|
|
|
|
|
<div id="MSearchSelectWindow"
|
|
|
|
|
onmouseover="return searchBox.OnSearchSelectShow()"
|
|
|
|
|
onmouseout="return searchBox.OnSearchSelectHide()"
|
|
|
|
|
onkeydown="return searchBox.OnSearchSelectKey(event)">
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<!-- iframe showing the search results (closed by default) -->
|
|
|
|
|
<div id="MSearchResultsWindow">
|
|
|
|
|
<iframe src="javascript:void(0)" frameborder="0"
|
|
|
|
|
name="MSearchResults" id="MSearchResults">
|
|
|
|
|
</iframe>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div class="header">
|
|
|
|
|
<div class="headertitle">
|
|
|
|
|
<div class="title">Abstract </div> </div>
|
|
|
|
|
</div><!--header-->
|
|
|
|
|
<div class="contents">
|
|
|
|
|
<div class="textblock"><p>
|
|
|
|
|
<p>The Modbus generally uses serial RS-232 or RS-485 as physical layer (then called Modbus Serial) and
|
|
|
|
|
TCP/IP via Ethernet or WiFi (Modbus IP).</p>
|
|
|
|
|
|
|
|
|
|
<p>In the current version the library allows the Arduino operate as a slave, supporting Modbus Serial and
|
|
|
|
|
Modbus over IP. For more information about Modbus see:</p>
|
|
|
|
|
|
|
|
|
|
<ul>
|
|
|
|
|
<li><a href="https://en.wikipedia.org/wiki/Modbus">Wikipedia article</a> </li>
|
|
|
|
|
<li><a href="http://www.modbus.org/docs/Modbus_Application_Protocol_V1_1b.pdf">MODBUS Application Protocol Specification</a> </li>
|
|
|
|
|
<li><a href="http://www.modbus.org/docs/Modbus_Messaging_Implementation_Guide_V1_0b.pdf">MODBUS Messaging on TCP/IP Implementation Guide</a> </li>
|
|
|
|
|
<li><a href="http://www.modbus.org/docs/Modbus_over_serial_line_V1_02.pdf">MODBUS over serial line specification and implementation guide </a></li>
|
|
|
|
|
</ul>
|
|
|
|
|
|
|
|
|
|
<p><strong>Author's note (motivation and thanks):</strong></p>
|
|
|
|
|
|
|
|
|
|
<p>It all started when I found the Modbus RTU Arduino library of Juan Pablo Zometa. I had extend the
|
|
|
|
|
library to support other Modbus functions.</p>
|
|
|
|
|
|
|
|
|
|
<p>After researching several other Modbus libraries I realized strengths and weaknesses in all of them.
|
|
|
|
|
I also thought it would be cool have a base library for Modbus and derive it for each type of physical layer used.</p>
|
|
|
|
|
|
|
|
|
|
<p>I appreciate the work of all the authors of the other libraries, of which I used several ideas to compose the modbus-arduino.
|
|
|
|
|
At the end of this document is a list of libraries and their authors.</p>
|
|
|
|
|
|
|
|
|
|
<h2>Features</h2>
|
|
|
|
|
|
|
|
|
|
<ul>
|
|
|
|
|
<li>Operates as a slave (master mode in development) </li>
|
|
|
|
|
<li>Supports Modbus Serial (RS-232 or RS485) and Modbus IP (TCP) </li>
|
|
|
|
|
<li>Reply exception messages for all supported functions </li>
|
|
|
|
|
<li>Modbus functions supported: <br />
|
|
|
|
|
<ul>
|
|
|
|
|
<li>0x01 - Read Coils </li>
|
|
|
|
|
<li>0x02 - Read Input Status (Read Discrete Inputs) </li>
|
|
|
|
|
<li>0x03 - Read Holding Registers </li>
|
|
|
|
|
<li>0x04 - Read Input Registers </li>
|
|
|
|
|
<li>0x05 - Write Single Coil </li>
|
|
|
|
|
<li>0x06 - Write Single Register </li>
|
|
|
|
|
<li>0x0F - Write Multiple Coils </li>
|
|
|
|
|
<li>0x10 - Write Multiple Registers </li>
|
|
|
|
|
</ul></li>
|
|
|
|
|
</ul>
|
|
|
|
|
|
|
|
|
|
<p><strong>Notes:</strong></p>
|
|
|
|
|
|
|
|
|
|
<ol>
|
|
|
|
|
<li><p>When using Modbus IP the transport protocol is TCP (port 502) and, by default, the connection is terminated to each transmitted message, that is, is not a keep-alive type connection. If you need a TCP keep-alive connection you have to remove comments of this line in ModbusIP.h header (or ModbusIP_* headers):</p>
|
|
|
|
|
|
|
|
|
|
<pre><code>#define TCP_KEEP_ALIVE
|
|
|
|
|
</code></pre></li>
|
|
|
|
|
<li><p>The offsets for registers are 0-based. So be careful when setting your supervisory system or your testing software. For example, in ScadaBR (http://www.scadabr.com.br)
|
|
|
|
|
offsets are 0-based, then, a register configured as 100 in the library is set to 100 in ScadaBR. On the other hand, in the CAS Modbus Scanner
|
|
|
|
|
(http://www.chipkin.com/products/software/modbus-software/cas-modbus-scanner/) offsets are 1-based, so a register configured as 100 in library should be 101 in this software.</p></li>
|
|
|
|
|
<li><p>Early in the library Modbus.h file there is an option to limit the operation
|
|
|
|
|
to the functions of Holding Registers, saving space in the program memory.
|
|
|
|
|
Just comment out the following line:</p>
|
|
|
|
|
|
|
|
|
|
<pre><code>#define USE_HOLDING_REGISTERS_ONLY
|
|
|
|
|
</code></pre></li>
|
|
|
|
|
</ol>
|
|
|
|
|
|
|
|
|
|
<p>Thus, only the following functions are supported:</p>
|
|
|
|
|
|
|
|
|
|
<ul>
|
|
|
|
|
<li>0x03 - Read Holding Registers </li>
|
|
|
|
|
<li>0x06 - Write Single Register </li>
|
|
|
|
|
<li><p>0x10 - Write Multiple Registers </p></li>
|
|
|
|
|
<li><p>When using Modbus Serial is possible to choose between Hardware Serial(default) or Software Serial. In this
|
|
|
|
|
case you must edit the ModbusSerial.h file and comment out the following line:</p>
|
|
|
|
|
|
|
|
|
|
<p>#define USE<em>SOFTWARE</em>SERIAL</p></li>
|
|
|
|
|
</ul>
|
|
|
|
|
|
|
|
|
|
<p>Now, You can build your main program putting all necessary includes:</p>
|
|
|
|
|
|
|
|
|
|
<pre><code>#include <Modbus.h>
|
|
|
|
|
#include <ModbusSerial.h>
|
|
|
|
|
#include <SoftwareSerial.h>
|
|
|
|
|
</code></pre>
|
|
|
|
|
|
|
|
|
|
<p>And in the setup() function:</p>
|
|
|
|
|
|
|
|
|
|
<pre><code>SoftwareSerial myserial(2,3);
|
|
|
|
|
mb.config(&myserial, 38400); // mb.config(mb.config(&myserial, 38400, 4) for RS-485
|
|
|
|
|
</code></pre>
|
|
|
|
|
|
|
|
|
|
<h2>How to</h2>
|
|
|
|
|
|
|
|
|
|
<p>There are five classes corresponding to five headers that may be used:</p>
|
|
|
|
|
|
|
|
|
|
<ul>
|
|
|
|
|
<li>Modbus - Base Library </li>
|
|
|
|
|
<li>ModbusSerial - Modbus Serial Library (RS-232 and RS-485) </li>
|
|
|
|
|
<li>ModbusIP - Modbus IP Library (standard Ethernet Shield) </li>
|
|
|
|
|
<li>ModbusIP_ENC28J60 - Modbus IP Library (for ENC28J60 chip) </li>
|
|
|
|
|
<li>ModbusIP_ESP8266AT - Modbus IP Library (for ESP8266 chip with AT firmware) </li>
|
|
|
|
|
</ul>
|
|
|
|
|
|
|
|
|
|
<p><strong>If you want to use Modbus in ESP8266 without the Arduino, I have news:</strong>
|
|
|
|
|
http://www.github.com/andresarmento/modbus-esp8266</p>
|
|
|
|
|
|
|
|
|
|
<p>By opting for Modbus Serial or Modbus IP you must include in your sketch the corresponding header and the base library header, eg:</p>
|
|
|
|
|
|
|
|
|
|
<pre><code>#include <Modbus.h>
|
|
|
|
|
#include <ModbusSerial.h>
|
|
|
|
|
</code></pre>
|
|
|
|
|
|
|
|
|
|
<h2>Modbus Jargon</h2>
|
|
|
|
|
|
|
|
|
|
<p>In this library was decided to use the terms used in Modbus to the methods names, then is important clarify the names of
|
|
|
|
|
register types:</p>
|
|
|
|
|
|
|
|
|
|
<p>| Register type | Use as | Access | Library methods |
|
|
|
|
|
| -------------------- | ------------------ | ----------------- | --------------------- |
|
|
|
|
|
| Coil | Digital Output | Read/Write | addCoil(), Coil() |
|
|
|
|
|
| Holding Register | Analog Output | Read/Write | addHreg(), Hreg() |
|
|
|
|
|
| Input Status | Digital Input | Read Only | addIsts(), Ists() |
|
|
|
|
|
| Input Register | Analog Input | Read Only | addIreg(), Ireg() |</p>
|
|
|
|
|
|
|
|
|
|
<p><strong>Notes:</strong></p>
|
|
|
|
|
|
|
|
|
|
<ol>
|
|
|
|
|
<li><em>Input Status</em> is sometimes called <em>Discrete Input</em>. </li>
|
|
|
|
|
<li><em>Holding Register</em> or just <em>Register</em> is also used to store values in the slave. </li>
|
|
|
|
|
<li>Examples of use: A <em>Coil</em> can be used to drive a lamp or LED. A <em>Holding Register</em> to
|
|
|
|
|
store a counter or drive a Servo Motor. A <em>Input Status</em> can be used with a reed switch
|
|
|
|
|
in a door sensor and a <em>Input Register</em> with a temperature sensor.</li>
|
|
|
|
|
</ol>
|
|
|
|
|
|
|
|
|
|
<h2>Modbus Serial</h2>
|
|
|
|
|
|
|
|
|
|
<p>There are four examples that can be accessed from the Arduino interface, once you have installed the library.
|
|
|
|
|
Let's look at the example Lamp.ino (only the parts concerning Modbus will be commented):</p>
|
|
|
|
|
|
|
|
|
|
<pre><code>#include <Modbus.h>
|
|
|
|
|
#include <ModbusSerial.h>
|
|
|
|
|
</code></pre>
|
|
|
|
|
|
|
|
|
|
<p>Inclusion of the necessary libraries.</p>
|
|
|
|
|
|
|
|
|
|
<pre><code>const int LAMP1_COIL = 100;
|
|
|
|
|
</code></pre>
|
|
|
|
|
|
|
|
|
|
<p>Sets the Modbus register to represent a lamp or LED. This value is the offset (0-based) to be placed in its supervisory or testing software.
|
|
|
|
|
Note that if your software uses offsets 1-based the set value there should be 101, for this example.</p>
|
|
|
|
|
|
|
|
|
|
<pre><code>ModbusSerial mb;
|
|
|
|
|
</code></pre>
|
|
|
|
|
|
|
|
|
|
<p>Create the mb instance (ModbusSerial) to be used.</p>
|
|
|
|
|
|
|
|
|
|
<pre><code>mb.config (&Serial, 38400, MB_PARITY_EVEN);
|
|
|
|
|
mb.setSlaveId (10);
|
|
|
|
|
</code></pre>
|
|
|
|
|
|
|
|
|
|
<p>Sets the serial port and the slave Id. Note that the serial port is passed as reference, which permits the use of other serial ports in other Arduino models.
|
|
|
|
|
The bitrate and parity is being set. If you are using RS-485 the configuration of another pin to control transmission/reception is required.
|
|
|
|
|
This is done as follows:</p>
|
|
|
|
|
|
|
|
|
|
<pre><code>mb.config (& Serial, 38400, MB_PARITY_EVEN, 2);
|
|
|
|
|
</code></pre>
|
|
|
|
|
|
|
|
|
|
<p>In this case, the pin 2 will be used to control TX/RX.</p>
|
|
|
|
|
|
|
|
|
|
<pre><code>mb.addCoil (LAMP1_COIL);
|
|
|
|
|
</code></pre>
|
|
|
|
|
|
|
|
|
|
<p>Adds the register type Coil (digital output) that will be responsible for activating the LED or lamp and verify their status.
|
|
|
|
|
The library allows you to set an initial value for the register:</p>
|
|
|
|
|
|
|
|
|
|
<pre><code>mb.addCoil (LAMP1_COIL, true);
|
|
|
|
|
</code></pre>
|
|
|
|
|
|
|
|
|
|
<p>In this case the register is added and set to true. If you use the first form the default value is false.</p>
|
|
|
|
|
|
|
|
|
|
<pre><code>mb.task ();
|
|
|
|
|
</code></pre>
|
|
|
|
|
|
|
|
|
|
<p>This method makes all magic, answering requests and changing the registers if necessary, it should be called only once, early in the loop.</p>
|
|
|
|
|
|
|
|
|
|
<pre><code>digitalWrite (ledPin, mb.Coil (LAMP1_COIL));
|
|
|
|
|
</code></pre>
|
|
|
|
|
|
|
|
|
|
<p>Finally the value of LAMP1_COIL register is used to drive the lamp or LED.</p>
|
|
|
|
|
|
|
|
|
|
<p>In much the same way, the other examples show the use of other methods available in the library:</p>
|
|
|
|
|
|
|
|
|
|
<pre><code>void addCoil (offset word, bool value)
|
|
|
|
|
void addHreg (offset word, word value)
|
|
|
|
|
void addIsts (offset word, bool value)
|
|
|
|
|
void addIreg (offset word, word value)
|
|
|
|
|
</code></pre>
|
|
|
|
|
|
|
|
|
|
<p>Adds registers and configures initial value if specified.</p>
|
|
|
|
|
|
|
|
|
|
<pre><code>bool Coil (offset word, bool value)
|
|
|
|
|
bool Hreg (offset word, word value)
|
|
|
|
|
bool Ists (offset word, bool value)
|
|
|
|
|
bool IReg (offset word, word value)
|
|
|
|
|
</code></pre>
|
|
|
|
|
|
|
|
|
|
<p>Sets a value to the register.</p>
|
|
|
|
|
|
|
|
|
|
<pre><code>bool Coil (offset word)
|
|
|
|
|
word Hreg (word offset)
|
|
|
|
|
bool Ists (offset word)
|
|
|
|
|
word IReg (word offset)
|
|
|
|
|
</code></pre>
|
|
|
|
|
|
|
|
|
|
<p>Returns the value of a register.</p>
|
|
|
|
|
|
|
|
|
|
<h2>Modbus IP</h2>
|
|
|
|
|
|
|
|
|
|
<p>There are four examples that can be accessed from the Arduino interface, once you have installed the library.
|
|
|
|
|
Let's look at the example Switch.ino (only the parts concerning Modbus will be commented):</p>
|
|
|
|
|
|
|
|
|
|
<pre><code>#include <SPI.h>
|
|
|
|
|
#include <Ethernet.h>
|
|
|
|
|
#include <Modbus.h>
|
|
|
|
|
#include <ModbusIP.h>
|
|
|
|
|
</code></pre>
|
|
|
|
|
|
|
|
|
|
<p>Inclusion of the necessary libraries.</p>
|
|
|
|
|
|
|
|
|
|
<pre><code>const int SWITCH_ISTS = 100;
|
|
|
|
|
</code></pre>
|
|
|
|
|
|
|
|
|
|
<p>Sets the Modbus register to represent the switch. This value is the offset (0-based) to be placed in its supervisory or testing software.
|
|
|
|
|
Note that if your software uses offsets 1-based the set value there should be 101, for this example.</p>
|
|
|
|
|
|
|
|
|
|
<pre><code>ModbusIP mb;
|
|
|
|
|
</code></pre>
|
|
|
|
|
|
|
|
|
|
<p>Create the mb instance (ModbusIP) to be used.</p>
|
|
|
|
|
|
|
|
|
|
<pre><code>mac byte [] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED};
|
|
|
|
|
ip byte [] = {192, 168, 1, 120};
|
|
|
|
|
mb.config (mac, ip);
|
|
|
|
|
</code></pre>
|
|
|
|
|
|
|
|
|
|
<p>Sets the Ethernet shield. The values of the MAC Address and the IP are passed by the config() method.
|
|
|
|
|
The syntax is equal to Arduino Ethernet class, and supports the following formats:</p>
|
|
|
|
|
|
|
|
|
|
<pre><code>void config (uint8_t * mac)
|
|
|
|
|
void config (uint8_t * mac, IPAddress ip)
|
|
|
|
|
void config (uint8_t * mac, IPAddress ip, IPAddress dns)
|
|
|
|
|
void config (uint8_t * mac, IPAddress ip, IPAddress dns, gateway IPAddress)
|
|
|
|
|
void config (uint8_t * mac, IPAddress ip, IPAddress dns, IPAddress gateway, subnet IPAddress)
|
|
|
|
|
</code></pre>
|
|
|
|
|
|
|
|
|
|
<p>Then we have:</p>
|
|
|
|
|
|
|
|
|
|
<pre><code>mb.addIsts (SWITCH_ISTS);
|
|
|
|
|
</code></pre>
|
|
|
|
|
|
|
|
|
|
<p>Adds the register type Input Status (digital input) that is responsible for detecting if a switch is in state on or off.
|
|
|
|
|
The library allows you to set an initial value for the register:</p>
|
|
|
|
|
|
|
|
|
|
<pre><code>mb.addIsts (SWITCH_ISTS, true);
|
|
|
|
|
</code></pre>
|
|
|
|
|
|
|
|
|
|
<p>In this case the register is added and set to true. If you use the first form the default value is false.</p>
|
|
|
|
|
|
|
|
|
|
<pre><code>mb.task ();
|
|
|
|
|
</code></pre>
|
|
|
|
|
|
|
|
|
|
<p>This method makes all magic, answering requests and changing the registers if necessary, it should be called only once, early in the loop.</p>
|
|
|
|
|
|
|
|
|
|
<pre><code>mb.Ists (SWITCH_ISTS, digitalRead (switchPin));
|
|
|
|
|
</code></pre>
|
|
|
|
|
|
|
|
|
|
<p>Finally the value of SWITCH_ISTS register changes as the state of the selected digital input.</p>
|
|
|
|
|
|
|
|
|
|
<h2>Modbus IP(ENC28J60)</h2>
|
|
|
|
|
|
|
|
|
|
<p>The Arduino standard Ethernet shield is based on chip WIZnet W5100, therefore the IDE comes
|
|
|
|
|
with this library installed. If you have a shield based on ENC28J60 from Microchip you must install
|
|
|
|
|
another Ethernet library. Among several available we chose EtherCard.</p>
|
|
|
|
|
|
|
|
|
|
<p>Download the EtherCard in https://github.com/jcw/ethercard and install it in your IDE.
|
|
|
|
|
Use the following includes in your sketches:</p>
|
|
|
|
|
|
|
|
|
|
<pre><code>#include <EtherCard.h>
|
|
|
|
|
#include <ModbusIP_ENC28J60.h>
|
|
|
|
|
#include <Modbus.h>
|
|
|
|
|
</code></pre>
|
|
|
|
|
|
|
|
|
|
<p>Done! The use of Modbus functions is identical to the ModbusIP library described above.</p>
|
|
|
|
|
|
|
|
|
|
<p><strong>Notes:</strong></p>
|
|
|
|
|
|
|
|
|
|
<ol>
|
|
|
|
|
<li>EtherCard is configured to use the pins 10, 11, 12 and 13.</li>
|
|
|
|
|
<li><p>The voltage for shields based on ENC28J60 is generally 3.3V.</p></li>
|
|
|
|
|
<li><p>Another alternative is to use the ENC28J60 UIPEthernet library, available from
|
|
|
|
|
https://github.com/ntruchsess/arduino_uip. This library was made so that
|
|
|
|
|
mimics the same standard Ethernet library functions, whose work is done by
|
|
|
|
|
Wiznet W5100 chip. As the ENC28J60 not have all the features of the other chip, the library
|
|
|
|
|
UIPEthernet uses a lot of memory, as it has to do in software what in the shield Wiznet
|
|
|
|
|
is made in hardware. If for some reason you need to use this library, just change
|
|
|
|
|
the file ModbusIP.h and your sketches, changing the lines:</p>
|
|
|
|
|
|
|
|
|
|
<pre><code>#include <Ethernet.h>
|
|
|
|
|
</code></pre></li>
|
|
|
|
|
</ol>
|
|
|
|
|
|
|
|
|
|
<p>by</p>
|
|
|
|
|
|
|
|
|
|
<pre><code> #include <UIPEthernet.h>
|
|
|
|
|
</code></pre>
|
|
|
|
|
|
|
|
|
|
<p>Then, you can use the ModbusIP library (not the ModbusIP<em>ENC28J60).
|
|
|
|
|
In fact it allows any library or skecth, made for
|
|
|
|
|
Wiznet shield be used in shield ENC28J60. The big problem with this approach
|
|
|
|
|
(and why we chose EtherCard) is that UIPEthernet library + ModbusIP uses about 60%
|
|
|
|
|
arduino program memory, whereas with Ethercard + ModbusIP</em>ENC28J60
|
|
|
|
|
this value drops to 30%!</p>
|
|
|
|
|
|
|
|
|
|
<h2>Modbus IP (ESP8266 AT)</h2>
|
|
|
|
|
|
|
|
|
|
<p>Modules based on ESP8266 are quite successful and cheap. With firmware that
|
|
|
|
|
responds to AT commands (standard on many modules) you can use them as a
|
|
|
|
|
simple wireless network interface to the Arduino.</p>
|
|
|
|
|
|
|
|
|
|
<p>The firmware used in the module (at<em>v0.20</em>on<em>SDKv0.9.3) is available at:
|
|
|
|
|
http://www.electrodragon.com/w/ESP8266</em>AT-command_firmware</p>
|
|
|
|
|
|
|
|
|
|
<p>(Other AT firmwares compatible with ITEAD WeeESP8266 Library should work)</p>
|
|
|
|
|
|
|
|
|
|
<p>Warning: Firmware such as NodeMCU and MicroPython does not work because libraries
|
|
|
|
|
used here depend on a firmware that responds to AT commands via serial interface.
|
|
|
|
|
The firmware mentioned are used when you want to use ESP8266 modules without the Arduino.</p>
|
|
|
|
|
|
|
|
|
|
<p>You will need the WeeESP8266 library (ITEAD) for the Arduino. Download from:</p>
|
|
|
|
|
|
|
|
|
|
<p>https://github.com/itead/ITEADLIB<em>Arduino</em>WeeESP8266 and install in your IDE.</p>
|
|
|
|
|
|
|
|
|
|
<p><strong>Notes:</strong></p>
|
|
|
|
|
|
|
|
|
|
<ol>
|
|
|
|
|
<li><p>The ESP8266 library can be used with a serial interface by hardware (HardwareSerial) or
|
|
|
|
|
by software (SoftwareSerial). By default it will use HardwareSerial, to change edit the file
|
|
|
|
|
ESP8266.h removing the comments from line:</p>
|
|
|
|
|
|
|
|
|
|
<pre><code>#define ESP8266_USE_SOFTWARE_SERIAL
|
|
|
|
|
</code></pre></li>
|
|
|
|
|
<li><p>Remember that the power of ESP8266 module is 3.3V.</p></li>
|
|
|
|
|
</ol>
|
|
|
|
|
|
|
|
|
|
<p>For Modbus IP (ESP8266 AT) there is four examples that can be accessed from the Arduino interface.
|
|
|
|
|
Let's look at the example Lamp.ino (only the parts concerning Modbus will be commented):</p>
|
|
|
|
|
|
|
|
|
|
<pre><code>#include <ESP8266.h>
|
|
|
|
|
#include <SoftwareSerial.h> //Apenas se utilizar Softwareserial para se comunicar com o módulo
|
|
|
|
|
#include <Modbus.h>
|
|
|
|
|
#include <ModbusIP_ESP8266AT.h>
|
|
|
|
|
</code></pre>
|
|
|
|
|
|
|
|
|
|
<p>Inclusion of the necessary libraries.</p>
|
|
|
|
|
|
|
|
|
|
<pre><code>SoftwareSerial wifiSerial(2 , 3);
|
|
|
|
|
</code></pre>
|
|
|
|
|
|
|
|
|
|
<p>Creates the serial interface via software using pins 2 (RX) and 3 (TX). So it can use
|
|
|
|
|
hardware for the serial communication with the PC (e.g. for debugging purposes) in Arduino models that have only one serial (Ex .: Arduino UNO).</p>
|
|
|
|
|
|
|
|
|
|
<pre><code>ESP8266 wifi(wifiSerial, 9600);
|
|
|
|
|
</code></pre>
|
|
|
|
|
|
|
|
|
|
<p>Create the wifi object (ESP8266) specifying the rate in bps.
|
|
|
|
|
Warning: If you use SoftwareSerial do not specify a baud rate of 115200bps or more for the serial because it will not function. Some firmware / modules comes with 115200bps by default. You will have to change the module via AT command:</p>
|
|
|
|
|
|
|
|
|
|
<pre><code>AT+CIOBAUD=9600
|
|
|
|
|
</code></pre>
|
|
|
|
|
|
|
|
|
|
<p>Continuing with our example:</p>
|
|
|
|
|
|
|
|
|
|
<pre><code>const int LAMP1_COIL = 100;
|
|
|
|
|
</code></pre>
|
|
|
|
|
|
|
|
|
|
<p>Sets the Modbus register to represent a lamp or LED. This value is the offset (0-based) to be placed in its supervisory or testing software.
|
|
|
|
|
Note that if your software uses offsets 1-based the set value there should be 101, for this example.</p>
|
|
|
|
|
|
|
|
|
|
<pre><code>ModbusIP mb;
|
|
|
|
|
</code></pre>
|
|
|
|
|
|
|
|
|
|
<p>Create the mb instance (ModbusSerial) to be used.</p>
|
|
|
|
|
|
|
|
|
|
<pre><code>mb.config(wifi, "your_ssid", "your_password");
|
|
|
|
|
</code></pre>
|
|
|
|
|
|
|
|
|
|
<p>Configure ESP8266 module. The values quoted correspond to the network name (SSID) and security key.
|
|
|
|
|
By default IP configuration is received via DHCP. See the end of the section how to have an Static IP
|
|
|
|
|
(important so you do not need to change the master / supervisor if the IP changes).</p>
|
|
|
|
|
|
|
|
|
|
<p>Folowing, we have:</p>
|
|
|
|
|
|
|
|
|
|
<pre><code>mb.addCoil (LAMP1_COIL);
|
|
|
|
|
</code></pre>
|
|
|
|
|
|
|
|
|
|
<p>Adds the register type Coil (digital output) that will be responsible for activating the LED or lamp and verify their status.
|
|
|
|
|
The library allows you to set an initial value for the register:</p>
|
|
|
|
|
|
|
|
|
|
<pre><code>mb.addCoil (LAMP1_COIL, true);
|
|
|
|
|
</code></pre>
|
|
|
|
|
|
|
|
|
|
<p>In this case the register is added and set to true. If you use the first form the default value is false.</p>
|
|
|
|
|
|
|
|
|
|
<pre><code>mb.task();
|
|
|
|
|
</code></pre>
|
|
|
|
|
|
|
|
|
|
<p>This method makes all magic, answering requests and changing the registers if necessary, it should be called only once, early in the loop.</p>
|
|
|
|
|
|
|
|
|
|
<pre><code>digitalWrite(ledPin, mb.Coil(LAMP1_COIL));
|
|
|
|
|
</code></pre>
|
|
|
|
|
|
|
|
|
|
<p>Finally the value of LAMP1_COIL register is used to drive the lamp or LED.</p>
|
|
|
|
|
|
|
|
|
|
<p>Quite similarly to other examples show the use of other methods available in the library.</p>
|
|
|
|
|
|
|
|
|
|
<p><strong>Using a static IP on the ESP8266 module</strong></p>
|
|
|
|
|
|
|
|
|
|
<p>We are aware today of two options:</p>
|
|
|
|
|
|
|
|
|
|
<ol>
|
|
|
|
|
<li><p>In your router configure the MAC address of the module so that the IP address provided by
|
|
|
|
|
DHCP is always the same (Most routers have this feature).</p></li>
|
|
|
|
|
<li><p>In your code, include two lines to change the IP address after the module configuration:</p>
|
|
|
|
|
|
|
|
|
|
<p>mb.config(wifi, "your<em>ssid", "your</em>password");
|
|
|
|
|
delay(1000);
|
|
|
|
|
wifiSerial.println("AT+CIPSTA=\"192.168.1.44\"");</p></li>
|
|
|
|
|
</ol>
|
|
|
|
|
|
|
|
|
|
<p>Note: For the module to receive IP via DHCP again you will need to remove the lines
|
|
|
|
|
and run (at least once) the command: AT + CWDHCP = 1.1 via direct connection to the module, either:</p>
|
|
|
|
|
|
|
|
|
|
<pre><code>wifiSerial.println("AT+CWDHCP=1,1");
|
|
|
|
|
</code></pre>
|
|
|
|
|
|
|
|
|
|
<h1>Other Modbus libraries</h1>
|
|
|
|
|
|
|
|
|
|
<p><strong>Arduino Modbus RTU</strong> <br />
|
|
|
|
|
Author: Juan Pablo Zometa, Samuel and Marco Andras Tucsni <br />
|
|
|
|
|
Year: 2010 <br />
|
|
|
|
|
Website: <a href="https://sites.google.com/site/jpmzometa/">https://sites.google.com/site/jpmzometa/</a></p>
|
|
|
|
|
|
|
|
|
|
<p><strong>Simple Modbus</strong> <br />
|
|
|
|
|
Author: Bester.J <br />
|
|
|
|
|
Year: 2013 Website: <a href="https://code.google.com/p/simple-modbus/">https://code.google.com/p/simple-modbus/</a></p>
|
|
|
|
|
|
|
|
|
|
<p><strong>Arduino-Modbus slave</strong> <br />
|
|
|
|
|
Jason Vreeland [CodeRage] <br />
|
|
|
|
|
Year: 2010 <br />
|
|
|
|
|
Website: <a href="http://code.google.com/p/arduino-modbus-slave/">http://code.google.com/p/arduino-modbus-slave/</a></p>
|
|
|
|
|
|
|
|
|
|
<p><strong>Mudbus (Modbus TCP)</strong> <br />
|
|
|
|
|
Author: Dee Wykoff <br />
|
|
|
|
|
Year: 2011 <br />
|
|
|
|
|
Website: <a href="http://code.google.com/p/mudbus/">http://code.google.com/p/mudbus/</a></p>
|
|
|
|
|
|
|
|
|
|
<p><strong>ModbusMaster Library for Arduino</strong> <br />
|
|
|
|
|
Author: Doc Walker <br />
|
|
|
|
|
Year: 2012 <br />
|
|
|
|
|
Website: <a href="https://github.com/4-20ma/ModbusMaster">https://github.com/4-20ma/ModbusMaster</a> <br />
|
|
|
|
|
Website: <a href="http://playground.arduino.cc/Code/ModbusMaster">http://playground.arduino.cc/Code/ModbusMaster</a></p>
|
|
|
|
|
|
|
|
|
|
<h1>Contributions</h1>
|
|
|
|
|
|
|
|
|
|
<p>http://github.com/epsilonrt/modbus-arduino <br />
|
|
|
|
|
prof (at) andresarmento (dot) com
|
|
|
|
|
epsilonrt (at) gmail (dot) com</p>
|
|
|
|
|
|
|
|
|
|
<h1>License</h1>
|
|
|
|
|
|
|
|
|
|
<p>The code in this repo is licensed under the BSD New License. See LICENSE.txt for more info.</p>
|
|
|
|
|
</p>
|
|
|
|
|
</div></div><!-- contents -->
|
|
|
|
|
</div><!-- doc-content -->
|
|
|
|
|
<!-- start footer part -->
|
|
|
|
|
<div id="nav-path" class="navpath"><!-- id is needed for treeview function! -->
|
|
|
|
|
<ul>
|
|
|
|
|
<li class="footer">Generated on Fri Jan 19 2018 01:17:49 for modbus-arduino by
|
|
|
|
|
<a href="http://www.doxygen.org/index.html">
|
|
|
|
|
<img class="footer" src="doxygen.png" alt="doxygen"/></a> 1.8.11 </li>
|
|
|
|
|
</ul>
|
|
|
|
|
</div>
|
|
|
|
|
</body>
|
|
|
|
|
</html>
|