Buonasera a tutti,
non so da dove cominciare per leggere un dato variabile da un plc sfruttando il protocollo Modbus su rs485.
Qualcuno mi può aiutare su come procedere?
Ho letto molti tutorial sul protocollo ma finora sono forse riuscito a capire che c'è una libreria (modbusrtu)che dovrebbe aiutarmi a configurare un arduino come slave per leggere da plc. E'giusto?
Grazie Fabio
Ciao
Nel ModBus lo slave riceve comandi/istruzioni dal master.
Quindi se tu devi recuperare dati da un device in modbus...tu sei il master.
di librerie per il modbus ce ne sono più di una...una di queste è la ModbusRtu.h.
In rete ho trovato questo esempio in cui Arduino Uno funge da slave(e fin qui ci sono), tuttavia esegue l'accensione di due led ed invia (non dovrebbe essere master qui?) comandi al plc tramite potenziometri.
Mi chiedo quindi è corretto impostare come master l'arduino che deve leggere da plc?
Questo esempio potrebbe essere preso in considerazione per il mio scopo?
#include <modbus.h>
#include <modbusDevice.h>
#include <modbusRegBank.h>
#include <modbusSlave.h>
modbusDevice regBank;
modbusSlave slave;
#define RS485TxEnablePin 2
#define RS485Baud 9600
#define RS485Format SERIAL_8E1
#define LED1 11
#define LED2 12
void setup()
{
//Assign the modbus device ID.
regBank.setId(1);
//Add Analog Input registers to the register bank
regBank.add(30001);
regBank.add(30002);
//Add Analog Output registers to the register bank
regBank.add(40001);
regBank.add(40002);
slave._device = ®Bank;
slave.setBaud(&Serial,RS485Baud,RS485Format,RS485TxEnablePin);
pinMode(LED1, OUTPUT);
pinMode(LED2, OUTPUT);
}
void loop()
{
digitalWrite(LED1, regBank.get(40001));
digitalWrite(LED2, regBank.get(40002));
regBank.set(30001, (word) analogRead(A0)); //from 0 - 1023
regBank.set(30002, (word) analogRead(A1)); //from 0 - 1023
slave.run();
}
Grazie Orso per avermi risposto
Ciao
a vederlo così sembra uno slave...in attesa di richieste dal master per impostare due output (LED1 e LED2) ed inviare, sempre su ruchiesta, i valori di due ingressi alanogici (A0 ed A1).
se tu devi richiedere info ed inviare comandi il tuo arduino deve essere master ed il PLC slave.
Nell'esempio postato arduino è uno slave: riceve comandi dal plc per accendere due led ma invia anche due valori analogici al plc che li riceve e farà altre cose....
Non ho ben capito una cosa fondamentale.
Se arduino invia dati al plc come nel caso degli analogici sopra, è ancora considerato uno slave?
Nel mio caso arduino fa richiesta al plc, è considerato master? (Qualcosa tipo: che valore hai in quel registro? Dammelo!)
Oppure il plc invia sempre il dato ed arduino è in ascolto, qui sarebbe slave? (Ok mi è arrivato il dato, spedisco via mqtt)
Grazie Orso, sei sempre molto puntuale
Lo slave invia solo su richiesta.
Quindi i valori analogici vengono aggiornati ogni ciclo loop...ma inviati al master solo quando lo richiede...alla fine del loop hai uno slave.run() che nal cado da al master i valori aggiornati
Finalmente ho trovato in rete qualcosa di molto simile: ho adattato il codice al mio caso ma non ottengo risposta dal dispositivo. Allego anche una immagine del collegamento filare ma ho un dubbio sull'alimentazione del modulo RS485: deve essere alimentato dall'arduino? I due dispositivi devono avere massa comune?
#include SoftwareSerial.h
#define SSerialRX 10 //Serial Receive pin
#define SSerialTX 11 //Serial Transmit pin
#define SSerialTxControl 3 //RS485 Direction control
#define RS485Transmit HIGH
#define RS485Receive LOW
#define Pin13LED 13
SoftwareSerial RS485Serial(SSerialRX, SSerialTX); // RX, TX
byte byteSend;
byte request[] = {0, 0x03, 0, 0, 0, 0x01, 0x85, 0xDB};
void setup()
{
// Start the built-in serial port, probably to Serial Monitor
Serial.begin(9600);
Serial.println("SerialRemote"); // Can be ignored
pinMode(Pin13LED, OUTPUT);
pinMode(SSerialTxControl, OUTPUT);
digitalWrite(SSerialTxControl, RS485Receive); // Init Transceiver
RS485Serial.begin(9600);
delay(2000);
RS485Serial.write(request, sizeof(request));
digitalWrite(Pin13LED, LOW);
delay(10);
digitalWrite(SSerialTxControl, RS485Receive);
}
void loop()
{
if (RS485Serial.available())
{
byteSend = RS485Serial.read(); // Read the byte
Serial.print(byteSend, HEX);
Serial.print(" ");
}
}
ciao,
il messaggio che stai inviando è:
byte request[] = {0, 0x03, 0, 0, 0, 0x01, 0x85, 0xDB};
il primo byte è l'indirizzo a cui invii la richiesta; gli indirizzi validi vanno da 1 a 247; se usi l'indirizzo 0 invii un messaggio "broadcast" cioè a tutti gli slave...di solito si utilizza per inviare comandi comuni (tipo accensione di tutti i dispositivi)...quando usi l'indirizzo 0 nessuno slave invia risposta.
il produttore del dispositivo dice proprio così:
we should operate as below: Sent by computer : 00 03 00 00 00 01 85 DB Return from controller : 00 03 02 02 AE 05 58.
quindi, se non ho capito male la richiesta è fatta correttamente
ciao...quello strumenti ha un menu impostazioni seriali?
se si cosa c'è scritto?
Lo strumento può essere settato a diverse velocità di baud rate (ho scelto 9600), e si può impostare l'indirizzo dello slave (dice di lasciarlo a zero come nell'esempio).
Inoltre:
Arduino invia: 00 03 00 00 00 01 85 DB, lo strumento ritorna: 00 03 02 02 AE 05 58.
Dove:
00 is 485 address;
03 is the function code;
02 is the data lengh of the ph value:2 bites
02 for the return of the ph value of 686 (hex hig byte);
AE for the return of the ph value of 686 (hex low byte);
05 58 is the CRC check value;