044-UART. Применение в электронных проектах.

Автор: | 15.06.2010

ТитлРаз уж я буду использовать UART для связки устройств блога с Вашими проектами немного расскажу как он устроен и как им пользоваться.

Универсальный асинхронный приемопередатчик (UART) довольно старый и распространенный интерфейс. До недавнего времени разъем COM порта (тот-же UART только уровни напряжения другие) был обязательным атрибутом каждого компьютера. Теперь COM порт постепенно «отмирает» и если на «башнях» он еще не редкость, то на ноутбуках его уже нет и в помине. Но в виду простоты и популярности интерфейса подавляющее большинство микроконтроллеров имеет UART в составе своей периферии. И если персональный компьютер UART перестает удовлетворять из-за низкой скорости и невозможности расширения, то для микроконтроллеров интерфейс удобен и использование его будет продолжаться.
Раз UART есть во многих микроконтроллерах, значит мы его будем использовать как один из интерфейсов связи устройств блога с Вашими электронными устройствами.
Для начала немного теории работы интерфейса (без лишних подробностей). Для связи по интерфейсу UART используется две ножки контроллера  RXD – для приема сообщений (Receiver) и TXD – для передачи сообщений (Transmitter). UART — полнодуплексный интерфейс. Это значит, что приемник и передатчик работают независимо друг от друга. Более того, передатчик или приемник можно отдельно отключить, освободив ножку контроллера для других нужд. Передача (соответственно и прием) сообщений осуществляется фиксированными пакетами битов (такой пакет называют кадром). Кадр состоит из старт-бита (с него начинается каждый кадр), битов данных (может быть от 5 до 9 бит), бита проверки четности (проверка правильности передачи данных) и одного или двух стоп-битов (сигнал об окончании кадра).

Формат кадра UART

где:
IDLE — ожидание обмена — должна быть 1;
St — Старт-бит — всегда 0;
(n) — Биты данных — может быть от 5 до 9 бит;
P — Бит четности;
Sp — Стоп бит — всегда 1.

Если посылка содержит более одного байта, каждый следующий байт передается отдельным кадром. Передача (и прием) данных ведется на определенных фиксированных частотах (измеряется в Бод=бит/сек) от 600 до 128 000 Бод. Условием правильной работы порта есть задание одинаковых параметров, как для приемника, так и для передатчика (скорость, количество бит данных, бит четности, количество стоп битов).

Договоримся о формате кадра (настройках UART) для устройств блога:
Скорость передачи – 9600 (это в пределах килобайта в секунду);
Количество бит данных – 8 (наиболее удобно работать);
Бит четности – Even (производится проверка на четность);
Количество стоп-бит – 1;
В сокращенном варианте это выглядит так:
Baud Rate: 9600, 8 Data, 1 Stop, Even Parity

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

Если нужны дополнительные возможности, то полное описание UART есть в datasheet на микроконтроллер – обращайтесь к нему.

Для того чтобы устройство с блога начало работать с Вашим проектом через интерфейс UART нужно:
1 Подключить устройство блога к соответствующим ножкам микроконтроллера.
2 Настроить приемо-передатчик UART Вашего контроллера. Для этого в соответствующие порта ввода/вывода записать определенные значения.
3 Иметь (написать)  процедуры приема/передачи сообщений по UART в Вашей программе.

Теперь рассмотрим подробно каждый пункт:


1 СОЕДИНЕНИЕ УСТРОЙСТВ ПОСРЕДСТВОМ UART.

Тут все просто:
— если планируется и прием и передача — устройства соединяются по двум линиям — TX_устройства с RX_проекта и TX _проекта с RX_устройства (здесь и далее под «устройством» я буду понимать устройство с блога, а под «проектом» — Ваш электронный проект);
— если нужен только прием (например принимаются данные с клавиатуры) — TX_устройства с RX_проекта;
— если нужна только передача (например передаются данные на устройство отображения) — TX _проекта с RX_устройства.

Соединение устройств по UART


2 НАСТРОЙКА ПРИЕМО-ПЕРЕДАТЧИКА UART.

Как мы договорились выше, формат кадра для наших устройств:
Baud Rate: 9600, 8 Data, 1 Stop, Even Parity
Для работы в с этим форматом кадра нужно в разделе инициализации устройств в Вашей программе, записать соответствующие значения в нужные порта ввода/вывода контроллера. Для этого нужно открыть раздел USART datasheet’а на Ваш микроконтроллер и выбрать/вычислить необходимые значения. Но можно сделать все гораздо проще – использовать автоматические настройщики периферии – CodeWisard’ы.
Возьмем для примера микроконтроллер Attiny2313 (по аналогии можно настроить любой микроконтроллер) и настроим UART в разных языках программирования.

Для начала — Algorithm Builder.
Тут все предельно просто – создаем проект (Файл/Новый). Выбираем микроконтроллер и частоту задающего генератора в Опции/Опции проекта… (ATtiny2313, внутренний задающий генератор на 8МГц). В панели инструментов жмем кнопочку «S» — настройщик управляющих регистров» выбираем USART и в открывшемся окошке заполняем все как на картинке. Там все подписано и понятно.

Инициализация UART в Algorithm Builder

Жмем «ОК».  Готово – UART проинициализирован и готов к работе.
Если нужен только приемник или только передатчик ставим только нужную галочку – незадействованную ножку можно использовать как порт ввода-вывода.

Так как в программе будут разрешены прерывания, нужно перед инициализацией USART установить указатель стека на конец памяти («S»/Stack Pointer SP) и озаглавить вершину блока ключевым словом «Reset».


В ассемблере. Честно говоря, я не знаю, есть ли в асемблерах для AVR настройщики периферии, но даже если нет, простое решение использовать все тот же Algorithm Builder. В окошке настройки USART, в правой части, прописаны мнемокоманды (Operations), обеспечивающие выбранные характеристики. Перевести их в ассемблерный код не составит труда.

Инициализация UART в ассемблере

Переводим в ассемблерные команды.

;USART initialization
;Communication Parameters: 8 Data, 1 Stop, Even Parity
;USART Receiver: On
;USART Transmitter: On
;USART Mode: Asynchronous
;USART Baud Rate: 9600
 
uart_init:	LDI 	R16, $00
		OUT 	UBRRH,R16
		LDI 	R16, $33
		OUT 	UBRRL,R16
 		LDI 	R16,$26
		OUT 	UCSRC, R16
		LDI 	R16,$00
		OUT 	UCSRA, R16
		LDI 	R16,$98
		OUT 	UCSRB, R16

Готово!

С — в программе CodeVisionAVR. CodeVision содержит свой настройщик периферии (CodeWisard), еще похлеще чем у Algorithm Builder’а. Для генерации настроек UART, нажимаем на значок шестеренку (CodeWisardAVR) на панели инструментов. В открывшемся окошке сначала выбираем вкладку Chip в ней выбираем микроконтроллер и устанавливаем частоту, с которой будет работать задающий генератор. Далее выбираем и заполняем вкладку USART в соответствии с нужными характеристиками (если нужен только приемник или только передатчик ставим соответствующую галочку).

Инициализация UART в CodeVisionsAVR

// USART initialization
// Communication Parameters:
// 8 Data, 1 Stop, Even Parity
// USART Receiver: On
// USART Transmitter: On
// USART Mode: Asynchronous
// USART Baud Rate: 9600
 
UCSRA=0x00;
UCSRB=0x98;
UCSRC=0x26;
UBRRH=0x00;
UBRRL=0x33;

Сохраняем сгенерированный проект (File\Generate, Save and Exit) — готово. Создан проект со всеми нужными установками для UART. В проекте инициализируется и другая периферия (зачастую не нужная).  После создания проекта его можно подкорректировать – удалить все не нужное.


3 СОЗДАНИЕ ПРОЦЕДУР ОБРАБОТКИ СООБЩЕНИЙ UART.

Небольшое отступление.
Работу с UART можно организовать различными способами. Например:
— просто ожидать в теле программы когда придет сообщение, постоянно проверяя бит приема сообщения;
— разрешить прерывание и в теле прерывания обрабатывать сообщение;
— создать буфер куда по прерываниям будут загоняться сообщения, а уже в теле программы, «по свободе», считывать из буфера значения;
— еще куча вариантов – выбор за Вами.
Но, исходя из того, что сообщения от устройств, в большинстве своем, единичные (один байт) и не слишком часты (взять, к примеру, клавиатуру – пару нажатий в секунду, не больше), наилучшим вариантом, в плане экономии памяти и скорости обработки, будет обработка сообщения UART в теле прерывания. Под обработкой я понимаю чтение регистров, проверка на правильность приема и сохранение принятого байта в глобальной переменной (своего рода буфер в один байт). Если предполагаются несложные манипуляции с принятым байтом можно их тоже организовать в теле прерывания.

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

Algorithm Builder.
Прием данных осуществляется в процедуре обработки прерывания по окончании приема байта (кадра). Принятый байт записывается в глобальную переменную FromGCnDevice. В теле программы проверяется значение FromGCnDevice ели оно нулевое ничего не принято.

Прерывание приема байта

Если работа с принятым значением несложна можно это сделать прямо в теле обработки прерывания.  
Передача данных производиться без использования прерываний и буфера (аппаратно у UART передатчика существует буфер на 2 байта). Это значит, что комфортно будут передаваться только единичные байты (что мы и планируем делать). Если зарядить сразу строку данных, то микроконтроллер будет заниматься только этой строкой.

Передача байта по UART

Ассемблер.
Прием байта осуществляется в прерывании, результат остается в регистре r17 (если нужно сохраните в SRAM).

;Обработка прерывания по окончании приема байта
 
		PUSH	R16
		IN	R16,SREG
		PUSH	R16
 
		IN	R16,UCSRA	;Читаем статус из UCSRA
		IN	R17,UDR		;Читаем данные из UDR
		ANDI 	R16,$1C
		BREQ	_END		;Проверяем на ошибки
		CLR  	R17
 _END:
 					;в R17 находится принятый байт
		POP	R16
		OUT	SREG,R16
		POP	R16
		RETI

Передача байта

		LDI	R16,значение
		SBIS 	UCSRA,UDRE
		RJMP	PC-1 		; ждем готовности принять байт
 		OUT	UDR, R16	; шлем байт


С — в программе CodeVisionAVR.
Тут все просто CodeWizard вместе с инициализацией UART создает и процедуры для приема-передачи. Единственно что можно тут поковырять так это выкинуть буфер для приема (если разрешить прерывания по приему или передаче автоматически создается буфер). Если этот буфер не нужен процедура обработки прерывания приема байта и процедура передачи могут выглядеть так:

// Глобальная переменная - полученные даные от устройства
// Эсли FromGCnDevice==0 - ничего не получено
char FromGCnDevice;
 
// Обработка прерывания окончания приема байта
interrupt [USART_RXC] void usart_rx_isr(void)
{
char status;
// Получаем байт статуса и данных
status=UCSRA;
FromGCnDevice=UDR;
// Если произошла ошибка при приеме байта то FromGCnDevice=0
if ((status & (FRAMING_ERROR | PARITY_ERROR | DATA_OVERRUN))!=0)FromGCnDevice=0;
}
 
// Процедура передачи байта
void ToGCnDevice (char c)
{
// Ждем окончания передачи предідущего байта
while ((UCSRA & DATA_REGISTER_EMPTY)==0);
// Передаем байт
UDR=c;
}


Во и все про UART. Этого должно хватить для того чтобы подключить устройство к Вашему проекту. По анологии приведенных примеров легко все можно проделать и для других микроконтроллеров АВР.
Ниже оставляю архивы  программ с примерами работы UART для ATtiny2313.
044-UART-CWAVR.zip [7.82 KB] - Пример проекта созданного автоматически CodeWisionsAVR
044-UART-AB.zip [5.11 KB] - Пример программы для работы с UART в Algorithm Builder


P.S. Я слабо знаю С и Asm, поэтому пинать и кидать тапками — разрешается! Мы все учимся.


Инициализируется

(Visited 3 931 times, 1 visits today)

044-UART. Применение в электронных проектах.: 26 комментариев

  1. alexandershahbazov

    Baud Rate Error : 0.2 % ( CodeVisionAVR ) — значит стоял не UART-овский
    кварц .

    Receiver Buffer : 8 ( CodeVisionAVR ) — если на МК посылается сразу
    более 8 байт , то могут быть ошибки , придется увеличивать размер буфера .

    С интересом ждем про SPI и 1-Wire !

  2. GetChiper Автор записи

    Да Baud Rate Error : 0.2 % — это погрешность(уход) частоты UART при использовании текущего задающего генератора (выбран внутренний генератор на 8МГц). Ставить специально для UART кварц не имеет смысла — только ножки потратишь (для UART допускается уход частоты до 10%).

    Receiver Buffer : 8 — можно конечно и увеличить, но память (SRAM) у микроконтроллера не безграничная. Кроме того скорость передачи относительно низкая — микроконтроллер должен успевать «переваривать» принятые байты до переполнения буфера.
    (При переполнении буфера ничего страшного не произойдет: установится переменная-флаг переполнения rx_buffer_overflow и дальше пойдет запись в буфер поверх не прочитанных данных)

    Про SPI следующий пост, а про 1-Wire пока повременю.

  3. plaza

    Прошу помощи в коде C, представленном в статье.
    Что это за оператор & ???
    Я правильно понял что для передачи байта необходимо использовать процедуру ToGCnDevice? а для приема что использовать?
    Заранее спасибо за ответ)

  4. plaza

    @plaza
    упс парсер съел… имел ввиду & amp ;

  5. GetChiper Автор записи

    Давно писал — уже и не помню. Походу это маска управляющих бит регистра UCSRA.

  6. andrianu

    Здравствуйте, у меня вопрос, можно использовать этот конвертер для использования с Arduino, то есть я могу общаться с ПК через HyperTerminal? Это замена конвертера FTDI? Я слышал, что этот чип может быть подключен между устройствами (RX и TX).
    Я планировал сделать клон Arduino, USB программатор я уже сделал, но не хватает общения в реальном времени

    Я прошу прощения за русский, я из Молдовы.

  7. GetChiper Автор записи

    Вы, наверное, немного не туда написали вопрос. Но если Вы имеете в виду соединение микроконтроллеров между собой, то это возможно.

  8. andrianu

    может быть я не ясно выразился. даваите по ступениками, и по проще. У меня контроллер, и ПК. И я тупо в хипертерминале хочу увидеть значение АЦП (разумеется, с положеным для этого кода). Грубо говоря, хочу зделать аналог FTDI кабеля. (в буржуиском литературе он хорошо описавается, но мне не достать мах232 микруху, и такое решение как у вас не увидел ещё). Вопрос, этот преобазаватель, будет замена коневртера(USB-TTL)? дело в том что я не разобрался с уровням RS232, и уровни TTL, что привело мне в заблуждение.

  9. andrianu

    @GetChiper
    Большое спосибо, за ответ. Там очень ясно всё описоно, это я не старался искать, гыы… Прочитал почти весь саит, очень приятно собирать что-то уже собраное в практике, надежда что заработает вырастает. Так держать!

  10. alexsey77

    Очень интересная статья, а как к примеру из МК ATMEGA32 через UART можно EEPROM считаь и записать-? (к примеру нужно константы там менять).

  11. GetChiper Автор записи

    Нужна программа внутри меги.

  12. alexsey77

    GetChiper :
    Нужна программа внутри меги.

    :)…..ну это я и сам понял.Может есть рабочий пример-? (образец)

  13. GetChiper Автор записи

    Если нужно просто посмотреть/поменять содержимое EEPROM проще считать программатором эту область с МК, посмотреть/подкорректировать и записать назад. Тот-же юнипроф http://www.getchip.net/posts/025-uniprof-universalnyjj-programmator-dlya-avr/ может прямо в окне показать содержимое EEPROM

  14. alexsey77

    GetChiper :
    Если нужно просто посмотреть/поменять содержимое EEPROM проще считать программатором эту область с МК, посмотреть/подкорректировать и записать назад. Тот-же юнипроф http://www.getchip.net/posts/025-uniprof-universalnyjj-programmator-dlya-avr/ может прямо в окне показать содержимое EEPROM

    Просто посмотреть меня не устраивает (можно просто PonyProg запустить и считаь только еепром), передо мной стоит задача минимум из командной строки считывать и записывать константы в определенные ячейки еепром. А в перспективе написать оболочку (например на Делфи)для быстрого перепрограммирования этих констант.И вот как это все в комплексе увязать не соображу.

  15. chipgetter

    в си и асм не силен, но других научу — настоящий педагогог!

    подскажи, а usart и uart — одно и то же? в codevision (он все же vision!) идет инициализация портов и таймеров — это просто для порядка, в нашем случае не используется?

    первые строчки define вообще непонятны — буду курить даташит по 2313
    что значит иф за решеткой? (про RX_BUFFER_SIZE)

    а как правильно отправлять сразу строчку, скажем, из 10 ascii символов?
    для отправки байта достаточно в основном цикле делать put(byte)?

  16. iamstreetstyle

    USART и UART одно и тоже.

    #define PI 3.14 это опредиление означает что теперь в тексте программы ты можеш писать так B=A*PI; вместо B=A*3.14;. Это макрос для сокращения печатного текста или удобства.#if #else #endif #ifdef #ifndef тоже самое но для акробатики с опредилениями :)))) Это часть языка си и искать инфу надо в самаучителе по си а не в даташите на мк.

    В CVAVR put(char a) для отправки символа, для отправки строчек puts(char a[])

  17. vanuha_63

    Здравствуйте, коллеги. Имется AtMega16 -с него требуется передать по конкретному адресу другому контроллеру ( AtMega8 или AtTiny 2313)несколько байт и сразу принять от этого контроллера несколко байт. И так по очереди несколько ( до 8 ) «периферийных» контроллеров. Есть идея замутить что-то вроде » умный дом» ( часы; регуляторы температуры, исполнительные реле, измерение влажности, и т. д). В програмировании AVR я новичок. Повторил несколько готовых проектов, некоторые доработал аппаратно и програмно. В инете есть много схем , реализующих связь по USART типа МК-комп, а вот сетевых решений мне не попадалось . Максимальная длина линии связи предпологается 50 метров, поэтому RS-485, хотя для передачи \ приема нескольких байт дорговато, но другие интерфейсы (I2S ; SPI) не имеют нужной дальности связи. Загвоздка как програмно реализовать обмен по адресам.Подскажите или сообщите ссылку.

  18. GetChiper Автор записи

    Почитайте дататшит на контроллер. UART микроконтроллера умеет адресно передавать данные.

  19. vanuha_63

    Может подскажете ссылку с даташитом на русском языке на Atmega 16; AtMega8 ; AtTiny2313

  20. GetChiper Автор записи

    Ищите поисковиком книгу Микроконтроллеры AVR семейства Mega А.В.Евстифеев
    Это своего рода подборка даташитов на русском.

  21. siema

    На просторах этого сайта уже задавал этот вопрос, но отложил, т.к. не получил ответ и до сих пор не решил самостоятельно проблему с соединением мобильника и мк. В HyperTerminale через MAX202 могу посылать АТ команды и получать отклики. В Proteus программа работает через COMPIM без проблем. И даже один раз удалось запустить в железе пока не решил унифицировать решение.
    Мобильник старый Siemens M35 с уровнем логики 2.75В, как понял. Запустилось когда с выхода 4 мобильника (3.7В) запитал схему МК. Этот выход как раз для таких целей и предназначен. Но хотелось универсальности, т.к. валяются другие Siemens и даже Motorola, поэтому стал искать решения по согласованию уровней на резисторах, резисторе и стабилитроне, резисторе и диоде со смещением по 2.75В. Пробовал подключить даже через MAX с заворотом сигналов…
    Плату сильно искорежил постоянными перепайками, поэтому припаял проводки на плате МК длиной 40-50мм, к которым паяю радиодетали. Так сказать, навесной монтаж.
    Если при положительном исходе на выходе 4-го контакта Siemens было напряжение 3.7В, то сейчас — 4.1В. Возможно что-то спалил в телефоне, возможно другой АКБ, но этот 4-й выход =выходу АКБ и должен быть 3.7В. Поэтому осталось единственное решение — согласование уровней. И где-то столкнулся на иносранных сайтах, что соединения по USART капризные на наличие «завитков» и других навесных проводных соединений. А у меня проводки по 5см и резисторы/диоды с длиной выводов по 3см…
    Прошу данную догадку подтвердить или опровергнуть информацию о неприемлимости использования навесного монтажа по трассе USART.

  22. GetChiper Автор записи

    Немного не понял вопроса.

  23. siema

    @GetChiper
    Я так и думал, что проще будет показать на фото :). Сделаю — перешлю ссылку. Имелось ввиду, что при навесном монтаже деталей будут создаваться помехи, которые будут препятствовать принятию решения на приемной стороне.

  24. siema

    И осциллографа нет… Буду заказывать с Китая USB-приставку после НГ.

  25. Сергей-Курушин

    2siema не люблю некропостить, но…
    по поводу вывода с меняющимся напряжением: похоже этот вывод подключен напрямую или через диод/резистор к АКБ телефона. полностью заряженный АКБ имеет напряжение около 4.2В, полностью севший — примерно 2.8-3.0В. так что всё норм.
    длина проводов тут не при чём. дело в в том, что длинна соединения зависит в основном только от качества применяемого проводника, наличия внешних помех и скорости передачи данных. главное найти золотую середину среди этих 3-х параметров. в вашем случае при работе с телефоном «на коленке» на это не стоит даже обращать внимания.
    Вывода RX и TX должны иметь подтяжку к питанию процессора/контроллера (как правило это делается или в самом МК, или внешне). Обычно ставлю 10К и этого хватает. Для согласования уровней советую ставить так называемые левел-шифтер (Level-Shifter) микросхемы. Они имеют общую землю и 2 разных порта (A — B) со своим питанием. Есть микросхемы с фиксированными уровнями портов (например, А — 3,3V, B — 5V), есть с линией опорного напряжения одного из портов и на второй порт выдаются сигналы по уровню одинаковые с этим напряжением (с небольшим смещением в минус). Есть и более простой способ: на одну линию повесить двойной инвертор на n-p-n транзисторах или N-MOS полевиках (схема включения с общим эмиттером или её ещё называют открытый коллектор). можно применить ULN2004, например. подтяжку для каждого коллектора идущего к телефону лучше сделать подключаемой перемычками и при необходимости брать с того самого 4-го выхода, а на выход/вход интерфейса подключаемого к телефону необходимо установить согласующие резисторы номиналом 100-300 Ом дабы не спалить порты. транзисторы можно брать любые имеющиеся под рукой (скорость интерфейсу не нужна), главное — одинаковые. неплохо было-бы быстренько схемку набросать, но я не вижу тут возможности прилепить её к комментарию.

Добавить комментарий