Go Down

Topic: Ancora problemi con stringhe e la porta seriale di Arduino (Read 1 time) previous topic - next topic

hermit274

Ciao a tutti ragazzi, qualche giorno fa ho creato un topic nel quale cercavo di salvare dei dati su EEPROM. Adesso mi sono accordo che per poter andare a salvare più dati (ricevuti da porta seriale) devo cercare di leggere delle stringhe per poi manipolarle ed estrarre i dati da queste.

Cercando e ricercando sul forum ho trovato qualche codice, e alla fine sono riuscito a scrivere questo
Code: [Select]

int led=13;
String stringa;                                        // stringa ricevuta

void setup() {
  pinMode(led, OUTPUT);
  Serial.begin(9600);
}

void loop() {

  stringa = "";                                     // azzera stringa

  while (Serial.available() > 0) {              // ricezione da Serial Monitor
    stringa += char(Serial.read());               // aggiungi carattere alla stringa
  }

  stringa.trim();                                   // elimina spazi iniziali e finali
  stringa.toLowerCase();                            // converti in minuscolo

  if (stringa == "accendi") digitalWrite(led, HIGH);
  else if (stringa == "spegni") digitalWrite(led, LOW);
}

perchè non funziona??non riesco proprio a capirlo

tuxduino

Stampa il contenuto di stringa sulla seriale prima del confronto.

hermit274

niente...ho provato a inserire
Code: [Select]
Serial.print(stringa);
subito dopo il ciclo while ma non mi scrive niente...

tuxduino

Appunto.

Ecco perché il test successivo fallisce.

Devi battezzare un carattere come "fine delle trasmissioni" a riempier la stringa fino a che non vedi quel byte.
A quel punto puoi fare il confronto per capire che comando hai ricevuto.

pablos

se non hai un carattere di chiusura potresti usare

Code: [Select]

while (Serial.available() > 0) {              // ricezione da Serial Monitor
   stringa += char(Serial.read());               // aggiungi carattere alla stringa
if string.indexof di stringa == accendi >>>  esegui ....
 }


no comment

tuxduino

Sì, ma in quel caso dovrebbe anche preoccuparsi di togliere il comando identificato dalla stringa di accumulo, altrimenti quella cresce fino a far resettare il micro.
Nel caso "classico" del carattere di terminazione la cosa è più semplice perché basta "svuotare" la stringa di accumulo ogni volta che lo si riceve.

Comunque sarebbe meglio usare un char[], non String.

hermit274

Allora ragazzi ho messo un carattere di fine stringa che io ho indicato con il punto. Quindi ogni qual volta che dovrebbe trovare questo benedetto punto la lettura dovrebbe interrompersi.
Ad esempio se io mando tramite seriale la parola "accendi." appena vede il punto dovrebbe interrompere l'acquisizione. Il codice che ho scritto è questo:
Code: [Select]
int led=13;
String stringa;                                        // stringa ricevuta

void setup() {
 pinMode(led, OUTPUT);
 Serial.begin(9600);
}

void loop() {

 stringa = "";                                     // azzera stringa

 while (Serial.available() > 0 && (Serial.read() != '.')) {    // ricezione da Serial Monitor
   stringa += char(Serial.read());               // aggiungi carattere alla stringa
 }
 //delay(4000);
 //Serial.print(stringa);

 stringa.trim();                                   // elimina spazi iniziali e finali
 stringa.toLowerCase();                            // converti in minuscolo

 if (stringa == "accendi") digitalWrite(led, HIGH);
 else if (stringa == "spegni") digitalWrite(led, LOW);
}

ma ancora non funzionaaaa :(

cmqe ritornando alla questione char[] o string ho preferito scegliere la soluzione delle string perchè innazi tutto gli operatori di stringa sono molto più semplici, cioè per catenare ho visto che basta utilzzare la sintassi
stringa1 + stringa 2...ecc...

poi per quanto riguarda i char[] ho visto che questi devono essere dichiarati e dimensionati a priori e il bello è che non so quanto sarà lunga questa stringa...

almeno queste sono nozioni che ho imparato nel giro di una settimana avendo arduino davanti...se ci sono scappatoie fatemi sapere!sono qui per imparare :D

pablos


Sì, ma in quel caso dovrebbe anche preoccuparsi di togliere il comando identificato dalla stringa di accumulo, altrimenti quella cresce fino a far resettare il micro.
Nel caso "classico" del carattere di terminazione la cosa è più semplice perché basta "svuotare" la stringa di accumulo ogni volta che lo si riceve.

Comunque sarebbe meglio usare un char[], non String.


ok  allora
Code: [Select]

while (Serial.available() > 0) {              // ricezione da Serial Monitor
    stringa += char(Serial.read());               // aggiungi carattere alla stringa
    if string.indexof di stringa == accendi >>> 
     {
       string="";
       esegui ....
     }
  }
no comment

hermit274

ma la mia soluzione con il punto nel ciclo while non va bene??

tuxduino


ma la mia soluzione con il punto nel ciclo while non va bene??


No, perché chiami Serial.available() ad un ritmo rapidissimo, mentre i caratteri impiegano un tempo molto più lungo per arrivare.
Devi uscire dal ciclo di ricezione quando hai ricevuto il carattere di fine riga (il punto va benissimo) oppure dopo un certo timeout, oppure quando hai ricevuto un certo numero massimo di caratteri ma il punto ancora non l'hai visto.

Poi devi mettere un tetto alla lunghezza del buffer di accumulo (cioè la String) altrimenti rischi di saturare la RAM.

hermit274

Ragazzi non ci crederete ma ho risolto. Ma adesso voi dovete risolvermi questo dubbio fra questi due codici. Il primo non funziona, mentre il secondo si. Ma in sostanza sono identici!!Come mai???
Code: [Select]

void loop() {

 stringa = "";                                     // azzera stringa

 while (Serial.available() > 0) {    // ricezione da Serial Monitor  
   delay(10);
   if (char(Serial.read()) ==  '.'){
     break;
   }
   stringa += char(Serial.read());               // aggiungi carattere alla stringa
 }

 stringa.trim();                                   // elimina spazi iniziali e finali
 stringa.toLowerCase();                            // converti in minuscolo

 if (stringa == "accendi") digitalWrite(led, HIGH);
 else if (stringa == "spegni") digitalWrite(led, LOW);
}


mentre il secondo che funziona è questo
Code: [Select]

void loop() {

 stringa = "";                                     // azzera stringa

 while (Serial.available() > 0) {    // ricezione da Serial Monitor  
   delay(10);
   char c = Serial.read();
   if (c == '.'){
     break;
   }
   stringa += c;               // aggiungi carattere alla stringa
 }

 stringa.trim();                                   // elimina spazi iniziali e finali
 stringa.toLowerCase();                            // converti in minuscolo

 if (stringa == "accendi") digitalWrite(led, HIGH);
 else if (stringa == "spegni") digitalWrite(led, LOW);
}


?????????

tuxduino

Che cosa vuol dire

Code: [Select]
(char(Serial.read()) ==  '.')

Esiste forse una funzione char() ? Non capisco come possa compilare una roba del genere... ?

hermit274

ok...capito.quindi era un problema di compilazione. Pensavo esistesse una funzione di quel tipo.
Comunque tuxduino volevo chiederti se a questo punto come hai suggerito conviene meglio utilizzare un char[].
Per poterlo riempire sicuramente devo utilizzare un ciclo, ma poi per poterci smanettare sopra?quali funzioni posso utilizzare?
Ad esempio per concatenare, cercare dei caratteri, sostituirli valgono esattamente le stesse funzioni del C?
Devo importare le librerie string.h??

tuxduino

Stiamo parlando di C-string, cioè char[] con la convenzione che la stringa è termianta da un byte nullo.
Tutte le funzioni della famiglia str* funzionano su questa convenzione.
Per aggiungere caratteri tieni un contatore e accedi direttamente a stringa[cnt], per il confronto usa strcmp().

Go Up