Rutina para arduino para recibir cadenas completas por el puerto serie

Hola Compañeros, quizás lo que expongo sea una cosa muy simple, pero resulta que con arduino tengo nula experiencia y estoy desarrollando una aplicación que requiere poder recibir instrucciones por medio del puerto serial y ejecutar ciertas rutinas o procedimientos.

Espero poder explanar más la situación:

De manera general el programa principal en el arduino estará en un estado de espera “escuchando” lo que entra en el puerto serie y en cuanto reciba un string muy particular “+IPD”; la aplicación deberá entrar en un subroceso que también estará escuchando comandos provenientes del puerto serie que son finalizados por el retorno de carro o return, o dicho coloquialmente en cada línea de texto podrá contener o no, un comando y que el fin de dicha línea será al recibir el carácter de retorno de carro, cosa muy obvia como podrán ver. Por ultimo al estar dentro de este subroceso si al recibir un “OK” con su debida retorno de carro saldremos de la rutina para regresar al estado inicial (esperar un nuevo “+IPD”).

Dejo parte de lo que he escrito y funciona muy bien, solo que siento que estoy gastando mucho código y por tanto memoria del microcontrolador, por estas razones vengo a buscar un poco de ilustración por parte de ustedes y me pudieran comentar si consideran correcta la forma como voy afrontando el desarrollando o si existe un comando, instrucción o libreria particular dentro del lenguaje del arduino que yo no conozca.

Código:
String Cadena; //Variable que contendra el contenido de cada linea
boolean prueba = true;//Bandera prueba que sirve en la rutina Recibe
                      //para saber que se deben seguir recibiendo datos o no

void setup() {
  
  Serial.begin(9600);
pinMode(2, OUTPUT);
pinMode(3, OUTPUT);
pinMode(4, OUTPUT);
pinMode(5, OUTPUT);
pinMode(6, OUTPUT);
pinMode(7, OUTPUT);
pinMode(8, OUTPUT);
pinMode(9, OUTPUT);

}

void loop() {  
  
 Serial.println("Esperando +IPD"); 
  while (!Serial.find("+IPD")){//ESPERAMOS PETICION DE SERVICIO "+IPD"
		digitalWrite(13, HIGH);
		 	 delay(100);              
	  	digitalWrite(13, LOW);    
	  		delay(100);
	}		
 
 Recibe();   
 
}


void Recibe(){//Rutina que sirve para analizar los datos recibidos por el puerto serie y aplicar "comandos" reconocidos
  prueba=true;// se coloca como verdadera la bandera
  
 /*Se recibiran datos desde el puerto serie hasta que dentro del while
 se decida dejar de hacerlo; cambiando la bandera de la variable "prueba" a falso */
 
  
  while(prueba==true){//=================================   
       
       while (Serial.available() > 0)
       {//*************************************
        char recibido = Serial.read();
        Cadena += recibido; 
        // procesamos la cadena cuando se recibe el caracter de "enter"
        if (recibido == '\r')
        {//-------------------------------------------------
            Serial.print("Se recibio: ");//estas dos lineas Sirven como debug
            Serial.println(Cadena);

            //A partir de Aqui colocamos el proceso que se quiera a la Cadena recibida al termino de cada "linea" como se muestra en el siguiente IF
     
            if(Cadena == "prende\r"){ // No debe olvidarse anexar "\r" al final para que la comparacion sea completa con la linea recibida.
              Serial.println("Enciende LED");
              digitalWrite(13, HIGH);
            }
            if(Cadena == "apaga\r"){ // No debe olvidarse anexar "\r" al final para que la comparacion sea completa con la linea recibida.
              Serial.println("Apaga LED");
              digitalWrite(13, LOW);
            }
                      


            if(Cadena == "show1\r"){ // No debe olvidarse anexar "\r" al final para que la comparacion sea completa con la linea recibida.
              Serial.println("Primer Show de Leds");
              for (int n=2; n<10; n++){
                            digitalWrite(n, HIGH);
                           delay(100);}               
          for (int n=9; n>1; n--){
                            digitalWrite(n, LOW);
                           delay(100);}  
          }
            
            if(Cadena == "show2\r"){ // No debe olvidarse anexar "\r" al final para que la comparacion sea completa con la linea recibida.
              Serial.println("Segundo Show de Leds");
                             
          for (int n=9; n>1; n--){
                            digitalWrite(n, HIGH);
                           delay(100);} 
                          
          for (int n=2; n<10; n++){
                            digitalWrite(n, LOW);
                           delay(100);} 
          }            
            
            if(Cadena == "OK\r"){ // con el comando OK salimos de la rutina.
              Serial.println("Salida");
              prueba=false;// cambiamos bandera de prueba a falsa; con lo que se dara por terminada la recepcion de datos en el puerto serie
            }   

Cadena = "";// Dejamos cadena en NULL para que en la proxima espera de caracteres este "vacio" su buffer y asi evitar que se incremente la variable de manera infinita
          }//------------------------------------------------------
      }//******************************************
}//===========================================================
}//    Fin de rutina Recibe

Este mal presentimiento que tengo es porque en otros lenguajes o compiladores he usado algunas funciones que me resuelven en una o dos líneas el poder recibir una cadena de caracteres de manera sencilla.

Los “comandos” que se ejecutan en base a los if´s como: “enciende” “apaga” “show1” “show2”, son meramente inventados para probar la rutina y en realidad tengo un manual del equipo con los verdaderos comandos donde estará conectado el arduino, pero eso es harina de otro costal y solo quería precisar qué lo que me interesa por el momento es lograr una rutina más eficiente.

Si alguien se toma el tiempo de probar mi rutina, les comento que en el “monitor serie” del IDE de arduino deberán especificar que solo mande el retorno de carro al enviar la línea para que funcione la rutina (tal como será mi caso).

De antemano les agradezco y disculpen la poca experiencia con arduino.

Reciban un cordial saludos
 
Yo lo veo bien.

Si, por ejemplo, todos los comandos se diferenciaran en algún carácter concreto, se podría reducir los if() en cascada con un switch/case. En tu caso, sería tomar el penúltimo carácter, ya que es distinto en todos los comandos.

Otra mejora sería no usar objetos String y usa solo cadenas de caracteres.

El código sería más eficiente en cuanto a consumo de memoria, pero quizás sería más oscuro de entender -sobre todo la parte del switch()-.

Otra forma de hacerlo sería meter todos los comandos en un vector de cadenas de caracteres. Cuando se reciba un '\r', hacemos un bucle por ese vector y comparamos lo recibido con todos los comandos. Si se encuentra, eso nos da un número entero -el índice dentro del vector donde están los comandos-. Ese número nos puede servir de índice dentro de otro vector, pero esta vez serán punteros a funciones, cada una de las cuales será la que ejecute el comando.

De esto último hemos hablado hace unas semanas. El código queda mucho más eficiente, pero quizás no muy claro para los que empiezan.
 
Aprecio mucho sus comentarios, en verdad sirven mucho y me intereso la idea de crear la bifurcación por su valor numérico o "checksum" que deberé crear previamente por cada comando que sera valido o reconocido.

Gracias
 
Última edición:
Atrás
Arriba