NORVI devices are cutting-edge technological solutions designed to enhance efficiency, connectivity, and control in various industries. Leveraging advanced IoT technology, NORVI devices offer seamless integration with existing infrastructure, providing real-time monitoring, analytics, and automation capabilities.
In this document, we will explore the process of MODBUS communication through two NORVI devices. We’ll be considering the one NORVI device as a slave and the other one as a master and read the digital inputs, and analog inputs and storing the values in the master device.
MODBUS Communication Through NORVI #
Here we’ll be considering the two NORVI ESP32 devices, one as a master and one as a slave. Here we are using the NORVI-GSM-AE08-I-L device and the NORVI-AT01-BM2 device.
We’ll be considering the NORVI-GSM-AE08-I-L device as a master and the NORVI-AT01-BM2 device as a slave. With the NORVI-GSM-AE08-I-L device, we’ll be reading the digital inputs, and analog inputs of the NORVI-AT01-BM2 device and storing the values in the NORVI-GSM-AE08-I-L device.
Requirements to get started #
- Two NORVI devices one as a master and one as a slave.
- Wires for connection
- USB cable (Type A to Type B mini) for NORVI-AT01-BM2.
- USB cable (Type A to Type B micro) for NORVI-GSM-AE08-I-L.
Circuit Connection #
Connect the NORVI-GSM-AE08-I-L module RS485 A & B pins with the RS485 A & B pins of the NORVI-AT01-BM2 module.
Power up the devices and connect the USB cables.
Compile and Upload the Test Program. #
Check out these links for detailed instructions on writing test programs.
NORVI Device as a MODBUS master
NORVI Device as a MODBUS slave
Upload the Master program to the NORVI-GSM-AE08-I-L device and the Slave program to the NORVI-AT01-BM2 device.
Download the test programs from here.
Check the pin configuration of the programs and run the programs separately.
Result of the MODBUS communication through two NORVI devices. #
COM33 – NORVI-GSM-AE08-I-L Serial window.
COM22 – NORVI-AT01-BM2 Serial window.
Initial State,
NORVI-GSM-AE08-I-L read and print the digital input status of the NORVI-AT01-BM2.
NORVI-GSM-AE08-I-L read and print the analog input status of the NORVI-AT01-BM2
Troubleshooting #
RS485 Check #
Before uploading the MODBUS code, RS485 two ways can be checked by setting the FC pin high and low. This test program sets up communication between two serial ports, the hardware serial port (Serial) and a software serial port (Serial1).
Download the RS485 example program from here and check the pin configuration of the program.
Here’s a breakdown of what each part of the code does,
Defined the FC (Flow Control) pin, RXD (Receive Data) pin and the TXD (Transmit Data) pin.
#define RXD 33
#define TXD 2
#define FC 4
Setup function:
Initializes the hardware serial port (Serial) with a baud rate of 9600 bits per second. Initializes the software serial port (Serial1) with a baud rate of 9600 bits per second, 8 data bits, no parity bit, and 1 stop bit. It also specifies the RXD and TXD PINs defined earlier. Sets the Flow Control pin (FC) as an output pin.
void setup() {
Serial.begin(9600);
pinMode(FC, OUTPUT);
Serial1.begin(9600, SERIAL_8N1,RXD,TXD);
}
Loop function:
Sets the Flow Control pin (FC) to HIGH, indicating that the Arduino is ready to transmit data. Sends the message “RS485 01 SUCCESS” over the RS485 protocol using the software serial port (Serial1). Then sets the Flow Control pin (FC) to LOW, indicating that the Arduino is ready to receive data.
void loop() {
digitalWrite(FC, HIGH); // Make FLOW CONTROL pin HIGH
Serial1.println(F("RS485 01 SUCCESS")); // Send RS485 SUCCESS serially
delay(500); // Wait for transmission of data
digitalWrite(FC, LOW) ; // Receiving mode ON
// Serial1.flush() ;
While loop checks if there is data available to read from the software serial port (Serial1). If there is data available: Reads a character from the software serial port and stores it in the variable n. Writes the character c to the hardware serial port.
while (Serial1.available()) { // Check if data is available
char c = Serial1.read(); // Read data from RS485
Serial.write(c); // Print data on serial monitor
Software serial window,
Once open both serial windows are open, enter the message into the serial window and send it. From this RS485 can check for both sides.
Hardware serial window,
Sharing RX and TX with USB #
Utilize the NORVI-IIOT-AE01 and NORVI-IIOT-AE02 product ranges RS485 communication where the TX (Transmit) and RX (Receive) pins are shared with the USB RX and TX pins. This means that the same physical pins are used for both serial communication with a computer via USB and RS485 communication.
As a result, direct use of serial print functions for communication is not possible when connected to such devices. An alternative solution would be to output the result to an OLED display, providing visual feedback on the data.
- NORVI as a MODBUS Master.
This program sets up a NORVI-IIOT-AE02 device acting as a MODBUS master. It reads the digital inputs, analog inputs, and relay/transistor outputs from the slave and stores the values in the device.
For specific RS485 GPIO allocations for NORVI devices, refer to the NORVI RS485 GPIO Allocation.
Download the test program from here.
we are using the NORVI-IIOT-AE02 device. It has common RX and TX pins.,
- RS485_RX – 3
- RS485_TX – 1
- RS485_FC – 4
- USB_RX – 3
- USB_TX – 1
Add the required libraries.
- Modbus-esp8266
- Adafruit GFX
- Adafruit SSD1306
#include <Wire.h>
#include <ModbusRTU.h>
#include <Adafruit_SSD1306.h>
#include <Adafruit_GFX.h>
Defines the screen width, height, and reset pin for the OLED display. Initializes the SSD1306 display object with these parameters. Defines the MODBUS slave ID, the first holding register address to read, the number of holding registers to read, and the function code.
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
#define SLAVE_ID 5
#define FIRST_HREG 2
#define HREG_COUNT 7
#define FC 4
Declares an instance of the MODBUS RTU class. Defines a callback function cb() which is not currently utilized.
ModbusRTU mb;
bool cb(Modbus::ResultCode event, uint16_t transactionId, void* data) {
if (event != Modbus::EX_SUCCESS) {
}
return true;
}
Setup function:
Initializes the serial communication, establishes MODBUS RTU communication with the specified function code, sets the Arduino pin corresponding to the function code to LOW, initializes MODBUS RTU as master, initiates I2C communication with the specified pins for the OLED display, and initializes the display.
void setup() {
Serial.begin(9600);
mb.begin(&Serial, FC);
digitalWrite(FC, LOW);
mb.master();
Wire.begin(16, 17);
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
display.display();
}
Loop function:
Reads holding registers from the slave device, if the Master device is not acting as a slave itself. It then displays the readings on the OLED screen.
void loop() {
uint16_t res[HREG_COUNT];
if (!mb.slave()) {
mb.readHreg(SLAVE_ID, FIRST_HREG, res, HREG_COUNT, cb);
display.clearDisplay();
display.setTextColor(WHITE);
display.setTextSize(1);
display.setCursor(0, 0);
display.print("INP 1- "); display.print(res[0]);
display.setCursor(70, 0);
display.print("INP 2- "); display.print(res[1]);
display.setCursor(0, 14);
display.print("INP 3- "); display.print(res[2]);
display.setCursor(70, 14);
display.print("INP 4- "); display.print(res[3]);
display.setCursor(0, 30);
display.print("INP 5- "); display.print(res[4]);
display.setCursor(70, 30);
display.print("INP 6- "); display.print(res[5]);
display.setCursor(0, 48);
display.print("INP 7- "); display.print(res[6]);
display.setCursor(70, 48);
display.print("INP 8- "); display.print(res[7]);
display.display();
}
- NORVI as a MODBUS Slave.
This program sets up a NORVI-IIOT-AE02 device acting as a MODBUS slave. It reads holding registers from the slave and displays the values on an OLED display.
For specific RS485 GPIO allocations for NORVI devices, refer to the NORVI RS485 GPIO Allocation.
Download the test program from here.
we are using the NORVI-IIOT-AE02 device. It has common RX and TX pins.,
- RS485_RX – 3
- RS485_TX – 1
- RS485_FC – 4
- USB_RX – 3
- USB_TX – 1
Add the required libraries.
- Modbus-esp8266
- Adafruit GFX
- Adafruit SSD1306
Defines the screen width, height, and reset pin for the OLED display. Initializes the SSD1306 display object with these parameters.
Defines the screen width, height, and reset pin for the OLED display. Initializes the SSD1306 display object with these parameters.
#include <Wire.h>
#include <Adafruit_SSD1306.h>
#include <Adafruit_GFX.h>
#include <ModbusRTU.h>
Defines the screen width, height, and reset pin for the OLED display. Initializes the SSD1306 display object with these parameters. Then defines the MODBUS slave ID, RX, TX, and the function code and the Inputs and Outputs of the device.
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
#define SLAVE_ID 5
#define RXD 3
#define TXD 1
#define FC 4
#define INPUT1 18
#define INPUT2 39
#define INPUT3 34
#define INPUT4 35
Declares an instance of the MODBUS RTU class.
ModbusRTU mb;
Setup function:
Initializes the serial communication, establishes MODBUS RTU communication with the specified function code, sets the Arduino pin corresponding to the function code to LOW, initializes MODBUS RTU as master, initiates I2C communication with the specified pins for the OLED display, and initializes the display. Defined the pin mode of each input.
void setup() {
//Serial.begin(9600);
Serial.begin(9600, SERIAL_8N1,RXD,TXD);
mb.begin(&Serial1, FC); // Use Serial for USB communication
mb.setBaudrate(9600);
Serial.println("Modbus Initialized");
//Initialize Digital Inputs
pinMode(INPUT1, INPUT);
pinMode(INPUT2, INPUT);
pinMode(INPUT3, INPUT);
pinMode(INPUT4, INPUT);
Wire.begin(16, 17);
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
display.display();
}
Loop function:
Reads Discreat Input Coils from the slave device stored in the master device.
mb.slave(SLAVE_ID);
mb.addIsts(1);
mb.Ists(1,digitalRead(INPUT1));
mb.addIsts(2);
mb.Ists(2,digitalRead(INPUT2));
mb.addIsts(3);
mb.Ists(3,digitalRead(INPUT3));
mb.addIsts(4);
mb.Ists(4,digitalRead(INPUT4));
Then display the readings on the OLED screen of the slave device.
display.clearDisplay();
display.setTextColor(WHITE);
display.setTextSize(1);
display.setCursor(0, 0);
display.print("INP 1- ");
display.print(digitalRead(INPUT1));
display.setCursor(70, 0);
display.print("INP 2- ");
display.println(digitalRead(INPUT2));
display.setCursor(0, 14);
display.print("INP 3- ");
display.print(digitalRead(INPUT3));
display.setCursor(70, 14);
display.print("INP 4- ");
display.println(digitalRead(INPUT4));