Модуль RS-485 не передает LF и CR

Я работаю над проектом, в котором участвуют два микроконтроллера ATMEGA328p, обменивающиеся данными на большом расстоянии (между двумя этажами здания). Один хозяин, а другой раб. Мастер всегда инициирует связь, отправляя пользовательские AT-команды, которые имеют возврат каретки '\r' и перевод строки '\n' в качестве терминаторов в конце.
Я использую UART (9600 бит/с с четностью). Вот что я заметил: При использовании прямого UART все работает как положено. Но когда я заменил канал связи очень длинным проводом (около 5-10 м), UART начал вызывать проблемы.
Поэтому мне пришлось использовать модули RS-485 по понятным причинам.

Проблема, которую я вижу, заключается в том, что вся AT-команда передается по пути RS-485, но два кода ASCII «\ r» и «\ n» вообще не принимаются. Я проверил с помощью клона FTDI, что вход в модуль на стороне передатчика RS-485 имеет CR и LF, как и ожидалось, но на приемном конце (после преобразования RS485 в UART) принимается вся команда, кроме CR и LF.

Пожалуйста, предложите мне, что делать, поскольку весь мой программный код зависит от обнаружения CR и LF как протокола. Я просмотрел множество блогов/QA, но не смог решить свою проблему. Похоже, что модуль RS-485 не отправляет CR и LF.

Это две функции UART, которые работают на самом низком уровне. Я проверил, что мой код всегда передает 1 в качестве аргумента 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
}

Обновление: я изменил код, заменив CR на @ и заменил LF на $. Тем не менее теряются только символы завершения, остальная часть команды (длинная или короткая) передается нормально. Я чувствую, что есть некоторая проблема, связанная с синхронизацией, поскольку оператор if (trm == 1) заставляет микросхему RS-485 отбрасывать последующие символы.

Посмотрите в прицел на линии RS485 - вы видите там CR/LF? Что именно представляют собой эти модули - есть ли в них какой-то «интеллектуальный» или это простые линейные драйверы?
Работает ли отправка CR или LF с помощью UART_TxByte()?
@brhans Я использую эти модули images-na.ssl-images-amazon.com/images/I/…
@Rodo Я неоднократно передавал эту последовательность UART_TxByte('S'); UART_TxByte('\r'); UART_TxByte('М'); UART_TxByte('\n'); задержки(100); И заметил на последовательном терминале, что принимаются только S и CR, M и LF не принимаются.
Я могу использовать конвертер USB-TTL только для трассировки пакетов, так как у меня нет доступа к какой-либо области. Что-то с этим модулем не могу понять.
Ваш модуль RS485 выглядит как простой интерфейс сдвига уровня — у него не хватит интеллекта для сброса CR/LF. Я мог бы предположить, что ваша процедура приема сбрасывает CR/LF или, возможно, проблема синхронизации - тактовая частота приема слишком далека от тактовой частоты передачи.
@Peter Bennett На самом низком уровне я отправляю только LF, но ничего не получаю. Кроме того, остальные персонажи принимаются правильно, но CR также вызывает падение других персонажей.
Вам действительно нужен способ взглянуть на сигналы (прицел), чтобы отследить, где теряется CR или LF.
В соответствии с текущим статусом я заметил, что LF потерян, а также потерян символ рядом с LF. Хотя CR не теряется, но ведет себя как LF на терминале (выдает новую строку)
Если вы отправите 'A' , '\r', '\n', 'B' , вы получите только A?
Txc проверяется перед отправкой символа. Вы должны убедиться, что последний символ отправлен полностью, прежде чем отключать разрешение передачи на приемопередатчике 485. Является ли TXC_FLAG официальным именем бита или это то, что вы создали?
Какую бы строку я ни отправлял, последние два символа всегда теряются. Если я отправлю "DC\r\n", CR и LF будут потеряны; если я отправлю "DC+T1MEAS?$%", только $ и % будут потеряны. Хотя причина до сих пор не известна, почему это происходит. Но я нашел обходной путь для этой проблемы. Какую бы строку я ни отправлял, я добавил два лишних бесполезных пробела в конце строки, и была получена правильная строка (поскольку бесполезные пробелы опущены). Я отправляю "DC+T1MEAS?\r\n__" и успешно получаю "DC+T1MEAS?\r\n".
Это не имеет никакого смысла. И ваш «обходной путь» будет работать, если вы непрерывно отправляете две строки, дважды вызывая эту функцию? И вы не сказали нам, как вы подтверждаете каждый полученный байт. Используется ли осциллограф или другая программа/терминал c? Может быть, это как-то связано с этим.
"Отключить Rx-прерывания при отправке данных" А? Если вы по какой-то странной причине ожидаете приема данных во время их передачи, то отключение прерывания вас не спасет. У вас произойдет столкновение в автобусе, и все данные будут повреждены. Это если вы не используете полный дуплекс RS-422, но, похоже, это не так.
Также это «клон FTDI»? Используйте простые приемопередатчики RS-485 с согласующими резисторами.

Ответы (1)

Не уверен на 100%, что это решит вашу проблему, но что-то нужно проверить:

согласно таблице данных Atmel, непосредственно перед передачей байтов вы должны дождаться бита UDREn, что означает, что регистр UDRn пуст и может принять новый байт.

UDRen отличается от бита TXCn, который вы, похоже, используете (но неясно, как вы определили эту маску).

В любом случае, TXCn предназначен для after , а не before . Другие отличия: UDREn происходит до того, как байт будет полностью передан, и TXCn может не очищаться автоматически так же, как UDRen.

Используйте UDRen при подаче пакета данных для передачи в блоке, используйте TXCn при ожидании завершения последнего байта, если это имеет значение.

Я заметил, что в коде нет ничего плохого. Модуль RS-485 пропускает последние два кода ascii любой строки, которую я отправляю. Поэтому я изменил код, чтобы отправить два дополнительных пробела после CR и LF. Это сработало.
Обратите особое внимание на линию направления. Если он будет изменен во время передачи, передатчик/приемник «пропустит» байты.