comando ignorato: while(!Serial.available())

Ciao a tutti, tanto per cominciare BUON ANNO!!!!

Sto cercando di creare un'interfaccia su seriale per il mio sketch.

Uso arduino uno originale e la ide 1.6.7.

Leggendo qua e là ho scelto di usare SerialEvent().

Il problema è quando devo attendere l'user input, in una parte del codice attende l'input su seriale in un altra no :o

Posto codice semplificato:

bool prog = true; // SE UNA BOOLEANA DIVENTA TRUE L'ALTRA VIENE MESSA A FALSE
bool time = false;

void loop()
{
if(inString == "code")
{
if(prog)
{

Serial.println("digita qualcosa");
while(!Serial.available())
      {  }
}
else if(time)
{
Serial.println("digita qualcosa");
while(!Serial.available())
      {  }

}

void SerialEvent()
{while(Serial.available() > 0)
  {
    inChar = Serial.read();
    if(inChar != '\n')
    {
      tempString += inChar;
    }
    else
    {
      inString = tempString;
      tempString = "";
    }
  }  

}

Quando lo sketch trova "if(prog)" attende come previsto che arrivi qualcosa dalla seriale, ma quando invece lo sketch trova "else if(time)" ignora completamente il "while(!Serial.available())" e lo sketch prosegue come se non ci fosse.

Cosa mi sono perso?

Hai scritto void SerialEvent() , ma la routine deve aver nome void serialEvent()

Scusa ho sbagliato quando ho postato qui, nel codice originale è corretto!

Ad ogni modo la routine funziona quando lo sketch si trova in if(prog) ma non quando in if(time).

Ho messo un Serial.println(inString) dentro ad entrambi i cicli 'if', dopo il while(!Serial.available()), in un ciclo attende e poi stampa correttamente l'input, mentre nell'altro NON attende l'input da seriale e ristampa il vecchio input.

Da nessuna parte metti "time" a true Poi usa un altro nome, in alcune lib la parola time è riservata.

Si si la metto a true ovviamente, non volevo fare copia/incolla dallo sketch ma postare il concetto.

Posto spezzone di sketch originale che faccio prima :)

if(inString == "prog" && normalMode)
  {
    if(normalMode)
    {
      Serial.println("Digita il settore che vuoi programmare (1-2-3-4)");
      while(!Serial.available())
      {  }
      inChar = Serial.read();
      s = inChar;      
      while(Serial.available())
      {
        Serial.read();
      }
      normalMode = false;
      programMode = true;
    }   
  } 
  else if(programMode)
  {
    Serial.println("Digita l'orario e la durata dell'intervallo con questo formato hh:mm-int");
      while(!Serial.available())
      {  }          
      Serial.println(inString);    
      programMode = false;
      normalMode = true;  
  }

Non vedendo tutto il codice non si può capire se esista un errore da qualche parte, comunque invece di pensare che il comando while() non venga eseguito, si dovrebbe pensare alla possibilità, che per qualche motivo ci sono caratteri inviati sulla seriale, di conseguenza il ciclo while non fa nessuna "attesa", questo potrebbe dipendere dal sistema di trasmissione se non usi il serial monitor di arduino, o ad un errore nel tuo codice, che noi non vediamo completo perché a te pare inutile postarlo :)

L'intero sketch sono oltre 1000 righe, per quello non l'ho postato tutto, e anche perché in quello che non ho postato ci sono al massimo dei Serial.println(""); i quali sono però legati a delle variabili che in questa fase tengo disattivate di default!!!

Scrivo il codice con codeblocks ma compilo, carico e monitoro con arduino ide 1.6.7.

Ad ogni modo stamattina mi sono rimboccato le maniche e ho semplificato il codice in modo da ridurre le variabili in gioco e poter fare più tentativi.

Il problema l'ho risolto facendo stampare qualcosa nel secondo while(!Serial.available()) , se invece lascio il blocco vuoto il while viene completamente ignorato :o il delay serve semplicemente a non creare una cascata nel serial monitor.

Mi piacerebbe tanto capire il perché!!!

E mi manca anche provare se un eventuale terzo blocco di attesa funzioni o no :) :) :)

void loop()
{
  actualMillis = millis();
  if((actualMillis - prevMillis) > 2500)
  {
    verificaLuminosita();
    verificaUmidita();
    getTemp();
    Valvola1();
    Valvola2();
    prevMillis = actualMillis;
  }

  if(inString == "prog")
  {
    Serial.println("Digita il settore:");
    while(!Serial.available())
    {    
      Serial.println("waiting for input..."); 
      delay(1000); 
    }
    serialEvent();
    Serial.println(inString);
    Serial.println("Digita l'intervallo:");   
    while(!Serial.available())
    { 
      Serial.println("waiting for input..."); 
      delay(1000);
    } 
    serialEvent();
    Serial.println(inString);
  }

}

void serialEvent()
{
  while(Serial.available() > 0)
  {
    inChar = Serial.read();
    if(inChar != '\n')
    {
      tempString += inChar;
    }
    else
    {
      inString = tempString;
      tempString = "";
    }
  }
}

EDIT: è possibile anche spostare if(inString == "xxx") nel serialEvent così da tenere pulito il loop!!

Ora se qualcuno mi svela l'arcano....

m265: Il problema l'ho risolto facendo stampare qualcosa nel secondo while(!Serial.available()) , se invece lascio il blocco vuoto il while viene completamente ignorato :o il delay serve semplicemente a non creare una cascata nel serial monitor.

Potrebbe essere il compilatore che "ottimizza" un pò troppo il codice.

Evita come la peste la SerialEvent. Usa la readStringUntil per leggere, il timeout di default è di 1s.

ecco un esempio completo

void setup() {
  Serial.begin(9600);
  Serial.setTimeout(10000);
}

void loop() {
  String comando;

  Serial.println("Wait comando");
  while(!Serial.available());
  
  comando = Serial.readStringUntil('\n');

  if ( comando == "prog" )
  {
      comando = Serial.readStringUntil('\n');
      if ( comando == "uno")
      {
          Serial.println("UNO");
      }
      else if ( comando == "due" )
      {
          Serial.println("DUE");
      }
      else if ( comando == "" )
      {
          Serial.println("sottocomando non ricevuto");
      }
      else
      {
          Serial.println("sottocomando errato");
      }
  }
  else
  {
      Serial.println("comando errato");
  }

}

vbextreme: Evita come la peste la SerialEvent. Usa la readStringUntil per leggere, il timeout di default è di 1s.

Adesso che lo sketch funziona? :o :fearful:

Lagne a parte sono un noob e ogni consiglio è ben accetto. Sono disposto anche a cambiare lo sketch, d'altronde prima l'approccio era su per giù come nel tuo esempio, contrallando l'input da seriale nel loop, sono passato al serialEvent per trovare una soluzione al problema presentato sopra.

Se hai due minuti per spiegarmelo però vorrei capire perché evitare il serialEvent. Sembra funzionare tutto correttamente.

Ottimo il readStringUntil, grazie! :sunglasses:

@m265: Se hai due minuti per spiegarmelo però vorrei capire perché evitare il serialEvent. Sembra funzionare tutto correttamente.

la serialEvent() è una funzione che viene richiamata dopo il loop, ovvero arduino lavora all'incirca cosi:

int main(void)
{
    setup();
    while( 1 )
    {
        loop();
        serialEvent();
    }
}

detta come va detta è un'inutile complicazione per il 90% dei progetti e toglie la logica del programma. Toglila.

Il comando

while(!Serial.available());

serve solo su microcontrollori tipo il 32U4 della Leonardo e solo per bloccare il programma in attesa di un collegamento sulla seriale. Se non devi lavorare per forza col serial monito aperto qual comando non serve. Inoltre è inutile sui micro della UNO e simili.

@PaoloP ti stai confondendo con

while( !Serial );

che attende la connessione al PC e funziona solo con la Leonardo.

la

while(!Serial.available());

attende dati sulla seriale.

:confused: Confuso!