Как я могу исправить этот код, чтобы мой AVR мог общаться через последовательный порт?

В последнее время я рву на себе волосы, пытаясь заставить ATmega162 на моем STK200 общаться с моим компьютером через RS232. Я проверил и убедился, что STK200 содержит микросхему MAX202CPE.

Я настроил чип на использование внутренней тактовой частоты 8 МГц и разделил ее на 8.

Я пытался скопировать код из таблицы данных (и внес изменения там, где компилятор жаловался), но безрезультатно.

Мой код ниже, может ли кто-нибудь помочь мне решить проблемы, которые у меня возникают?

Я подтвердил, что мой последовательный порт работает на других устройствах и исправен.

Спасибо!

#include <avr/io.h>
#include <avr/iom162.h>

#define BAUDRATE 4800

void USART_Init(unsigned int baud)
{
    UBRR0H = (unsigned char)(baud >> 8);
    UBRR0L = (unsigned char)baud;

    UCSR0B = (1 << RXEN0) | (1 << TXEN0);

    UCSR0C = (1 << URSEL0) | (1 << USBS0) | (3 << UCSZ00);
}

void USART_Transmit(unsigned char data)
{
    while(!(UCSR0A & (1 << UDRE0)));

    UDR0 = data;
}

unsigned char USART_Receive()
{
    while(!(UCSR0A & (1 << RXC0)));

    return UDR0;
}

int main()
{

    USART_Init(BAUDRATE);

    unsigned char data;

    // all are 1, all as output
    DDRB = 0xFF;

    while(1)
    {
        data = USART_Receive();

        PORTB = data;

        USART_Transmit(data);


    }
}

person samoz    schedule 10.05.2009    source источник


Ответы (4)


Я прокомментировал ответ Грега, но хотел бы добавить еще кое-что. Для такого рода проблем золотой стандарт отладки заключается в том, чтобы сначала понять асинхронную последовательную связь, а затем взять осциллограф и посмотреть, что происходит на линии. Если происходит обмен символами, и это просто проблема скорости передачи, это будет особенно полезно, поскольку вы можете рассчитать скорость передачи, которую вы видите, а затем соответствующим образом настроить делитель.

Вот очень быстрый учебник для начинающих, без сомнения, вы можете найти что-то гораздо более полное в Википедии или где-либо еще.

Предположим, 8 бит, без четности, 1 стоповый бит (наиболее распространенная установка). Тогда, если передаваемый символ, скажем, 0x3f (= ascii '?'), то строка выглядит так;

...--+   +---+---+---+---+---+---+       +---+--...
     | S | 1   1   1   1   1   1 | 0   0 | E
     +---+                       +---+---+

Высокий (1) уровень составляет +5В на микросхеме и -12В после преобразования в уровни RS232.

Низкий (0) уровень — это 0 В на микросхеме и +12 В после преобразования в уровни RS232.

S — начальный бит.

Затем у нас есть 8 битов данных, наименее значащие первыми, поэтому здесь 00111111 = 0x3f = '?'.

E — стоповый (e для конца) бит.

Время идет слева направо, как на дисплее осциллографа. Если скорость равна 4800 бод, то каждый бит охватывает (1/4800) секунды = 0,21 миллисекунды (приблизительно).

Приемник работает, осуществляя выборку линии и ища спадающий фронт (неподвижная линия всегда просто логическая «1»). Приемник знает скорость передачи данных и количество начальных битов (1), поэтому он измеряет половину времени бита от заднего фронта, чтобы найти середину начального бита, затем последовательно производит выборку строки 8 битов, чтобы собрать биты данных. Затем получатель ждет еще один бит (до половины стопового бита) и начинает поиск другого стартового бита (т. е. заднего фронта). Тем временем прочитанный символ становится доступным для остальной части системы. Передатчик гарантирует, что следующий спадающий фронт не начнется, пока стоповый бит не будет завершен. Передатчик можно запрограммировать на более длительное ожидание (с дополнительными стоповыми битами), но это устаревшая проблема, дополнительные стоповые биты требовались только при очень медленных аппаратных и/или программных настройках.

person Bill Forster    schedule 10.05.2009

У меня нет под рукой справочного материала, но регистр скорости передачи UBRR обычно содержит значение делителя, а не саму желаемую скорость передачи. быстрый поиск в Google показывает, что правильное значение делителя для 4800 бод может быть 239. Таким образом, пытаться:

divisor = 239;
UBRR0H = (unsigned char)(divisor >> 8);
UBRR0L = (unsigned char)divisor;

Если это не сработает, сверьтесь со справочной документацией для вашего конкретного чипа, чтобы узнать правильную формулу расчета делителя.

person Greg Hewgill    schedule 10.05.2009
comment
Я просмотрел старый проект AVR, над которым работал, и наиболее подходящая строка кода была: делитель = (u16)(SYSTEMCLOCK / (скорость передачи * 16)) - 1; С моей частотой SYSTEMCLOCK получилось 191. С вашей может быть 13?. Но ответ Грега, скорее всего, будет точным. В такой ситуации важна точная характеристика чипа и тактового генератора. - person Bill Forster; 11.05.2009

Для отладки связи UART есть две полезные вещи:

1) Сделайте петлю на разъеме и убедитесь, что вы можете прочитать то, что вы пишете. Если вы отправляете символ и возвращаете его точно, вы знаете, что оборудование подключено правильно и что по крайней мере базовый набор конфигурации регистров UART верен.

2) Повторно отправить символ 0x55 ("U") - бинарный битовый шаблон 01010101 позволит быстро увидеть разрядность на осциллографе, что позволит убедиться в правильности настройки скорости.

person Toybuilder    schedule 11.05.2009
comment
Второй способ удивительный и полезный. Он также заботится о начальном и вспомогательном битах. - person iama; 19.01.2015

Прочитав техническое описание немного более внимательно, я неправильно установил скорость передачи данных. В листе данных ATmega162 была диаграмма тактовых частот в зависимости от скорости передачи и соответствующей ошибки.

Для скорости 4800 бод и тактовой частоты 1 МГц погрешность составила 0,2%, что для меня было приемлемо. Хитрость заключалась в передаче 12 в функцию USART_Init() вместо 4800.

Надеюсь, это поможет кому-то еще!

person samoz    schedule 11.05.2009