Go Down

Topic: 4 Arduino Master Slave in RS485 (Read 14103 times) previous topic - next topic

leo72

Vediamo come potrebbe essere un codice di ricezione di uno slave (usa serialEvent):

Code: [Select]
void loop() {
... il resto del codice
}

void serialEvent() {
  byte myCommand = 0;
  boolean dataIsValid = false;
  if (Serial.read() == 0xFF) { //byte di start giusto
    if (Serial.read() == 0x00) { //accetto comandi solo dal master
      if (Serial.read() == 0x01) { //è un comando destinato a me?
        myCommand = Serial.read(); //leggo il comando
        byte lenComm = Serial.read(); //quanto è lungo il pacchetto dati?
        byte tempPack[lenComm];
        byte i = 0;
        unsigned long oldMillis = millis();
        while (lenComm && Serial.available && (millis() - oldMillis < 500) {
          tempPack[i] = Serial.read();
          i++;
          lenComm--;
        }
        if (lenComm != 0) { //se lenComm non è a 0, vuol dire che è uscito per time
          break;
        }
        byte tempCksm = Serial.read();
        if (calcolaChecksum() != tempCksm) { //non torna il checksum
          break;
        }
        switch (myCommand) {
          case 0x00:
            .....
            break;
          case 0x01: //accendo un pin
            digitalWrite(tempPack[0], HIGH); //so che in tempPack[0] c'è il numero del pin 
            break;
        }
        dataIsValid = true;
      }
    }
  }
  if (!dataIsValid) { //c'è stato un errore
    //svuoto il buffer
    while (Serial.available()) {
      byte temp = Serial.read();
    }
  }
}


Il codice NON è testato, il codice fa SCHIFO, il codice NON è ottimizzato, il codice è solo un ESEMPIO.
Non prendetelo per oro colato  :smiley-sweat: :smiley-sweat:

vittorio68

Io forse posso contribuire un po' di più perchè prossimamente dovrò sviluppare concretamente i concetti discussi sinora (e forse si era notato dal tono del mio confronto con leo72).

Purtroppo però non posso promettere tempi certi perchè dipenderà dall'evoluzione del progetto (probabilmente prima dovrò sviluppare un po' di hardware...).

leo72


Io forse posso contribuire un po' di più perchè prossimamente dovrò sviluppare concretamente i concetti discussi sinora (e forse si era notato dal tono del mio confronto con leo72).

Quale tono?  XD

vittorio68

:) :) :) volevo solo dire che avevo insistito molto su aspetti che potevano forse sembrare un po' il pelo nell'uovo

leo72


:) :) :) volevo solo dire che avevo insistito molto su aspetti che potevano forse sembrare un po' il pelo nell'uovo

Beh, ognuno tende a tirar l'acqua verso il proprio mulino.
Quindi se hai intravisto degli aspetti che, per tuo interesse, volevi approfondire, è normale che cercavi di analizzarli a fondo più di altri.

pietro78

Per motivi di tempo e lavoro chiaramente ho dovuto abbandonare questo topic che mi stava tanto a cuore...
Per il protocollo ho lasciato perdere in quanto almeno al momento per le conoscenze che ho significherebbe chiedere giorni e giorni di studio sui libri ...piuttosto ho "semplificato" il concetto di trasmissione tra due Arduino1 collegati in rs485...
Mi spiego meglio:
L'Arduino master invia dei comandi a degli arduino Slave sul bus che sono collegati solo per ricevere comandi e eseguirli senza nessun feedback al master...per il momento il master invia dei comandi tipo serial.Write(O1) ...serial.Write(O2) e lo slave confrontando il byte esegue e pilota in HIGH l'uscita pin in modalità passo-passo...


Per tutto il resto adesso è tutto fermo...spero che almeno con questo post ho riacceso qualche neurone per proseguire il progetto del "simple protocol"...
Ciao un saluto a tutti...

AMPS-N

Can Someone tell me where i can get the code example
AMPS

veseo

Perdonatemi se mi intrometto nella discussione in evidente ritardo, ma credo che ci sia un'aspetto importante da considerare. Parto da quanto ho contributo a realizzare, ovvero lavorare in peer to peer su RS485 evitando l'uso di protocolli Master/Slave.

Per applicazioni domestiche usare una comunicazione in polling a frequenze molto alte è uno spreco, mentre utilizzare un protocollo di comunicazione ad eventi offre tempi rapidi di risposta ed un minore utilizzo delle risorse. Su RS485 il problema è che mancano degli strumenti per gestire le collisoni a livello hardware, ma in casi come le applicazioni domestiche, con poco traffico si possono realizzare delle soluzioni in software.
Cercando qualche soluzione da cui partire, ho trovato uLAN come una soluzione semplice e funzionale (qui il link).

Come anticipavo, sia il protocollo che i driver per la comunicazione sono stati implementati nel progetto Souliss (opensource, basato su Arduino ed Android) dove inoltre c'è una sorta di strato di networking, per cui i dati possono viaggiare anche su Ethernet ed in wireless senza azioni nello sketch (viene gestito tutto in background). Di conseguenza si può usare un Arduino Ethernet come ponte verso SoulissApp (l'applicazione Android dal quale gestire i nodi Souliss) altri nodi sul bus RS485.
Essendoci già il protocollo (binario ed a eventi) per inviare un comando da un nodo ad un'altro, basta una riga di codice.

Per ora alcune persone nel gruppo che segue il progetto hanno realizzato una rete con 4-5 nodi su RS485 a 9600bps, ma è da verificare quale sia il numero massimo ottenibile con questa tecnica. A naso credo che si possa arrivare ad una ventina di nodi per ogni segmento, quindi si possono realizzare diversi segmenti ognuto dei quali unito attraverso una connessione Ethernet, rendendo tutti i nodi visibili tra loro.

Se avete domande sono ben felice di rispondere, se volete collaborare al progetto (adesso siamo una decina di persone attive in sviluppo e circa mille utilizzatori) meglio ancora :)

Saluti,
Dario.
Souliss - Open-source Distributed Home Automation with Arduino and Android

http://www.souliss.net
Follow at @soulissteam

@veseotech

pinox61

Ciao Dario,

sto progettando un sistema di automazione domestica basato su una architettura simile a quella da te descritta, ossia 4-5 nodi Arduino collegati tramite RS-485 e protocollo Modbus ad un Master, sempre Arduino, che opera come gateway verso Souliss. Sto pero' trovando grosse difficolta', per lo piu' dovute alla mia scarsa esperienza in materia, a trovare delle librerie Modbus per Arduino che siano affidabili e semplici da usare. Potresti suggerirmi qualcosa a riguardo?

Grazie
Pino

veseo

Ciao Pino,

librerie Modbus Slave RTU c'è ne sono in giro, non saprei consigliarti quale utilizzare perché ai tempi scrissi una libreria Modbus da zero per Souliss, volendo puoi recuperare quella scaricando al versione A4.5.1, però dovrai rimaneggiarla per utilizzarla all'esterno di Souliss.

Saluti,
Dario.
Souliss - Open-source Distributed Home Automation with Arduino and Android

http://www.souliss.net
Follow at @soulissteam

@veseotech

pinox61

OK, provo a darci uno sguardo. Grazie ancora

Ciao a tutti,

Scrivo qui anche se il topic è vecchio ma almeno so che avete trattato il problema.
Ho provato a creare un piccolo protocollo di comunicazione su RS485, quindi scrivo su pin 1 e leggo su pin 0 tra Arduino Leonardo e PC con Python.

Python:
Code: [Select]

import serial, time
import random
ser = serial.Serial("COM12", 115200, bytesize=8, parity='N', stopbits=1, writeTimeout=1, timeout=0)
time.sleep(2)
ser.flushInput()
ser.flushOutput()
a = 1
k = 0
e = 0
while 1:
                    ser.write(b'1')
                    x = ser.read(2)
                    if x != b'1':
                                k = k + 1
                                print(k)
                                print(x)



Arduino:

Quote
const byte LED = 13;
const byte Address = 49; // Indirizzo fisico Leonardo
int inByte;
int lastState;
int changeState;

void setup()
{
  pinMode(LED, OUTPUT);
  pinMode(3, OUTPUT);
  digitalWrite(LED, LOW);
  digitalWrite(3, LOW);
  Serial1.begin(115200, SERIAL_8N1);
  while (!Serial1) {
  }
  Serial1.flush();
  delay(500);
}

void loop()
{
  if (Serial1.available()) {
    inByte = Serial1.read();
    Serial1.flush();
    digitalWrite(3, HIGH);
    Serial1.write(inByte);
    Serial1.flush();
    digitalWrite(3, LOW);
  }
}
Mi parte una marea di errori nel ciclo di Python creato apposta per verificare se la cumunicazione funziona correttamente
Code: [Select]
    if x != b'1':
                                k = k + 1
                                print(k)
                                print(x)


Se collego la seriale attraverso USB (cioè Serial e non Serial1) tutto funziona a dovere.
Cosa c'è che non va?

pines

#87
Dec 01, 2014, 09:35 am Last Edit: Dec 01, 2014, 10:51 am by pines
Ciao

per far comunicare 1 master e 4 slave ho utilizzato questa libreria molto semplice gammon library, che ti impacchetta i dati  inviati e fa il crc , ho fatto dei test a 28800 con un cavo di 100 mt circa twistato ed il tempo di risposta è molto breve ad 15 ai 18 ms il timeout l'ho messo a 200ms ed in quasi 8 ore di funzionamento non cè stato nessun errore .
Ho fatto una piccola modifica alla libreria in modo da non dover mettere ogni volta l'abilitazione alla trasmissione e poi dopo aver spedito disabilita il pin .

La libreria utilizza la softserial e occorre fare attenzione al pin di trasmissione (non sono sicuro se è la trasmissione) che bisogna vedere e se viene utilizzato.

Per il discorso del timeout bisogno prendere il tempo maggiore che lo slave è impegnato in una routine  del tipo rilevamento e aggiungerci il tempo di risposta e aggiungerci un tempo di scarto,

ricapitolando 20 ms per la risposta, 90 ms per la routine 40 ms tempo di scarto, sommano 150ms quindi se lo slave non risponde dopo 150 ms cè un problema.

Aggiungo che per far "viaggiare" qualsiasi dato con questa libreria, cè una discussione iniziata da @astrobeed     link che tratta di come codificare e decodificare i dati.

andreino

Buongiorno.

Anch'io sono interessato alla comunicazione tra più Arduino. Sono in attesa dei pezzi  :)

Vedendo il post di pines, mi chiedevo quali complicazioni si hanno se si volesse gestire un discreto numero di "sensori". Parlo, per esempio, di voler conoscere "continuamente" (1 volta al secondo? Ogni 500ms? ecc.) lo stato di alcuni ingressi (per la gran parte 0/1, altri con valori analogici, altri su bus OneWire come DS18B20) disposti su più Arduino.

Le richieste di lettura da parte del master potrebbero quindi essere tranquillamente alcune decine.

150ms per ogni richiesta non mi sembrano pochi.

Quali accorgimenti si devono predisporre?
P.es.
- richieste Master->Slave: una ogni X ms
- richieste in sequenza: attesa della risposta prima di procedere con la richiesta successiva?
- si può calcolare il tempo complessivo minimo sufficiente per elaborare N richieste?

Grazie


pines

@Andreino

ciao per ora sto solo sviluppando il progetto a pezzi per poi unificarli.

Nella mia casa inserirò solo dei sensori di temperatura 1 wire in ogni stanza e spero di utilizzare 1 solo arduino nano, sara collegato con un cavo a 4 fili 2 per rs 485 ed altri 2 per l'alimentazione , verso un mega cui sara il master per rs485, voglio alimentarlo con un rele proveniente dal mega cosi se per qualche motivo non comunica o si impalla il mega provvederà al distacco di alimentazione e dopo qualche secondo lo riattiverà provando se comunica , in caso negativo visualizzerà sul display tft il malfunzionamento .

Dovrò inserire un altro nano in un contenitore din da inserire nel quadro elettrico che mi rilevi il consumo di corrente, con quei sensori tipo pinze amperometriche sct 013 000 e la bussata del campanello e del citofono se possibile.
Ora per quanto riguarda la lettura del master rs485 dei valori di temperatura penso che 1 volta al minuto può andar bene, anche il valore di lettura del consumo 1 minuto, ma le bussate dovrei vederle almeno 1 volta al secondo.

Tornando alla tua richiesta vedi che 150 - 200 ms con una velocità di 28800 per sapere se il campanello ha suonato va benissimo,  quello che non ho provato sono un treno di valori piu lungo del tipo 8 valori di temperatura. Il problema principale è che gli slave devono rispondere solo quando interrogati , avendo 4 slave interrogandoli a sequenza con un timeout di 250ms li leggi tranquillamente 1 volta al secondo, ma considera che se tutti rispondono e li leggi sempre in sequenza niente di più strano che in 1 secondo  legge 10 volte ogni sensore 25ms a slave.

Considera che questi dati debbono andare da qualche parte e che li metti su sd o in un db in rete devi prenderti del tempo per fare le scritture.

Potresti dare pure un inizio sincronismo, mandi un comando con il master fai una routine che quando il master comunica con l'indirizzo 100 i vari contatori degli slave partono da 0, cosi da sapere che ogni 60 secondi si devono aspettare l'interrogazione e magari non iniziano una routine lunga. Questo perchè magari ci sono dei moduli o dei sensori che han bisogno di piu tempo per essere letti o inizializzati, esempio leggo un valore di consumo di corrente continua con un acs 712 ho notato che per avere una lettura il piu fedele possibile debbo fare 100 campionamenti per cui occorre un certo tempo (ora non ricordo) , altro esempio il modulo gsm per leggere gli sms impiega un certo numero di secondi e se la richiesta del master mi arriva in questo periodo lo slave va in timeout.

Concludendo ti consiglio di provare su banco prima di chiudere il tutto nelle scatole, se ti serve velocità maggiore di trasmissione dati per rs485 devi fare delle prove, stendi la lunghezza dei cavi per terra e lasciali funzionare per settimane, poi metti tutto nelle scatole.
Ha penso che lo sai ma per la lunghezza dei cavi fino ad una certa lunghezza va bene il cavo normale, se no devi utilizzare cavo twistato, quello lan per interderci.



Ciao
Pino


Go Up