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
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
8; Please visit documentation for the other options and examples
9; http://docs.platformio.org/page/projectconf.html
12description = Changing a setting and reading data from a modbus sensor
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.
7 * @brief This is a testing program to scan through all possible holding registers.
9 * @m_examplenavigation{example_scan_registers,}
11 * ======================================================================= */
13// ---------------------------------------------------------------------------
14// Include the base required libraries
15// ---------------------------------------------------------------------------
17#include <SensorModbusMaster.h>
19// ---------------------------------------------------------------------------
20// Set up the sensor specific information
21// ie, pin locations, addresses, calibrations and related settings
22// ---------------------------------------------------------------------------
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
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
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
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;
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;
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;
66// Construct the modbus instance
69void printPaddedHex(byte val) {
72 Serial.print(val, HEX);
74 Serial.print(val, HEX);
77void printPaddedBin(byte val) {
78 if (val >= 0b10000000) {
80 Serial.print(val, BIN);
81 } else if (val >= 0b01000000) {
83 Serial.print(val, BIN);
84 } else if (val >= 0b00100000) {
86 Serial.print(val, BIN);
87 } else if (val >= 0b00010000) {
89 Serial.print(val, BIN);
90 } else if (val >= 0b00001000) {
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);
103 // if (val > 0b0000000010000000) {
104 // Serial.print("00000000");
105 // Serial.print(val, BIN);
107 // if (val > 0b0000000001000000) {
108 // Serial.print("000000000");
109 // Serial.print(val, BIN);
111 // if (val > 0b0000000000100000) {
112 // Serial.print("0000000000");
113 // Serial.print(val, BIN);
115 // if (val > 0b0000000000010000) {
116 // Serial.print("000000000000");
117 // Serial.print(val, BIN);
119 // if (val > 0b0000000000001000) {
120 // Serial.print("0000000000000");
121 // Serial.print(val, BIN);
123 // if (val > 0b0000000000000100) {
124 // Serial.print("00000000000000");
125 // Serial.print(val, BIN);
127 // if (val > 0b0000000000000010) {
128 // Serial.print("000000000000000");
129 // Serial.print(val, BIN);
131 // if (val > 0b0000000000000001) {
132 // Serial.print("0000000000000000");
133 // Serial.print(val, BIN);
137void printPaddedString(String val) {
138 int len = val.length();
161void printPaddedInt16(uint16_t val) {
165 } else if (val < 100) {
168 } else if (val < 1000) {
171 } else if (val < 10000) {
178// ==========================================================================
179// Main setup function
180// ==========================================================================
182 if (DEREPin >= 0) { pinMode(DEREPin, OUTPUT); }
184 // Turn on the "main" serial port for debugging via USB Serial Monitor
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);
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
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.
214 // Turn on debugging, if desired
215 // modbus.setDebugStream(&Serial);
217 // Start the modbus instance
218 modbus.begin(modbusAddress, modbusSerial, DEREPin);
221 Serial.println("Full scan of all input and holding registers");
223 // Allow the sensor and converter to warm up
224 Serial.println("Waiting for sensor and adapter to be ready.");
228 Serial.println("Register Type, Reg #, Hex , Binary "
229 " , Char , uInt16 , Float32");
231 // Get values two at a time
232 for (long i = 0; i < 65535; i++) {
233 Serial.print("Input (0x04), ");
236 if (modbus.getRegisters(0x04, i, 2)) {
237 printPaddedHex(modbus.responseBuffer[3]);
239 printPaddedHex(modbus.responseBuffer[4]);
241 printPaddedHex(modbus.responseBuffer[5]);
243 printPaddedHex(modbus.responseBuffer[6]);
245 printPaddedBin(modbus.responseBuffer[3]);
247 printPaddedBin(modbus.responseBuffer[4]);
249 printPaddedBin(modbus.responseBuffer[5]);
251 printPaddedBin(modbus.responseBuffer[6]);
253 printPaddedString(modbus.StringFromFrame(4));
255 printPaddedInt16(modbus.uint16FromFrame(bigEndian, 3));
257 printPaddedInt16(modbus.uint16FromFrame(bigEndian, 5));
259 Serial.print(modbus.float32FromFrame(bigEndian, 3), 4);
262 Serial.println("Read Register Failed!");
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");
271 // Get values two at a time
272 for (long i = 0; i < 65535; i++) {
273 Serial.print("Holding (0x03), ");
276 if (modbus.getRegisters(0x03, i, 2)) {
277 printPaddedHex(modbus.responseBuffer[3]);
279 printPaddedHex(modbus.responseBuffer[4]);
281 printPaddedHex(modbus.responseBuffer[5]);
283 printPaddedHex(modbus.responseBuffer[6]);
285 printPaddedBin(modbus.responseBuffer[3]);
287 printPaddedBin(modbus.responseBuffer[4]);
289 printPaddedBin(modbus.responseBuffer[5]);
291 printPaddedBin(modbus.responseBuffer[6]);
293 printPaddedString(modbus.StringFromFrame(4));
295 printPaddedInt16(modbus.uint16FromFrame(bigEndian, 3));
297 printPaddedInt16(modbus.uint16FromFrame(bigEndian, 5));
299 Serial.print(modbus.float32FromFrame(bigEndian, 3), 4);
302 Serial.println("Read Register Failed!");
305 Serial.println("=======================");
308// ==========================================================================
310// ==========================================================================