Interferencia del Serial Port

Hoola!

Soy muy nueva con Arduino y estoy realizando un proyecto conectando Arduino vía WiFi con mi PC (donde los proceso con LabVIEW) para el intercambio de paquetes UDP con un delay de 10ms.
El intercambio se realiza sin problemas, con la temporización adecuada y he comprobado que el contenido de los paquetes es el deseado.

Sin embargo, mientras que con el Serial Monitor cerrado se intercambian muchísimos paquetes, al abrirlo, la conexión solo dura un par de rondas send-receive.

Me estoy volviendo un poco loca buscando posibles soluciones y supongo que puede ser debido a que hay interferencia entre puertos, pero... alguna ayuda sobre como solucionarlo??

Muchiiiiiisimas gracias a cualquier aportacion :slight_smile:

Bueno, evidentemente esos 10 mseg se ven comprometidos al disponer del monitor Serie.
No se como es tu programa, pero si por ejemplo tuvieras un timer dedicado a sostener la comunicación WiFI cada 10 mseg tal vez no comprometieras el flujo de datos al abrir el puerto Serie.
El puerto serie encontraría la manera usando su buffer para lidiar con el momento en que la interrupción envia datos/recibe datos por WIFI.
Es una idea.

Porque no pones los códigos en este caso ambos. (los códigos van con etiquetas, si no sabes cómo, mira otros hilos y lee las normas del foro).
Tambien explica que hardware estas usando.

Muchas gracias por tu respuesta

No entiendo a que te refieres cuando dices que ponga un timer "dedicado a sostener la comunicacion WiFi".

Pongo aquí debajo el código que he usado:

#include <SPI.h>
#include <WiFi101.h>
#include <WiFiUdp.h>

int status = WL_IDLE_STATUS;
int cont = 0;
int cont2 = 0;
int j = 0;
int k = 0;
int i = 0;
int n = 1;
unsigned long totalTime = 0;
unsigned long startTime = 0;
unsigned long sentPacketTime = 0;
unsigned long receptionTime = 0;
unsigned long currentTime = 0;
unsigned long exchangeTime = 0;

char ssid[] = "networkID"; //My network ID
char pass[] = "password";

unsigned int localPort = 2000; //port to listen on
IPAddress timeServer(192, 168, 10, 40); // PC IP Address
char packetBuffer[255] = {0}; //buffer to hold incoming and outgoing packets
char payload[50];

//UDP instance to send and receive packets
WiFiUDP udp;

void setup() {
  //Configure the pins for Adafruit ATWINC1500 Feather
  WiFi.setPins(8, 7, 4, 2);
  //Initialize serial and wait for port to open
  Serial.begin(9600);

  //Try to connect to WiFi network, keeps looping while the status is not connected
  while (status != WL_CONNECTED) {
    Serial.print("Trying to connect to SSID: ");
    Serial.println(ssid);
    status = WiFi.begin(ssid, pass);
    //Wait 3 seconds for connection process to complete
    delay(3000);
  }

  //Exit the loop when connected, so we print on screen the IP assigned
  Serial.println("Connected to WiFi");
  Serial.println(ssid);
  IPAddress ip = WiFi.localIP();
  Serial.println("IP Address: ");
  Serial.println(ip);
  Serial.println("\nStarting connection to server...");

  //If you get a connection, you can start listening to the incoming packets
  udp.begin(localPort);
  startTime = millis(); //returns the millisenconds since the arduino began running the program
}

void loop() {
  
  int num1 = random(1, 10);
  int num2 = random(1, 10);
  int num3 = random(1, 10);
  snprintf(payload, sizeof(payload), "%d%d%d", num1, num2, num3);

  if (i == 0) {
    sendPacket(timeServer); //sends a packet to a time server
    sentPacketTime = millis();
    cont++;
    j++;
    Serial.print("SENT PACKET: ");
    Serial.println(cont);
    Serial.print("Data content in the packet: ");
    Serial.println(payload);
    Serial.print("Packet sent in (ms): ");
    Serial.println(sentPacketTime);
    i++;
  }

  //Read the incoming packets
  int packetSize = udp.parsePacket(); //parsePacket detects the presence of a packet and reports the size

  if (packetSize)
  {
    //I save the time of arrival of each packet, to calculate RTT
    unsigned long receptionTime = millis();
    cont2++;
    k++;
    Serial.print("\nRECEIVED PACKET ");
    Serial.print(cont2);
    Serial.print(" of size ");
    Serial.println(packetSize);
    Serial.print("from ");
    IPAddress remoteIp = udp.remoteIP();
    Serial.print(remoteIp);
    Serial.print(", port ");
    Serial.println(udp.remotePort());

    Serial.print("Packet received in (ms): ");
    Serial.println(receptionTime);
    unsigned long exchangeTime = receptionTime - sentPacketTime;
    Serial.print("The exchange lasted (ms) [RTT]: ");
    Serial.println(exchangeTime);

    //read the packets in the buffer
    int dataRead = udp.read(packetBuffer, 255);

    //Serial.printf("UDP packet contents %s\n", packetBuffer);
    Serial.print("Data in UDP packet: ");
    Serial.println(packetBuffer);

    /*Serial.print("Data in UDP packet: ");
      Serial.println(dataRead);
      //Print the content of the received UDP packet
      Serial.readBytesUntil('\n', packetBuffer, 255);
      int data = atoi(packetBuffer);
      DEBUG(data);*/

    //Different time depending of the exchange time
    if (exchangeTime < 10) {
      do {
        currentTime = millis();
        n=1;
      } while (currentTime != (sentPacketTime + 10));
    }
    else{
      n = (exchangeTime/10)+1; //Divide RTT and force it to send it in the next 10 multiple
      do {
        currentTime = millis();
      } while (currentTime != (sentPacketTime + (n*10)));
    }

    if (millis() == (sentPacketTime + (n*10))) {
      //Everytime I get a packet from the PC I can send another one
      sentPacketTime = millis();
      sendPacket(timeServer);
      cont++;
      j++;
      Serial.print("\n\n\nSENT PACKET: ");
      Serial.println(cont);
      Serial.print("Data content in the packet: ");
      Serial.println(payload);
      Serial.print("Packet sent in (ms): ");
      Serial.println(sentPacketTime);
      Serial.print("Time between the last packet received and the next one sent: ");
      Serial.println(n*10 - exchangeTime);
    }

    totalTime = sentPacketTime - startTime;
    Serial.print("Time since the first packet (ms): ");
    Serial.println(totalTime);
    Serial.print("\n");

    //I will calculate how many packets I can exchange in 1 second
    if (totalTime > 1000) {
      Serial.println("**********************************************");
      Serial.print("In one second: ");
      Serial.println(j + k - 1);
      Serial.println("Packets sent by Arduino: ");
      Serial.println(j);
      Serial.println("Packets sent by PC: ");
      Serial.println(k - 1);
      Serial.println("**********************************************");
      //I initialize the values again
      totalTime = 0;
      j = 0;
      k = 0;
      startTime = millis();
    }

  }
}

unsigned long sendPacket(IPAddress& address) {
  //Send a reply to the IP that send the packet
  udp.beginPacket(address, 2001);
  udp.write(payload, sizeof(payload));
  udp.endPacket();
}

Muchas gracias :slight_smile:

Un Timer, una interrupcción cada 10 mseg para que haga el servicio de enviar paquetes UDP a la PC que parece ser el elemento restrictivo.

Primero restringe las lineas del monitor serie a las necesarias o al menos coméntalas para comenzar.

Luego explica esto

    //Different time depending of the exchange time
    if (exchangeTime < 10) {
      do {
        currentTime = millis();
        n=1;
      } while (currentTime != (sentPacketTime + 10));
    }
    else{
      n = (exchangeTime/10)+1; //Divide RTT and force it to send it in the next 10 multiple
      do {
        currentTime = millis();
      } while (currentTime != (sentPacketTime + (n*10)));
    }

Esto tiene un coportamiento como si fuera un delay()
hasta que no se cumple alguna de las expresiones lógicas dentro de los while permanecemos ahi.
Mide por favor cuanto tiempo demora en cada caso.
Usando millis o micros.

EDITO: No indicaste tu hardware, tu arduino y la placa WIFI o usas un MKR o un ESP?
Tampoco adjuntaste el archivo Labview.

Hola!

En esas lineas de código lo que hago es que si el paquete tarda menos de 10ms en el intercambio send-receive se envíe el siguiente a los 10ms desde Arduino. Si por el contrario, tarda más, se envía en el siguiente múltiplo de 10. Entiendo que se cumplirá alguna de las dos y entonces será cuando se pueda enviar el siguiente paquete en el intante de tiempo "sentPacketTime" + 10ms (el siguiente) (no se si me he explicado muy allá)

El intercambio de paquetes suele durar unos 4-5ms, por lo que ahí se suele demorar unos 5-6, para cumpliar la condición. En algunos casos (aparentemente aleatorios) tardaba más (unos 15ms o 18) y por eso introduje el else, porque si no, el programa se bloqueaba al nunca cumplirse la siguiente condición.

Estoy usando Adafruit Feather M0 WiFi con ATWINC1500.

Los archivos que no son ino, pde y formato de imagenes deben subirse en .zip como dicen las normas del foro sin superar 2MB

Prueba subir la velocidad del puerto serie de 9600 a 115200. Cambiando la línea:

  Serial.begin(9600);

por:

  Serial.begin(115200);

Y configurando el monitor serie a esa misma velocidad.

IgnoranteAbsoluto, muchas gracias por la sugerencia, pero eso lo probé ya y no funciona :frowning:

No sé si lo he entendido bien y tengo un par de dudas. ¿Pretendes mandar por el puerto serie un mensaje cada 10 milisegundos? ¿Y de qué tamaño (en bytes) es cada uno de esos mensajes?

Lo pregunto porque si se trata de transmitir por el puerto serie “un mensaje” cada 10 milisegundos a 115200 baudios, configurado a 8 bits de datos y uno de parada: en el mejor de los casos se pueden transmitir, de media, un máximo de 128 bytes en cada mensaje.

8 bits de datos y uno de parada significa que para transmitir un byte se necesita enviar 9 bits. Los 115200 baudios significa que como máximo se envían 115200 bits en un segundo, con lo que en ese segundo se transmiten 12800 bytes (115200 / 9). Por lo que en un milisegundo serían 12.8 bytes (12800 / 1000). Así que en 10 milisegundos serían 128 bytes (12.8 * 10).

Los datos que se transmiten vía serie no se envían inmediatamente, sino que se copian en un buffer y se envía un byte tras otro hasta que el buffer se vacíe.

Por lo general el Arduino no se queda esperando a que se termine de enviar un byte para enviar el siguiente, para eso es el buffer, sino que se configura para que se genere una interrupción cada vez que se termina de transmitir un byte (siempre que se trate de un puerto serie “de verdad”, por hardware, y no uno emulado por software).

La transmisión por hardware se realiza entonces “por sí sola”, mientras continúa la ejecución normal del programa. Una vez terminada la transmisión de un byte se genera la interrupción, se “aparca” lo que se estaba haciendo, pone para enviar otro byte (si lo hubiera) y continúa con lo que se estaba haciendo. Vamos, que el enviar los datos que están en el buffer apenas detiene la ejecución del resto del programa.

Repito, cada vez que se quiere enviar algo por el puerto serie, se copia todo al buffer y continúa la ejecución del programa mientras se envía cada byte “de forma autónoma” e interrumpiendo la ejecución brevemente cada vez que se termina de transmitir un byte para “poner” el siguiente a transmitir. ¿Pero qué pasa si tratamos de poner más y más datos en el buffer de transmisión sin darle tiempo a que se transmiten? Pues que el buffer “se llena”. ¿Y si se llena se desborda? Pues no. Si está lleno simplemente “se espera” a que se vacíe para poder copiar los datos al buffer y continuar.

He ahí cuando aparecen los problemas. “Se espera” es que “se espera”. Y no hace otra cosa más que esperar a que se vacíe lo suficiente el buffer para “meter” los nuevos datos y continuar. Por lo que, si está esperando, no continúa con el resto del programa (a no ser que salte alguna interrupción) y se pasa el tiempo sin hacer otra cosa.

Así que supongo que se está llenando el buffer y deteniendo la ejecución porque envías por el puerto serie demasiados datos. Y como parece que mandas los paquetes UDP a intervalos de 10 milisegundos exactos y si se ha pasado un milisegundo ya no lo mandas y te esperas a que pasen otros 9 para mandar el siguente, tienes “pérdidas” de paquetes.

¿Posibles soluciones? Aumentar más la velocidad de transmisión (que no sé si el Arduino lo soportará) o asegurarse de mandar cada 10 milisegundos por el puerto serie “mensajes” de menos de 128 bytes. Incluso, para ir sobre seguro, de menos de 100 bytes ya que los 128 bytes cada 10 milisegundos sería “en el mejor de los casos”, dando por hecho que el Arduino “no se entretiene mucho” en preparar cada byte que se ha de transmitir (téngase en cuenta que la interrupción del puerto serie se puede “bloquear” temporalmente y no tiene porqué ser atendida inmediatamente).

Esto es lo que creo que te puede estar pasando, pero tal vez me equivoco.

1 Like