Go Down

Topic: Lettura seriale con array di char (Read 1 time) previous topic - next topic

davix10

Salve a tutti, non riesco a trovare il modo di leggere da seriale ogni singolo carattere che ricevo dal modulo SIM800L.
Ogni volta che scrivo "AT" vorrei leggere la risposta "OK" o "ERROR" e pensavo di dover mettere la risposta in un array di caratteri e leggere i primi due caratteri ma non riesco a farlo.

Code: [Select]
if (serialSIM800.available()) {
    Serial.write(serialSIM800.read());
    char response[200];
    for (int i = 0 ; Serial.available() > 0 && i < 200 ; i++) {
      response[i++] = Serial.read();
    }
}


Cercando su google ho trovato questo ma non mi funziona

Code: [Select]
if (strstr(response, "OK")) {
    /*Do your code to handle OK response*/
      digitalWrite(LED_PIN, HIGH);
    }
    else if (strstr(response, "ERROR")) {
    /*Do your code to handle ERROR response*/
    }
    else {
    /* You got some other response*/
    }



Grazie in anticipo

gpb01

#1
Oct 05, 2016, 03:27 pm Last Edit: Oct 05, 2016, 03:28 pm by gpb01
L'idea è corretta, l'implementazione è sbagliata ...

1. metti 0x00 nel primo elemento dell'array per indicare che è vuoto
2. fai un ciclo in cui ti chiede se qualche cosa è disponibile sulla seriale (available())
3. leggi il carattere e salvalo nell'array
4. se il carattere è il terminatore (credo sia CR), metti nell'array 0x00 per indiocare che la stringa è finita

solo a questo punto puoi trattarla e cercare ciò che ti interessa.

Guglielmo

P.S.: Per avere tutte le informazioni sul formato dei messaggi e come sono terminati, devi guardare il manuale dei comandi AT di quel SimCOM.
Search is Your friend ... or I am Your enemy !

davix10

Ho provato a fare così e funziona ma non so se è il metodo migliore/giusto.
Cosa ne pensi?

Code: [Select]
int byteAvailable = serialSIM800.available();
    String str = "";
 
    str = serialSIM800.readString();
   // Serial.println(str);
   
    int str_len = str.length() + 1;

    // Prepare the character array (the buffer)
    char char_array[str_len];

    // Copy it over
    str = str.substring(str.indexOf('\n') + 1, str.length());

   
    //Serial.println(str);
   
    str.toCharArray(char_array, str_len);


    Serial.write(char_array[0]);
    Serial.write(char_array[1]);
    if (str[0] == 'O' && str[1] == 'K')
    {
      digitalWrite(LED_PIN, HIGH);
      delay(10);
    }

    if (str[0] == 'E' && str[1] == 'R')
    {
      digitalWrite(LED_PIN, LOW);
      delay(10);
    }

gpb01

#3
Oct 05, 2016, 04:58 pm Last Edit: Oct 05, 2016, 05:00 pm by gpb01
Non capisco l'uso della classe String ... o usi gli array di char (ovvero le strighe classiche del 'C') oppure usi la classe String del C++ ... mischiare le due per fare cosa ? Crearsi problemi ?

Giusto una piccola nota ...
... ti rammento 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 !!!   :smiley-evil:

Guglielmo
Search is Your friend ... or I am Your enemy !

davix10

Grazie per il consiglio!
Purtroppo non sono riuscito a trovare una soluzione usando solo char.
Non riesco a capire quali controlli dover fare per riuscire a localizzare la risposta "OK"

gpb01

Purtroppo non sono riuscito a trovare una soluzione usando solo char.
Non riesco a capire quali controlli dover fare per riuscire a localizzare la risposta "OK"
Impara ad usare le funzioni che trovi nella libreria standard (... che, oltretutto, è automaticamente inclusa dal IDE) AVR libc ed, in particolare, quanto è in <string.h> ... vedrai che tovi tutto quello che ti serve ;)

Guglielmo
Search is Your friend ... or I am Your enemy !

davix10

C'è qualche esempio di lettura da moduli GSM per capire meglio come farlo funzionare?

gpb01

#7
Oct 06, 2016, 11:19 am Last Edit: Oct 06, 2016, 11:19 am by gpb01
C'è qualche esempio di lettura da moduli GSM per capire meglio come farlo funzionare?
Non so, magari in qualche libreria GSM ... ::)

Comunque guadati la strcmp() e la strtok() ... ;)

Guglielmo
Search is Your friend ... or I am Your enemy !

SukkoPera

Nel primo codice che hai postato ci sono parecchi problemi:
1. Confondi serialSIM800 e Serial, tanto che arrivi a leggere da quest'ultima.
2. Incrementi i 2 volte ogni ciclo.
3. Ti aspetti sempre di leggere 200 caratteri (a meno del Serial.available() che non ha senso). Quando il modulo invia "OK\r\n" ne ricevi solo 4. Per cui devi smettere di leggere, oltre che quando il buffer è pieno, anche quando hai ricevuto un terminatore di linea (verifica che sia \r\n), e quindi processare quel che hai ricevuto.
Make your Sega MegaDrive/Genesis region-free with Arduino! https://goo.gl/X7zBcq

Guida rapida a ESP8266: https://goo.gl/kzh62E

davix10

Nel primo codice che hai postato ci sono parecchi problemi:
1. Confondi serialSIM800 e Serial, tanto che arrivi a leggere da quest'ultima.
2. Incrementi i 2 volte ogni ciclo.
3. Ti aspetti sempre di leggere 200 caratteri (a meno del Serial.available() che non ha senso). Quando il modulo invia "OK\r\n" ne ricevi solo 4. Per cui devi smettere di leggere, oltre che quando il buffer è pieno, anche quando hai ricevuto un terminatore di linea (verifica che sia \r\n), e quindi processare quel che hai ricevuto.
Ho provato a fare qualche modifica ma non riesco a capire perchè tutta la risposta (compresa di echo) finisce completamente nella variabile "response[0]".

Non dovrebbe finire ogni carattere in una posizione diversa?

gpb01

#10
Oct 06, 2016, 12:34 pm Last Edit: Oct 06, 2016, 12:34 pm by gpb01
Non dovrebbe finire ogni carattere in una posizione diversa?
Incrementi l'indice del vettore per ogni carattere ricevuto ?

Metti lo 0x00 alla fine ?

Guglielmo
Search is Your friend ... or I am Your enemy !

davix10

Incrementi l'indice del vettore per ogni carattere ricevuto ?

Metti lo 0x00 alla fine ?

Guglielmo
Code: [Select]
char ch = Serial.read();

    if ( ch == '\r')
    {
      response[index] = 0;
     
    }
    else
      response[index++] = ch;
    Serial.write(response[0]);



Ho provato a fare così

SukkoPera

#12
Oct 06, 2016, 12:54 pm Last Edit: Oct 06, 2016, 12:56 pm by SukkoPera
Io riformulo il primo codice che hai postato:

Code: [Select]
#define BUFLEN 200

char response[BUFLEN] = {'\0'};
byte i = 0;
do {
  if (serialSIM800.available()) {
    char c = serialSIM800.read();
    Serial.write(c);
    response[i++] = c;
    response[i] = '\0';
  }
} while (i < BUFLEN - 1 && response[i] != '\n');


(Non testato)
Make your Sega MegaDrive/Genesis region-free with Arduino! https://goo.gl/X7zBcq

Guida rapida a ESP8266: https://goo.gl/kzh62E

davix10

Io riformulo il primo codice che hai postato:

Code: [Select]
#define BUFLEN 200

char response[BUFLEN] = {'\0'};
byte i = 0;
do {
  if (serialSIM800.available()) {
    char c = serialSIM800.read();
    Serial.write(c);
    response[i++] = c;
    response[i] = '\0';
  }
} while (i < BUFLEN - 1 && response[i] != '\n');


(Non testato)
Grazie per l'esempio ma non capisco un paio di cose.

1) Perchè "i" è una variabile byte e non int?
2) Dopo il ciclo do while se io volessi vedere quale carattere c'è in posizione 1 basta che io scriva Serial.write(response[1]);
Quindi in teoria dovrebbe esserci il carattere 'K' giusto?

SukkoPera

Perché un singolo byte è sufficiente per contare da 0 a 255. Puoi usare anche un int ma in questo caso è "esagerato".

Il resto è corretto.
Make your Sega MegaDrive/Genesis region-free with Arduino! https://goo.gl/X7zBcq

Guida rapida a ESP8266: https://goo.gl/kzh62E

Go Up