Serial1 Arduino mega

hola buenos tardes. estoy usando un arduino mega en conjunto con un modulo Wisol Sigfox y un modulo xbee el modulo sigfox lo tengo anclado al puerto Serial y el xbee al puerto Serial1 me pasa algo que no puedo decifrar. al momento de splitear los datos que quiero recibir me los hace un determinado tiempo y ya no hace nada mas. lo cual me tiene desconcertado porque se supone que va a estar recibiendo 24/7;

  if(Serial1.available()>0){
    buff[Serial1.readBytesUntil('#',buff, sizeof(buff))]=0;
    cadRX=buff;
        

    do{
      posfin= cadRX.indexOf("/",posini);
      valor=cadRX.substring(posini,posfin);
      posini=posfin+1;
      datos_RX[i]=valor.toInt();

      i++;
      
      } while (posfin>=0);
      Serial.println(datos_RX[0]);
    Serial.println(datos_RX[1]);
   }

esa es la parte donde recibo datos y los divido para a su vez guardarlo en su determinada variable.

y estos son los datos totales que me llegan y no mas

No te lo podría garantizar, pero mi sospecha es que quizá se cuelga por falta de memoria. En teoría esto no debería suceder porque los objetos String se supone que liberan espacio cuando son declarados localmente y la función declaradora termina.

Había leído que a veces se le achacan males al objeto String; por lo tanto, aquí te dejo un equivalente sin usarlos:

  if(Serial1.available()>0){
    buff[Serial1.readBytesUntil('#',buff, sizeof(buff))]=0;
        
    char* parte = strtok(buff, "/");

    while (parte != NULL) {
      datos_RX[i++] = atoi(parte);
      parte = strtok(NULL, "/");
    }

    Serial.println(datos_RX[0]);
    Serial.println(datos_RX[1]);
   }

Segunda sospecha: ¿el contador i se llega a reiniciar?

Si nunca se llega a reinciar, no me sorprendería que el programa se cuelgue.

Coincido con Lucario448, estás usando String para algo que puedes resolver fácilmente con char *. Y siempre que puedas, en microcontroladores, evita las String. Pueden llegar a consumir demasiada memoria.

También a mi me surge la duda de si inicializas la variable

i

. También falta poder ver cuándo y cómo inicializas posini.

Ayudaría también ver cómo has declarado las variables. Vamos, que sin todo el código (o buena parte de él) es más difícil saber qué puede estar pasando.

Aún así, hay una cosa que “salta a la vista” en la línea:

    buff[Serial1.readBytesUntil('#',buff, sizeof(buff))]=0;

Debería de ser:

    buff[Serial1.readBytesUntil('#',buff, sizeof(buff) - 1)]=0;

E incrementar en uno el tamaño de buff en su definición.

¿Por qué? Pues porque, tal como lo tienes, readBytesUntil pone en buff los bytes que lee del puerto serie hasta que se encuentra un ‘#’ o ha leído sizeof(buff) bytes sin encontrar lo que busca. Hasta ahí todo bien, porque readBytesUntil no te va a leer más bytes de los que cabe en buff, como mucho lo va a llenar si no encuentra antes lo que busca. El “problema” lo tienes después, con la parte buff=0. Esto está para que “la cadena” termine con un carácter nulo (el valor cero). Para ello lo que hacer es usar como índice el valor retornado por la función readBytesUntil y ahí poner el cero. Por ejemplo, si los caracteres que lee con abcd#, mete en buff abcd (el carácter buscado se descarta) y retorna un 4, que es el número de bytes que ha metido en buff. Luego se “ejecutará” el equivalente a buff[4]=0. Pone un cero en la quinta posición de buff (el índice empieza en cero). Supongamos, ya que esa parte del código no la has puesto, que has definido buff como:

char buff[10];

Eso significa que hemos reservado 10 bytes para buff, por lo tanto ese es su tamaño, así que el valor de sizeof(buff) será 10. Así que readBytesUntil leerá 10 bytes si no encuentra lo que busca. Entonces ejecutará lo equivalente a buff[10]=0. Esto pondrá a cero el undécimo byte de buff. ¿Cómo? ¿El undécimo byte? ¿Pero si sólo tiene diez? Pues sí, el undécimo. Ya sé que sólo tiene 10, pero el C++ no verifica que sólo tiene 10 y si le dicen que lo ponga en el 11, él lo pone sin hacer comprobaciones (por eso es tan rápido, porque no pierde el tiempo con ciertas comprobaciones).

Si esto pasa, que escribe un cero fuera del rango de buff, seguramente está “invadiendo” el espacio de memoria de otra variable, y si esa otra variable tiene un valor distinto de cero en esa posición de memoria… te está corrompiendo el valor de esa variable. Y dependiendo de qué variable sea, y qué hagas con ella, puede ser que ocurra un “desastre” (puede o casi seguro). Pero eso sólo te pasará si en “la búsqueda” del ‘#’ éste no está y por lo tanto no lo encuentra. ¿Solución? Limitar la búsqueda a un byte menos de lo que cabe en buff. Por eso le resto uno al sizeof(buff). Y si es necesario se agranda en uno el tamaño de buff, para que quepa lo mismo que hasta ahora, más el terminador de cadena.

Pero ahí no acaba la cosa. Tienes otra “bomba” en potencia un poco más adelante. Con la

i

del do while. En este caso ocurre todo lo contrario, el problema no viene si no lo encuentra, viene si lo encuentra de más. ¿Qué pasa si hay un “/” de más (o dos, o tres… de más)? Pues que

i

llegará a valer 2 (… y 3, 4, etc, dependiendo de cuántos encuentre de más). Y por lo tanto escribirá en datos_RX[2] (… y datos_RX[3], datos_RX[4]…). No sé con qué tamaño has declarado datos_RX, pero si es de dos elementos (o aunque sea de más, existe la posibilidad de salirte de su rango) se estará escribiendo valores fuera de él. Recuerda que C++ no verifica si te sales del rango. Y recuerda que esto significa que se está “corrompiendo” otras variables. Y esto puede llevar a que haga “cosas raras”, funcione mal o incluso “colgar” el programa. Para evitar esto, en el caso de que datos_RX fuera de dos elementos, yo lo habría hecho con un for tal que así:

    for (i = 0, posini = 0, posfin = 0; (i < 2) && (posfin >= 0); i++) {
      posfin= cadRX.indexOf("/",posini);
      valor=cadRX.substring(posini,posfin);
      posini=posfin+1;
      datos_RX[i]=valor.toInt();
    }

No descarto que la causa de tu problema sea que en algún momento te lleguan datos que se salgan de “lo previsto” y que se esté saliendo de rango a la hora de asignar los datos en los array. Aunque esto no fuera así, te sugiero que hagas los cambios que te he dicho para que sea “más robusto” a los fallos de transmisión.

IgnoranteAbsoluto: Aún así, hay una cosa que "salta a la vista" en la línea:

    buff[Serial1.readBytesUntil('#',buff, sizeof(buff))]=0;

Debería de ser:

    buff[Serial1.readBytesUntil('#',buff, sizeof(buff) - 1)]=0;

Esa fue una sugerencia que le había dado varios hilos atrás, pero por alguna razón no había contemplado la resta que ahora sí lo haría...

Lucario448: pero por alguna razón no había contemplado la resta que ahora sí lo haría...

Seguramente fue por despiste. A mi me suele ocurrir que se me olvida tener en cuenta el reservar un carácter para el terminador de cadena y tengo muy claro que eso es peligroso.

No hace mucho propusiste la misma solución en otro post y ahí sí que le restaste uno.