UART работает корректно только в одну сторону (ATmega328p)

У меня есть Arduino Uno, управляемая ATmega328P. И я хотел отойти от его библиотек и сделать все на более низком уровне для учебных целей. Однако я не могу заставить uart работать правильно, теперь он работает только при отправке на устройство. Получение возвращает странный мусор, который терминал не может распечатать.

#define BAUDRATE (((F_CPU / (BAUD * 16UL))) - 1)
void init_uart()
{
    UBRR0H = BAUDRATE >> 8; // set high baud
    UBRR0L = BAUDRATE; //set low baud
    UCSR0B = _BV(TXEN0) | _BV(RXEN0); //enable duplex
    UCSR0C = _BV(UCSZ00) | _BV(UCSZ01) | _BV(USBS0); //8-N-1
}

void putchar_uart(char c, FILE* stream)
{
    loop_until_bit_is_set(UCSR0A, UDRE0);   //wait till prev char is read
    UDR0 = c;
}

char getchar_uart(FILE* stream)
{
    loop_until_bit_is_set(UCSR0A, RXC0);    //wait if there is data
    return UDR0;
}

//^ actually is in a seperate file which gets linked

int main()
{
    DDRD |= PIN_LED;
    PORTD |= PIN_LED;

    stdout = &mystdout;
    stdin = &mystdin;

    char buf[0xFF];

    init_uart();
    while (1)
    {
        char c = getchar_uart(NULL);
        if (c == 'a')
        {
            PIND = PIN_LED;
            printf("%s\n", "Hallo");
        }
    }
}

Я использую Ubuntu 14.04 LTS и использую minicom для связи. Который настроен как: 115200 8N1 (конечно, с правильным последовательным устройством).

Он компилируется как:

avr-gcc -Wall -Os -mmcu=atmega328p -DF_CPU=16000000UL -DBAUD=115200 -std=c99 -L/home/joel/avr-libs/lib -I/home/joel/avr-libs/inc -o firmware.o main.c  -luart

Итак, как я узнаю, что один из способов работает? Из-за того, что светодиод переключается только при вводе «а». Но ответ - недопустимые символы. В шестнадцатеричном формате:

c8 e1 ec ec ef 8a

person joell    schedule 26.01.2015    source источник
comment
Вы в основном получаете то, что отправляете, только с ошибочно установленным битом 7. Это может свидетельствовать о разногласиях по поводу количества битов данных, стоповых битов или четности. Рассмотрите возможность создания быстрого эскиза Arduino, который выводит значения регистров конфигурации UART для сравнения с вашими настройками.   -  person Chris Stratton    schedule 27.01.2015
comment
@ChrisStratton Я создал простой скетч, который сбрасывает все регистры, в которые я писал (включая USCR0A), поэтому в этом не было ничего особенного. Единственное отличие состоит в том, что Arduino устанавливает биты RXCIE, UDRIE в регистре UCSR0B, а в регистре UCSR0A — бит U2X. Так что в основном он использует прерывания и двойной режим, сейчас я проверю двойной режим, если он сработает.   -  person joell    schedule 27.01.2015


Ответы (2)


Установив бит USBS, вы задаете второй стоповый бит.

Похоже, это приводит к тому, что ваш компьютер ошибочно полагает, что MSB (который является последним битом данных) установлен, когда это не приводит к тому, что ваши полученные данные объединяются по ИЛИ с 0x80.

Хотя это вызовет ошибку кадрирования, это, вероятно, не является причиной неправильного MSB. Ваш собственный ответ о переключении в режим 2x (и, следовательно, более точном приближении скорости передачи данных) является более важным для решения, хотя вы также должны исправить это.

person Chris Stratton    schedule 26.01.2015
comment
Вы правы, я неправильно понял даташит. Большое спасибо :) - person joell; 27.01.2015
comment
Вам определенно не нужен USBS, но я не уверен, что это ошибка или ошибка скорости передачи, которая испортила ваши данные. - person Chris Stratton; 27.01.2015
comment
Это также работало при включении режима 2x, знаете почему? Или это было совпадением? - person joell; 27.01.2015
comment
Это говорит о том, что, возможно, реальная проблема заключается в ошибке скорости передачи данных (выясните, какая фактическая скорость передачи данных определяется целыми делителями в каждом случае), а USBS просто вызывает ошибку кадрирования, которую можно игнорировать. Я думаю, вам следует восстановить свой ответ. - person Chris Stratton; 27.01.2015

Я исправил проблему, когда Крис предложил распечатать регистры конфигурации, которые использует Arduino, я заметил, что он использует двойной режим. Я не смог настроить это с помощью minicom или пропустил это. Возможно, по умолчанию используется такой режим. Во всяком случае, это работает сейчас.

Я также узнал, что avr-libc предоставляет заголовок util/setbaud.h, который автоматически вычисляет правильную скорость передачи данных. В полях UBRRL_VALUE и UBRRH_VALUE.

person joell    schedule 26.01.2015
comment
Двойной режим — это не свойство последовательного слова, а скорее конфигурация UART. Это может привести к большей точности синхронизации для определенных ситуаций передачи часов/цели. Я предполагаю, что ошибка скорости передачи может привести к тому, что стоповый бит попадет в окно оценки для MSB. - person Chris Stratton; 27.01.2015
comment
Когда я запускаю числа, ближайшая скорость, которую вы можете получить в обычном режиме, - это 125 кбод, что я мог видеть при этом. Режим 2x дает вам около 117,6 кбод, гораздо лучшее приближение. Поэтому я думаю, что ошибочный MSB, вероятно, связан с ошибкой в ​​бодах. - person Chris Stratton; 27.01.2015