Buongiorno.
Sto realizzando una comunicazione tra un Arduino OPTA (Master) e un ARDUINO NANO (slave) tramite RS485 con protocollo MODBUS RTU.
La necessità è quella di comandare l'uscita 12 dell'arduino NANO e trasmettere la lettura di tre sensori ad ultrasuoni che faccio con l'arduino NANO.
Ho utilizzato le librerie <ModbusMaster.h> per l'OPTA e <ModbusSlave.h> per il NANO.
Ho trovato diverse guide per impostare la ricezione/trasmissione per l'Arduino NANO attraverso i PIN RE/DE del modulo MAX 485.
Invece per l'Arduino OPTA, che ha la porta di comunicazione RS485 integrata, ho fatto alcune modifiche al solito codice mettendo nel
void preTransmission(){
RS485.beginTransmission();
RS485.noReceive();
}
e nel
void postTransmission(){
RS485.endTransmission();
RS485.receive();
}
Il sistema sembra funzionare ma sembra instabile. Inoltre noto che per ogni lettura/scrittura MODBUS il sistema impieghi oltre 1500ms.
Qualcuno potrebbe indicarmi se la modifica fatta va bene?
Allego il codice del master e dello slave.
Grazie a tutti in anticipo
per il master
#include <ArduinoRS485.h>
#include <ModbusMaster.h>
unsigned long mymillis = millis();
unsigned long differenza;
unsigned long mymillis1 = millis();
unsigned long differenza1;
uint8_t result;
uint8_t result1;
int ciclo;
ModbusMaster node;
void setup() {
constexpr auto baudrate { 9600 };
constexpr auto btime { 1.0f / baudrate };
constexpr auto predl { btime * 9.6f * 3.5f * 1e6 };
constexpr auto postdl { btime * 9.6f * 3.5f * 1e6 };
Serial.begin(9600);
RS485.begin(baudrate);
RS485.setDelays(predl, postdl);
node.begin(1, RS485);
node.preTransmission(preTransmission);
node.postTransmission(postTransmission);
RS485.receive();
}
void loop() {
modbus_relay();
modbus_sensore_distanza();
delay(50);
}
void modbus_relay(){ /////attivazione PIN 12 dello slave 1 - ARDUINO NANO
mymillis = millis();
Serial.print("ciclo= ");
Serial.println(ciclo);
result = node.writeSingleCoil(12, 1); ///scrittura del valore 1 all'indirizzo 12 dello slave 1
Serial.println("PRIMO NODO");
Serial.print("node.ku8MBSuccess= ");
Serial.println(node.ku8MBSuccess);
Serial.print("result= ");
Serial.println(result);
if (result == node.ku8MBSuccess)
{
differenza = millis() - mymillis;
Serial.print("tempo ciclo ID1= ");
Serial.print(differenza);
Serial.println(" ms");
mymillis = millis();
}
ciclo++;
}
void modbus_sensore_distanza(){
mymillis1 = millis();
Serial.print("ciclo= ");
Serial.println(ciclo);
///leggo i 16 registri dell'indirizzo 30001
result1=node.readInputRegisters(30001, 16);
Serial.print("node.ku8MBSuccess= ");
Serial.println(node.ku8MBSuccess);
Serial.print("result= ");
Serial.println(result1);
if (result == node.ku8MBSuccess)
{
differenza1 = millis() - mymillis1;
Serial.print("tempo ciclo ID1= ");
Serial.print(differenza1);
Serial.println(" ms");
mymillis1 = millis();
Serial.print("distanza_1 ");
Serial.println(node.getResponseBuffer(0));
Serial.print("distanza_2 ");
Serial.println(node.getResponseBuffer(1));
Serial.print("distanza_3 ");
Serial.println(node.getResponseBuffer(2));
}
ciclo++;
}
void preTransmission(){
RS485.beginTransmission();
RS485.noReceive();
}
void postTransmission(){
RS485.endTransmission();
RS485.receive();
}
e per lo slave ARDUINO NANO
#include <ModbusSlave.h>
#include <SoftwareSerial.h>
int SLAVE_ID=1; ///1= slave ID
int RS485_CTRL_PIN=3; /// 3 = PIN TX/RX per RS485
#define trigPin1 4////sensore vasca 1
#define echoPin1 5///sensore vasca 1
#define trigPin2 6////sensore vasca 2
#define echoPin2 7///sensore vasca 2
#define trigPin3 8////sensore vasca 3
#define echoPin3 9///sensore vasca 3
long intervallo=1000; ///2secondi intervallo tar una lettuar e la successiva dei sensori di livello ad ultrasuoni
long distanza_1; /////sensore vasca 1
long distanza_1m; /////media del sensore vasca 1
long tempo_lettura_1=0; /////sensore vasca 1
int sommaValoriValidi_1;/////sensore vasca 1
int conteggioValoricorretti_1;/////sensore vasca 1
long distanza_2; /////sensore vasca 2
long distanza_2m; /////media del sensore vasca 2
long tempo_lettura_2=0; /////sensore vasca 2
int sommaValoriValidi_2;/////sensore vasca 2
int conteggioValoricorretti_2;/////sensore vasca 2
long distanza_3; /////sensore vasca 3
long distanza_3m; /////media del sensore vasca 3
long tempo_lettura_3=0; /////sensore vasca 3
int sommaValoriValidi_3;/////sensore vasca 3
int conteggioValoricorretti_3;/////sensore vasca 3
SoftwareSerial RS485Serial(10, 11); // RX, TX
Modbus slave(RS485Serial, SLAVE_ID, RS485_CTRL_PIN);
void setup() {
pinMode(3, OUTPUT); // settaggio PIN di controllo RX/TX per l'RS485
pinMode(12, OUTPUT); //LED
pinMode(trigPin1, OUTPUT);
pinMode(echoPin1, INPUT);
/* register handler functions.
* into the modbus slave callback vector.
*/
slave.cbVector[CB_WRITE_COILS] = writeDigitalOut; ///all'oggetto slave applico il codice della funzione (write coil) per il relè
slave.cbVector[CB_READ_INPUT_REGISTERS] = readAnalogIn; ///all'oggetto slave applico il codice della funzione (leggi registro) per i sensori di distanza
// set Serial and slave at baud 9600.
Serial.begin( 9600 );
RS485Serial.begin(9600);
slave.begin( 9600 );
}
void loop() {
/* listen for modbus commands con serial port.
*
* on a request, handle the request.
* if the request has a user handler function registered in cbVector.
* call the user handler function.
*/
slave.poll();
sensore1();
sensore2();
sensore3();
delay(200);
}
////////////////SENSORRE ULTRASUONI VASCA 1
void sensore1 (){
if (millis()<tempo_lettura_1) {
tempo_lettura_1=millis();
}
if (millis()-tempo_lettura_1>intervallo) {
digitalWrite(trigPin1, LOW);
delayMicroseconds(2);
digitalWrite(trigPin1, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin1, LOW);
int durata1 = pulseIn(echoPin1, HIGH);
distanza_1 = durata1 / 58; // per i pollici la formula è durata / 148;
tempo_lettura_1=millis();
}
if (distanza_1>0) { ////se la sonda sta leggendo; quando non ha alimentazione il valore restituito è zero
/////quindi non consideriamo il dato
sommaValoriValidi_1=sommaValoriValidi_1+distanza_1;////consideriamo il dato valido
conteggioValoricorretti_1=conteggioValoricorretti_1+1;
}
if (conteggioValoricorretti_1>=10) { ////dopo circa xxx secondi se tutte le letture sono corrette
distanza_1m= sommaValoriValidi_1/conteggioValoricorretti_1; ////media
conteggioValoricorretti_1 = 0;
sommaValoriValidi_1 = 0;
Serial.print("distanza_1 ");
Serial.println(distanza_1m); ///media del sensore della vasca 1
}
}
////////////////SENSORE ULTRASUONI VASCA 2
void sensore2 (){
if (millis()<tempo_lettura_2) {
tempo_lettura_2=millis();
}
if (millis()-tempo_lettura_2>intervallo) {
digitalWrite(trigPin2, LOW);
delayMicroseconds(2);
digitalWrite(trigPin2, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin2, LOW);
int durata2 = pulseIn(echoPin2, HIGH);
distanza_2 = durata2 / 58; // per i pollici la formula è durata / 148;
tempo_lettura_2=millis();
}
if (distanza_2>0) { ////se la sonda sta leggendo; quando non ha alimentazione il valore restituito è zero
/////quindi non consideriamo il dato
sommaValoriValidi_2=sommaValoriValidi_2+distanza_2;////consideriamo il dato valido
conteggioValoricorretti_2=conteggioValoricorretti_2+1;
}
if (conteggioValoricorretti_2>=10) { ////dopo circa xxx secondi se tutte le letture sono corrette
distanza_2m= sommaValoriValidi_2/conteggioValoricorretti_2; ////media
conteggioValoricorretti_2 = 0;
sommaValoriValidi_2 = 0;
Serial.print("distanza_2 ");
Serial.println(distanza_2m); ///media del sensore della vasca 1
}
}
void sensore3 (){
if (millis()<tempo_lettura_3) {
tempo_lettura_3=millis();
}
if (millis()-tempo_lettura_3>intervallo) {
digitalWrite(trigPin3, LOW);
delayMicroseconds(2);
digitalWrite(trigPin3, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin3, LOW);
int durata3 = pulseIn(echoPin3, HIGH);
distanza_3 = durata3 / 58; // per i pollici la formula è durata / 148;
tempo_lettura_3=millis();
}
if (distanza_3>0) { ////se la sonda sta leggendo; quando non ha alimentazione il valore restituito è zero
/////quindi non consideriamo il dato
sommaValoriValidi_3=sommaValoriValidi_3+distanza_3;////consideriamo il dato valido
conteggioValoricorretti_3=conteggioValoricorretti_3+1;
}
if (conteggioValoricorretti_3>=10) { ////dopo circa xxx secondi se tutte le letture sono corrette
distanza_3m= sommaValoriValidi_3/conteggioValoricorretti_3; ////media
conteggioValoricorretti_3 = 0;
sommaValoriValidi_3 = 0;
Serial.print("distanza_3 ");
Serial.println(distanza_3m); ///media del sensore della vasca 1
}
}
//////INVIO DATI SENSORI ULTRASUONI A MASTER TRAMITE RS485-MODBUS
uint8_t readAnalogIn(uint8_t fc, uint16_t address, uint16_t length) {
Serial.print("FC=04: ");
Serial.println(fc);
Serial.print("indirizzo: ");
Serial.println(address);
Serial.print("byte: ");
Serial.println(length);
if (address == 30001) {
int valori[3]={distanza_1m, distanza_2m, distanza_3m};
for (int i=0; i<length; i++){
if (i<3) {
slave.writeRegisterToBuffer(i, valori[i]); //Inserisco nel buffer i 3 valori distanza1, 2 e 3
}
else{
slave.writeRegisterToBuffer(i, 0); ///completo le informazioni di ritorno verso il master con uno zero
}
}
return STATUS_OK;
}
}
/**
* Handle Force Single Coil (FC=05) and Force Multiple Coils (FC=15)
* set digital output pins (coils).
*/
uint8_t writeDigitalOut(uint8_t fc, uint16_t address, uint16_t length) {
Serial.print("FC=05: ");
Serial.println(fc);
Serial.print("indirizzo: ");
Serial.println(address);
Serial.print("byte: ");
Serial.println(length);
Serial.print("valore: ");
Serial.println(slave.readCoilFromBuffer(0));
if (address == 12) {
int relay=slave.readCoilFromBuffer(0); ///prendi il dato dal buffer
///digitalWrite(12, slave.readCoilFromBuffer(0));
digitalWrite(12,relay); ////attiva PIN 12
Serial.println("accendo led");
}
return STATUS_OK;
}