[UPDATE: I've now added new examples at the very bottom of this post so that the code runs with the new Arduino_PortentaMachineControl.h library. The code is similar but there are some slight adjustments that are neccesary to get the new library to work. At the moment this library is incomplete and I don't understand why Arduino couldn't just improve the Arduino_MachineControl.h library (???), but it is what it is.]
[UPDATE 2: Feel free to check out my new basic guide on MODBUS TCP with the Portenta Machine Control where I also give an example sketch of running MODBUS TCP and RS485 at the same time.]
Hello everyone,
I feel somewhat pretentious posting a guide since I'm quite the beginner, however I thought I would still post this since there may be other people who are trying to establish RS485 with the PMC and the ArduinoModbus library.
There is also currently very limited information available on this topic.
I have made these sketches based on: a example sketch given to me by the Arduino support team, the examples in the ArduinoModbus library, and by looking through the .cpp files of the RS485 & ArduinoModbus libraries. I have by no means "mastered" these libraries so the sketches will be very basic.
I am assuming everyone reading this knows the basics of Modbus protocol, wiring, IDE, library manager, etc.
So... this will show you how to establish both a simple slave/server and master/client setup with the Portenta Machine Control and the ArduinoModbus library:
Hardware:
Portenta machine control
Computer
USB to RS485 TTL converter
24V Power supply (for PMC)
Software:
Arduino IDE
ModbusTool (http://modbusmaster.com/)
Modbus Tools Modbus Slave (Modbus Slave Simulator) (NOTE: these guys will try to annoy you into giving them your money - DONT GIVE IN!)
Arduino_MachineControl library
ArduinoRS485 library
ArduinoModbus library
The connection configuration in both Modbus simulation softwares should be:
Connection: Serial
Baudrate: 9600
Parity: None
Stop bits: 1
Mode: RTU
Byte order: 4321 (This is for master software only)
Physical connection:
- 24V Power supply --> PMC
- Computer --> PMC
- Computer --> [USB to RS485 TTL]
- [USB to RS485 TTL] --> PMC :
(-) --> GND
A --> TXP 485
B --> TXN 485
SLAVE/SERVER:
Here is the code for a basic slave/server configuration:
#include <Arduino_MachineControl.h>
#include <ArduinoRS485.h>
#include <ArduinoModbus.h>
using namespace machinecontrol;
constexpr unsigned long baudrate { 9600 };
void setup() {
// put your setup code here, to run once
Serial.begin(9600);
delay(10);
comm_protocols.init();
comm_protocols.rs485Enable(true);
comm_protocols.rs485.setDelays(50, 1600);
ModbusRTUServer.begin(comm_protocols.rs485, 1, baudrate, SERIAL_8N1);
/*
The above part is the configuration of the slave:
1) Selection of pins
2) Assigned slave ID
3) Baudrate (as defined above)
4) Byte size: 8, Parity: None, Stop bits: 1
*/
ModbusRTUServer.configureHoldingRegisters(0, 16); //create 16 holding registers starting at address 0 [0-15].
ModbusRTUServer.holdingRegisterWrite(1, 500); //write the value 500 into address 1.
}
void loop() {
// put your main code here, to run repeatedly:
ModbusRTUServer.poll();
int regVal = ModbusRTUServer.holdingRegisterRead(1);
Serial.print("regVal: ");
Serial.println(regVal); //This part is here so you can see that the configuration has been done correctly before connecting to master simulation software.
Serial.println("-");
delay(500);
}
After uploading this code start ModbusTool.exe, configure the connection, and connect. You should see the value 500 in address 1.
Here is a .ino file with the above sketch:
PMCSlaveBasic.ino (790 Bytes)
MASTER/CLIENT:
Here is the code for a basic master/client configuration:
#include <Arduino_MachineControl.h>
#include <ArduinoRS485.h>
#include <ArduinoModbus.h>
using namespace machinecontrol;
constexpr unsigned long baudrate { 9600 };
int readVal;
uint16_t sendVal = 125;
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
comm_protocols.init();
comm_protocols.rs485Enable(true);
comm_protocols.rs485.setDelays(50, 1600);
ModbusRTUClient.begin(comm_protocols.rs485, baudrate, SERIAL_8N1);
}
void loop() {
// put your main code here, to run repeatedly:
readVal = ModbusRTUClient.holdingRegisterRead(1, 0); //send a read request (one holding register) to slave 1, address 0.
ModbusRTUClient.holdingRegisterWrite(1, 1, sendVal); //send a write message to slave 1, address 1. Write the value sendVal (125).
Serial.print("Value of holding register 1 in slave: ");
Serial.println(readVal);
Serial.println();
}
After uploading this code start Modbus Slave, configure the connection, and connect.
You should see that the value of address 1 is 125.
Then write some value (not 0!) into address 0.
Then go back into the IDE and open Serial Monitor - it should display whatever value you wrote into address 0.
Here is a .ino file with the above sketch:
PMCMasterBasic.ino (727 Bytes)
I should also note that there seem to be multiple ways of writing commands with this library.
For instance you could alternatively construct the read request as:
ModbusRTUClient.requestFrom(1, HOLDING_REGISTERS, 0, 1);
readVal = ModbusRTUClient.read();
I hope someone found this helpful in any way!
Kind regards
/ Einar
SLAVE/SERVER WITH Arduino_PortentaMachineControl.h :
#include "mbed.h"
#include <Arduino_PortentaMachineControl.h>
#include <ArduinoRS485.h>
#include <ArduinoModbus.h>
constexpr unsigned long baudrate = 115200;
constexpr int predelay = 50;
constexpr int postdelay = 1600;
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
MachineControl_RS485Comm.begin(baudrate, predelay, postdelay);
ModbusRTUServer.begin(MachineControl_RS485Comm, 1, baudrate, SERIAL_8N1);
ModbusRTUServer.configureHoldingRegisters(0, 19); //Configures 18 holding registers.
ModbusRTUServer.holdingRegisterWrite(1, 153);
}
void loop() {
// put your main code here, to run repeatedly:
ModbusRTUServer.poll();
}
MODBUS_server_WORKING.ino (683 Bytes)
MASTER/CLIENT with Arduino_PortentaMachineControl.h":
#include "mbed.h"
#include <Arduino_PortentaMachineControl.h>
#include <ArduinoRS485.h>
#include <ArduinoModbus.h>
constexpr unsigned long baudrate = 115200;
constexpr int predelay = 50;
constexpr int postdelay = 1600;
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
MachineControl_RS485Comm.begin(baudrate, predelay, postdelay);
ModbusRTUClient.begin(MachineControl_RS485Comm, baudrate, SERIAL_8N1);
}
void loop() {
// put your main code here, to run repeatedly:
ModbusRTUClient.holdingRegisterWrite(3, 0, 1); //Slave ID (int), Address (int), value
}
MODBUS_client_WORKING.ino (605 Bytes)