Comunicazione seriale e delay

Ciao a tutti,
Sto inviando via seriale ad una scheda Arduino 2 byte di dati. Quando però aumento il baud rate la ricezione del secondo byte é corrotta.

if(serial1.avaiable()){
for(int i =0; i < 2; i++){
inByte = serial1.read();
Delay (1);
}
}
Serial.write(inByte[1]);
Questo funziona quando imposto 115200. Mentre se imposto un valore più alto es. 230400 mi legge il secondo byte corrotto. Presumo dipenda tutto dal delay all’interno del ciclo for. Ma non riesco a capire come fare per aggirare il problema.

In realtà, il test sulla disponibilità di un carattere lo devi fare SEMPRE prima di leggere il carattere (ovvero prima della Serial.read), altrimenti rischi che il carattere non ci sia ancora e ti ritorna indietro un bel -1

Guglielmo

Ma infatti faccio la lettura dentro alla condizione if(serial1.avaiable()). Devo fare un ulteriore verifica dentro al For?

maverikgoos: Devo fare un ulteriore verifica dentro al For?

Perché, chi ti garantisce dentro il for che i dati siano presenti e quanti ce ne siano disponibili ? ? ? :o :o :o

Guglielmo

Ho provato ma non funziona.

Anche se faccio:

if(Serial1.avaiable()){
for(int i = 0; i<2;){
if(Serial1.avaiable()){
inByte[i++] = Serial1.read();
}
}
}

... mmm ... io non eliminerei la delay(1) dopo la Serial.read ... spesso aiuta ;)

In ogni caso ... ho idea che 230400 baud siano un po' tanti per Arduino e per la classe Serial ::)

Guglielmo

Quindi é in problema del delay. Ho provato a diminuire con DelayMicroseconds() ma senza risultato. Se guardo il datasheet di Leonardo i 230400 sono nella tabella del baud rate con % di errore 0%.

maverikgoos:
Se guardo il datasheet di Leonardo i 230400 sono nella tabella del baud rate con % di errore 0%.

… vorrai dire il datasheet del Atmega32u4 :slight_smile: e … non mi sembra se guardi la tabella per fosc = 16.0000 MHz (che, oltretutto, non trovo più nell’ultima versione del datasheet, ma che è presente nella vecchia del 02/2014) ::slight_smile:

Guglielmo

Mi sa che hai ragione. Non so cos'ho letto. Domani provo con 250000 vediamo se cambia qualcosa.ma credo che sia tutto dovuto al delay dentro al ciclo For.

Ho fatto una prova veloce sta mattina e con 250000 e funziona. Questa sera proverò a fare controlli più accurati.

Fatto prove accurate. A 250000bps riceve e legge i 2 byte ma non è stabile. Diciamo che su 10 invii 3 vanno persi. Tengo a precisare che sto usando Serial1 perché comunico con modulo RS 485.

Se ti serve una velocità così alta e l'affidabilità dei dati ricevuti ... ... l'unica è aggiungere un byte di checksum dei precedenti ed implementare un "protocollo" dove, se ti arriva il pacchetto errato, chiedi la ritrasmissione.

Guglielmo

hai provato con 500000? io generalmente uso quella velocità senza problemi. dovresti postare anche il codice che usi nei test perché sento puzza di bruciato.... comunque un protocollo con checksum è assolutamente necessario.

250.000 è la velocità del DMX che uso normalmente e non perdo mai un carattere , però usando l'interrupt

VB, icio ... il problema è che ... ... NON sappiamo COME legge la seriale ... se con le chiamate di Arduino (classe Serial) o in modo ... un po' più sofisticato :D

Guglielmo

@gpb01, infatti ho scritto che sento puzza di bruciato nel suo codice......

Allora per prima cosa vi spiego come avviene la comunicazione. Due schede Galileo Gen 2 e una Leonardo. Collegate tra loro da moduli RS485.

Codice Galileo:

const byte LED = 13;
byte inByte[4];
unsigned long lastSend = 0;
byte ClientAddress[]= {49,50,51,52,53,54,55,56,57,58,59,60,61,63,64,65,66,67,68,69,70};
byte k = 0;

void setup()
{
  pinMode(LED, OUTPUT);
  pinMode(3, OUTPUT);
  digitalWrite(LED, LOW);
  digitalWrite(3, HIGH);
  Serial1.begin(115200);
  digitalWrite(LED, HIGH);
}

 if( micros() - lastSend > 100){
         digitalWrite(3,HIGH);              //Attivo il driver RS485
         Serial1.write(ClientAddress[k]);   //Chiamo gli indirizzi nell'array
         Serial1.flush();
         lastSend = micros();

                       //Salvo il timestamp dell'invio
           
         k++;                               //Incremento l'indirizzo
          if(k == sizeof(ClientAddress)){   //Controllo il numero di indirizzi e lo resetto quando lo raggiungo
            k = 0;
           
            }
            
        }

      }
    }

Mentre quello di Leonardo é questo:

const byte LED = 13;
byte inByte[4];
boolean lastState;
boolean changeState;
unsigned long lastSend = 0;
unsigned long lastRead = 0;
int alt = false;

void setup()
{
  pinMode(LED, OUTPUT);
  pinMode(3, OUTPUT);
  pinMode(2, INPUT);
  digitalWrite(LED, LOW);
  digitalWrite(3, LOW);
  Serial.begin(115200);
  Serial1.begin(115200);
}



void loop()
{

  if (Serial1.available()) {

      for(int i = 0; i < 2;){
      inByte[i++] = Serial1.read();
      delay(1);
      }

    Serial.write(inByte[1]);
    

    if (inByte[0] == Address) {
      switch (inByte[1]) {
        case 97:
          digitalWrite(LED, HIGH);
          break;

        case 98:
          digitalWrite(LED, LOW);
          break;
  
    		}
        }
        
     }
  }
        
}

Quando apro la seriale (serial) su Leonardo leggo sia il primo che il secondo byte. Se alzo la velocità non mi legge più il secondo byte. Se tolgo il delay dentro al ciclo For riesco a leggerlo qualche volta.

hai due errori, il primo è il serial.flush(), tale comando non assicura che siano inviati tutti i dati ma azzera semplicemente il buffer quindi eliminalo. Il secondo è la ricezione che non segue una logica, primo punto cruciale è che leggi due byte anche se molto probabilmente ne hai uno solo.(come poi ti avevano già detto di fare). Inizia a modificare il codice e spiegaci cosa dovresti fare.

Infatti non ho mai capito bene l'utilizzo di serial.flush(). Elimino subito. Galileo interroga gli indirizzi che vedi nell'array ogni 100 microsecondi. Se non ha risposta passa a indirizzo successivo. Leonardo è in ascolto, se lo stato degli ingressi digitali non è cambiato rimane in silenzio, se sono cambiati risponde a Galileo. Posso comandare direttamente inviando 1a cioè 49 97. Primo byte indirizzo secondo byte comando. Spero di essermi spiegato ma sono senza Internet e scrivo il codice con lo p Smartphone.

attacca il tethering sullo smartphone! :wink:

Allora hai un’altro problema, il codice della leonardo invia sempre un dato anche quando non dovrebbe.
Quindi se deve solo aspettare di ricevere 2 byte potresti scrivere

while( Serial.available() < 2);

....

cosi blocchi leonardo in quella riga di codice fino a che non hai due dati, dopodiche li leggi e rispondi, poi esegui il comando.