Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Микропроцессорные системы пособие.doc
Скачиваний:
0
Добавлен:
12.02.2026
Размер:
2.53 Mб
Скачать

8. Передача данных по uart

Каждый микроконтроллер семейства Mega и некоторые из семейства Tiny имеет в своем составе аппаратный блок универсального последовательного интерфейса – UART. По структуре это обычный асинхронный последовательный протокол, то есть передающая сторона по очереди выдает в линию нули и единицы, а принимающая отслеживает и запоминает их. Синхронизация идет по времени – мы заранее задаем скорость передачи данных как на стороне передатчика информации, так и на стороне приемника (именно поэтому передача асинхронная – отдельная линия для передачи тактовых синхронизирующих импульсов отсутствует). Это весьма важное замечание, так как расхождение в скоростях передачи может привести к ошибкам в распознавании информации, при этом ошибки будут накапливаться с увеличением скорости передачи данных.

Интерфейс UART – двухпроводной (не считая линии земли), линии имеют разное назначение – линия RXD используется для приема сообщений (Receiver), а TXD – для передачи сообщений (Transmitter). UART – полнодуплексный интерфейс. Это значит, что приемник и передатчик работают независимо друг от друга, позволяя одновременно как передавать, так и принимать данные (полнодуплексная передача данных).

Протокол передачи данных.

Передача (соответственно, и прием) сообщений осуществляется фиксированными пакетами битов (такой пакет называют кадром). Кадр состоит из стартового бита (с него начинается каждый кадр), битов данных (их количество можно изменять от 5 до 9), бита проверки четности (проверка правильности передачи данных) и одного или двух стоп-битов (обязательный сигнал окончания кадра).

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

В конце байта, перед стоповым битом, может находиться бит проверки четности. Так называют контрольный бит, служащий для проверки общей чётности двоичного числа (чётности количества единичных битов в числе). Он формируется при выполнении операции «Исключающее-ИЛИ» со всеми передаваемыми битами. Стоповых битовых может быть два, для повышения надежности передачи. Все эти параметры задаются строго перед началом передачи данных и не могут быть изменены в процессе. Самый распространенный формат передачи данных для микроконтроллеров – 8 бит данных, 1 стартовый бит, 1 стоповый бит, без проверки на четность.

Рис. 8.1. Пакет данных для передачи по интерфейсу UART

Настройка и программирование интерфейса UART.

Вначале рассмотрим регистры, имеющие отношение к нашему приёмопередатчику.

У каждого микроконтроллера, поддерживающего UART, есть регистр UDRx UART Data Register (в микроконтроллере AtMega128 два UART’а, поэтому и регистров тоже два – UDR0 и UDR1). На физическом уровне UDR представляет собой два разных регистра, имеющих одинаковый адрес. При записи данных информация поступает в первый регистр (регистр передатчика), а при чтении берется из другого (регистр приемника). Таким образом, и при чтении, и при записи данных мы используем один регистр, что значительно облегчает процесс программирования.

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

Поскольку передача идет довольно медленно, то бездумно посылать всё новые и новые данные в регистр UDR нельзя – необходимо дождаться окончания передачи предыдущего байта. О том, что UDR пуст и готов к приему нового байта сигнализирует бит UDRE, он же вызывает аппаратное прерывание по опустошению буфера (USART Data Register Empty Interrupt Enable).

Все настройки приемопередатчика хранятся в регистрах конфигурации, которые известны как UCSRA, UCSRB и UCSRC, скорость передачи данных задается регистровой парой UBBRH:UBBRL. Рассмотрим подробнее наиболее важные регистры.

Регистр UCSRxA (UART Control and Status Register).

Здесь наибольший интерес вызывают биты RXCn (Receive Complete) и TXCn (Transmit Complete) – это флаги завершения приема и передачи данных, соответственно. RXC устанавливается в единицу, когда принимаемый байт запишется в регистр UDR для последующего чтения, а TXC – после прохождения последнего стоп-бита и отсутствия новых данных в регистре UDR, то есть после окончания передачи всех битов.

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

Биты UDREn (USART Data Register Empty) сигнализирует о том, что регистр UDR приемника пуст, и в него можно записывать новый байт. Сбрасывается он аппаратно после записи новой порции данных в UDR, при этом генерируется соответствующее прерывание.

Бит U2Xn (Double the USART Transmission Speed) – бит удвоения скорости передачи данных при работе в ассинхронном режиме. Его надо учитывать при расчете значения в регистровой паре UBBRH:UBBRL.

Регистр UCSRxB.

В этом регистре основную роль играют биты RXEN (Receiver Enable) и TXEN (Transmitter Enable) – при записи в них логической единицы осуществляется разрешение приема и передачи, соответственно.

RXCIEn (RX Complete Interrupt Enable) – осуществляет разрешение прерывания по завершению приема данных.

TXCIE (TX Complete Interrupt Enable) – осуществляет разрешение прерывания по завершению передачи данных.

UDRIEn (UART Data Register Empty Interrupt Enable) – осуществляет разрешение прерывания по опустошению регистра передачи данных UDR.

Регистр UCSRxC

В этом регистре мы можем выбрать необходимый протокол передачи данных.

UMSELn (UART Mode Select) – здесь мы задаем формат передачи – синхронный либо асинхронный, в зависимости от значения бита, как показано в таблице 8.1.

Таблица 8.1. Выбор режима передачи данных по UART

UMSELn (значение бита)

Режим передачи

0

Асинхронный

1

Синхронный

UPMn1:0 (UART Parity Mode) – установка проверки на четность, в наших практических работах данная опция не используется, по умолчанию в оба бита записаны логические нули, передача данных ведется без проверки на четность.

USBSn (UART Stop Bit Select) – определяет количество стоповых битов, здесь возможно всего два варианта, в соответствии с таблицей 8.2.

Таблица 8.2. Выбор количества стоп-бит.

USBSn Stop Bit (значение бита)

Количество стоп-бит

0

1 стоповый бит

1

2 стоповых бита

UCSZn1:0 (UART Character Size) – определяет количество передаваемых битов данных – от 5 до 9, в соответствии с таблицей 8.3.

Таблица 8.3. Выбор количества передаваемых бит данных.

UCSZn2

UCSZn1

UCSZn0

Количество бит

0

0

0

5 бит

0

0

1

6 бит

0

1

0

7 бит

0

1

1

8 бит

1

0

0

зарезервировано

1

0

1

зарезервировано

1

1

0

зарезервировано

1

1

1

9 бит

Скорость передачи данных

Здесь всё зависит от значения, записанного в регистровую пару UBBRH:UBBRL. Вычисляется требуемое значение по следующей формуле:

для U2X=0 (обычная скорость передачи);

для U2X=1 (удвоенная скорость передачи),

где XTAL – рабочая тактовая частота контроллера, baudrate – требуемая скорость. Чем выше скорость, тем больше ошибка рассинхронизации, поэтому на высоких скоростях целесообразно использовать специализированные кварцы (те самые, с неровным значением вроде 11.0592 МГц).

Теперь можно приступить к процедуре непосредственной инициализации, используется стандартный протокол передачи, и единственный канал UART’а, доступный для нашего микроконтроллера. Задача простейшей программы для передачи данных на персональный компьютер крайне проста – в бесконечном цикле мы увеличиваем значение регистра на единицу, начиная с нуля, передаём полученное значение, далее вызываем подпрограмму задержки, затем цикл повторяется.

Программа на языке Ассемблер.

//****************************************************************//

// вектор прерываний

ORG 0x000

RJMP RESET // Reset Handler

ORG 0x001

RETI // IRQ0 Handler

ORG 0x002

RETI //PCINT0 Handler

ORG 0x003

RETI // PCINT1 Handler

ORG 0x004

RETI // Timer/Counter0 Capture Handler

ORG 0x005

RJMP Tim_OVF // Timer/Counter0 Overflow Handler

ORG 0x006

RETI // Timer/Counter0 Compare Match A Handler

ORG 0x007

RETI // Timer/Counter0 Compare Match B Handler

ORG 0x008

RETI // Analog Comparator Handler

ORG 0x009

RETI // Watchdog Timer Handler

ORG 0x00A

RETI // Voltage Level Monitor Handler

ORG 0x00B

RETI // ADC Conversion Handler

ORG 0x00C

RETI // USART0 Rx Start Handler

ORG 0x00D

RETI // USART0 Rx Complete Handler

ORG 0x00E

RETI // USART0 Data Register Empty Handler

ORG 0x00F

RETI // USART0 Tx Complete Handler

ORG INT_VECTORS_SIZE // Конец таблицы прерываний

RESET:

// Обязательная инициализация стека

LDI R16, Low(RAMEND)

OUT SPL, R16

LDI R16, High(RAMEND)

OUT SPH, R16

//Инициализация периферии

.equ XTAL = 8000000 // Тактовая частота МК

.equ baudrate = 9600 // Скорость передачи данных

.equ bauddivider = (XTAL/(16*baudrate)-1) // Расчет коэффициента

LDI R16, 0xD8

OUT CCP, R16

LDI R16, 0x00

OUT CLKPSR,R16

// Инициализируем UART

LDI R16, bauddivider>>8

OUT UBRRH, R16

LDI R16, bauddivider

OUT UBRRL, R16

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

OUT UCSRC, R16

// Прерывания разрешены, передача данных разрешена

LDI R16, (1 << TXEN)

OUT UCSRB, R16

LDI R20, 0x00

//*******************************************************//

// Основной цикл программы

Main:

// Увеличиваем данные в регистре на единицу (инкремент)

INC R20

OUT UDR, R20 // Помещаем данные (R16) в буфер и отсылаем их

RCALL Delay // Вызываем подпрограмму задержки

RJMP Main // Возвращаемся в основной цикл

//****************************************************************//

// Обработка подпрограмм

.equ LowByte = 255

.equ MedByte = 255

.equ HighByte = 40

Delay:

LDI R16, LowByte // Грузим три байта

LDI R17, MedByte // Нашей задержки

LDI R18, HighByte

loop:

dec R16

brne loop

dec R17

brne loop

dec R18

brne loop

ret

Повторяем ту же самую программу на языке Си.

//****************************************************************//

#define F_CPU 8000000UL

#include <avr/io.h>

#include <util/delay.h>

#define USART_BAUDRATE 9600

#define BAUD_PRESCALE ((F_CPU / (USART_BAUDRATE * 16UL)) - 1)

int main(void)

{

CCP = 0xD8;

CLKPSR = 0x00;

UCSRC = (1 << UCSZ0) | (1 << UCSZ1);

UBRRH = (BAUD_PRESCALE >> 8);

UBRRL = BAUD_PRESCALE;

UCSRB = (1 << TXEN); // Enable Tx on USART

uint8_t counter = 0;

while (1)

{

UDR = counter;

while (!(UCSRA & (1 << UDRE))) {};

counter++;

_delay_ms(1000);

}

}