Ver Mensaje Individual
  #5  
Antiguo 09-01-2018
tsk tsk is offline
Miembro
 
Registrado: dic 2017
Posts: 52
Reputación: 7
tsk Va por buen camino
Gracias por el tip, incluso agregué al final dos vídeos. Saludos
---------------------------------------------------------------------

Hay que tener en cuenta que estas trabajando con el puerto serie a 115200bps

Código:
    Serial.begin(115200);
El significado de esto es que el tiempo de bit será de aproximadamente 8.7us. Si consideramos que el formato es de un bit de inicio, 8 bits de datos más un bit de paro, tendremos un caracter en el buffer del UART del Microcontrolador cada 87us.

Luz_ON equivale a 5.22ms y Luz_OFF a 6.09ms

Código:
    while (Serial.available() > 0)
    {
        caracter = Serial.read();
        comando.concat(caracter);
        delay(10);
    }
Con ese while está bloqueando el sistema hasta que todo el comando sea recibido. No existe absolutamente ningún indicio de cuando tengo un comando válido, además de considerar que todos somos buenos chicos que nunca vamos a enviar datos de forma continua que llene la memoria RAM y/o que pueda ocasionar perdida de datos y que el sistema quede bloqueado hasta que me decida a parar mi ataque DoS ya que la única esperanza para salir de ese bloque es que pare de transmitir.

Luego llegamos a ese delay de 10ms. A pesar de poder recibir un caracter cada 87us tenemos que esperar un total de 60 a 70 ms para recibir toda la cadena que compone un comando. Esto también puede ocasionar perdida de datos y además podemos ocasionar un OverRun en el Hardware U(S)ART.

Reproduje tu código para mostrar a lo que me refiero



Envío 1024 bytes más "\\r\\n" de los cauales se pierden 954 bytes

En cambio, si lo hacemos con

Código:
  if(Serial.available()>0)
  {
    caracter = Serial.read();
    if(caracter == '\n')
    {
      Serial.println(comando.length());
      Serial.println(comando);
      comando = "";
    } else {
      comando.concat(caracter);
    }
  }
[/IMG]

Otro aspecto, envuelve el uso de la función loop. Si metes todo en esa función y si tienes retardos considerables, aun con el código que muestro arriba vas a tener algunos problemas de perdida de datos. Podríamos pensar en usar la función serialEvent, pero no todo es lo que parece. Esta función se llama después de llamar la función loop, así que cualquier retardo dentro de la función loop va a impactar el momento exacto en el que podemos procesar los datos entrantes.

Arduino, internamente maneja una interrupción en la recepción que manda cada caracter recibido a un buffer de 63 bytes, la solución sería definir nosotros esa interrupción, pero si no nos queremos salir de las funciones que arduino nos provee, entonces debemos aprender a trabajar con lo que nos ofrece.

Por lo pronto si en estos momentos le agregara un retardo de 500ms para hacer parpadear un led, enfrentaríamos los mismos problemas de posible perdidas de datos.

Código:
    const uint8_t Led=13;
    String comando;
    boolean stringComplete = false;

    void setup() {
        // put your setup code here, to run once:

        pinMode(Led, OUTPUT);
        Serial.begin(115200);
    }

    void loop() {
      // put your main code here, to run repeatedly:
        digitalWrite(Led,!digitalRead(Led));
        delay(500);
        if(stringComplete)
        {
            Serial.println(comando.length());
            Serial.println(comando);
            comando = "";
            stringComplete = false;
        }
    }

    void serialEvent(){
        while(Serial.available())
        {
            char c = Serial.read();
            comando.concat(c);
            if(c == '\n'){
                stringComplete = true;
            }
        }
    }
Incluso podemos terminar con un sistema que no responde en periodos más largos de los 500ms, previstos, cuando usamos cadenas largas.



En esta última imagen se percibe que hay perdida de datos ya que los últimos debería de recibir los 1026 bytes, pero las perdidas pueden ser variables, además de que el U(S)ART deja de responder si el tamaño de la cadena que le llega es mayor a los 63 bytes del buffer de recepción. De este estado sale cuando introducimos una cadena que sea menor a 63 bytes, pero nos enfrentamos a la penosa perdida de datos.

Aunque todo no esta perdido, ya que podemos hacer uso de la función micros de la siguiente forma para poder tener nuestro retardo de 500ms (aproximadamente)

Código:
    const uint8_t Led=13;
    String comando;
    boolean stringComplete = false;
    unsigned long c_time = 0;
    unsigned long t_delay = 500000;
    void setup() {
        // put your setup code here, to run once:

        pinMode(Led, OUTPUT);
        Serial.begin(115200);
        c_time = micros();
    }

    void loop() {
        // put your main code here, to run repeatedly:
        if(micros() - c_time >= t_delay)
        {
            digitalWrite(Led,!digitalRead(Led));
            c_time = micros();
        }
        if(stringComplete)
        {
            Serial.println(comando.length());
            Serial.println(comando);
            comando = "";
            stringComplete = false;
        }
    }

    void serialEvent(){
        while(Serial.available())
        {
            char c = Serial.read();
            comando.concat(c);
            if(c == '\n'){
                stringComplete = true;
            }
        }
    }


No soluciona todo ya que ahora nos enfrentamos al overflow de la variable que almacena los micro segundos que han pasado desde que el Arduino fue encendido, pero el código de arriba no bloquea el funcionamiento de otras secciones del sistema.

A partir de esto ya se pude vislumbrar una mejor forma de desarrollar un sistema embebido que sea más confiable ya que tomamos conciencia de lo que puede ocasionar nuestras decisiones de diseño.

Anexo dos vídeos donde se puede percibir de forma clara el problema que se ocasiona. Para las pruebas estoy enviando 40000 bytes al inicio con 0 ms entre byte y después 1 ms entre byte. En el primer vídeo vemos como el parpadeo del led se detiene mientras espera a que termine de enviar los datos y además se puede apreciar perdida de datos.



En este segundo vídeo, la perdida de datos es debida a que no existe más RAM, pero no bloquea el parpadeo del led, así que ya tenemos la ventaja que el sistema no se va a bloquear mientras espera que todos los datos sean recibidos.



Cabe aclarar que siempre hay mejores formas, pero con esto ya podemos ir un paso adelante.

Última edición por Casimiro Notevi fecha: 09-01-2018 a las 11:11:21.
Responder Con Cita