Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

AVR / Передача данных через UART

.doc
Скачиваний:
64
Добавлен:
20.03.2015
Размер:
51.2 Кб
Скачать

Передача данных через UART

Почти каждый микроконтроллер имеет на борту универсальный последовательный интрфейс - UART. AVR тут не исключение и поддерживает этот протокол в полном обьеме полностью аппаратно. По структуре это обычный асинхронный последовательный протокол, то есть передающая сторона по очереди выдает в линию 0 и 1, а принимающая отслеживает их и запоминает. Синхронизация идет по времени — приемник и передатчик заранее договариваются о том на какой частоте будет идти обмен.

Протокол Вначале передатчик бросает линию в низкий уровень - это старт бит. Почуяв что линия просела, приемник выжидает интервал Т1 и считывает первый бит, потом через интервалы Т2 выковыриваются остальные биты. Последний бит это стоп бит. Говорящий о том, что передача этого байта завершена. Это в самом простом случае.

В конце байта, перед стоп битом, может быть и бит четности. Который получается если поксорить между собой все биты, для контроля качества передачи. Также может быть два стопа, опять же для надежности. Битов может быть не 8, а 9. О всех этих параметрах договариваются на берегу, до начала передачи. Самым же популярным является 8 бит, один старт один стоп, без четности.

Причем с самим протоколом можно не заморачиваться - все реализованно аппаратно. Разве что захочется завести второй UART, тогда придется делать его программно.

Аппаратная часть Ну тут все просто, соединяем крест-накрест приемник с передатчиком и готово.

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

Использование UART’a У AVR есть регистр UDR это UART Data Register. На самом деле это два разных регистра, но имеют один адрес. Просто на запись попадает в один (регистр передатчика), а на чтение берет из другого (регистр приемника). Таким образом достаточно просто пихать данные в этот регистр и они улетят приемнику, и, наоборот, считывать их оттуда по приходу.

О том, что байт пришел в регистр UDR нам скажет прерывание по завершению приема, которое вызывается сразу же, как приемник засосет в себя все биты (обычно 8, но может быть и 9, в зависимости от настройки).

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

Передача данных через UART

Так что постоянно следить за UART вручную не нужно, все обслуживание можно повесить на прерывания и он сам будет все делать. Можно в памяти организовать буфер и туда тупо пихать данные, а на прерывании по опустошению UDR следить за тем есть ли что в буфере и если есть - отправлять.

А по приему, не тупить, а также, по прерыванию, пихать данные в ОЗУ, но уже в буфер приема, откуда их считает уже программа.

Настройка UART Все настройки приемопередатчика хранятся в регистра конфигурации. Это UCSRA, UCSRB и UCSRС. А скорость задается в паре UBBRH:UBBRL.

Досконально все расписывать не буду — на это есть даташит. Напишу лишь то, что жизненно необходимо.

Регистр UCSRA Тут нам интересны только биты RXC и TXC это флаги завершения приема и передачи, соответственно. RXC встанет когда непрочитанный байт вылезет в регистр UDR, а TXC встает когда последний стоп-бит прошел, а новое значение в UDR не поступило. Т.е. после прохода всех байтов. Также одновременно с этими флагами вызывается прерывание (если оно было разрешено). Сбрасываются они аппаратно — принимающий после чтения из регистра UDR, передающий при переходе на прерывание, либо программно (чтобы сбросить флаг программно в него надо записать 1)

Биты UDRE сигнализирует о том, что регистр UDR приемника пуст и в него можно пихать новый байт. Сбрасывается он аппаратно после засылки в UDR какого либо байта. Также генерируется прерывание “Регистр пуст”

Бит U2X - это бит удвоения скорости при работе в ассинхронном режиме. Его надо учитывать при расчете значения в UBBRH:UBBRL

Регистр UCSRB Тут в первую очередь это биты RXEN и TXEN — разрешение приема и передачи. Стоит их сбросить как выводы UART тут же становятся обычными ножками I/O.

Биты RXCIE, TXCIE, UDRIE разрешают прерывания по завершению приема, передачи и опустошении буфера передачи UDR. Регистр UCSRC Самый прикол тут это бит селектора URSEL дело в том, что по неизвестной причине создаетели решили сэкономить байт адреса и разместили регистры UCSRC и UBRRH в одной адресном пространстве. А как же определять куда записать? А по старшему биту! Поясню на примере. Если мы записываем число у которого седьмой бит равен 1, то оно попадет в UCSRC, а если 0 то UBRRH.

Остальные биты задают число стопов, наличие и тип контроля четности. Если оставить все по дефолту то будет стандартный режим. Надо только выставить формат посылки. Делается это битами UCSZ0, UCSZ1 и UCSZ2 (этот бит тусуется в регистре UCSRB). Для стандартной 8ми битной посылки туда надо записать две единички.

Скорость обмена. Тут все зависит от пары UBBRx Вычисляется требуемое значение по формуле: UBBR=XTAL/(16*baudrate)-1 для U2X=0 UBBR=XTAL/(8*baudrate)-1 для U2X=1

Где: XTAL - рабочая тактовая частота контроллера. baudrate - требуемая скорость (я люблю 9600 :) )

Передача данных через UART

Пример кода:

Для начала инициализация UART

.equ XTAL = 8000000

.equ baudrate = 9600

.equ bauddivider = XTAL/(16*baudrate)-1

uart_init: LDI R16, low(bauddivider)

OUT UBRRL,R16

LDI R16, high(bauddivider)

OUT UBRRH,R16

LDI R16,0

OUT UCSRA, R16

LDI R16, (1<<RXEN)|(1<<TXEN)|(0<<RXCIE)|(0<<TXCIE)

; Прерывания запрещены, прием-передача разрешен.

OUT UCSRB, R16

LDI R16, (1<<URSEL)|(1<<UCSZ0)|(1<<UCSZ1)

; Формат кадра - 8 бит, пишем в регистр UCSRC, за это отвечает бит селектор

OUT UCSRC, R16

RET

Теперь посылка байта:

RCALL uart_init ; вызываем нашу процедуру инициализации.

LDI ; загоняем в регистр код буквы «E»

uart_snt: SBIS UCSRA,UDRE RJMP uart_snt ; ждем готовности - флага UDRE

OUT UDR, R16 ; шлем байт!

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

Ошибки К сожалению мир наш не идеален, поэтому возможны ошибки при приеме. За них отвечают флаги в регистре UCSRA FE - ошибка кадрирования. Т.е. мы ждали стоп бит, а пришел 0. OR - переполнение буфера. То есть данные лезут и лезут, а из UDR мы их забирать не успеваем. PE - не совпал контроль четности.

3