Работа с UART в AVR
   
				

Работа с UART в AVR



	
В библиотеке AXLIB есть набор функций для работы с UART.

Что такое UART? По русски "Универсальный Асинхронный Приемо-Передатчик". Под словом "Универсальный" подразумевается что он не привязан к какому-либо протоколу. Передача происходит чисто стандартным пакетом, равным одному байту. "Асинхронный" говорит о том что данная линия не имеет синхро-сигнала, такие как у I2C(SCL), SPI(SCK). Отсюда возникает жесткое требование к соблюдению четких временных интервалов с обеих сторон. "Приемо-Передатчик" говорит о том что мы можем как принимать данные, так и передавать, но в полудуплексном режиме. Либо принимаем, либо передаем. К сожалению у МК всего один регистр данных(точнее их два, для приема и для передачи свой, но адрес у них один и то тже). Теперь давайте разберем пакет. У UART есть две линии, приемника RxD и передатчика TxD. Для того чтобы передать байт, нам нужно всего навсего занести его в регистр данных. Далее тракт UARTа МК подхватит данные и отправит их в линию. А что именно он отправит. На линии TxD передатчика всегда висит логическая единица. Это связано с помехоустойчивостью. Если к примеру тишину в эфире принять логический ноль, то любая наводка сможет инициировать передачу, а этого нам не надо. Отсюда и была принята единица. Что происходит когда передатчик начинает передавать данные в линию. Сначала он подает стартовый бит. Просто прижимает линию к нулю.(Все биты передаются со строгими временными интервалами, то есть для каждой скорости свое количество времени для передачи бита. Пока это рассматривать не будем, оставим на потом). Приемник в свою очередь увидев на линии стартовый бит начинает слушать в ожидании первого бита байта. Передатчик продержав на линии определенное время ноль начинает передавать первый бит байта. Удержав так же первый бит на линии, передает следующий и так пока не передаст весь байт. (UART поддерживает передачу не только восьми бит, но и девяти. Все зависит от настройки порта. Но как показала практика, чаще всего 98% используют восьми битную передачу). После переданного байта идет бит четности или как его еще называют паритет. Что он делает. Данный бит дополняет байт но таким образом, чтобы число единиц в байте вместе с битом четности было не четное количество. Вот откуда такое название. Если к примеру передаем 0xFF(0b11111111) число единиц восемь. Непорядок, добавляем бит четности единицу. Стало девять единиц, не четное количество. Если к примеру посылаем 0x7F(0b01111111) число единиц теперь семь, то бит четности будет равен нулю. По приему приемник посмотрит и посчитает количество бит и если число будет четным, то пакет будет считаться битым. Далее после бита четности идет(идут) стоп бит(биты). Они идут единицами. Бывают один, полтора, два стоп бита. Такое количество связано с надежной передачей. Из личного опыта бит четности сейчас мало кто использует и самый распространенный расклад, восемь бит, один стоп-бит и без бита четности. А теперь давайте взглянем на пакет в живую. Я не стал особо мудрить и подключил осциллограф к порту ПК. Далее я постоянно выдавал в порт число 9. В бинаре девятка будет выглядеть 0b00111001. Да, да именно 0x31. Дело в том что ПК выдает не чистую девятку, а ее код ASCII.

Байт переданный через UART
на осциллограмме

Что мы здесь видим. Если смотреть слева на право, то видно что сначала линия в единице. Затем следует ноль(Старт). После старта идут восемь бит нашей девятки, а за ней стоповый. Теперь что касается временных интервалов. Временные интервалы задаются путем указания скорости передачи. Об этой скорости должны знать оба устройства обязательно. К примеру берем скорость 9600 бод. Что это значит. 1 бод равен одному биту пройденному по шине за одну секунду. То есть скорость 9600 бод говорит нам что за одну секунду шина может передать 9600 бит. Но тут есть закавыка. Количество бит в секунду учитывается байт и все к нему прилагающиеся биты. И стоп и старт и даже бит четности. То есть к примеру если скорость 9600 бод, а мы передаем один старт плюс восемь бит данных и один стоп, то 9600 разделив на 10 мы получим 960 байт в секунду. Вот так не хитро работает UART. А теперь можно забыть про всю эту лабуду, так как весь этот огород с временными задержками, формирования стоп и старт битов ложится на плечи МК. Наша задача лишь рассказать ему что как и что слать и как и что получать. Для этих целей у МК есть несколько регистров. UCSRA - Регистр управления состоит из восьми бит. Что для чего. 0 - MPCM Режим мультипроцессорного обмена. (Нам он не понадобится) 1 - U2X Режим удвоения скорости. (Никогда им не пользовался) 2 - PE Флаг ошибки контроля четности. Помните бит четности? Вот если в регистр данных придет пакет, а единичек будет четное количество, то этот флажок выставится. Если все нормально или вообще нет проверки, то этот флажок будет всегда сброшен, то есть ноль. 3 - OR Флаг переполнения. Выставляется если пришел стартовый бит, а в регистре данных еще лежит не прочитанный байт. Некуда пихать новый. 4 - FE Флаг ошибки кадрирования. Выставится если вместо единицы стоп бита мы получим ноль. Битый пакет. 5 - UDRE Этот флаг установится в единицу когда в регистре данных ничего нет. Так же по этому флагу происходит прерывание. Если оно разрешено. 6 - TXC Флаг завершения передачи. Установится в единицу когда все биты убегут из сдвигового регистра в линию, а в регистре данных ничего пока нет. Так же может быть инициатором прерывания. Сбросить его можно программно, либо сам сбросится при обработке прерывания. 7 - RXC Флаг завершения приема. Данный флаг устанавливается в единицу когда в регистре данных появился новый байт. Сбрасывается сам после чтения байта из регистра данных. Так же генерит прерывание. UCSRB - Регистр управления. Состоит из восьми бит. Что для чего. 0 - TXB8 Сюда надо записать девятый бит при 9-ти битной передаче. 1 - RXB8 Сюда запишется 9-й бит при приеме 9-ти битной передаче 2 - CHR9 Сам бит разрядности. Если "1" то 9-ти битная передача, если "0", то 8-ми битная передача. По умолчанию 8-ми. 3 - TXEN Разрешение передачи. Выставляем в "1" если нужно разрешить передачу. 4 - RXEN Разрешение приемника. Выставляем в "1" если нужно принимать данные. 5 - UDRIE Разрешение прерывания при очистке регистра данных. То есть если мы выставим здесь "1", то при пустом регистре данных будет генериться прерывание. 6 - TXCIE Данный флаг разрешает прерывания по завершению передачи. 7 - RXCIE Данный флаг разрешает прерывания по приему данных. UCSRC Регистр управления. Состаит из восьми бит. Что для чего. 0 - UCPOL Полярность тактового сигнала. (На него можно забить и забыть) 1,2 - UCSZ0, UCSZ1 Формат посылок. Разрядность. 3 - USBS Количество стоп битов. Помним про них? "0" один стоп бит, а "1" два стоп бита. 4,5 - UPM0, UPM1 Режим контроля четности. Нафик его, не трогаем. 6 - UMSEL Режим работы USART. Если выставить этот разряд в "1", то модуль перейдет в синхронный режим. Нам это не надо. 7 - URSEL Выбор регистра. А вот это вынос мозга. Данный разряд нужен для выбора регистра для записи. Если мы хотим произвести запись в регистр UCSRC, то сюда нужно записать "1", а если мы сюда запишем "0", то запись будет идти уже в регистр UBRRH. У этих двух регистров один и тот же адрес. Вот это надо вкурить! UBRRx - Задание скорости передачи. Тот самый битрейт. Что нужно записать в этот регистр. Есть две формулы, одна для обычной скорости, а вторая для удвоенной скорости. Помним разряд U2X? Считается это так. Для обычной скорости U2X = 0. UBRR = XTAL/(16*битрейт)-1 (XTAL - частота кварца) Для удвоенной скорости U2X = 1. UBRR = XTAL/(8*битрейт)-1 (XTAL - частота кварца) Да совет. Для более надежной передачи старайтесь использовать кварцы с частотами 1.8432МГц, 3.6864МГц, 7.3728МГц и тому подобные. Данные частоты кратны основным скоростям и при их использовании вероятность возникновения ошибки при расинхронизации сведена к нулю. Все, с теорией закончили. Переходим к практике. #include<avr/io.h> #include<util/delay.h> #define F_CPU 7372800UL // Частота кварца int main(void) { unsigned char out = 0; // Настройка UART // USART Инициализация // Параметры связи: 8 бит, 1 стоп-бит, Без проверки четности // USART TXD: Включен // USART Режим: Асинхронный // USART Битрейт: 9600 UCSRA = 0x00; // Флаги. Здесь будем только читать. UCSRB = 0x08; // Разрешаем только передачу 0x00001000 4-й бит TXEN UCSRC = 0x86; // Формат посылки. Количество бит в пакете. Примем 8 бит(байт) // Разряды UCSZ0 = 1, UCSZ1 = 1. И не забываем // что у нас есть бит селектор URSEL. // Помните Что если нам надо писать в URSEL, // то этот бит надо выставить в "1" // Отсюда и записываем 0b10000110 3-й и 4-й // разрядность, а 7-й выбор записи в регистр // UCSRC UBRRH = 0x00; // Скорость передачи UBRR = XTAL/(16*битрейт)-1 // 7372800/(16*9600)-1 = 47 в HEX 0x2F UBRRL = 0x2F; // Так как у нас регистр 16 битный, то мы имеем два // 8-ми битных UBRRH и UBRRL. // В старший пишем 0x00. Опять помня про // селектор. Здесь уже нужно записать в него "0" // А в младший пишем наще расчитанное число // 0x2F. Собственно вот и вся настройка. while(1) { // А здесь мы будем просто раз в секунду пихать байт в порт // предварительно его увеличив на единицу. // Для этого создадим переменную unsigned char out = 0; после // записи int main(void) { // Так как переменная unsigned char, то после переполнения она // вернется опять к нулю и все пойдет по кругу. // Для того чтобы полать в порт байт, его нужно записать в // регистр данных. Называется он UDR // Но просто так в него писать ничего нельзя. Вдруг там что-то // лежит. Поэтому сначало нужго // проверить флаг UDRE в регистре UCSRA. Помните, если он // установлен в "1", значит регистр данных // пуст, а если в "0", то что-то еще там есть. while(!( UCSRA & (1 < <UDRE))); // Ждем пока не взведется // флаг UDRE (станет "1") UDR = out; // Отправляем текущее значение в порт out++; // Увеличиваем текущее значение на 1 _delay_ms(1000); // Делаем паузу на 1 секунду. } } В библиотеке AXLIB есть набор функций для работы с UART.

Проект в AtmelStudio 6.2
JW Player goes here




Вверх


Рейтинг@Mail.ru Яндекс.Метрика