Detectar bit de Stop en comunicación Serial.

Buenas tardes. Estoy utilizando la comunicación Serial para transmitir datos entre 2 arduinos. El tema es que ambos transmiten una gran cantidad de datos por segundo, y cuando uno transmite y el otro también, se vuelve un choclo de datos. Claramente esto se soluciona haciendo que si un Arduino transmite, el otro no lo haga hasta que detecte que este dejo de transmitir.

El detectar que transmite es facil, con if( Serial.available>0) ya sale.Con esta sentencia hago que el Arduino escuche lo que se transmite por el puerto serie. El problema sale cuando ese ciclo if se termina, y el Arduino que estaba escuchando empieza a transmitir. En ese momento los monitores seriales de ambos lados empiezan a lanzar caracteres aleatorios. Supongo que es porque ambos arduinos, al tener distintas longitudes de código, en un momento terminan "hablando" los 2 al mismo tiempo por el puerto serie.

Entonces se me ocurrió que si pudiese leer el bit de Stop de cada transmisión Serial podría saber cuando el canal esta libre, y que ese Arduino después de escuchar, pueda transmitir. Alguien sabe como puedo detectar ese bit de stop?.

Otra forma que se me ocurrió, es calcular los uS que tarda cada bit en transmitirse dependiendo del BaudRate que les configure a ambos arduinos, esto podría hacerlo esperando la cantidad de tiempo multiplicado por los 8 bits de transmisión, y detectar si no hay datos en el puerto serial por el tiempo de los siguientes 2 bits. Pero no se cuanto tiempo tarda el Arduino en detectar el bit de Start con la sentencia Serial.available( ), y al no conocer ese dato, desconozco si leería los bits equivocos cuando quiero detectar los de STOP.

Intente utilizar la misma sentencia de if(Serial.available>0) else...... para transmitir en ese momento. Pero obtuve los mismos resultados. También intente negar el If(!Serial.available>0) pero nada. Asi que muero en la opción de leer el bit de Stop. Muchas gracias.

Mira los comandos AT, se inventaron para eso

TonyDiana:
Mira los comandos AT, se inventaron para eso

Gracias por responde TonyDiana. Tengo entendido que los comandos AT se utilizan para modulos gprs, bluethoot, wifi, entre otros. Pero no en Arduino. De todos modos intente imprimirle algunos comandos AT y no hubo respuesta del otro Arduino. Te recuerdo que estoy haciendo que un Arduino Uno hable a otro Arduino Uno, y que posteriormente este ultimo le hable al primero y así sucesivamente.

Los comandos AT no son exclusivos de ninguna tecnología, de hecho establecen un protocolo de comunicación. La idea es que envíes un comando AT cuando quieres que el arduino responda:

Arduino 1, AT quiero hablar

Arduino 2, AT quiero hablar
Arduino 2, vaya, debo esperar a que hable el jefe
Arduino 2, AT estoy escuchando

Arduino 1, ahora hablo
y hablo
y hablo
y hablo
Arduino 1, comando AT (ACABE)

Arduino 2, AT, lo recibií todo
Arduino 2 AT, quiero hablar

Arduino 1, ok, voy a escuchar
Arduino 1 AT escucho

y sigues

No me acuerdo bien todo el manejo de los AT, pero así es como nos comunicábamos por modem en la época en que tenías que hacer la comunicación tú a pelo

Hablo de antes de 1993, cuando internet no existía, y era un éxito

Quien dice comandos at dice comandos GIU de Giulano, te puedes inventar los tuyos propios

@Gatul te contará como es comunicarse por radio es lo mismo

"breiko breiko alguien me copia"

Entiendo lo que me explicas Tony, pero como te digo. Al enviarle comandos AT no hay respuesta por parte del otro Arduino. Tengo el monitor seria de c/u abierto en ambas pantallas, y cuando le en vio el AT desde uno, el otro si lo recibe correctamente, pero no genera una respuesta como me lo genera el SIM808 que tengo aca. Ese si le envío cualquier AT y te tira el OK. Pero el otro Arduino no genera una respuesta, la respuesta que necesitaría para saber por ejemplo, si el canal esta "libre" para poder hablar.

Claramente no es exclusivo de ninguna tecnología, pero el otro procesador tiene que entender a que me refiero cuando le envié un "AT+IPR=19200", y si no esta configurado para entenderlo no lo va a hacer. En este caso como te decía, al enviar cualquier AT al otro Arduino, solo consigo que este lo pase como si fuera una transmisión de datos comuny corriente, no como una solicitud de su status por decirlo asi.

Por eso se me había ocurrido lo de medir el timing de cada bit hasta llegar al de STOP, armar un If para comprobar el status en ese momento y si tanto ese como el otro bit corresponden a final de transmisión, entonces tener vida libre para hablar. Pero como dije antes, desconozco los uS que se toma Arduino desde que detecta el bit de START, hasta que detecta el 1er bit de datos.

No tienes respuesta a los comandos AT (que los desarrollo Hayes para manejar sus modems, allá lejos y hace tiempo, y lo que significaba era "ATención, te envío un comando, atiéndelo") porque tú tendrías que programar el arduino para que lo haga. O sea, no viene como el SIM808 preprogramado para ser manejado como un modem vía comandos AT.

Aclarado eso, lo que tienes que hacer es algún tipo de protocolo.

Volviendo al ejemplo de los handies, como mínimo, que haría un usuario? Escucharía para saber que nadie ocupa el canal, diría su mensaje y, normalmente, lo terminaría diciendo "cambio". Ese "cambio" significa que queda en escucha de una respuesta (si la hubiese). O podría decir "cambio y fuera" avisando que queda en escucha pero no espera respuesta porque terminó la charla.

En base a eso tendrías que plantear tu estrategia.

Por ejemplo, podrías hacer que cada trama termine con un caracter (o una secuencia) en particular, por caso podría ser "#". Así envias tus datos y al final un "#" para indicar que terminó el envío. O puedes hacerlo para cada dato enviado.
Algo así: "dato1,dato2,dato3#" o "dato1#dato2#dato3#"

También podrías, con la filosofía de los comandos AT, iniciar con un caracter distintivo. ¿Por qué no algo así: "" ? O "<dato, dato,dato>"

En resumen, la idea es no mandar el dato "pelado", agrega algo que tu definas para indicar que lo que viene detrás es un dato y algo más que diga donde termina, o solamente donde termina, tu lo decides.

Te sugiero que pegues una mirada en la sección Documentación que hay un post muy bueno sobre comunicación Serial.

Justo eso es lo que se debe hacer, crear un protocolo, es lo mejor en tu caso, eso eran los AT

Perdón que te corrija @TonyDiana, no eran, son.

Los comandos se siguen usando en la actualidad por popularidad pero más aún por conveniencia, de hecho muchos comandos están estandarizados (y se trata de no utilizarlos con fines diferentes, pero se podría).

En el código cuando detectas que la cadena que has recibido empieza con "AT" sabes que lo que sigue es un comando y si no empieza con esos dos caracteres solo son datos. Puedes usar el caracter que quieras para distinguir entre comandos y datos, nada lo impide (de hecho hay sensores que usan sus propios sets de control, como ser una cadena HEX), pero salvo que la reducción de trafico (de datos) sea algo esencial ¿para que reinventar la rueda si gira hermosamente? :wink:

Por ej. Un arduino que asignamos como master le pide a otro que asignamos como esclavo que envíe los datos de uno de varios sensores DHT que tiene conectados, bien podría hacerlo enviando el comando "AT+T=1" (lo estoy inventando, no verifiqué si coincide con algún comando estandarizado) para pedir los datos de temperatura del sensor 1, o pedir los de humedad del sensor 3 con "AT+H=3". El esclavo estaría siempre a la espera de un comando y solo respondería cuando, y a lo que, se le pide en lugar estar continuamente enviado todos los datos uno tras otro, y el master sabría que lo va a recibir son los datos solicitados.

Claro está que el primer comando podría ser, por decir, "$T1" y el segundo "$H3", como dije antes, cada uno puede hacer su propio protocolo, pero con comandos AT podríamos hacer nuestro código y nuestro proyecto más "compatible".

Si @Gatul dije eran porque ya no hago nada con ellos pero me parecen de lo mejo

De hecho ten presente una cosa, en HTML también sucede:

Tienes que enviar comandos (o metacomandos sería más apropiado decir) que especifican cómo ha funcionado la comunicación, por ejemplo, si tienes un servidor web y recibes datos de un jquery de un formulario, tienes que enviar un 200 o el formulario esperará de por vida la respuesta.

Esa es la razón por la cual cuando te conectas a una web y envías un formulario, si la conexión es lenta o falla, tu computadora parece "congelarse"

Sin protocolo de comunicación no vas a tener éxito, sea serial (rs232, USB, bluetook) o tcp/ip

Crea tu propio protocolo de envío y listo

Consejos:

  • Que tus comandos empiecen siempre por algo fijo (AT es sólo una idea)
  • Que todos tus mensajes no comandos (datos) empiecen por un marcador fijo diferente al comando, por ejemplo si usas comandos AT, usar un asterisco, lo que sea, una letra que no sea A, porque si después envías un dato, por ejemplo la palabra ATLANTICO, imagínate que tu arduino va a querer ejecutar el comando LANTICO (no es que a mi me haya pasado, fue a un amigo mío claro).
  • Establece protocolos de confirmación de recepción de la información, nunca supongas que siempre funciona.
  • Tampoco supongas, si son muchos datos, que la información se recibe perfecta, un buen consejo es enviar una cadena de verificación de todo el mensaje, a mi me gusta el MD5, pequeño sencillo y compacto, te añado un enlace con una librería MD5 para arduino (GitHub - tzikis/ArduinoMD5: The first easily-embeddable MD5 library for Arduino)

Nos cuentas por favor, es molesto ver gente que pregunta y ni vuelve a responder cuando lo resuelven o ni se molestan en hacer un click y darte karma, dan ganas de no ayudar a nadie

@gatul
Comprendo perfectamente tu idea y me parece genial. Se me ocurrió que podría como decís vos, agregarle el "#" al final de cada transmisión de datos, y que, por ejemplo si el Arduino A acabo de hablar en el canal, que este entre en un while a la espera de que el Arduino B le envié otro "#" , o que se cumpla una X cantidad de uS dentro de ese ciclo (lo cual significaría que el otro Arduino no tuvo nada que transmitir).
Y claramente debería implementar un orden entre ambos para que, al momento de que uno quiera hablar al iniciar otro ciclo, el otro no lo este haciendo. Por ejemplo podría hacer que el Arduino A, siempre espere a que primero hable el Arduino B, y después de que lee el "#", recién ahi hable. Lo que me preocupa es que no puedo hacer que el Arduino A espere indefinido tiempo hasta que el B conteste, ya que hay mas código que procesar, por ende debería de limitar ese tiempo de "espero a que el B hable" Y ahi va mi duda. Si le asigno un tiempo a A para que escuche el canal, y en ese tiempo B no habla. Posteriormente A hablaria y puede que B lo haga al mismo tiempo. Ahi es donde se transmiten choclos de datos y me enclavan el programa, porque hacer una cuenta aritmética con "@!?" es imposible.

Ahora me pongo a leer sobre esa documentación que me recomendaste, gracias.

@TonyDiana
Voy a mirar lo del MD5, tal vez eso me sirva justamente para evitar los incidentes que me preocuparon en el párrafo anterior. De cualquier forma, si todo esto no llegase a funcionar, pensé en probar abrir 2 puerto Seriales, uno para el envío de datos de A hacia B, y el otro de B hacia A. Lo cual seria poco profesional por decir así, porque no estaría siendo eficiente con el hardware al inhabilitar tantos pines, pero solamente debería leer el buffer de cada Serial y no preocuparme porque uno hable en el mismo canal que el otro(Si es que funciona así, puede que me este equivocando y estoy hablando pavadas no se). Prometo seguir contándote el progreso, es lo mínimo que puedo hacer para agradecerles la ayuda que ambos me están brindando.

No te pongas a esperar, mejor milis

@victorjam lo explicó de maravilla en este tutorial

https://forum.arduino.cc/index.php?topic=654615.0

@TonyDiana
No con esperar no me refería a meterle un Delay, claramente eso me estanca el programa y no es lo que busco. Pensé por ejemplo, una vez transmitidos los datos de A a b, hacer que A se estanque en un while leyendo el buffer de entrada aproximadamente 100uS. ya que como ambos transmiten a 115200Baudios/seg, si no me falla el calculo, cada bit tardaría 8.68uS, y a 1 bit de Start, 1 de stop y 8 de datos, serian masomenos 9*10=90uS de transmisión + 10uS de gracia por si las dudas. Entonces en ese tiempo ya habría leído los datos entrantes de B.

Eso es cuestión de probar más que otra cosa

Recuerda que Serial tiene un buffer de 64 bytes, si los datos caben en el buffer no tendrías que esperar a que lleguen, podrías hacer otras cosas y luego leerlos. En el peor caso, que todo el tiempo haya datos entrando, tienes 5.5 mseg para que el buffer se llene, algo de tiempo te da para otras cosas.

@gatul
Bueno al final no se como hacerlo funcionar. Se me había ocurrido sincronizar con micros() los tiempos de ambos arduinos para que ambos arranquen al mismo tiempo la comunicación (A escucha y B envía) y después de x cantidad de tiempo al revés. Pero para eso requeria que ambos arduinos arranquen su loop al mismo tiempo aproximadamente. Intente hacer que un Arduino envié un byte de inicio para indicar el inicio del loop (esperando que ambos arranquen a la par), pero aun así se me hace un desastre de datos. Lo que no entiendo es el porque falla, ósea cada Arduino tiene su propio buffer como vos decís. No debería un Arduino poder enviar cuando quiere los datos, y que el otro los lea de su buffer cuando se le de la gana (mientras no sobrepase la capacidad claro)? Si así fuese, no entiendo el motivo de este malfuncionamiento. Como dije al inicio del post, si uno envía un par de bytes, y después de X tiempo el otro envia, funciona perfecto, pero al aumentar la cantidad de datos y al modificarse los tiempos de transmisión por la longitud del código o los clocks de c/u, ocurre cualquier cosa.
Y dudo que se sobrecargue el buffer, ya que por cada ciclo transmito, en el peor de los casos, 20 bytes. Y en el siguiente ciclo suponiendo que quedasen esos datos en el buffer, el Arduino ya los leería y liberaría el espacio.
Estoy pensando seriamente en usar I2C llegado el caso de que no le encuentre la vuelta.

Tengo una pregunta ¿Para que necesitas una comunicación donde los dos arduinos la inicien ? En el 99.9 % de los casos es suficiente una comunicación maestro-esclavo. De hecho ¿para que reinventar la rueda?existen multitud de protocolos que tienen librerías de Arduino.

¿Por qué no subes los códigos de ambos a ver si encontramos algo raro?

@PeterKantTropus
La verdad que si, me estaba complicando la vida innecesariamente. Me puse a darle mil vueltas para solucionarlo y no encontré forma. Me termine poniendo a aprender I2C y ya logre tanto enviar como recibir datos entre ambos arduinos. Aunque aun así tengo un par de errores locos, pero es cuestión de ir probando y depurando, la parte mas pesada ya se resolvió. Muchas gracias a todos igualmente.