Módulo RS-485 que no transmite LF y CR

Estoy trabajando en un proyecto que involucra dos MCU ATMEGA328p que se comunican a larga distancia (entre dos pisos de un edificio). Uno es amo y el otro es esclavo. El maestro siempre inicia la comunicación mediante el envío de comandos AT personalizados que tienen un retorno de carro '\r' y un salto de línea '\n' como terminadores al final.
Estoy usando UART (9600 bps con paridad uniforme). Esto es lo que noté: cuando se usa UART directo, todo funciona como se esperaba. Pero cuando reemplacé la ruta de comunicación con un cable muy largo (aproximadamente 5-10 m), el UART comenzó a causar problemas.
Así que tuve que usar módulos RS-485 por razones obvias.

El problema que veo es que todo el comando AT se transmite a través de la ruta RS-485, pero los dos códigos ASCII de '\r' y '\n' no se reciben en absoluto. Verifiqué usando un clon FTDI que la entrada al módulo del lado del transmisor RS-485 tiene CR y LF como se esperaba, pero en el extremo receptor (después de la conversión de RS485 a UART), se recibe el comando completo excepto CR y LF.

Sugiérame qué hacer, ya que todo mi código de software depende de la detección de CR y LF como protocolo. Revisé muchos blogs/controles de calidad, pero no pude resolver mi problema. Parece que el módulo RS-485 no envía CR y LF.

Estas son las dos funciones UART que funcionan en el nivel más bajo. He comprobado que mi código siempre pasa 1 como argumento trm

void UART_TxSTRING (char string[], int trm)     //This string function does not sends the NULL character '\0'
{   
    int i = 0;
    while (string[i] != '\0')       //Detect end of string
    {
        UART_TxByte(string[i]);
        i++;
    }
    if (trm == 1)                   //if trm=1, terminators will be sent with string
    {
        UART_TxByte('\r');          //Terminator
        UART_TxByte('\n');          //Terminator
    }
}

void UART_TxByte(char tx_data)
{   
    UCSR0B  &= ~RXIE;               //Disable Rx interrupts while sending data
    while (!(UCSR0A & TXC_FLAG));   //Check flag before transmitting
    UDR0 = (tx_data & 0xFF);        //Send the ASCII code
    UCSR0B  |= RXIE;                //Enable Rx interrupts again after transmission
}

Actualización: Modifiqué el código para reemplazar CR con @ y reemplacé LF con $ Aún así, solo se pierden los caracteres de terminación, el resto del comando (largo o corto) se transmite normalmente. Siento que hay algún problema relacionado con el tiempo, ya que la declaración if (trm == 1) está causando que el IC RS-485 elimine los caracteres posteriores.

Mire las líneas RS485 con un alcance: ¿ve el CR / LF allí? ¿Qué son exactamente estos módulos? ¿Tienen algún tipo de "inteligencia" o son simples controladores de línea?
¿Funciona el envío de un CR o LF con UART_TxByte()?
@brhans Estoy usando estos módulos images-na.ssl-images-amazon.com/images/I/…
@Rodo Transmití esta secuencia repetidamente UART_TxByte('S'); UART_TxByte('\r'); UART_TxByte('M'); UART_TxByte('\n'); retrasos(100); Y observo en el terminal serial que solo se reciben S y CR, no se reciben M y LF.
Solo puedo usar el convertidor USB-TTL para rastrear paquetes ya que no tengo acceso a ningún tipo de alcance. Hay algo con este módulo que no puedo entender.
Su módulo RS485 parece ser una interfaz de cambio de nivel simple: no tendrá la inteligencia para eliminar CR / LF. Podría sugerir que su rutina de recepción está dejando caer el CR/LF, o posiblemente un problema de sincronización: la frecuencia del reloj de recepción está demasiado lejos de la frecuencia del reloj de transmisión.
@Peter Bennett En el nivel más bajo, solo envío LF pero no se recibe nada. Además de eso, el resto de los caracteres se reciben correctamente, pero aún así CR también provoca la caída de otros caracteres.
Realmente necesita una forma de mirar las señales (alcance) para rastrear dónde se pierde el CR o LF.
Según el estado actual, he observado que LF se pierde, junto con eso, el personaje justo al lado de LF también se pierde. Aunque CR no se pierde pero se está comportando como un LF en el terminal (está produciendo una nueva línea)
Si envía 'A', '\r', '\n', 'B', ¿obtendrá solo A?
Txc se prueba antes de enviar el char. Debe asegurarse de que el último carácter se envíe por completo antes de desactivar la habilitación de transmisión en el transceptor 485. ¿Es TXC_FLAG el nombre de bit oficial o es algo que ha creado?
Cualquiera que sea la cadena que estoy enviando, los dos últimos caracteres siempre se pierden. Si envío "DC\r\n" CR y LF se pierde; si envío "DC+T1MEAS?$%" solo se pierde $ y %. Aunque todavía no se sabe la razón por la que esto está sucediendo. Pero encontré una solución para este problema. Independientemente de la cadena que envíe, agregué dos espacios inútiles adicionales al final de la cadena y se recibe la cadena correcta (ya que se omiten los espacios inútiles). Estoy enviando "DC+T1MEAS?\r\n__" y recibí correctamente "DC+T1MEAS?\r\n".
No tiene ningún sentido. ¿Y su "solución alternativa" funcionará si envía continuamente dos cadenas llamando a esa función dos veces? Y no nos dijiste cómo confirmas cada byte que recibes. ¿Está usando un osciloscopio u otro programa/terminal c? Tal vez tenga algo que ver con eso.
"Deshabilitar las interrupciones de Rx al enviar datos" ¿Eeh? Si, por alguna extraña razón, espera recibir datos mientras los transmite, deshabilitar la interrupción no lo salvará. Tendrás una colisión en el autobús y todos los datos se corromperán. Eso es a menos que esté haciendo RS-422 dúplex completo, pero ese no parece ser el caso.
¿También es un "clon FTDI"? Utilice transceptores RS-485 sencillos y tontos con resistencias de terminación.

Respuestas (1)

No estoy 100% seguro de que esto resuelva su problema, pero hay algo que debe verificar:

según la hoja de datos de Atmel, inmediatamente antes de transmitir bytes, debe esperar el bit UDREn, lo que significa que el registro UDRn está vacío y puede aceptar un nuevo byte.

UDREn es diferente al bit TXCn, que parece estar usando (pero no está claro cómo definió esa máscara).

De todos modos, TXCn es para después , no para antes . Otras diferencias: UDREn ocurre antes de que el byte se haya transmitido por completo, y es posible que TXCn no se borre automáticamente de la misma manera que UDREn.

Use UDREn cuando ingrese un montón de datos para transmitir en un bloque, use TXCn cuando espere que termine el último byte, en caso de que eso importe.

Me di cuenta de que no hay nada malo con el código. El módulo RS-485 está omitiendo los dos últimos códigos ASCII de cualquier cadena que envíe. Así que modifiqué el código para enviar dos espacios adicionales después de CR y LF. Esto funcionó.
Tenga especial cuidado con la línea de dirección. Si se cambia durante la transmisión, el transmisor/receptor "omitirá" los bytes