Lettura seriale con array di char

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.

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

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

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.

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

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);
    }

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 !!! :smiling_imp:

Guglielmo

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"

davix10:
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 :wink:

Guglielmo

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

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

Non so, magari in qualche libreria GSM ... ::slight_smile:

Comunque guadati la strcmp() e la strtok() ... :wink:

Guglielmo

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.

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.

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?

davix10:
Non dovrebbe finire ogni carattere in una posizione diversa?

Incrementi l'indice del vettore per ogni carattere ricevuto ?

Metti lo 0x00 alla fine ?

Guglielmo

gpb01:
Incrementi l'indice del vettore per ogni carattere ricevuto ?

Metti lo 0x00 alla fine ?

Guglielmo

char ch = Serial.read();

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

Ho provato a fare così

Io riformulo il primo codice che hai postato:

#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)

SukkoPera:
Io riformulo il primo codice che hai postato:

#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?

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

Il resto è corretto.

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.

In questo momento il mio loop() è questo:

void loop() {
  serialSIM800.write("AT\r\n");
  risposta();
}

void risposta() {
  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] != '\r');
}

Così però funziona solo al primo giro e anche aggiungendo il comando Serial.write(response[1]); non mi stampa nessun valore.

Posta lo sketch intero.

SukkoPera:
Posta lo sketch intero.

#include <SoftwareSerial.h>

//SIM800 TX is connected to Arduino D8
#define SIM800_TX_PIN 8

//SIM800 RX is connected to Arduino D7
#define SIM800_RX_PIN 7

#define LED_PIN 2
#define BUFLEN 200
//Create software serial object to communicate with SIM800
SoftwareSerial serialSIM800(SIM800_TX_PIN, SIM800_RX_PIN);
char lastCharRead[16];
char firstRead;
int index;
String content = "";
String readStrings;
char string[32];
char byteRead;
char response[200];
int indexByteMessaggio;
byte inByte;
byte messaggio[] = {
  0, 0, 0, 0, 0, 0, 0, 0
};
void setup() {
  //Begin serial comunication with Arduino and Arduino IDE (Serial Monitor)
  Serial.begin(9600);
  while (!Serial);

  //Being serial communication witj Arduino and SIM800
  serialSIM800.begin(9600);
  delay(1000);
  pinMode(LED_PIN, OUTPUT);

  Serial.println("Setup Complete!");
}

void loop() {
  serialSIM800.write("AT\r\n");
  risposta();
}

void risposta() {
  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] != '\r');
}

Cosa vuol dire che "funziona solo al primo giro"?

SukkoPera:
Cosa vuol dire che "funziona solo al primo giro"?

Il ciclo while è infinito quindi non esco mai dal ciclo.