UART — это Universal Asynchronius Receiver Transmitter, универсальный асинхронный приемо-передатчик. Но если говорить проще, это обычный последовательный порт (он же COM-порт, он же RS-232), которые раньше часто использовались в персональных компьютерах для подключения мыши, модема и прочих периферийных устройств. С повсеместным распространением USB последовательный порт потерял свою популярность, но в микроконтроллерах он все еще довольно часто используется, так как это один из самых простых способов связать два устройства. При помощи uart к микроконтроллеру можно подключить GSM модем, GPS приемник, или другой микроконтроллер. В зависимости от используемых преобразователей уровня можно получить rs232 или rs485. Так же существуют конвертеры rs232-USB, rs232-ethernet, rs232-bluetooth которые позволяют подключить устройство на микроконтроллере с rs232 используя более современные интерфейсы.
В UART используются две линии (вывода микроконтроллера): rx — для приема и tx — для передачи. В USART добавлена дополнительная линия clk для синхронизации приемника и передатчика, что позволяет увеличить скорость обмена.
Данные по uart передаются в следующем формате:
Старт-бит — служит для определения начала посылки
Биты данных — может быть от 5 до 9 бит, но наиболее часто используется 8 бит — один байт.
Бит контроля четности — позволяет проверить не произошел ли при передаче сбой.
Стоп биты — 1 или 2 бита, служат для определения окончания посылки.
Для uart в avr atmega настраивается несколько параметров:
- скорость обмена
- количество бит данных
- контроль четности
- количество стоп-бит
Рассмотрим настройку uart/usart для avr atmega8.
Настройка скорости обмена по uart в avr
Для настройки скорости используется регистр UBRR (Usart Boud Rate Register)
Для установки скорости в этот регистр надо записать значение рассчитанное по формуле:
UBRR = ( F /( B * 16 ) ) - 1
Где:
- F — тактовая частота, на которой работает микроконтроллер avr, например 11059200 для кварца 11.0592 МГц
- B — требуемая скорость, например 115200 (бит/с)
Пример расчета для кварца 11.0592 МГц и скорости 115200 бит/с:
( 11059200/( 115200*16 ) ) - 1 = 5
Полученный результат записываем в UBRR, т.к. этот регистр 16-битный то доступ организован через два 8-ми битных регистра
UBRRH = 0; //старший байт UBRRL = 5; //младший байт |
Если в результате вычисления UBRR получалось не целое число, то в регистр записывается округленное значение, частота обмена при этом будет отличаться от той, что была заданна при расчете. Расхождение в частоте может приводить к сбоям при обмене данными, по этому надо выбирать такой кварц, при котором для заданной скорости обмена UBRR будет целым числом.
Также в регистре UCSRA имеется бит U2X, позволяющий удвоить скорость обмена. В случае когда этот бит выставлен, для расчета значения UBBR используется следующая формула:
UBRR = ( F /( B * 8 ) ) - 1
Настраиваем количество бит данных для uart в avr
Зависимость количества бит данных от состояния бит UCSZx регистра UCSRC для uart/usart в atmega8
UCSZ2 | UCSZ1 | UCSZ0 | количество бит данных |
0 | 0 | 0 | 5 |
0 | 0 | 1 | 6 |
0 | 1 | 0 | 7 |
0 | 1 | 1 | 8 |
1 | 1 | 0 | 9 |
Пример настройки uart/usart avr atmega8 на 8 бит данных:
UCSRC = ( 1 << URSEL ) | ( 0 << UCSZ2 ) | ( 1 << UCSZ1 ) | ( 1 << UCSZ0 ); |
Настройка контроля четности для uart в avr
Зависимость режима контроля четности от состояния бит UPMx регистра UCSRC для uart/usart в atmega8
UPM1 | UPM0 | контроль четности |
0 | 0 | запрещен |
1 | 0 | дополнение до четности |
1 | 1 | дополнение до нечетности |
Пример настройки uart/usart avr atmega8 на режим с отключенным контролем четности:
UCSRC = ( 1 << URSEL ) | ( 0 << UPM1 ) | ( 0 << UPM0 ) ; |
Настройка количества стоп-бит для uart в avr
USBS | количество стоп-бит |
0 | 1 |
1 | 2 |
Пример настройки uart/usart avr atmega8 на режим с одним стоп-битом:
UCSRC = ( 1 << URSEL ) | ( 0 << USBS ); |
Разрешение приема и передачи данных по uart
Для того что бы разрешить прием и передачу данных надо выставить соответствующие биты в регистре UCSRB:
UCSRB = ( 1 << TXEN ) | ( 1 << RXEN ); |
Обобщенная функция настройки uart для avr atmega8
Так как настройка количества бит данных, контроля четности и количества стоп бит производится через регистр UCSRC, то установку всех необходимых бит объединим в одну строку. Также не будем указывать биты которые сбрасываются в 0.
Пример настройки uart/usart avr atmega8 на 8 бит данных, 1 стоп-бит, отсутствие контроля четности, скорость обмена 115200 бит/с:
void uart_init( void ) { //настройка скорости обмена UBRRH = 0; UBRRL = 5; //8 бит данных, 1 стоп бит, без контроля четности UCSRC = ( 1 << URSEL ) | ( 1 << UCSZ1 ) | ( 1 << UCSZ0 ); //разрешить прием и передачу данных UCSRB = ( 1 << TXEN ) | ( 1 <<RXEN ); } |
Передача байта по uart в avr
Для передачи надо записать данные в регистр UDR, но перед этим надо убедиться что предыдущий байт уже отправлен.
Пример функции для передачи байта по uart/usart avr atmega8:
void uart_putc( char c ) { //ждем окончания передачи предыдущего байта while( ( UCSRA & ( 1 << UDRE ) ) == 0 ); //передача данных UDR = c; } |
Прием байта по uart в avr
Для того что бы определить принят ли байт или нет используется бит RXC регистра UCSRA.
Так же в этом регистре находятся флаги говорящие о том что произошла ошибка при приеме данных:
- бит FE (Frame Error ) — ошибка кадрирования. То есть вместо стоп бит пришел 0.
- бит PE (Parity Error) — ошибка контроля четности. То есть не совпали принятый и рассчитанный биты четности.
- бит OR (OveRflow)- переполнение буфера. То есть следующий байт уже принят а предыдущий еще не считан из регистра UDR.
Пример функции для приёма байта по uart/usart avr atmega8:
unsigned char uart_getc( void ) { //ждем приема байта while( ( UCSRA & ( 1 << RXC ) ) == 0 ); //считываем принятый байт return UDR; } |
Простая программа для avr
Теперь можно написать простую программу, которая выводит в uart «Hello world» а потом переходит в режим «эха» — отправляет обратно принятые символы.
#include <avr/io.h> void uart_init( void ) { //настройка скорости обмена UBRRH = 0; UBRRL = 5; //8 бит данных, 1 стоп бит, без контроля четности UCSRC = ( 1 << URSEL ) | ( 1 << UCSZ1 ) | ( 1 << UCSZ0 ); //разрешить прием и передачу данных UCSRB = ( 1 << TXEN ) | ( 1 <<RXEN ); } unsigned char uart_getc( void ) { //ждем приема байта while( ( UCSRA & ( 1 << RXC ) ) == 0 ); //считываем принятый байт return UDR; } void uart_putc( char c ) { //ждем окончания передачи предыдущего байта while( ( UCSRA & ( 1 << UDRE ) ) == 0 ); UDR = c; } void uart_puts( char *str ) { unsigned char c; while( ( c = *str++ ) != 0 ) { uart_putc( c ); } } int main( void ) { uart_init(); uart_puts( "Hello uart\r\n" ); while( 1 ) { char c = uart_getc(); uart_putc( c ); } return 0; } |
Cкачать исходники под avr-gcc (WinAvr) можно тут.
Спасибо за статью. Все предельно понятно.
Сначала написал свою программу, выдает околесицу.
Думаю возможно я криворук, забил вашу… Тоже не понятные символы.
Дело ясное скорость обмена не совпадает. Естественно я перещитал опираясь на свою мегу. Стоит кварц на 5мГц, но фьюзы стоят по умолчанию, значит мега работает от внутреннего генератора с частотой 1мГц.
значит (1000 000 / (9600 * 16) )-1 = 5,5 брал 5 и 6 для UBRRL/ Ни одно не подходит. Схема исправна, так как уже забивал прогу для UART, работала норм. В коде расчет UBRRL был «автоматический» под 9600, а что вместо частоты МК там бралось не разобрался, прогу найти не могу…
Подскажите в чем дело может быть?(может быть частота МК всеже не 1мГц?, можноли както выяснить?)
foton6, какой у вас микроконтроллер?
Что бы проверить частоту можно через заданный промежуток времени изменять состояние какого-нибудь вывода и осциллографом посмотреть. Ну или в крайнем случае светодиодом мигать раз в секунду и посмотреть сколько раз он мигнет за минуту.
Atmega 8A-PU да как раз сегодня почитаю вашу статейку на счет таймеров и выясню частоту. На крайний случай поиграю с фьюзами и выставлю частоту.
Что-бы сделать задержку не обязательно использовать таймеры, можно использовать функцию _delay_ms.
Кстати вспомнил, я когда-то тоже делал обмен по uart с тактированием от внутреннего RC-генератора. У меня тоже выводились крокозябры. Эту проблему тогда решил используя регистр подстройки частоты OSCCAL.
Сделал цикл в котором изменял этот регистр от 0 до 255 и выводил это значение в uart.
В каком-то диапазоне значений OSCCAL текст стал выводиться нормально. Взял значение из середины этого диапазона и записывал его в регистр OSCCAL при старте программы. После этого все заработало.
Но лучше все-таки тактировать от кварца, причём подбирать его так что-бы не надо было округлять значение, записываемое в UBRR, например кварц 11.0592 или 7.3728 МГц.
Не стал морочится с высчитыванием точной частоты ))
Просто фьюзы под внешний кварц выставил, работает отлично.
В статье очень порадовали таблицы с битами, а то в большенстве статей(которые я читал) люди пишут куда ставить биты, а зачем, а уж темболее что будет если иначе поставить, не пишут.
Конечно все есть в дата шите(по крайней мере по утверждениям) , а с ин-язами дела обстоят очень плохо. Я конечно летом пойду на курсы английского(сейчас физически не получается: учеба, работа.). Благодаря подобным статьям лишь удается пока двигаться )))))
СПАСИБО !
Пожалуйста! Будут еще вопросы — пишите, буду рад помочь :)
Спасибо за подробную статью. Но есть один вопрос, который лично я никак не могу реализовать — это прием строки байт через UART в МК. Пробовал все возможные способы с буфером, но обрабатывать передачу МК так и не захотел.
Если Вам нужен приём текстовой строки, то попробуйте следующий код :
доброе время суток, у мя вопрос: есть N устройств хочется их объединить в сеть много прочитал, везде видится логика 1-master N-slave. теории и букав много, а вот схем реальных рабочих устройств нет т.е. я пытаюсь понять логику работы учитывая что у всех устройств может быть разная частота работа разные кварцевые генераторы внешние или внутренние, скорость uart по логике как то уравновешивает эти вопросы приводя работу по обмену между master любым slave по примерно одной частоте, но вот все равно присутствует ощущение вероятности сбоя/потери чего то. есть подозрения что МК между собой кроме TX и RX объединены чем то еще чтото типа синхронизации. Огромная просьба разъяснить эти моменты с приведенными ссылками на какие то схемы/проекты/статьи. Спасибо вам Артем за рожденный энтузиазм и интерес
Доброго времени суток, Vital.
Вы всё правильно поняли, при обмене по сети есть один мастер и несколько ведомых.
Тактовая частота у них может быть разная, но частота обмена должна быть одинаковая, при этом если используется внутренний RC генератор, то его лучше откалибровать, что бы было меньше ошибок.
При этом обычно используется RS485. Дополнительной синхронизации нет. Сбои и потери отслеживаются при помощи таймаутов(timeout) и контрольной суммы.
Алгоритм работы такой:
Мастер отправляет пакет, в котором содержится адрес устройства
Все ведомые этот пакет получают, но отвечает только то устройство адрес которого совпал.
Мастер принимает ответ от ведомого и переходит к опросу следующего устройства.
Если ответа от ведомого нет в течении некоторого времени (таймаут), то мастер повторяет попытку опроса ведомого.
Пакет обычно имеет следующий вид:
| адрес | длина данных | данные | контрольная сумма |
Можно взять за основу modbus.
Если есть ещё вопросы — пишите, постараюсь ответить.
P/S Если не секрет, что за сеть из устройств?
Да все прозаичнее Артем, пока все устройства у меня в голове) не было не единой практики работы в живую лишь чтение и фантазии, поэтому столько вопросов. Касаемо протокола в голове тоже есть представление так как сам программист чистой воды разные структуры данных сложные алгоритмы это для меня легко, работал с сетями вплотную и свои протоколы использовал и чужие слушал) а вот опыта с схемотехникой не было, и стоило задуматься на уровне устройства и учитывая практику с дискретизацией задумался о том как же железяка работает то, в голове логика вроде работает и без всяких чтений но очень хочется увидеть какие то готовые проекты со схемами разных устрой и исходниками кодов, может есть такой источник который послужил бы мне хорошим материалом?) спасибо
как только познаю мастерство хоть по минимуму начну практику, и обязательно поделюсь всеми бредовыми идеями) на самом деле вопрос разных много и по разным тематикам, если интересно передать навыки или помочь найти решения могу мучить вопросами)
Готовые проекты поищу, что-то было.
А пока готов к мучению вопросами :)
Пишите — постараюсь помочь.
Доброе время суток) вопрос у мя прозаичный, может подскажите простой uart терминал как сделать/где взять? т.е. не хочется к ПК прикручивать а смотреть о чем думает микросхема хотелось бы
спасибо
А почему к ПК не хотите подключать?
можно взять готовый uart-usb переходник, на мой взгляд, это самое простое решение
у меня проблем )))) помогите мне пожалуйста))) буду очень благодарен))))) я прошил atmega8A-PU на usart-эхо на кварце 16Mhz на скорости 115200 бод (что я подаю то и принимаю в терминале)……… atmega8A-PU на кварце 16Mhz подключен к COM-USB адаптер к ноутбук и через терминал подаю символы на atmega8A-PU а принимаю другие символы (например подаю «6» а получаю в ответ «3») вот в этом проблема))) помогите , объясните в чем причина
Мне кажется, всё дело в кварце. При расчете значения которое надо записать в UBRR получается не целое число. В результате частота обмена не 115200 а немного другая. Попробуйте поставить другой кварц например на 11059200 Гц, 7372800 Гц, или 14745600 Гц.
все получилось ))))дело было в купленном мной usb-uart ))) я купил FT232RL собрал плату на нем , подключил к нему мою atmega8 и все получилось ))) кварц поставил на 7372800 Гц))) ура )))
дело за малым
Создал программку на делфи для управление через uart )))запрограмировал на кнопку посылается «1» на atmega но аtmega не зажигает светодиод))) а в терминале посылаю ,зажигается свето диод )))вопрос вчем причина )))
Здравствуйте Артем! У меня есть один вопрос, прочитал вашу статью про работу с UART, почему то когда отправляю данные через преобразователь USB-RS232 на комп, в терминалке выходят непонятные символы, можете что нибуть посоветовать?
Здравствуйте!
Посоветовал бы проверить, совпадает ли скорость обмена, настроенная на контроллере и компьютере.
А еще убедиться, что выставлены нужные fuse-bit’ы. Если расчет велся для кварцевого резонатора, то и fuse-bit’ы должны выбирать работу от кварца.
Спосибо, проверил еще раз преобразователь USB-RS232 оказывается в нем проблема, драйвер для него установил не тот))
Пожалуйста! Удачи в разработке и безглючных программ ))
на сколько режимов можно настроить UART, если не менять скорость приема/передачи?
Добрый вечер! Большое спасибо за вашу статью, все понятно и доступно изложено! У меня вопрос. У меня atmega8a.
Пробовал в протеусе — скорость правильная, как и должно по документации, а на практике совсем другая скорость. в чем дело?
Доброго времени суток, Ваха.
Мне кажется, у Вас ошибка в формуле:
Должно быть:
И два дефайна MYUBRR не нужны, Вы же задаете скорость при помощи макроса BAUD.
Если и это не поможет, проверьте fuse биты, может быть микроконтроллер работает от внутреннего RC генератора, а не от внешнего кварца.
«И два дефайна MYUBRR не нужны, …» — это я вам работающие варианты хотел показать, в том числе и удвоение скорости. а вот с (BAUD * 8UL) не заработало ни на какой скорости
Добрый день! Спасибо, что нашли время! МК работает от внутреннего генератора. Значения перебирал разные, остановился на этих (16 и 64), они только и работали. Просто не могу понять, почему не соответствуют формуле. Вроде у всех на сайте работает правильно, как и рассчитывали, а у меня методом тыка получается.
Если работает от внутреннего RC генератора, то проверьте на какую частоту он настроен fuse битами. По умолчанию настроено на 1МГц.
В этом случае надо задавать другую частоту.
#define F_CPU 1000000UL
Установил fuse и все заработало правильно. Это не единственное где у меня были проблемы с этой частотой, но теперь то все понятно. Большое спасибо! Всем удачи!
Пожалуйста! Заходите ещё :)
Поясните пожалуйста строчку
uart_puts( «Hello uart\r\n» ); я принципе понимаю что мы тут отправляем значения Hello uart и переносим курсор на следующий строчку. Здесь опять же условие if( (c == ‘\n’) || ( c == ‘\r’ ) ) подскажите почему \n и почему \r есть ли еще такие обозначения .. и как правильно принять строчку с С#
Сергей,
вы правы, uart_puts( «Hello uart\r\n» ) передает в UART строку «Hello uart» а затем символ перевода коретки ‘\r’ и символ перевода строки ‘\n’.
Если принимать эту строку в терминале, то при приеме символа ‘\r’ текущая позиция переместится на начало строки, а при приеме символа ‘\n’ перейдем на новую строку.
Кроме этих символов еще часто используются ‘\t’ — символ табуляции, ‘\0′ — нулевой символ (конец строки).
При вводе строки с терминала ввод заканчивается нажатием на ENTER, и в зависимости от настроек терминала он отправляет либо ‘\r\n’ либо ‘\n\r’ или ‘\n’. По этому признаку и заканчиваем принимать строку и переходим к её обработке.
Я не специалист по C# но могу подсказать что в среде Net2.0 для работы с COM портом можно использовать класс SerialPort и для чтения строки вызывать метод ReadLine.
Максимальная скорость в битах в секунду или (kb/s), как установвит Atmega8
один пример Напишите пожалуйста
Максимально возможную скорость можно рассчитать по простой формуле — (тактовая частота микроконтроллера)/8.
Чтобы UART стал работать на этой скорости надо установить регистр UBRR = 0 и выставить бит U2X в регистре UCSRA.
Вы можете помочь написать программу для UART на проект вольтамперметр на atmega8a.
ниже бросаю то я уже сделал
если кто-то поможет буду очень благодарен
схема прибора https://yadi.sk/i/w3PaJNftgC2fv