I have developed an application using yaacov ArduinoModbusSlave via RS485 serial
That library requires the program allocating the array of data structures and then using
a union to link the application memory and the modbus holding register space.
This enables conserving memory by having only a single array in memory.
I need to upgrade the application to use TCP rather than RTU and so far I am not clear how to migrate
the ethernet support from ESP to Ethernet shield v2 W5500
I have successfully upgraded the RTU version of the Kitchen Sink which was/is missing from the TCP examples.
Is there a way to create an array of data structures and have it overlay the memory
which is allocated by:
I'm guessing this allocates memory somewhere which is normally only accessed via
modbusTCPServer.holdingRegisterWrite(i,2*i+3);
As I write this I am realizing I could probably do what I need by sacrificing the struct and the element naming
and just brute force the accesses by organized indexing...
something like defining the current structure element names as constants
and then i = struct_index * struct_size + struct_element
Anyway, I thought I would ask the question anyway... maybe there is a way to find the address of the
HoldingRegister array and union it with the structure array...
Oh... I noticed one little anomaly related to my conversion of KitchenSink RTU to TCP...
In both RTU and TCP, toggling the LED to ON takes effect immediately
in RTU the LED goes off immediately. In TCP version there is initially no change, and then after a few seconds
the LED kinda fades to OFF - a shaky dimming rather than switching OFF
Feel free to check this code and stick it in the TCP examples...
I always think example code should be more than the bare minimalist simplest functionality
leaving any practical implementation as further mysteries ;-)
/*
Modbus TCP Server Kitchen Sink
This sketch creates a Modbus RTU Server and demonstrates
how to use various Modbus Server APIs.
Circuit:
- MKR board
- MKR ETH shield
- ISO GND connected to GND of the Modbus RTU server
- Y connected to A/Y of the Modbus RTU client
- Z connected to B/Z of the Modbus RTU client
- Jumper positions
- FULL set to OFF
- Z \/\/ Y set to OFF
created 18 July 2018
by Sandeep Mistry
*/
#include <SPI.h>
#include <Ethernet.h>
#include <ArduinoRS485.h> // ArduinoModbus depends on the ArduinoRS485 library
#include <ArduinoModbus.h>
// Enter a MAC address for your controller below.
// Newer Ethernet shields have a MAC address printed on a sticker on the shield
// The IP address will be dependent on your local network:
byte mac[] = {
// 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED
0xA8, 0x61, 0x0A, 0xAF, 0x18, 0x27
};
IPAddress ip(192, 168, 1, 177);
EthernetServer ethServer(502);
ModbusTCPServer modbusTCPServer;
const int ledPin = LED_BUILTIN;
const int numCoils = 10;
const int numDiscreteInputs = 10;
const int numHoldingRegisters = 10;
const int numInputRegisters = 10;
void setup() {
// You can use Ethernet.init(pin) to configure the CS pin
Ethernet.init(10); // Most Arduino shields
//Ethernet.init(5); // MKR ETH shield
//Ethernet.init(0); // Teensy 2.0
//Ethernet.init(20); // Teensy++ 2.0
//Ethernet.init(15); // ESP8266 with Adafruit Featherwing Ethernet
//Ethernet.init(33); // ESP32 with Adafruit Featherwing Ethernet
Serial.begin(9600);
while (!Serial);
Serial.println("Modbus TCP Server Kitchen Sink");
// start the Ethernet connection and the server:
Ethernet.begin(mac, ip);
// Check for Ethernet hardware present
if (Ethernet.hardwareStatus() == EthernetNoHardware) {
Serial.println("Ethernet shield was not found. Sorry, can't run without hardware. :(");
while (true) {
delay(1); // do nothing, no point running without Ethernet hardware
}
}
delay(3);
if (Ethernet.linkStatus() == LinkOFF) {
Serial.println("Ethernet cable is not connected.");
} else {
Serial.println("Ethernet cable is now connected.");
}
// start the server
ethServer.begin();
// start the Modbus TCP server
if (!modbusTCPServer.begin()) {
Serial.println("Failed to start Modbus TCP Server!");
while (1);
}
// configure coils at address 0x00
modbusTCPServer.configureCoils(0x00, numCoils);
// configure discrete inputs at address 0x00
modbusTCPServer.configureDiscreteInputs(0x00, numDiscreteInputs);
// configure holding registers at address 0x00
modbusTCPServer.configureHoldingRegisters(0x00, numHoldingRegisters);
// configure input registers at address 0x00
modbusTCPServer.configureInputRegisters(0x00, numInputRegisters);
}
void loop() {
// listen for incoming clients
EthernetClient client = ethServer.available();
if (client) {
// a new client connected
Serial.println("new client");
// let the Modbus TCP accept the connection
modbusTCPServer.accept(client);
while (client.connected()) {
// poll for Modbus TCP requests, while client connected
modbusTCPServer.poll();
// update the LED
updateLED();
}
// map the coil values to the discrete input values
for (int i = 0; i < numCoils; i++) {
int coilValue = modbusTCPServer.coilRead(i);
modbusTCPServer.discreteInputWrite(i, coilValue);
}
for (int i = 0; i < numHoldingRegisters; i++) {
modbusTCPServer.holdingRegisterWrite(i,2*i+3);
}
for (int i = 0; i < numHoldingRegisters; i++) {
modbusTCPServer.inputRegisterWrite(i,3*i+2);
}
// output the value of each analog input pin
for (int analogChannel = 0; analogChannel < 6; analogChannel++) {
int sensorReading = analogRead(analogChannel);
Serial.print(sensorReading); Serial.print(" ");
modbusTCPServer.inputRegisterWrite(analogChannel,sensorReading);
}
// map the holding register values to the input register values
for (int i = 0; i < numHoldingRegisters; i++) {
long holdingRegisterValue = modbusTCPServer.holdingRegisterRead(i);
//modbusTCPServer.inputRegisterWrite(i, holdingRegisterValue);
Serial.print(holdingRegisterValue); Serial.print(" ");
}
Serial.println("client disconnected");
}
}
void updateLED() {
// read the current value of the coil
int coilValue = modbusTCPServer.coilRead(0x00);
if (coilValue) {
// coil value set, turn LED on
digitalWrite(ledPin, HIGH);
} else {
// coil value clear, turn LED off
digitalWrite(ledPin, LOW);
}
}
I have developed an application using yaacov ArduinoModbusSlave via RS485 serial That library requires the program allocating the array of data structures and then using a union to link the application memory and the modbus holding register space.
This enables conserving memory by having only a single array in memory. I need to upgrade the application to use TCP rather than RTU and so far I am not clear how to migrate the ethernet support from ESP to Ethernet shield v2 W5500
I have successfully upgraded the RTU version of the Kitchen Sink which was/is missing from the TCP examples. Is there a way to create an array of data structures and have it overlay the memory which is allocated by:
I'm guessing this allocates memory somewhere which is normally only accessed via
As I write this I am realizing I could probably do what I need by sacrificing the struct and the element naming and just brute force the accesses by organized indexing... something like defining the current structure element names as constants and then
i = struct_index * struct_size + struct_element
Anyway, I thought I would ask the question anyway... maybe there is a way to find the address of the
HoldingRegister
array and union it with the structure array...Oh... I noticed one little anomaly related to my conversion of KitchenSink RTU to TCP... In both RTU and TCP, toggling the LED to ON takes effect immediately in RTU the LED goes off immediately. In TCP version there is initially no change, and then after a few seconds the LED kinda fades to OFF - a shaky dimming rather than switching OFF
Feel free to check this code and stick it in the TCP examples... I always think example code should be more than the bare minimalist simplest functionality leaving any practical implementation as further mysteries ;-)