Работаем с UART на AVR

 
UART_logo
 

 

Пару слов о источнике информации

 

В начале поста, я стараюсь приводить источники, откуда я беру информацию. Обычно это ссылки на сайты разработчиков, где, я указываю какие стандарты и даташиты описывают данное устройство или технологию. Редко, в порядке исключения даю ссылки на хорошие (на мой взгляд) посты блогов, которым можно доверять. У технической информацию должен быть незыблемый источник

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

Но, забегу вперед, описание UART все таки есть, но косвенное … его можно найти в описаниях на физический протоколы RS-232, RS-422, RS-423, RS-485, но об этом позже.

 

 

Немного теории

 

UART (универсальный асинхронный приёмопередатчик)   — одна из старейших и самых распространенных на сегодняшний день технологий передачи данных. Слово «асинхронный» означает, что интерфейс не использует линию для синхросигнала, приемник и передатчик заранее настраиваются на одну частоту.

Можно сказать с уверенностью, что каждый микроконтроллер/микропроцессор имеет в своем составе универсальный последовательный интерфейс — UART. Умея работать с данным портом вы развязываете себе руки, когда необходимо согласовать работу старых и современных электронных устройств, принять или передать данные в устройства.

В современных микроконтроллерах, часто вместо UART используют полностью с ним совместимый — USART (универсальный асинхронный/синхронный приёмопередатчик).

USART это более гибкий в настройки UART с дополнительными возможностями. Например в USART можно регулировать длину слова с более большим диапазоном (от 5 до 9) чем в UART (от 8 до 9). В USART как видно из названия возможна как асинхронная так и синхронная передача данных (в UART только асинхронная). При синхронной передачи помимо 2-ух линиданные и питания, используется дополнительная линия (XCK) с синхросигналом. С такой конфигурацией USART уже пересекается с интерфейсом SPI и его можно использовать как «ведущий» в интерфейсе SPI.

Мы будем рассматривать классический случай, когда интерфейс асинхронный (т.е. без линии синхросигнала).

Передача данных в UART осуществляется по одному биту в равные промежутки времени. Этот временной промежуток определяется заданной скоростью UART и для конкретного соединения указывается в бодах, что соответствует количество бит в секунду. Существует общепринятый ряд стандартных скоростей: 300; 600; 1200; 2400; 4800; 9600; 19200; 38400; 57600; 115200; 230400;460800; 921600 бод;

Скорость (S, бод) и длительность бита (T, секунд) связаны соотношением T=1/S.

Байт данных отправляются в пакетах (1-й бит перед байтом данных и 2-а бита после, количество бит опциональны).

UART

 (p.s. наличие и количество проверочного и стопового бита опциональны)

 

Для приема и передачи данных UART использует две линии данных и земля:

  • передающая данные (TXD или TX);
  • принимающая данные (RXD или RX);
  • земля (GND).

Уровню логической единицы и нуля соответствует уровням TTL:

  • т.е. 1-ца это +5В;
  • а 0 это .

 

 

Немного отступлю… все равно этот вопрос рано или поздно у вас возникнет…

UART понятно, а что тогда такое RS-232, COM ?

читайте в посте по ссылке

 

 

Как работать с USART на AVR?

 

В качестве AVR микроконтроллера я буду рассматривать ATmega8.

  • за прием данных в USART (RxD) отвечает ножка PDO
  • за передачу данных из USART (TxD) отвечает ножка PD1
  • если будет использоваться линия синхронизации, то данную функцию несет ножка XCK

ATmega8_USART_pin

Для передачи и приема данных необходимо записать или считать данные из регистра UDR. При чтение вы обращаетесь к буферу приемника, при записи к буферу передатчика, важно заметить, что при считывание состояние UDR изменяется. Это означает что считывать информацию можно только однажды. С передачей и приемом все просто, идем далее, как управлять USART?

Для управлением работы с USART используются следующие регистры:

  • UCSRA — содержит в основном флаги состояния приема/передачи данных.
  • UCSRB — определяет какие прерывания генерировать при наступление событий, разрешает/запрещает передачу/прием, совместно с регистром UCSRC определяет разрядность передаваемого/принимаемого слова.
  • UCSRC — задает режим работы синхронный/асинхронный, определяет правила работы контроля данных — проверка на четность/не честность или отключено, количество стоп битов, совместно с регистром UCSRB определяет разрядность передаваемого/принимаемого слова, определяет по какому фронту принимать/передавать данные — по спадающему или по нарастающему.
  • UBRR — определяет скорость приема/передачи данных

 

О каждом регистре немного поподробнее…

Регистр UCSRA состоит из следующих бит:

 

UCSRA

 

  • RXC — флаг завершения приема, устанавливается в 1 при наличие непрочитанных данных в буфере приемник — UDR;
  • TXC — флаг завершения передачи, устанавливается в 1 при передачи всех разрядов из передатчика — UDR;
  • UDRE — флаг опустошения регистра передатчика, устанавливается в 1 при пустом буфере передатчика — UDR после передачи;
  • FE — флаг ошибки кадрирования, устанавливается в 1 при обнаружение неправильного кадра, когда стоп бит равен 0-лю
  • DOR —  флаг переполнения регистра приемника, устанавливается в 1, когда байт данных принят, а предыдущий еще не прочитан из UDR;
  • PE —  флаг ошибки контроля четности, устанавливается в 1 при обнаружение ошибки контроля четности (если включена проверка);
  • U2X — бит установки удвоенной скорости обмена, если установлена 1, то скорость передачи удваивается (частота делится на 8, а не на 16), данный бит используется только при асинхронном режиме работы;
  • MPCM — бит мультипроцессорного обмена, если установлена 1, то контроллер аппаратно не принимает информацию, а только кадры с адресами, далее устанавливается бит завершения приема (или прерывание) и программа обрабатывает адрес, её ли это адрес. Отличие информации от адреса определяется  с помощью 9-ого бита в режиме 9-и битового обмена.

 

Регистр UCSRB состоит из следующих бит:

 

UCSRB

 

  • RXCIE — бит разрешения прерывания по завершению приема, если установлена 1, то при установке флага RXC регистра UCSRA произойдет прерывание «прием завершен«;
  • TXCIE — бит разрешения прерывания по завершению передачи, если установлена 1, то при установке флага TXC регистра UCSRA произойдет прерывание «передача завершена«;
  • UDRIE — бит разрешения прерывания по опустошению регистра передатчика, если установлена 1, то при установке флага UDRE регистра UCSRA произойдет прерывание «регистр данных пуст«;
  • RXEN — бит разрешения приема, при установки 1 разрешается работа приемника USART и переопределяется функционирование вывода RXD;
  • TXEN —  бит разрешения передачи, при установки 1 разрешается работа передатчика USART и переопределяется функционирование вывода TXD;
  • UCSZ2 — бит формат посылок, данный бит совместно с битами UCSZ1 и UCSZ0 регистра UCSRC определяют количество бит данных в кадрах

count_data_USART

  • RXB8 9-ый разряд принимаемых данных при использование 9-и битого режима, считывать из данного бита нужно до считывание регистра UDR;
  • TXB8 — 9-ый разряд передаваемых данных при использование 9-и битного режима, записывать в данный бит нужно до записи в регистр UDR.

 

Регистр UCSRC состоит из следующих бит:

 

UCSRC

 

  • URSEL — тут надо пояснить, это немного странный бит, он отвечает за выбор регистра UCSRC или UBRR, при установке 1 мы работаем с регистром UCSRC, при 0 мы работаем с регистром UBRR;
  • UMSEL — бит выбора режима асинхронный или синхронный, если установлен 1 — режим синхронный (т.е. с использованием линии синхронизации XCK), если 0 — режим асинхронный;
  • UPM1, UPM0 — биты выбора режима проверки на четность/нечетность;

UPM0_UPM1_UART

  • USBS — бит отвечающий за количество стоп-битов, если установлена 1два стоп-бита, если 0один стоп-бит;
  • UCSZ1, UCSZ0 — совместно с битом UCSZ2 регистра UCSRB определяют количество бит данных в кадрах (см. таблицу выше);
  • UCPOL — бит полярность тактового сигнала, при синхронном режиме определяет по какому фронту принимать/передавать данные – по спадающему или по нарастающему.

 

Регистр UBRR отвечает за скорость обмена, он состоит из двух 8-и битных регистров —  UBRRH и UBRRL

 

UBRR

 

Повторюсь, бит URSEL отвечает за выбор регистра UCSRC или UBRR, при установке 1 мы работаем с регистром UCSRC, при 0 мы работаем с регистром UBRR. Биты с UBRR0 до UBR11 устанавливают скорость передачи в бодах, но не прямую, а через следующие формулы:

UBRR = ( fCK /( BAUD * 16 ) ) — 1

UBRR = ( fCK /( BAUD * 8 ) ) — 1

Где fCK — тактовая частота микроконтроллера в герцах;

BAUD — требуемая скорость в бодах;

16 и 8 коэффициент делителя частоты, зависит от бита U2X регистра UCSRA,

      • при 1 — коэффициент 8;
      • при 0 — коэффициент 16;

UBRR — содержимое регистра UBRRH и UBRRL.

Мы будем использовать «классический UART» (т.е. асинхронный без линии синхронизации) с скоростью 9600 бод, 8-бит данных, 1-ин стоп-бит, без проверки на четность.

(в сокращенной записи данную конфигурацию записывают в виде «9600/8-N-1«, где 9600 это скорость, 8-количество бит данных в кадре, N-без проверки четности, 1-количество стоп-битов, если интересно описание сокращенного формата записи легко можно нагуглить)

Итак, я опишу последовательность действий для передатчика UART и далее приведу ассемблерный и С код для ATmega8, который можно будет опробовать на проекте Proteus.

Последовательность действий для инициализации UART в режиме 9600/8-N-1 и передачи байта данных:

1. пусть ATmega8 тактируется от 8 МГц, первым делом, установим скорость 9600 бод, для этого рассчитаем значение регистра UBRR по формуле UBRR = ( 8 000 000 /( 9 600 * 16 ) ) – 1, результат равен 52,083, округлим его до 52 (или 0x34), запишем в UBRR значение 0x34;

2. разрешаем работу передатчика, записываем в регистр UCSRB значение 00001000 (установили бит TXEN);

3. устанавливаем формат кадра 8 бит данных, без проверки четности и асинхронный режим, записываем в UCSRC значение 10000110 или 0x86 (установили биты URSEL, UCSZ1, UCSZ0);

4. отправляем байт данных, записываем байт в регистр UDR и делаем задержку пока бит UDRE регистра UCSRA не будет равен нулю.

 

Код на ассемблере для ATmega8

 

Код на С для ATmega8

 

Результат работы в Proteus:

USART_Work

Скачать hex файл прошивки и проект в Proteus ссылка

 

Если к TxD микроконтроллера подключить логический анализатор в Proteus, то можно увидеть осциллограмму работы USART.  Я продемонстрирую скриншот с логического анализатора, с фрагментом импульсов для знака ‘E’ (0x45).

 

UART_time_data

 

 


P.S. Если вы захотите создать собственный проект в Proteus, то вам необходимо настроить контролер ATmega8 на 8 МГц (для работы UART), как это сделать см. скриншот ниже:

 

ATmega8_option_UART_Proteus




Буду признателен если вы поделитесь данным постом

Комментарии
  1. Basel пишет:

    Почему все ставят скорость 9600 бод? Какое -то магическое число))) С резонатором 16 МГц можно реализовать 2 МБ/с — В протеусе без ошибок))). К тому же RS232 — Уже динозавр. Лучше уж RS485 использовать, через переходник USB-RS485, которых на Али куча, по 15 баксов за ведро.

  2. admin пишет:

    Basel, почему такая скорость сам не знаю) видимо есть исторические предпосылки.
    RS232 уже староват, конечно, в технике где нужна скорость побыстрее (встраиваемые системы, станки ЧПУ, которые я встречал) от 232 уже отказались.

  3. Анатолий пишет:

    Объясните мне новичку!Я в Ваш код(на Си)добавил еще 13 символов для передачи по UART (ATD+xxxxxxxxxxx),скомпилировал.Запустил-пришло только 13 символов(а не 15).Вроде бы никаких ограничений по количеству байт в коде нет.И еще:идет бесконечный цикл,а хотелось бы,
    чтобы только один раз пришло(для управления GSM модулем.
    Заранее спасибо!

  4. admin пишет:

    Добрый день Анатолий.

    Хм, ограничения в код на количество символов действительно нет.

    Я попробовал и вывел в UART числа с 1 до 9 два раза, VIRTUAL TERMINAL вывел все числа, т.е. вывелось 18 символов. Специально ничего не настраивал, скомпилировал и просто запустил в Proteus.
    Возможно проблема у вас.

    int main(void)
    {
    init_USART(); //инициализация USART в режиме 9600/8-N-1
    send_UART(0x31); //посылаем ASCII код знака '1'
    send_UART(0x32); //посылаем ASCII код знака '2'
    send_UART(0x33); //посылаем ASCII код знака '3'
    send_UART(0x34); //посылаем ASCII код знака '4'
    send_UART(0x35); //посылаем ASCII код знака '5'
    send_UART(0x36); //посылаем ASCII код знака '6'
    send_UART(0x37); //посылаем ASCII код знака '7'
    send_UART(0x38); //посылаем ASCII код знака '8'
    send_UART(0x39); //посылаем ASCII код знака '9'
    send_UART(0x31); //посылаем ASCII код знака '1'
    send_UART(0x32); //посылаем ASCII код знака '2'
    send_UART(0x33); //посылаем ASCII код знака '3'
    send_UART(0x34); //посылаем ASCII код знака '4'
    send_UART(0x35); //посылаем ASCII код знака '5'
    send_UART(0x36); //посылаем ASCII код знака '6'
    send_UART(0x37); //посылаем ASCII код знака '7'
    send_UART(0x38); //посылаем ASCII код знака '8'
    send_UART(0x39); //посылаем ASCII код знака '9'
    while(1)

    {
    _delay_ms(1000);
    }
    }

    Не понял насчет цикла, символы посылаются только один раз, код же в функции main.
    Я добавил только один цикл, для зацикливания в конце, это необходимо для контроллеров.
    while(1)
    {
    _delay_ms(1000);
    }

  5. Анатолий пишет:

    P.S.Кстати,в протеусе все нормально.Может быть дело в Терминальной программе?

  6. Анатолий пишет:

    Здравствуйте!Прошил контроллер.Подключил его к COM порту
    через MAX232.Запускаю терминальную программу.Она выводит:
    ATD+712345678ATD+712345678ATD+712345678…..и т.д.
    Все окно программы заполняет.
    int main(void)
    {
    init_USART(); //инициализация USART в режиме 9600/8-N-1
    send_UART(0×41); //посылаем ASCII код знака ’A′
    send_UART(0×54); //посылаем ASCII код знака ’T′
    send_UART(0×44); //посылаем ASCII код знака ’D′
    send_UART(0×2B); //посылаем ASCII код знака ’+′
    send_UART(0×37); //посылаем ASCII код знака ’7′
    send_UART(0×31); //посылаем ASCII код знака ’1′
    send_UART(0×32); //посылаем ASCII код знака ’2′
    send_UART(0×33); //посылаем ASCII код знака ’3′
    send_UART(0×34); //посылаем ASCII код знака ’4′
    send_UART(0×35); //посылаем ASCII код знака ’5′
    send_UART(0×36); //посылаем ASCII код знака ’6′
    send_UART(0×37); //посылаем ASCII код знака ’7′
    send_UART(0×38); //посылаем ASCII код знака ’8′
    send_UART(0×39); //посылаем ASCII код знака ’9′
    send_UART(0×30); //посылаем ASCII код знака ’0′

    while(1)

    {
    _delay_ms(1000);
    }
    }

  7. Анатолий пишет:

    Да,насчет протеуса-там все нормально,а вот в железе такая
    ерунда.

  8. Анатолий пишет:

    ATD+712345678.После восьмерки ноль в угловых скобках.
    Я выше ставил ноль в угловых скобках,но он почемуто не
    отразился в моем послании.

  9. Анатолий пишет:

    Забыл еще одну строку в коде:
    send_UART(0x3B);//в конце
    Вообщем вместо последних трех символов приходит совсем другое.

  10. admin пишет:

    Хм, это странно, я не помню проблем с UART в реальности. Анатолий, с такой проблемой я не сталкивался.

  11. Анатолий пишет:

    Здравствуйте!Вопрос исчерпан.Поставил кварц на 11059200,
    все работает как надо.Большое спасибо за консультацию!!!

  12. admin пишет:

    Спасибо вам! Буду знать)

  13. Анатолий пишет:

    Здравствуйте.Опять обращаюсь к Вам.Все тестирую Ваш исходник.МК-Atmega8,кварц-11059200,скорость-115200,gsm
    модуль-sim800l.С компьютера(Terminal v1.9b)посылаю команду
    ATD+71234567890; на модуль,в ответ приходит звонок на мой
    номер.С микроконтроллера(при нажатии RESET)эта же команда
    приходит в терминал.При подключении микроконтроллера к
    gsm модулю и нажатии RESET,ничего не происходит.
    Уже в конце добавлял 0x0D и 0x0A,но никаких изменений.
    В чем может быть причина?UART-ом только занялся и опыта
    никакого.Может быть и не по теме,но все же.Заранее спасибо!

  14. Анатолий пишет:

    Здравствуйте.Спасибо Вам большое за помощь!Все работает.
    В резисторном делителе был непропай.Сам себя замучал и Вас
    озадачил.А Ваш исходник мне очень помог!

  15. admin пишет:

    Добрый день!

    Да ничего страшного) заодно почитал про «sim800l».
    Сам хотел заняться GSM-ом. Анатолий, у меня есть одна идейка, пока рассказывать не буду.
    В будущем планирую себе купить, «что-нибудь», что может работать с GSM. Мне нужен человек, который сможет принимать звонки на свой модуль.

    Могу ли я обратиться к вам в будущем для проверки своей «идеи» ?

  16. Анатолий пишет:

    Здравствуйте.Конечно,можете обращаться.Придется мне купить
    еще один модуль.Этот я настроил только на передачу(для сигнализации)и прием поUART еще толком не изучал.Но какие
    наши годы!Пишите.

  17. Анатолий пишет:

    Здравствуйте!Мне очень помогла эта Ваша статья.Спасибо Вам
    большое.Не могли бы Вы также доходчиво написать о приеме
    по UART? Зарание благодарю.

  18. admin пишет:

    Добрый день Анатолий!

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

  19. Анатолий пишет:

    Спасибо.Буду пробовать.



Ваш комментарий


Ответ в цифрах

 
© s-engineer.ru, 2012-2017 | Все права защищены