Pienso que el problema al que muchos se refieren es COMO hacer para manejar el conversor 485 desde la PC. rs485 es una norma half-duplex, eso implica que hay que poder elegir en qué momento se transmite, en qué momento se recibe... O puesto en modo más científico, cuándo el transceiver 485 está en modo transmisión (cuando está en modo transmisión, no se puede recibir nada) y cuándo está en modo recepción.
La PC saca rs232, que es full-duplex. DE ahúi va a un conversor 485, que es half duplex. En el medio, hace falta algo que diga cuándo el conversor 485 debe transmitir, y cuándo debe de recibir.
Lo que usualmente se hace, es abusar de alguna línea auxiliar del puerto serie de la PC para indicar qué es lo que tiene que hacer. Usualmente, se usa la línea RTS, pero controlada por software.
La idea, es poner la línea a 0 (o a 1, dependiendo del adaptador rs485 usado!) para poner en modo transmisión el conversor 485, y en el estado inverso para ponerlo en modo recepción. Pero hay que advertir varios problemas acá:
No es posible conmutar RTS por cada byte transmitido (8 bits+ bit start + bit stop, usualmente), porque entre bytes, si ninguno de los tranceivers 485 que están conectados al bus está en modo TX, la linea queda "suelta" ... Es decir, el nivel que está en la línea es completamente indeterminado. Y como ningún transceiver la maneja, se nos meterá ruido.
Ese ruido, es captado por todos los transceivers que están en modo RX, que lo pueden llegar a interpretar como un bit de start, lo que les hace perder el sincronismo a las usarts que están conectadas al mismo.
Por eso, es importantísimo que RTS (que es la que controla el transceiver) se mantenga durante todos los bytes que componen un paquete y mientras se transmiten completamente todos ellos, en el modo correcto para que esté en modo TX el transceiver.
También es importante, de hecho, validar los paquetes recibidos... PAra asegurarse que el primer byte sea el inicio realmente de un paquete... para asegurarse de la integridad de los datos...
En líneas generales, para que un protocolo como el 485 sea explotable en forma correcta, los paquetes de información deberían ser del estilo
|MAGIC|ADDR|LEN| ...... |CKSUM|
donde MAGIC es un valor único poco probable que se dé en los paquetes, que indica el inicio de un paquete. Por ejemplo, yo uso 0x5A (=01011010)
ADDR = Dirección del nodo al que va destinado el mensaje
LEN = Largo del paquete en bytes, sin incluir MAGIC,ADDR,LEN y CKSUM
.... Representa una cantidad LEN de bytes a transmitir (sería el payload del paquete)
CKSUM = Un checksum de todo el paquete, sin incluir MAGIC ni CKSUM
Para transmitir este paquete, tendríamos que usar un algoritmo similar a éste:
1) Activar RTS para poner el transceiver en modo TX
2) Esperar al menos el tiempo de transmisión de un byte y medio al baudrate que usamos. Este tiempo es realmente necesario, para permitir la estabilización de los niveles de tensión de la línea 485, y además, resincronizar todas las UARTs que están conectadas al bus 485 de los nodos que están escuchando el bus. Usando un byte y medio de tiempo, nos aseguramos que si por un problema de ruido alguna UART estaba recibiendo basura, la termine de recibir completamente, y quede esperando correctamente el bit de start del MAGIC del paquete que vamos a enviar
3) Transmitir el paquete completo
4) ESPERAR a que realmente se termine de transmitir el {ultimo BIT del último BYTE del paquete. Esto es MUY importante, ya que muchas UARTs tienen un buffer de transmisión y transmiten en segundo plano. Por eso es tan importante ver la forma de esperar. La UART de PC tiene un bit que indica cuándo está IDLE, o sea, terminó de transmtir. Idem casi todas las UARTs que conozco. Y en el peor de los casos, usar una demora suficientemente grande
5) Sacar RTS para pasar a modo escucha el transceiver RS485
Para la rutina de recepción la idea es la siguiente
1) Leer un byte
2) Si no es MAGIC, volver a 1 (probablemente es ruido en la línea, o estamos mal sincronizados=
3) Leer ADDR -- Validar que esté en rango... Acá no se valida que sea la dirección de nuestro módulo, sólo que el valor sea un valor válido., Por ejemplo, con 32 módulos, ADDR debería ser siempre menor a 32. Si no lo es,volver a 1.
4) Leer LEN --- Validar que el largo sea menor o igual al máximo posible para el paquete con la longitud más larga. Si no lo es, volver a 1.
5) Leer los bytes del payload (LEN bytes)
6) Leer el checksum y verificar que coincide con el calculado para los datos. Si no coincide, volver a 1
7) Si llegamos acá, verificar ADDR para ver si se trata de un mensaje dirigido a este mmodulo. Si no lo es, volver a 1. El motivo de verificar ADDR acá es no perder el sincronismo en la comunicación. Así sea que el mensaje no fuera dirigido a nosotros, necesitamos saber cuándo mirar el bus para encontrar el próximo inicio de paquete (byte=MAGIC) para no perder el sincronismo en el flujo de paquetes.
Además de todo ésto, deberíamos pensar en algún mecanismo de reintento de la transmisión si un módulo no contesta, y en un mecanismo de timeout para la recepción de la respuesta, si el módulo direccionado no responde por alguna causa.
Para la implementación en la PC, el algoritmo de transmisión es el complicado de implementar, porque requiere tiempos relativamente exactos en el manejo de RTS. Lo primero que necesitamos es que el lenguaje que usemos para programar admita el control directo de RTS. La gran mayoría lo admite, pero no todos.
Lo segundo que se necesita, es saber cuándo se terminó de transmitir el {ultimo bit del {ultimo byte. Eso es más complejo, hay lenguajes que no nos permiten saber eso. Otros cuentan con una primitiva flush() que sirve para forzar que todos los bytes salgan, pero no garantiza que se haya transmitido el {ultimo bit... Y en otros, la primitiva flush() hace exactamente lo que necesitamos. Programando a bajo nivel (DOS) podemos leer el bit de la UART que nos da esa info, por lo que es implementable.
Y el tercer problema, que puede ser o no irresoluble, es qué tanto tiempo tarda el lenguaje usado en pasar el transceiver del modo TX al modo RX, desde el momento en que el último bit se transmitió. Eso es un problema, porque el módulo que responde a nuestra petición puede llegar a ser demasiado rápido en responder, y comenzar a transmitir la respuesta antes que el módulo que transmite libere el bus.
Para eso, las 2 {unicas posibles soluciones son, o usar un lenguaje más rápido para el que transmite, o colocar una demora antes de que el módulo que responde inicie la respuesta. Ambas pueden o no ser viables.
Enfin, espero que les haya dado una idea de los problemas y las soluciones necesarias, y el porqué de las mismas
Saludos
Eduardo