Scanning Registers

This is a testing program to scan through all possible holding registers. This was written to try to guess the structure of the modbus registers when a map isn't available.


PlatformIO Configuration

1; PlatformIO Project Configuration File
2;
3; Build options: build flags, source filter
4; Upload options: custom upload port, speed and extra flags
5; Library options: dependencies, extra library storages
6; Advanced options: extra scripting
7;
8; Please visit documentation for the other options and examples
9; http://docs.platformio.org/page/projectconf.html
10
11[platformio]
12description = Changing a setting and reading data from a modbus sensor
13
14[env:mayfly]
15monitor_speed = 57600
16board = mayfly
17platform = atmelavr
18framework = arduino
19lib_deps =
20 SensorModbusMaster

The Complete Code

1/** =========================================================================
2 * @example{lineno} scanRegisters.ino
3 * @author Sara Geleskie Damiano <sdamiano@stroudcenter.org>
4 * @copyright Stroud Water Research Center
5 * @license This example is published under the BSD-3 license.
6 *
7 * @brief This is a testing program to scan through all possible holding registers.
8 *
9 * @m_examplenavigation{example_scan_registers,}
10 * @m_footernavigation
11 * ======================================================================= */
12
13// ---------------------------------------------------------------------------
14// Include the base required libraries
15// ---------------------------------------------------------------------------
16#include <Arduino.h>
17#include <SensorModbusMaster.h>
18
19// ---------------------------------------------------------------------------
20// Set up the sensor specific information
21// ie, pin locations, addresses, calibrations and related settings
22// ---------------------------------------------------------------------------
23
24// Define the sensor's modbus address
25byte modbusAddress = 0x01; // The sensor's modbus address, or SlaveID
26long modbusBaudRate = 38400; // The baud rate the sensor uses
27
28// Define pin number variables
29const int DEREPin = -1; // The pin controlling Receive Enable and Driver Enable
30 // on the RS485 adapter, if applicable (else, -1)
31 // Setting HIGH enables the driver (arduino) to send text
32 // Setting LOW enables the receiver (sensor) to send text
33
34
35// Construct a Serial object for Modbus
36#if defined(ARDUINO_AVR_UNO) || defined(ARDUINO_AVR_FEATHER328P)
37// The Uno only has 1 hardware serial port, which is dedicated to comunication with the
38// computer. If using an Uno, you will be restricted to using AltSofSerial or
39// SoftwareSerial
40#include <SoftwareSerial.h>
41const int SSRxPin = 10; // Receive pin for software serial (Rx on RS485 adapter)
42const int SSTxPin = 11; // Send pin for software serial (Tx on RS485 adapter)
43#pragma message("Using Software Serial for the Uno on pins 10 and 11")
44SoftwareSerial modbusSerial(SSRxPin, SSTxPin);
45// AltSoftSerial modbusSerial;
46#elif defined ESP8266
47#pragma message("Using Software Serial for the ESP8266")
48#include <SoftwareSerial.h>
49SoftwareSerial modbusSerial;
50#elif defined(NRF52832_FEATHER) || defined(ARDUINO_NRF52840_FEATHER)
51#pragma message("Using TinyUSB for the NRF52")
52#include <Adafruit_TinyUSB.h>
53HardwareSerial& modbusSerial = Serial1;
54#elif !defined(NO_GLOBAL_SERIAL1) && !defined(STM32_CORE_VERSION)
55// This is just a assigning another name to the same port, for convienence
56// Unless it is unavailable, always prefer hardware serial.
57#pragma message("Using HarwareSerial / Serial1")
58HardwareSerial& modbusSerial = Serial1;
59#else
60// This is just a assigning another name to the same port, for convienence
61// Unless it is unavailable, always prefer hardware serial.
62#pragma message("Using HarwareSerial / Serial")
63HardwareSerial& modbusSerial = Serial;
64#endif
65
66// Construct the modbus instance
67modbusMaster modbus;
68
69void printPaddedHex(byte val) {
70 if (val < 16) {
71 Serial.print("0");
72 Serial.print(val, HEX);
73 } else
74 Serial.print(val, HEX);
75}
76
77void printPaddedBin(byte val) {
78 if (val >= 0b10000000) {
79 Serial.print("");
80 Serial.print(val, BIN);
81 } else if (val >= 0b01000000) {
82 Serial.print("0");
83 Serial.print(val, BIN);
84 } else if (val >= 0b00100000) {
85 Serial.print("00");
86 Serial.print(val, BIN);
87 } else if (val >= 0b00010000) {
88 Serial.print("000");
89 Serial.print(val, BIN);
90 } else if (val >= 0b00001000) {
91 Serial.print("0000");
92 Serial.print(val, BIN);
93 } else if (val >= 0b00000100) {
94 Serial.print("00000");
95 Serial.print(val, BIN);
96 } else if (val >= 0b00000010) {
97 Serial.print("000000");
98 Serial.print(val, BIN);
99 } else /*if (val > 0b00000001)*/ {
100 Serial.print("0000000");
101 Serial.print(val, BIN);
102 }
103 // if (val > 0b0000000010000000) {
104 // Serial.print("00000000");
105 // Serial.print(val, BIN);
106 // }
107 // if (val > 0b0000000001000000) {
108 // Serial.print("000000000");
109 // Serial.print(val, BIN);
110 // }
111 // if (val > 0b0000000000100000) {
112 // Serial.print("0000000000");
113 // Serial.print(val, BIN);
114 // }
115 // if (val > 0b0000000000010000) {
116 // Serial.print("000000000000");
117 // Serial.print(val, BIN);
118 // }
119 // if (val > 0b0000000000001000) {
120 // Serial.print("0000000000000");
121 // Serial.print(val, BIN);
122 // }
123 // if (val > 0b0000000000000100) {
124 // Serial.print("00000000000000");
125 // Serial.print(val, BIN);
126 // }
127 // if (val > 0b0000000000000010) {
128 // Serial.print("000000000000000");
129 // Serial.print(val, BIN);
130 // }
131 // if (val > 0b0000000000000001) {
132 // Serial.print("0000000000000000");
133 // Serial.print(val, BIN);
134 // }
135}
136
137void printPaddedString(String val) {
138 int len = val.length();
139 if (len == 4) {
140 Serial.print("");
141 Serial.print(val);
142 }
143 if (len == 3) {
144 Serial.print(" ");
145 Serial.print(val);
146 }
147 if (len == 2) {
148 Serial.print(" ");
149 Serial.print(val);
150 }
151 if (len == 1) {
152 Serial.print(" ");
153 Serial.print(val);
154 }
155 if (len == 0) {
156 Serial.print(" ");
157 Serial.print(val);
158 }
159}
160
161void printPaddedInt16(uint16_t val) {
162 if (val < 10) {
163 Serial.print(" ");
164 Serial.print(val);
165 } else if (val < 100) {
166 Serial.print(" ");
167 Serial.print(val);
168 } else if (val < 1000) {
169 Serial.print(" ");
170 Serial.print(val);
171 } else if (val < 10000) {
172 Serial.print(" ");
173 Serial.print(val);
174 } else
175 Serial.print(val);
176}
177
178// ==========================================================================
179// Main setup function
180// ==========================================================================
181void setup() {
182 if (DEREPin >= 0) { pinMode(DEREPin, OUTPUT); }
183
184 // Turn on the "main" serial port for debugging via USB Serial Monitor
185 Serial.begin(57600);
186
187 // Turn on your modbus serial port
188#if defined(ARDUINO_AVR_UNO) || defined(ARDUINO_AVR_FEATHER328P) || \
189 defined(ARDUINO_SAM_DUE) || not defined(SERIAL_8O1)
190 modbusSerial.begin(modbusBaudRate);
191 // NOTE: The AVR implementation of SoftwareSerial only supports 8N1
192 // The hardware serial implementation of the Due also only supports 8N1
193#elif defined(ESP8266)
194 const int SSRxPin = 13; // Receive pin for software serial (Rx on RS485 adapter)
195 const int SSTxPin = 14; // Send pin for software serial (Tx on RS485 adapter)
196 modbusSerial.begin(modbusBaudRate, SWSERIAL_8O1, SSRxPin, SSTxPin, false);
197 // NOTE: See
198 // https://github.com/plerup/espsoftwareserial/blob/40038df/src/SoftwareSerial.h#L120-L160
199 // for a list of data/parity/stop bit configurations that apply to the ESP8266's
200 // implementation of SoftwareSerial
201#else
202 modbusSerial.begin(modbusBaudRate, SERIAL_8O1);
203 // ^^ use this for 8 data bits - odd parity - 1 stop bit
204 // Serial1.begin(modbusBaudRate, SERIAL_8E1);
205 // ^^ use this for 8 data bits - even parity - 1 stop bit
206 // Serial1.begin(modbusBaudRate, SERIAL_8N2);
207 // ^^ use this for 8 data bits - no parity - 2 stop bits
208 // Serial1.begin(modbusBaudRate);
209 // ^^ use this for 8 data bits - no parity - 1 stop bits
210 // Despite being technically "non-compliant" with the modbus specifications
211 // 8N1 parity is very common.
212#endif
213
214 // Turn on debugging, if desired
215 // modbus.setDebugStream(&Serial);
216
217 // Start the modbus instance
218 modbus.begin(modbusAddress, modbusSerial, DEREPin);
219
220 // Start up note
221 Serial.println("Full scan of all input and holding registers");
222
223 // Allow the sensor and converter to warm up
224 Serial.println("Waiting for sensor and adapter to be ready.");
225 delay(500);
226
227 // Print a header
228 Serial.println("Register Type, Reg #, Hex , Binary "
229 " , Char , uInt16 , Float32");
230
231 // Get values two at a time
232 for (long i = 0; i < 65535; i++) {
233 Serial.print("Input (0x04), ");
234 printPaddedInt16(i);
235 Serial.print(", ");
236 if (modbus.getRegisters(0x04, i, 2)) {
237 printPaddedHex(modbus.responseBuffer[3]);
238 Serial.print(" ");
239 printPaddedHex(modbus.responseBuffer[4]);
240 Serial.print(" ");
241 printPaddedHex(modbus.responseBuffer[5]);
242 Serial.print(" ");
243 printPaddedHex(modbus.responseBuffer[6]);
244 Serial.print(", ");
245 printPaddedBin(modbus.responseBuffer[3]);
246 Serial.print(" ");
247 printPaddedBin(modbus.responseBuffer[4]);
248 Serial.print(" ");
249 printPaddedBin(modbus.responseBuffer[5]);
250 Serial.print(" ");
251 printPaddedBin(modbus.responseBuffer[6]);
252 Serial.print(", ");
253 printPaddedString(modbus.StringFromFrame(4));
254 Serial.print(", ");
255 printPaddedInt16(modbus.uint16FromFrame(bigEndian, 3));
256 Serial.print(" ");
257 printPaddedInt16(modbus.uint16FromFrame(bigEndian, 5));
258 Serial.print(", ");
259 Serial.print(modbus.float32FromFrame(bigEndian, 3), 4);
260 Serial.println();
261 } else
262 Serial.println("Read Register Failed!");
263 i++;
264 }
265 Serial.println("=======================");
266 Serial.println("\n\n\n\n\n\n\n\n");
267 Serial.println("=======================");
268 Serial.println("Register Type, Reg #, Hex , Binary "
269 " , Char , uInt16 , Float32");
270
271 // Get values two at a time
272 for (long i = 0; i < 65535; i++) {
273 Serial.print("Holding (0x03), ");
274 printPaddedInt16(i);
275 Serial.print(", ");
276 if (modbus.getRegisters(0x03, i, 2)) {
277 printPaddedHex(modbus.responseBuffer[3]);
278 Serial.print(" ");
279 printPaddedHex(modbus.responseBuffer[4]);
280 Serial.print(" ");
281 printPaddedHex(modbus.responseBuffer[5]);
282 Serial.print(" ");
283 printPaddedHex(modbus.responseBuffer[6]);
284 Serial.print(", ");
285 printPaddedBin(modbus.responseBuffer[3]);
286 Serial.print(" ");
287 printPaddedBin(modbus.responseBuffer[4]);
288 Serial.print(" ");
289 printPaddedBin(modbus.responseBuffer[5]);
290 Serial.print(" ");
291 printPaddedBin(modbus.responseBuffer[6]);
292 Serial.print(", ");
293 printPaddedString(modbus.StringFromFrame(4));
294 Serial.print(", ");
295 printPaddedInt16(modbus.uint16FromFrame(bigEndian, 3));
296 Serial.print(" ");
297 printPaddedInt16(modbus.uint16FromFrame(bigEndian, 5));
298 Serial.print(", ");
299 Serial.print(modbus.float32FromFrame(bigEndian, 3), 4);
300 Serial.println();
301 } else
302 Serial.println("Read Register Failed!");
303 i++;
304 }
305 Serial.println("=======================");
306}
307
308// ==========================================================================
309// Main loop function
310// ==========================================================================
311void loop() {}