Problema reading seriale e attesa condizione

Salve a tutti,
io sono nuovo di questo forum ed ho appena iniziato ad usare ArduinoUNO.
Sto cercando di realizzare un programmino che faccia delle cose (non è questo il mio problema) e si interfacci con PuTTY via seriale e possa ricevere dei comandi.
il mio problema è realizzare il ciclo di controllo sulla seriale per verificare che il byte ricevuto soddisfi una mia condizione.....

int byteInArrivo = 0; // per iniziare la trasmissione seriale
int serial =0;
void setup( ) {
Serial.begin(9600); // apertura porta seriale, impostazione velocità di
// trasmissione dati a 9600bps
}
void loop( ) {
Serial.println("\E[H\E[2J" ); //Clear Screen in PuTTY
Serial.println("Scegli tra le seguenti opzioni:");
delay(5);
Serial.println("a - Leggi x");
delay(5);
Serial.println("b - Leggi y");
delay(5);
Serial.println("c - Leggi z");
delay(5);
Serial.print("\n");
delay(5);

if (Serial.available()>0){
byteInArrivo = Serial.read( );
}

delay(50);
while (byteInArrivo!= 97 |attachment](upload://uK5zzUDKUsAUbDLcp5TJozB6jC1.jpeg) (14.1 KB)

Ti scrivo qualche riga senza averla provata... usala solo come punto di partenza

int byteInArrivo = 0; // per iniziare la trasmissione seriale
int serial =0;

void setup( ) 
{
   Serial.begin(9600); // apertura porta seriale, impostazione velocità di
                                // trasmissione dati a 9600bps

   prompt()
}

void loop( ) 
{
 
   if (Serial.available()>0)
   {
      byteInArrivo = Serial.read( );
      
      switch (byteInArrivo)
      {
           case 97:
              Serial.print("Hai premuto a");
              // qui chiami la funzione da eseguire quando viene premuto a
              break;
           case 98:
              Serial.print("Hai premuto b");
              // qui chiami la funzione da eseguire quando viene premuto b
              break;
           case 99:
              Serial.print("Hai premuto c");
              // qui chiami la funzione da eseguire quando viene premuto c
              break;
           default:
              Serial.print("Comando sconosciuto");
              break;
      }
      
      delay(2000); // serve per dare 2 secondi di tempo per vedere l'eventuale output della funzione richiesta
                         // magari è inutile o vuoi sostituirlo con qualcos'altro
      prompt();
   }
}

void prompt()
{
   Serial.println("\E[H\E[2J" );  //Clear Screen in PuTTY
   Serial.println("Scegli tra le seguenti opzioni:");
   // perchè le delay? A cosa servono?
   //delay(5);
   Serial.println("a - Leggi x");
   //delay(5);
   Serial.println("b - Leggi y");
   //delay(5);
   Serial.println("c - Leggi z");
   //delay(5);
   Serial.print("\n");
   //delay(5);
}

vittorio68:
Ti scrivo qualche riga senza averla provata... usala solo come punto di partenza

int byteInArrivo = 0; // per iniziare la trasmissione seriale

int serial =0;

void setup( )
{
   Serial.begin(9600); // apertura porta seriale, impostazione velocità di
                                // trasmissione dati a 9600bps

prompt()
}

void loop( )
{

if (Serial.available()>0)
   {
      byteInArrivo = Serial.read( );
     
      switch (byteInArrivo)
      {
           case 97:
              Serial.print("Hai premuto a");
              // qui chiami la funzione da eseguire quando viene premuto a
              break;
           case 98:
              Serial.print("Hai premuto b");
              // qui chiami la funzione da eseguire quando viene premuto b
              break;
           case 99:
              Serial.print("Hai premuto c");
              // qui chiami la funzione da eseguire quando viene premuto c
              break;
           default:
              Serial.print("Comando sconosciuto");
              break;
      }
     
      delay(2000); // serve per dare 2 secondi di tempo per vedere l'eventuale output della funzione richiesta
                         // magari è inutile o vuoi sostituirlo con qualcos'altro
      prompt();
   }
}

void prompt()
{
   Serial.println("\E[H\E[2J" );  //Clear Screen in PuTTY
   Serial.println("Scegli tra le seguenti opzioni:");
   // perchè le delay? A cosa servono?
   //delay(5);
   Serial.println("a - Leggi x");
   //delay(5);
   Serial.println("b - Leggi y");
   //delay(5);
   Serial.println("c - Leggi z");
   //delay(5);
   Serial.print("\n");
   //delay(5);
}

It works very well!!! Thank you so much! :slight_smile:

Ho solo un altro quesito da chiederti...
con che criterio hai scelto di mettere la lettura della seriale nel loop e invece il menu su un alta routine?
se premo invio un comendo seriale prima che abbia stamapato il menu a poco senso, no?!
Sto solo cercando di capire come strutturare i programmi. Sono nuovo e non ho la flessibilità suff. per vedere in modo chiaro, come scrivere un programma.

Grazie per l'aiuto!

è una semplice questione di ordine del codice... leggibilità

ciao

ho messo la stampa del menu in una funzione per poterlo richiamare sia da setup() che da loop(). L'ho messo anche in setup proprio per evitare che l'utente possa scrivere qualcosa sulla seriale prima della stampa del menu.

In generale però l'aspetto importante è un'altro. Nel codice che avevi scritto tu, bloccavi l'esecuzione di loop in attesa di un carattere sulla seriale. Questo magari funziona pure ma mi sembra un approccio meno "generico". Nel codice che ho proposto io invece il controllore esegue sempre il loop e quindi tu potrai fargli fare altre cose ad ogni ciclo in attesa che arrivi un comando.

Ti faccio un esempio. Immagina di voler realizzare un termostato che legga all'infinito una temperatura ed attivi un relè quando questa è più bassa di una certa soglia. In più, come hai fatto tu, ogni volta che sulla seriale arriva il carattere 'a' mi risponde con l'ultima temperatura letta, quando arriva 'b' mi risponde con la media, quando arriva 'c' mi cambia di stato al relè a prescindere dalla temperatura (magari quest'ultimo esempio andrebbe approfondito per non essere assurdo...).

Con il mio approccio puoi inserire il codice per la lettura del sensore e per l'attivazione del relè all'interno del loop (prima o dopo l'if sulla Serial.Available non ha molta importanza...) ed essere sicuro che sia la gestione del sensore e del relè sia la gestione della seriale avvenga "contemporaneamente" (o almeno che sembri così).

vittorio68:
ciao

ho messo la stampa del menu in una funzione per poterlo richiamare sia da setup() che da loop(). L'ho messo anche in setup proprio per evitare che l'utente possa scrivere qualcosa sulla seriale prima della stampa del menu.

In generale però l'aspetto importante è un'altro. Nel codice che avevi scritto tu, bloccavi l'esecuzione di loop in attesa di un carattere sulla seriale. Questo magari funziona pure ma mi sembra un approccio meno "generico". Nel codice che ho proposto io invece il controllore esegue sempre il loop e quindi tu potrai fargli fare altre cose ad ogni ciclo in attesa che arrivi un comando.

Ti faccio un esempio. Immagina di voler realizzare un termostato che legga all'infinito una temperatura ed attivi un relè quando questa è più bassa di una certa soglia. In più, come hai fatto tu, ogni volta che sulla seriale arriva il carattere 'a' mi risponde con l'ultima temperatura letta, quando arriva 'b' mi risponde con la media, quando arriva 'c' mi cambia di stato al relè a prescindere dalla temperatura (magari quest'ultimo esempio andrebbe approfondito per non essere assurdo...).

Con il mio approccio puoi inserire il codice per la lettura del sensore e per l'attivazione del relè all'interno del loop (prima o dopo l'if sulla Serial.Available non ha molta importanza...) ed essere sicuro che sia la gestione del sensore e del relè sia la gestione della seriale avvenga "contemporaneamente" (o almeno che sembri così).

Ti ringrazio per la spiegazione! è stata molto esaustiva e chiara! Lo so sto muovendo i primi passi in questo mondo e qualsiasi consiglio è ben accettto!
Grazie ancora.

Alex

vittorio68:
ciao

ho messo la stampa del menu in una funzione per poterlo richiamare sia da setup() che da loop(). L'ho messo anche in setup proprio per evitare che l'utente possa scrivere qualcosa sulla seriale prima della stampa del menu.

In generale però l'aspetto importante è un'altro. Nel codice che avevi scritto tu, bloccavi l'esecuzione di loop in attesa di un carattere sulla seriale. Questo magari funziona pure ma mi sembra un approccio meno "generico". Nel codice che ho proposto io invece il controllore esegue sempre il loop e quindi tu potrai fargli fare altre cose ad ogni ciclo in attesa che arrivi un comando.

Ti faccio un esempio. Immagina di voler realizzare un termostato che legga all'infinito una temperatura ed attivi un relè quando questa è più bassa di una certa soglia. In più, come hai fatto tu, ogni volta che sulla seriale arriva il carattere 'a' mi risponde con l'ultima temperatura letta, quando arriva 'b' mi risponde con la media, quando arriva 'c' mi cambia di stato al relè a prescindere dalla temperatura (magari quest'ultimo esempio andrebbe approfondito per non essere assurdo...).

Con il mio approccio puoi inserire il codice per la lettura del sensore e per l'attivazione del relè all'interno del loop (prima o dopo l'if sulla Serial.Available non ha molta importanza...) ed essere sicuro che sia la gestione del sensore e del relè sia la gestione della seriale avvenga "contemporaneamente" (o almeno che sembri così).

ma in setup () gli si può anche far fare delle cose come stampare il menu?!...non credo di aver capito bene la cosa! Credevo che li si potesse solo configurare e inizializzare le cose. Inoltre, mi puoi spiegare la funzione di controllo dati disponibili sulla seriale?!

Ciao
Alex

puoi fare quello che vuoi dove vuoi, l'unico caso a parte sono i vettori di interrupt ma direi che non devi preoccupartene per ora.

per le funzioni disponibili nelle librerie ufficiali dalla pagina principale arduino.cc fai reference -> libraryes

lesto:
puoi fare quello che vuoi dove vuoi, l'unico caso a parte sono i vettori di interrupt ma direi che non devi preoccupartene per ora.

per le funzioni disponibili nelle librerie ufficiali dalla pagina principale arduino.cc fai reference -> libraryes

non so se mi puoi spiegare, ma non ho capito come non far fare il refresh continuo al menù....ora me lo fa di continuo (con il sw che mi ha scritto sopra) non è piacevole vederlo lampeggiare di continuo.... scusa la mia profonda ignoranza.

cosa vuol dire il refresh? da quel che vedo ridisegna il menù solo se necessario

lesto:
cosa vuol dire il refresh? da quel che vedo ridisegna il menù solo se necessario

si forse ho detto una minchiata...
switchio la domanda... diciamo che tramite il menu arrivo in un punto in cui voglio inserire un dato da salvare in una variabile...
se premo un numero lui esce subito dalla routine...perchè ha visto che è stato trasmesso un dato! come faccio per dirgli di aspettare due caratteri?
esempio...voglio scrivere la temperatura da impostare....se premo 2 lui lo prende subito....io invece volevo scrivere 25!
Come si gestisce questa cosa?! ci sto diventando scemo!

if (Serial.available()>0)

dice di aspettare almeno 1 carattere... a te il resto

lesto:

if (Serial.available()>0)

dice di aspettare almeno 1 carattere... a te il resto

ho provato così per acquisire 2byte (?)...ma non mi funziona ugualmente...

if (Serial.available()>1)
        {
        RifTemp = Serial.read( );
        Serial.println("Hai inserito"); 
        Serial.println(RifTemp,DEC); 
      }

la serial read legge un solo carattere... quindi semmai

RifTemp = Serial.read()+Serial.read( ) //se vuoi LA SOMMA DEI VALORI NUMERICI DEI BYTE (e quindi riftemp è un int o superiore)
RifTemp = (Serial.read()<<8)+Serial.read( ) //se riftemp è un int spdito in modo "grezzo" (prima parte alta e poi la LSB)
RifTemp = Serial.read()+""+Serial.read( ) //se riftemp è una stringa il "" (carattere vuoto) fa in modo che i valori di read NON si simmino, ma vengano affiancati. Ottimo per ricostruire parole, ad esempio

tu cosa vuoi fare?

lesto:
la serial read legge un solo carattere... quindi semmai

RifTemp = Serial.read()+Serial.read( ) //se vuoi LA SOMMA DEI VALORI NUMERICI DEI BYTE (e quindi riftemp è un int o superiore)

RifTemp = (Serial.read()<<8)+Serial.read( ) //se riftemp è un int spdito in modo "grezzo" (prima parte alta e poi la LSB)
RifTemp = Serial.read()+""+Serial.read( ) //se riftemp è una stringa il "" (carattere vuoto) fa in modo che i valori di read NON si simmino, ma vengano affiancati. Ottimo per ricostruire parole, ad esempio




tu cosa vuoi fare?

well...
voglio fare un sistema di controllo della temperatura per scaldare una vasca con dell'acqua.
La mia idea era di poter dialogare con arduino tramite emulazione terminale (con PuTTY) e poter impostare la temperatura, rileggere il valore impostato e leggere la temperatura dell'acqua...
questo a grandi linee è quello che vorrei fare. Devo solo trovare un santo che mi scriva un software grezzo, tramite il quale possa capire: come si struttura un programma,come si pensa lo stesso e capire come aggredire il software per personalizzarlo e ampliarlo. Devo solo trovare il la, dopo di che posso ampliare la mia conoscenza ed entrare ancora più nel dettaglio con il linguaggio di programmazione.
Io lavoro nell'elettronica di potenza, sono un hardwareista ma mi manca la parte software!

Alex

alexsgv:
Devo solo trovare un santo che mi scriva un software grezzo, tramite il quale possa capire: come si struttura un programma,come si pensa lo stesso e capire come aggredire il software per personalizzarlo e ampliarlo. Devo solo trovare il la, dopo di che posso ampliare la mia conoscenza ed entrare ancora più nel dettaglio con il linguaggio di programmazione.

Premesso che nessuno "nasce imparato", l'apprendimento di Arduino è composto da 2 binari da percorrere parallelamente: la strada dell'elettronica e la strada della programmazione. Senza uno dei 2, il "treno" deraglia.
Nel mondo dei microcontrollori la parte HW non può prescindere da quella SW e viceversa. Se uno ha lacuna su uno dei 2 argomenti, deve colmarlo. Forse stai affrontando un problema al di là delle tue conoscenze attuali?

leo72:

alexsgv:
Devo solo trovare un santo che mi scriva un software grezzo, tramite il quale possa capire: come si struttura un programma,come si pensa lo stesso e capire come aggredire il software per personalizzarlo e ampliarlo. Devo solo trovare il la, dopo di che posso ampliare la mia conoscenza ed entrare ancora più nel dettaglio con il linguaggio di programmazione.

Premesso che nessuno "nasce imparato", l'apprendimento di Arduino è composto da 2 binari da percorrere parallelamente: la strada dell'elettronica e la strada della programmazione. Senza uno dei 2, il "treno" deraglia.
Nel mondo dei microcontrollori la parte HW non può prescindere da quella SW e viceversa. Se uno ha lacuna su uno dei 2 argomenti, deve colmarlo. Forse stai affrontando un problema al di là delle tue conoscenze attuali?

Ammetto la mia lacuna e sto appunto cercando di colmarla. Comprendo il tuo punto di vista, ma credo che sia nello spirito di questo forum e nei forum in generale, quello di aiutare chi muove i primi passi. Comprendo che il tuo consiglio sia quello di partire nel far accendere un led. A mia volta ritengo che sia poco stimolante. Del resto seguo questa cosa come passione o hobby, chiamala come vuoi, e per mantenere l'interesse vivo, mi sono posto un progetto da raggiungere e cerco persone più erudite di me per ottenere un punto di partenza da poter usare come start up per lo studio/apprendimento/divertimento dello stesso. Anche quando si studia una lingua straniera non si aspetta di aver letto tutta la grammattica prima di aprire bocca, ma si da volta volta qualche istruzione/conoscienza per poter prendere confidenza e parlare un pò.
Sono qui, senza avanzare pretese verso nessuno, ma con la speranza che qualcuno dedichi un pò di tempo ad una persona che rappresenta quello che un tempo eravate anche voi.
alex

in pratica quello che vuoi fare, se ho capito bene, è che alla pressione di una delle tre opzioni, per esempio la 'a', l'arduino si metta in attesa di un valore diciamo a n cifre (nel tuo caso credo due ma magari anche una soltanto).

Per prima cosa devi quindi gestire una sorta di stato in cui il tuo software passa nel momento in cui riceve il comando 'a' e fino a quando non riceve un carattere di conferma, per esempio 13 che è il codice ASCII del 'return' della tastiera.

Mentre il software si trova in questo stato dovrà accettare i caratteri numerici 0-9 (ASCII da 48 a 57) e magari il carattere di cancellazione (backspace, non ricordo l'ASCII ma a memoria direi l'8 ). Per quanto riguarda i caratteri numerici, per avere la cifra corrispondente ti basta fare n = c - 48; dove c è il carattere ASCII ricevuto sulla seriale e n è la cifra decimale corrispondente.

Purtroppo i metodi indicati da lesto temo non vadano bene. Infatti si riferiscono alla ricezione di dati binari mentre tu invece invii caratteri ASCII e vuoi ottenere non una stringa (il terzo caso da lui proposto) ma l'intero corrispondente. Avevo già proposto una possibile implementazione in questo thread: Inserire una cifra tramite Keypad 4*4 - #3 by vittorio68 - Software - Arduino Forum . Lì i caratteri arrivavano da una tastiera e tu invece li ricevi dalla seriale. Tuttavia, dopo la conversione ASCII/decimale che ti ho indicato, la questione diventa la stessa.

Ricapitolando il codice diventerebbe qualcosa del genere (ti ricordo che non l'ho provato...)

boolean flagmenu = true;
int byteInArrivo = 0; // per iniziare la trasmissione seriale
int serial =0;

void setup( ) 
{
   Serial.begin(9600); // apertura porta seriale, impostazione velocità di
                                // trasmissione dati a 9600bps

   prompt()
}

void loop( ) 
{
 
   if (Serial.available()>0)
   {
      byteInArrivo = Serial.read( );
      
      if (flagmenu)
      {
         switch (byteInArrivo)
         {
              case 97:
                 Serial.print("Hai premuto a");
                 flagmenu=false;
                 break;
              case 98:
                 Serial.print("Hai premuto b");
                 // qui chiami la funzione da eseguire quando viene premuto b
                 break;
              case 99:
                 Serial.print("Hai premuto c");
                 // qui chiami la funzione da eseguire quando viene premuto c
                 break;
              default:
                 Serial.print("Comando sconosciuto");
                 break;
         }
      
         delay(2000); // serve per dare 2 secondi di tempo per vedere l'eventuale output della funzione richiesta
                            // magari è inutile o vuoi sostituirlo con qualcos'altro
         prompt();
      }
      else
      {
         // qui dovresti inserire il pezzo di codice che gestisce la lettura del parametro partendo dal valore contenuto in byteInArrivo
         if (byteInArrivo == 13)
         {
             // ora una tua variabile conterrà il valore ricevuto dalla seriale
             // ritorni nello stato di attesa di un comando
             flagmenu = true;
         } 
      }
}

void prompt()
{
   Serial.println("\E[H\E[2J" );  //Clear Screen in PuTTY
   Serial.println("Scegli tra le seguenti opzioni:");
   // perchè le delay? A cosa servono?
   //delay(5);
   Serial.println("a - Leggi x");
   //delay(5);
   Serial.println("b - Leggi y");
   //delay(5);
   Serial.println("c - Leggi z");
   //delay(5);
   Serial.print("\n");
   //delay(5);
}

Non me ne volere... volutamente non ho scritto il pezzo di codice che ricostruisce il valore del parametro per due motivi. Il primo è che richiede un minimo di attenzione in più e magari qualche test. Il secondo è che condivido il suggerimento di leo72. Ho provato a darti qualche spunto ma poi, se vuoi veramente imparare a programmare, l'unico modo che conosco è quello di "perderci le nottate...". Non è mancanza di disponibilità da parte degli amici del forum è solo l'unica strada possibile.

Ciò premesso, se hai ancora altri dubbi, chiedi pure.

Ciao.
Vittorio.

vittorio68:
in pratica quello che vuoi fare, se ho capito bene, è che alla pressione di una delle tre opzioni, per esempio la 'a', l'arduino si metta in attesa di un valore diciamo a n cifre (nel tuo caso credo due ma magari anche una soltanto).

Per prima cosa devi quindi gestire una sorta di stato in cui il tuo software passa nel momento in cui riceve il comando 'a' e fino a quando non riceve un carattere di conferma, per esempio 13 che è il codice ASCII del 'return' della tastiera.

Mentre il software si trova in questo stato dovrà accettare i caratteri numerici 0-9 (ASCII da 48 a 57) e magari il carattere di cancellazione (backspace, non ricordo l'ASCII ma a memoria direi l'8 ). Per quanto riguarda i caratteri numerici, per avere la cifra corrispondente ti basta fare n = c - 48; dove c è il carattere ASCII ricevuto sulla seriale e n è la cifra decimale corrispondente.

Purtroppo i metodi indicati da lesto temo non vadano bene. Infatti si riferiscono alla ricezione di dati binari mentre tu invece invii caratteri ASCII e vuoi ottenere non una stringa (il terzo caso da lui proposto) ma l'intero corrispondente. Avevo già proposto una possibile implementazione in questo thread: Inserire una cifra tramite Keypad 4*4 - #3 by vittorio68 - Software - Arduino Forum . Lì i caratteri arrivavano da una tastiera e tu invece li ricevi dalla seriale. Tuttavia, dopo la conversione ASCII/decimale che ti ho indicato, la questione diventa la stessa.

Ricapitolando il codice diventerebbe qualcosa del genere (ti ricordo che non l'ho provato...)

boolean flagmenu = true;

int byteInArrivo = 0; // per iniziare la trasmissione seriale
int serial =0;

void setup( )
{
   Serial.begin(9600); // apertura porta seriale, impostazione velocità di
                                // trasmissione dati a 9600bps

prompt()
}

void loop( )
{

if (Serial.available()>0)
   {
      byteInArrivo = Serial.read( );
     
      if (flagmenu)
      {
         switch (byteInArrivo)
         {
              case 97:
                 Serial.print("Hai premuto a");
                 flagmenu=false;
                 break;
              case 98:
                 Serial.print("Hai premuto b");
                 // qui chiami la funzione da eseguire quando viene premuto b
                 break;
              case 99:
                 Serial.print("Hai premuto c");
                 // qui chiami la funzione da eseguire quando viene premuto c
                 break;
              default:
                 Serial.print("Comando sconosciuto");
                 break;
         }
     
         delay(2000); // serve per dare 2 secondi di tempo per vedere l'eventuale output della funzione richiesta
                            // magari è inutile o vuoi sostituirlo con qualcos'altro
         prompt();
      }
      else
      {
         // qui dovresti inserire il pezzo di codice che gestisce la lettura del parametro partendo dal valore contenuto in byteInArrivo
         if (byteInArrivo == 13)
         {
             // ora una tua variabile conterrà il valore ricevuto dalla seriale
             // ritorni nello stato di attesa di un comando
             flagmenu = true;
         }
      }
}

void prompt()
{
   Serial.println("\E[H\E[2J" );  //Clear Screen in PuTTY
   Serial.println("Scegli tra le seguenti opzioni:");
   // perchè le delay? A cosa servono?
   //delay(5);
   Serial.println("a - Leggi x");
   //delay(5);
   Serial.println("b - Leggi y");
   //delay(5);
   Serial.println("c - Leggi z");
   //delay(5);
   Serial.print("\n");
   //delay(5);
}




Non me ne volere... volutamente non ho scritto il pezzo di codice che ricostruisce il valore del parametro per due motivi. Il primo è che richiede un minimo di attenzione in più e magari qualche test. Il secondo è che condivido il suggerimento di leo72. Ho provato a darti qualche spunto ma poi, se vuoi veramente imparare a programmare, l'unico modo che conosco è quello di "perderci le nottate...". Non è mancanza di disponibilità da parte degli amici del forum è solo l'unica strada possibile.

Ciò premesso, se hai ancora altri dubbi, chiedi pure.

Ciao.
Vittorio.

Grazie mille per il tuo spunto. Sicuramente avrò delle domande. Ma ora mi devo concentrare nell'analizzare il tuo codice per capire un sacco di cose.
Grazie ancora per la disponibilità.
Ale