problema con stringa

int pinOut = 8;
char c;
String controllo;

void setup()

{
  pinMode(pinOut, OUTPUT);
  Serial.begin(9600);
}

void loop()
{
  while(Serial.available())
  {
    c = Serial.read();
    controllo += c;
  }
  if(controllo == "accendi")
   {
    digitalWrite(pinOut, HIGH);
   }
   if(controllo == "spegni")
   {
    digitalWrite(pinOut, LOW);
   }
   controllo = "";
}

Mi spieghereste perché questo codice non funziona?
Non riesco a trovare l'errore

Cosa dovrebbe fare?
Cosa fa?

Silente:
Cosa dovrebbe fare?
Cosa fa?

Mah ... secondo me, semplicemente NON aspettando lui un carattere terminatore, ma, erroneamente, basandosi SOLO sulla Serial.available() ... esce dal while() prima del tempo, NON riconosce la stringa e ... azzera tutto, impedendone quindi un successivo riconoscimento :wink:

Guglielmo

>germino3: Consiglio …

… ricordarti che NON sei su un PC dove c’è un sistema operativo ed un “garbage collector”, sei su una piccola MCU con solo 2KBytes di SRAM, dove devi fare tutto tu e dove usare la classe “String”, a causa dell’allocazione e riallocazione dinamica della memoria, porta quasi sempre … a grossi problemi e sicuri mal di testa !!! :smiling_imp:

Impara ad usare le stringhe classiche del C … ovvero semplici array di char terminati dal carattere null (0x00) e le funzioni che trovi nella libreria standard (… che, oltretutto, è automaticamente inclusa dal IDE) AVR libc ed, in particolare, quanto è in <string.h> :wink:

Naturalmente è solo un “consiglio” … poi fai come meglio credi … ::slight_smile:

Guglielmo

Mi accodo al 3d per porre una domanda ai più esperti.
Molto spesso ricorro alle stringhe proprio per la loro semplicità di costruzione ovvero

String myNum = "il mio numero è ";
int numeroCell =33311;
myNum += numeroCell;

se volessi iniziare a detestare String come ho deletato dai miei codici il delay() come posso convertire il tutto come da esempio riportato per utilizzare ovviamente l'array di char per raggiungere lo stesso obbiettivo?

Silente:
Cosa dovrebbe fare?
Cosa fa?

In pratica dovrebbe accendere un Led, quando la stringa riconosciuta è "accendi" e spegnere il Led quando la stringa è "spegni".

gpb01:
Mah ... secondo me, semplicemente NON aspettando lui un carattere terminatore, ma, erroneamente, basandosi SOLO sulla Serial.available() ... esce dal while() prima del tempo, NON riconosce la stringa e ... azzera tutto, impedendone quindi un successivo riconoscimento :wink:

Guglielmo

Esattamente in pratica non mi accende né spegne il led, perché è come se la stringa non fosse davvero "accendi"...
Ma in teoria con "Serial.available()" non si dovrebbe uscire dal ciclo solamente quando non ci sono più caratteri in input?
Volevo solo capire perché non funziona, anche perché un metodo molto più facile sarebbe non considerare proprio le stringe e andare solo di char: 0 spento, 1 acceso. Tu dici che non devo scervellarmi, e lasciare stare in partenza questo tipo di lavoro sulle stringhe?

Non mi piace quel controllo="". Cosa fa?

Silente:
Non mi piace quel controllo="". Cosa fa?

In teoria dovrebbe riassegnare alla stringa un valore nullo, per ricominciare da capo nella funziona loop

germino3:
Ma in teoria con "Serial.available()" non si dovrebbe uscire dal ciclo solamente quando non ci sono più caratteri in input?

Esattamente, peccato che NON tieni conto della velocità di elaborazione di Arduino rispetto alla velocità di arrivo dei caratteri ...
... dato che la MCU è più veloce, mentre ancora sta arrivando un carattere, nel buffer già non ce ne sono più e quindi, giustamente, Serial.available() ritorna 0.

Devi verificare la ricezione di un "terminatore" e solo alla sua ricezione uscire dal while() ... esempio, potresti attendere la ricezione del carattere CR (0x0D).

Guglielmo

miky_police:
se volessi iniziare a detestare String come ho deletato dai miei codici il delay() come posso convertire il tutto come da esempio riportato per utilizzare ovviamente l’array di char per raggiungere lo stesso obbiettivo?

Mike … vale lo stesso suggerimento che ho dato nel post sopra … studiati tutte le funzioni che trovi in <string.h> (ho messo il link sopra) e trovi esattamente quella che cerchi.

Sono cattivo e NON te la dico … così ti costringo a studiarle tutte :smiling_imp: :smiling_imp: :smiling_imp:

Guglielmo

P.S.: … in realtà lo faccio per il tuo bene … così impari un sacco di cose …

gpb01:
Esattamente, peccato che NON tieni conto della velocità di elaborazione di Arduino rispetto alla velocità di arrivo dei caratteri …
… dato che la MCU è più veloce, mentre ancora sta arrivando un carattere, nel buffer già non ce ne sono più e quindi, giustamente, Serial.available() ritorna 0.

Devi verificare la ricezione di un “terminatore” e solo alla sua ricezione uscire dal while() … esempio, potresti attendere la ricezione del carattere CR (0x0D).

Guglielmo

int pinOut = 8;
char c;
String controllo;

void setup()

{
  pinMode(pinOut, OUTPUT);
  Serial.begin(9600);
}

void loop()
{
  controllo = "";

  while(Serial.available() > 0 || c != '\n')
  
 {
    if(Serial.available())
    {
    c = Serial.read();
    
    if (c != '\n') 
    controllo += c;
    
    }
  }

  if(controllo == "accendi")
    digitalWrite(pinOut, HIGH);

    if(controllo == "spegni")
     digitalWrite(pinOut, LOW);
}

Perfetto così funziona, grazie mille per l’aiuto e ora mi metterò sotto per studiare le funzioni in <string.h>.

Grazie mille per gli aiuti!

Funziona, ma penso che potresti migliorarla un po...
per me quell'if Serial.available() non ha senso perché sei già dentro il while che verifica la stessa condizione fondamentalmente... io, dopo aver visto milioni di esempi qua e la per la lettura della seriale (via filo via radio non importa) ho adottato come mio "standard" una guida di Leonardo Miliani, che oltre a leggere i dati in seriale, spiega come ricostruire un int sparato in write dall'altra parte... mooooooooolto comodo.
PS: grazie Leonardo, so che sei in questo forum! (almeno io ricordo di si).

EDIT: gugliemo sto iniziando a strizzare il cervello su strcat() :smiley:

miky_police:
PS: grazie Leonardo, so che sei in questo forum! (almeno io ricordo di si).

Si, anche se non lo frequenta da molto tempo, leo72 è anche uno degli Admin del forum :wink:

miky_police:
EDIT: gugliemo sto iniziando a strizzare il cervello su strcat() :smiley:

Dai, è banale, strcat(string_destinazione, stringa_da_aggiungere); ... più facile di così che vuoi ? :smiley:

Studiati bene anche le altre funzioni ... che ce ne sono delle belle :wink:

Guglielmo

@ miky_police, esistono più sistemi per leggere una stringa da seriale.
In questo sistema la if(Serial.available()) all'interno del while è indispensabile, ed è quella che fa
funzionare il codice.
Lo ha spiegato nei post precedenti gpb01 , arduino è più veloce della comunicazione seriale, quindi se non ci sono caratteri sulla seriale, viene eseguita comunque la Serial.read() che restituisce zero e che viene concatenato alla stringa, la stringa risultante quindi non corrisponde a quella voluta.

Mettendo invece if(Serial.available()) Serial.read(), gli diciamo "leggi solo se effettivamente c'è un carattere sulla seriale".

Come ho detto esistono delle varianti, ad esempio l'if potrebbe essere sostituito da un while( !Serial.available()) ; , che attende fino a quando ci sono caratteri disponibili sulla seriale. :slight_smile:

Se si fanno un po' di ricerche sul forum Italiano, da qualche parte si trova anche una bella routine che tiene conto sia del carattere terminatore, sia di un'eventuale gestione del timeout che di caratteri rimasti nel buffer ... :wink:

Guglielmo

Infatti gpb01, dopo avere imparato a leggere una stringa da seriale con terminatore da un esempio sul forum, adotto sempre questo sistema :slight_smile:

Personalmente, per queste funzioni su stringa, se c’è, preferisco usare la versione con n
strncpy invece di strcpy La versione n obbliga ad indicare la dimensione massima della stringa destinataria,
in questo modo la funzione stessa fa attenzione a non uscire dal buffer.

nid69ita:
Personalmente, per queste funzioni su stringa, se c’è, preferisco usare la versione con n …

SI, vero, è una buona cosa per evitare “sorprese” dovute a propri errori …

Nel caso della strcat(), che serve a Mike, abbiamo strncat (char *, const char *, size_t), ovvero, la stessa sintassi, ma con in più il parametro indicante la lunghezza massima della stringa destinazione :slight_smile:

Guglielmo

Con questo ho risolto, tempo addietro, gran parte dei miei problemi, applicandolo ad una comunicazione senza fili. Se si inserisce un semplice carattere terminatore il gioco è fatto, almeno credo. ::slight_smile: ::slight_smile:
Nulla vieta che si può costruire un char fino al terminatore e poi eseguire il resto del codice comportandosi come un while di fatto.

Dai, è banale, strcat(string_destinazione, stringa_da_aggiungere); ... più facile di così che vuoi ? :smiley:

Si, ma ci ho messo 20 minuti per capire come azzerare la stringa di destinazione... ma l'ho fatto ad intuito senza google :smiley: :smiley:
Carino quando entri nel meccanismo...
Capisci anche come ragiona il compilatore...

PS: vado a spulciare un altro po string.h magari trovo soluzione a dei problemi che manco mi immagino :smiley: :smiley: