Comunicazione seriale che a volte non prende

Ciao a tutti!
Ho provato a utilizzare la comunicazione seriale tra due Arduino uno ( che chiamero A e B), utilizzando gli appositi pin TX e RX.
Scopo:
Per poter pilotare un relay collegato ad Arduino A ho previsto un pulsante collegato in pulldown ad Arduino B utilizzando il codice qui sotto, il tutto funziona bene (o quasi), solo che a volte premendo il pulsante non accade nulla, quindi credo che il codice non sia propriamente corretto, o meglio instabile.

Codice Arduino A:

if (Serial.available()) {

char H, attivorelay= Serial.read();

delay(10);

if (attivorelay== H) {

Serial.println("Relay Attivo");

digitalWrite(9, HIGH); //Attivo Relay

delay(100);

}

}

if (digitalRead(11) == HIGH) { //pulsante di spegnimento

Serial.println("Relay spento");

digitalWrite(9, LOW); //Spego Relay

char R; //PER RESETTARE

attivorelay=R;

}

Codice Arduino B:

if (Serial.available()){

if (digitalRead(12) == HIGH) {

char H,R,pulsante = H;

Serial.write(pulsante);

Serial.println(pulsante);

delay(100);

pulsante = R; 
/*rendo pulsante diverso da H per evitare che di avere il relay acceso dopo averlo spento con altra funzione*/

Serial.write(pulsante);

Serial.println(pulsante);

delay(100);

}

}

Suggerimenti per questa problematica? vanno bene anche soluzioni exnovo :smiley:

Salve,
Non ho ancora letto il codice, quindi potrei non essere di aiuto.
Comunque per come descrive il progetto mi pare di capire che sono necessarie comunicazioni b/a ma non risposte, e che le comunicazioni sono di un dato solo (tasto premuto). Giusto?
In questo caso sei sicuro che ti serva la seriale? Io userei metodi più semplici, come collegare 1 pin di output dall'arduino del pulsante ad un input a quello del relè. Comandando opportunamente il primo, letto dal secondo, il secondo é informato sul cambio di stato del tasto. Più semplice e più sicuro

La soluzione piu ovvia non è sempre quella più pratica, questo progetto è volto alla sperimentazione della comunicazione seriale mediante semplici esperimenti per scopi autodidattici, quindi la situazione è voluta di proposito.

In futuro, questo piccolo sketch sarà integrato in un programma più complesso dove non ci saranno pin disponibili, se non quelli del TX e RX.

grazie comunque per la risposta :smiley:

Ciao AlPinkish,

un passo alla volta...secondo il tuo ragionamento questo pezzo di codice tratto dall'Arduino A cosa dovrebbe fare e come dovrebbe funzionare!?

if (Serial.available()) {

char H, attivorelay= Serial.read();

delay(10);

if (attivorelay== H){
.....
 }
}

char H e char attivorelay sono due variabili locali che hanno "vita" solo all'interno di questi if() annidati...attivorelay la crei e subito la assegni alla Serial.read()...ma H!?...

ORSO2001:
Ciao AlPinkish,

un passo alla volta...secondo il tuo ragionamento questo pezzo di codice tratto dall'Arduino A cosa dovrebbe fare e come dovrebbe funzionare!?

if (Serial.available()) {

char H, attivorelay= Serial.read();

delay(10);

if (attivorelay== H){
.....
}
}



char H e char attivorelay sono due variabili locali che hanno "vita" solo all'interno di questi if() annidati...attivorelay la crei e subito la assegni alla Serial.read()...ma H!?...

il primo if controlla se è disponibile la comunicazione seriale, in quel caso associa al char attivorelay quello che legge da seriale, se non legge niente suppongo sia attivorelay=0 oppure stato precedente. successivamente c'è il secondo if che accende il ralay

edit:
non avevo letto la frase sotto, ti rispondo:
La variabile H è all'interno del secondo if che a sua volta è all'interno dell' if (Serial.available()) {.... .

Ho guardato il primo programma e credo sia utile una sistemata alle variabili, il secondo non ho ancora avuto la pazienza di vederlo, ma farò il prima possibile.

Ora, vediamo di raccogliere le idee

Il primo programma corrisponde al ricevitore, giusto?

E il secondo al trasmettitore

Tu hai postato la loop, vero?

La seriale che usi per comunicare tra i due arduino, ti rendi conto che è quella attaccata allo usb?

La variabile char H è automatica, che vuol dire non inizislizzata, che vuol dire che potrebbe esserciscritto di tutto, non 0

Che poi non sarebbe zero, ma il codice esadecimale 000, corrisponde a nessun carattere si indica con /n

Stesso discorso per la R

Comunque la H non la inizializzi mai

Peggio ancora il secondo programma

Dovedichiari tre variabili automatiche, una uguale ad un'altra appena dichiarata,
Di fatto non ne inizializzi nessuna

Ripensa bene il programma

edit:
non avevo letto la frase sotto, ti rispondo:
La variabile H è all'interno del secondo if che a sua volta è all'interno dell' if (Serial.available()) {.... .

si avevo visto...la crei ma non ci associ mai un valore...docsavage ha dato una descrizione un po' più ampia di quello che hai postato...direi da seguire.

per precisione nel primo if ci entri se c'è qualche cosa nella seriale...quindi se poi leggi da seriale qualche cosa sarà salveto nella variabile.

Aggiungo che alla fine del secondo programma rendi la attivorelay uguale alla R, non inizializzata, poi esci dalla loop perdendo tutti i valori....
Al prossimo ciclo riparte tutto da capo

Vediamo un po'

adesso da casa posso pensare con calma

arduino B ha un pulsante che tu vuoi accenda un relè su arduino A

il relè lo puoi spegnere anche da un secondo pulsante su A, ma se ho ben capito non lo puoi spegnere da B, solo accendere

cose non chiare:

usi la seriale di B sia per comandare A, sia per fare debug, perché?

ti incasini un tocco, così

usi la seriale di A sie per ricevere comandi che per fare debug, parimenti ti domando: perché?

spero ti sia chiaro che tutte le volte che scrivi qualcosa sulla seriale te la ritrovi a dare fastidio sull'altro arduino

e quindi diventa difficile controllarlo

buongiorno e buona domenica

ho pensato un poco e credo che una cosa del genere sia buona e giusta

Arduino B, trasmettitore

ogni T tempo, con T sufficentemente basso da garantire il servizio richiesto
esempio, per irrigare anche ogni 3 secondi, tanto parliamo di acqua, per luci un decimo di secondo, e via così)

dicevo, ogni T

acquisisco due pulsanti (accendi e spegni)

costruisco una stringa (intesa come array di caratteri, non Stringa oggetto)
dicevo costruisco una stringa con:
preambolo fisso (usato dal ricevitore per riconoscere la trasmissione)
un carattere di comando (tipo A accendo S spegni, facili da codificare)
un carattere di stop trasmissione (per dire al ricevitore che abbiamo finito)

sul ricevitore,
in un ciclo, controllerei:
se serial.available
se 1°carattere=preambolo
se 2°carattere = comando accettato
se 3°carattere= stop trasmissione
se tempo di ricezione minore di un time out
se passati tutti questi test
controllo l'uscita a seconda del secondo carattere della stringa ricevuta

aggiungendo comunque un pulsante di on e uno di off, locali

usando due soft-serial, per riservare al debug la seriale USB

facendo debug prima sul trasmettitore, che mostra quella che trasmette

poi sul ricevitore, che mostrerà quello che riceve

sono sicuro che così otterrai ottimi risultati, come li ho ottenuti io facendo più o meno lo stesso esperimento quando pochi mesi fa ero alle prima armi con arduino

casomai, cera con calma e pazienza nei vari post del forum

non sei il primo che vuole fare questa cosa
ci sono varii post sull'argomento
ci sono molti esempi e anche qualche codice completo

docsavage:
Vediamo un po'

adesso da casa posso pensare con calma

arduino B ha un pulsante che tu vuoi accenda un relè su arduino A

il relè lo puoi spegnere anche da un secondo pulsante su A, ma se ho ben capito non lo puoi spegnere da B, solo accendere

Esatto, un pulsante è collegato a B, B manda il segnale ad A, A accende il Relay. Solo A può spegnere il relay.

cose non chiare:

usi la seriale di B sia per comandare A, sia per fare debug, perché?

ti incasini un tocco, così

usi la seriale di A sie per ricevere comandi che per fare debug, parimenti ti domando: perché?

spero ti sia chiaro che tutte le volte che scrivi qualcosa sulla seriale te la ritrovi a dare fastidio sull'altro arduino

e quindi diventa difficile controllarlo

Infatti controllare tramite monitor seriale e allo stesso tempo usare Tx e RX per i due arduino risulta difficoltoso se non impossibile, per cui mi voglio limitare a far funzionare il circuito senza collegamento seriale USB.

ogni T tempo, con T sufficentemente basso da garantire il servizio richiesto
esempio, per irrigare anche ogni 3 secondi, tanto parliamo di acqua, per luci un decimo di secondo, e via così)

dicevo, ogni T

acquisisco due pulsanti (accendi e spegni)

Intendi ad esempio un rapido delay per leggere il cambiamento di stato del pulsante?

AlPinkish:
Esatto, un pulsante è collegato a B, B manda il segnale ad A, A accende il Relay. Solo A può spegnere il relay.

Infatti controllare tramite monitor seriale e allo stesso tempo usare Tx e RX per i due arduino risulta difficoltoso se non impossibile, per cui mi voglio limitare a far funzionare il circuito senza collegamento seriale USB.

Intendi ad esempio un rapido delay per leggere il cambiamento di stato del pulsante?

Non è una bella idea rinunciare al debug, specialmente se sei alle prime armi

per acquisire intendo fare le digitalread, per sapere se il pulsante è premuto uppure no
poi hai ragione, testare se ci sono stati cambiamenti e trasmettere solo il cambiamento

oppure puoi usare una differente logica di funzionamento

non un pulsante accende e uno spegne, ma finchè il pulsante è premuto il carico è acceso

questo richiede una trasmissione più cadenzata,

ma la scelta dipende da cosa ci devi fare

docsavage:
in un ciclo, controllerei:
se serial.available
se 1°carattere=preambolo
se 2°carattere = comando accettato
se 3°carattere= stop trasmissione
se tempo di ricezione minore di un time out
se passati tutti questi test
controllo l'uscita a seconda del secondo carattere della stringa ricevuta

aggiungendo comunque un pulsante di on e uno di off, locali

usando due soft-serial, per riservare al debug la seriale USB

Con il sistema messaggi di cui sopra potrebbe benissimo fare debug dalla stessa seriale in quanto solo i messaggi corretti #X* verrebbero accettati dal ricevitore.

Mai provato, questa non la so

Non si danno fastidio elettricamente, un collegamento seriale verso l'altro arduino e la usb?

Non lo sapevo, buona.....

Guardando lo schematico di una UNO direi che si:

A: riceve soltanto da B
trasmette alla sua USB

B: trasmette verso A e verso la sua USB
riceve dalla sua USB

Collegando anche l'altro verso i due Arduino si possono parlare e le USB "sniffano" la relativa trasmissione senza poter parlare.

Disattivando la seriale su un Arduino (e configurando i pin in input) l'altro potrebbe usare la USB del primo in trasmissione (in questo caso il collegamento va dritto e non incrociato).

Allo stesso modo un circuito diverso potrebbe usare la USB di Arduino anche in ricezione.... e questo mi sta facendo venire l'idea di uno Zarduino.... aka Z80+Arduino senza bisogno di (E)EPROM :stuck_out_tongue: :stuck_out_tongue: :stuck_out_tongue:

Dunque ho riscritto tutto da capo e mi sono basato sul ragionamento proposto da docsavage.

Non ho inserito tutte le condizioni, come quella del timeout, magari mi illuminate su questo, nel frattempo azzardo questo codice nella speranza di non aver scritto assurdità.
Il codice si compila ma non l'ho testato ancora.

Su Arduino A (inteso come ricevitore):

#define SPENGO 11
#define RELAY 9

char Ist [3] = {"EAS"}; // E=com.stabilita, A=Accendi, S=Spegni 
char attivorelay; //VARIABILE DI CONTROLLO

  
void setup() {

pinMode(SPENGO,INPUT);
pinMode(RELAY,OUTPUT);
 digitalWrite(RELAY, LOW);
attivorelay = Ist [3];

}
void loop() {

 



  if (Serial.available()) { //controllo la connessione
    Serial.write(Ist [1]); //inizio la comunicazione
    if (Serial.read() == Ist [1]) { // verifico risposta dell'arduino B che deve essere 'E'
      if (Serial.read() == Ist [2] ) { //leggo lo stato del pulsante
        attivorelay = Ist [2]; 
        if (  attivorelay == Ist [2]) {
          digitalWrite(RELAY, HIGH); //Accendo il Relay
          delay(10);
        }
      }
    }
  }
  
  if (digitalRead(SPENGO) == HIGH or attivorelay == Ist [3]) { //pulsante di spegnimento esterno alla C.seriale
    digitalWrite(RELAY, LOW); //Spego il Relay
    delay(10);
    attivorelay = Ist [3]; //S = spegni
  }


}

Su Arduino B (inteso come trasmettitore):

#define PULSANTE 8
char Ist [2] = {"EA"}; // E=comunicaz.stabilita, A=Accendi
bool pulsanteON = false;

void setup() {

  pinMode(PULSANTE, INPUT);


}

void loop() {

  if (digitalRead(PULSANTE) == HIGH) {
    pulsanteON = true;
    if (Serial.available()) { //controllo la connessione
      if (Serial.read() == Ist [1]) { // leggo se Arduino A dice qualcosa
        Serial.write(Ist [1]); //rispondo con E
        if ( pulsanteON == true) {
          Serial.write(Ist [2]); //invio A per accendere il Relay
        }
      }
    }

  }
  else   pulsanteON = false;
}

probabilmente ci sono errori banali se non gravi, ma sono pur sempre un neofita. :-[

Non capisco perché il ricevitore deve trasmettere

Non mi è chiaro quale tra i due inizia la trasmissione

Secondo me il trasmettitore trasmette tenendo in considerazione il solo pulsante

Il ricevitore non deve trasmettere, o almeno non prima di aver ricevuto ed eseguito il comando

docsavage:
Non capisco perché il ricevitore deve trasmettere

Non mi è chiaro quale tra i due inizia la trasmissione

Secondo me il trasmettitore trasmette tenendo in considerazione il solo pulsante

Il ricevitore non deve trasmettere, o almeno non prima di aver ricevuto ed eseguito il comando

In effetti è inutile far parlare chi deve ascoltare, quindi tolgo da arduino A:

Serial.write(Ist [1]); //inizio la comunicazione

ed elimino da Arduino B

if(Serial.read() == Ist [1]) { // leggo se Arduino A dice qualcosa

adesso la situazione è questa:
Il ricevitore è in ascolto e il trasmettitore è in attesa che venga premuto il pulsante, se questo avviene, controlla se la connessione seriale è presente ed invia il carattere 'E' al ricevitore, successivamente, invia il carattere 'A' per attivare il relay. Se il ricevitore legge il carattere di prova 'E', prosegue e se legge il carattere 'A' accende il relay. Suppongo che tra questi due momenti differenti, debba essere inserito un tempo.

ma a questo punto vorrei sapere se il ragionamento è giusto.

Tieni pure conto che la seriale sia sempre libera per il trasmettitore