Lettura Seriale-Arduino separando i dati

Salve, ho iniziato da pochissimo ad usare arduino ed è la prima volta che scrivo qui.

Vi spiego il mio problema:
ho un sensore che mi comunica via RS232 (2400 baude) inviandomi delle stringe tipo: 016,520,052,001
Ho bisogno di usare solamente il secondo dato (520) e trasformarlo in un intero,non mi interessa degli altri.

Potreste darmi per caso una mano?
Grazie a tutti

Salve,
Se i dato sono divisi da uno stesso simbolo (punto, virgola o altro) usato soltanto a tale scopo, si potrebbe fare che ogni volta che comincia a sentire un contatore arriva a 1. Ogni volta che sente il segno il contatore sale. Se il contatore é a 2 (ammesso che la variabile utile sia sempre allo stesso posto) la variabile int di uscita (tornata a zero ad inizio lettura) si aggiorna così: a=a*10+ricevuto. Prima ti tale controllo é necessario inserire una if che controlli se ricevo un numero.
Così credo che vada bene. Serve una mano per il codice?

>mariaru: essendo il tuo primo post, nel rispetto del regolamento (… punto 13, primo capoverso), ti chiedo cortesemente di presentarti QUI (spiegando bene quali conoscenze hai di elettronica e di programmazione ... possibilmente evitando di scrivere solo una riga di saluto) e di leggere con MOLTA attenzione il su citato REGOLAMENTO ... Grazie.

Guglielmo

P.S.: Qui una serie di link utili, NON necessariamente inerenti alla tua domanda:
- serie di schede by xxxPighi per i collegamenti elettronici vari: ABC - Arduino Basic Connections
- pinout delle varie schede by xxxPighi: Pinout
- link generali utili: Link Utili

>giovepluvio: Ti prego, prima di rispondere, di verificare sempre se l'utente abbia effettuato la presentazione, cosa che, ovviamente, NON può essere possibile se il suo numero di post è 1. Grazie anticipatamente per la collaborazione. :slight_smile:

giovepluvio:
Salve,
Se i dato sono divisi da uno stesso simbolo (punto, virgola o altro) usato soltanto a tale scopo, si potrebbe fare che ogni volta che comincia a sentire un contatore arriva a 1. Ogni volta che sente il segno il contatore sale. Se il contatore é a 2 (ammesso che la variabile utile sia sempre allo stesso posto) la variabile int di uscita (tornata a zero ad inizio lettura) si aggiorna così: a=a*10+ricevuto. Prima ti tale controllo é necessario inserire una if che controlli se ricevo un numero.
Così credo che vada bene. Serve una mano per il codice?

Si la virgola ha lo scopo di dividere i dati. Io banalmente avevo pensato di fare nel seguente modo:

void setup(){
Serial.begin(2400);
}
void loop()
{}
void Lettura()
{ if(Serial.available( ))
            char dato = Serial.read();
            char dato2 = dato.substring(4,6); //in questo modo dovrei prendere la sotto stringa 520
            int valore = atoi(dato2); // trasformo il dato in intero
}

Sinceramente non so se è corretto; no ho capito molto bene quello che dicevi te, forse mi servirebbe una mano con il codice xD

>mariaru: ti ricordo che in conformità al regolamento, punto 7, devi editare il tuo post (quindi NON scrivendo un nuovo post, ma utilizzando il bottone More -> Modify che si trova in basso a destra del tuo post) e racchiudere il codice all'interno dei tag CODE (... sono quelli che in edit inserisce il bottone con icona fatta così: </>, tutto a sinistra).

Grazie :slight_smile:

Guglielmo

gpb01:
>mariaru: ti ricordo che in conformità al regolamento, punto 7, devi editare il tuo post (quindi NON scrivendo un nuovo post, ma utilizzando il bottone More -> Modify che si trova in basso a destra del tuo post) e racchiudere il codice all'interno dei tag CODE (... sono quelli che in edit inserisce il bottone con icona fatta così: </>, tutto a sinistra).

Grazie :slight_smile:

Guglielmo

Fatto tutto, scusa se avevo sbagliato prima.

Relativamente al tuo problema ...
... la Serial.read() legge UN solo carattere (un 'char') alla volta, quindi a te prima fare un ciclo per ricevere l'intera serie di caratteri e, finita la stringa (tipicamente alla ricezione del CR) fare il parsing per separare le varie cose.

Ti SCONSIGLIO l'uso della classe String ...
... 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:

Guglielmo

.... dimenticavo, in <string.h> guarda la funzione strtok() che fa proprio quello che serve a te, cercare un separatore (esempio, la tua virgola) e separare i vari token :slight_smile:

Guglielmo

gpb01:
Relativamente al tuo problema ...
... la Serial.read() legge UN solo carattere (un 'char') alla volta, quindi a te prima fare un ciclo per ricevere l'intera serie di caratteri e, finita la stringa (tipicamente alla ricezione del CR) fare il parsing per separare le varie cose.

Ti SCONSIGLIO l'uso della classe String ...
... 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:

Guglielmo

Grazie mille per i consigli, per caso sai se ci sono esempi di codice in cui viene fatto questo (o qualcuno me lo potrebbe far vedere)?
Essendo una delle prime volte che lo faccio preferirei vedere come è implementato correttamente.

Per la lettura da seriale, se cerchi qui sul forum se ne è parlato centinaia di volte ... :smiley:

Per il resto, basta che fai una ricerca su Google per "strtok C example" e ... escono oltre 85'000 risultati :wink:

Guglielmo

Se ti dovesse venire complicato, per iniziare c'è anche:

paulus1969:
Se ti dovesse venire complicato, per iniziare c'è anche:
Serial.parseInt() - Arduino Reference

... che ha nulla a che vedere con la divisione in token.

La parte di conversione degli int mi sembra che gli sia già chiara (vedo che nel codice ha usato la atoi()) quindi .. la parseInt non gli serve a nulla visto che riceve una lunga stringa con tanti int.

Guglielmo

... al limite, se proprio vuole evitare di studiare come ricevere i vari caratteri, potrebbe usare la readStringUntil(), ma poi, comunque, la ricerca delle virgole, la separazione dei token e la conversione in int la deve fare.

Guglielmo

La parseint fa anche la suddivisione (o meglio riconosce le virgole come delimitatori), basta fare quattro parseint una dietro l'altra ed ottiene i quattro numeri dei quali poi userà il secondo.
Ovviamente è più rozzo (e lento, a meno di agire sul timeout).
Questo intendevo.
Farlo come dici tu è indubbiamente il modo migliore ma per chi sta iniziando potrebbe essere un po' complicato.

Non sono sicuro che con 4 parseInt in fila ci riesci, perchè c'è sempre il rischio che ti perdi qualche cosa per strada dato che la funzione NON ha una suddivisione in token, ma semplicemente esce quando incontra un carattere NON numerico o per timeout ... e comunque, anche se funzionasse, se domani gli int crescono che fa? Modifica ogni volta il programma per aggiungere parseInt() una dopo l'altra ? ... una vera porcheria :smiling_imp:

Molto meglio un banale ciclo con la strtok() che, quando non ha più nulla da darti ti ritorna NULL e quindi NON sei vincolato ad un numero fisso di token :wink:

Guglielmo

Ciao ragazzi, in questi giorni ho studiato un po' sia il tipo char con le sue funzioni sia qualche esempio trovato qui sul forum.
Il mio sensore invia un dato seriale ogni minuto del tipo come detto in precedenza. Dopodichè utilizzo questo dato per decidere se accendere una luce o meno, fatemi sapere che ne pensate.
Ancora non ho il sensore quindi non posso provarlo, essendo alle prime armi ho paura di aver sbagliato da qualche parte.

//Dichiarazione variabili

#define LUCE numero_pin;
int lettura_ok = 5;
byte i;
int Visibilita;
int constant Soglia_Visibilita = 5000;
char LetturaSeriale; //quello che leggerò sulla seriale

char* separatore =","; //carattere utilizzato per separare i dati ricevuti
char* pelemento = NULL;
char* pProssimoElemento = NULL;
char Dato[3];

void setup(){
    pinMode(LUCE,OUTPUT); //Utilizzato per accendere luce in caso di visibilità bassa
    Serial.begin(2400);
}

void loop(){
    if (Serial.available()>0) { //inizio a ricevere i dati sulla seriale
        
       while (Serial.available()>0){
              Lettura_Seriale = Serial.read();
              } // Ho ricevuto tutti i dati inviati

       // Vado a recuperare il primo dato ricevuto di Lettura_Seriale
       pelemento = strtok_r(Lettura_Seriale,Separatore,&pProssimoElemento);
       strcpy(Dato[0],pElemento);
       //Vado a recuperare anche gli altri dati

       for (i=1; i<3; i++){
           pelemento = strtok_r(NULL,elementoSeparatore,&pProssimoElemento);
           strcpy(Dato[i],pElemento);
           }
       Serial.println("Visibilità: ");
       Serial.println("Datp[2]);
       Visibilita = atoi(Dato[2]); // ho recuperato solamente il 2 elemento e traformato in intero

       if( Visibilita <= Soglia_Visibilita){
          lettura_ok = 0;
          LUCE_ON = 1 ;
          }
       else {
             if (lettura_ok < 5){
                 lettura_ok++;
                 LUCE_ON = 1;
                 }
             else{
                  LUCE_ON = 0;
                  }
             }
    }// chiusura dell if(Serial.Available()>0)
    
    // Accensione o meno del LED
    if (LUCE_ON == 1){
        ACCENSIONE_LUCE();
        }
    else{
        SPEGNI_LUCE();
        }

Più che altro mi serve capire se ho fatto bene nel prendere solamente la seconda parte del dato inviato
A presto ragazzi