Программирование AVR. Использование UART.

Микроконтроллеры AVR, как и большинство современных контроллеров, имеют на своем борту аппаратный модуль UART, являющийся отличным решением для передачи данных. Именно про UART будет эта статья 😉 Разберем как можно настроить этот модуль в AVR’ках, посмотрим куда там надо пихать свои данные и откуда забирать, ну и небольшой примерчик по традиции в конце статьи.

Сам протокол UART мы расписывать не будем, поэтому сразу начнем с описания регистров.

Кстати, я для своих опытов буду использовать ATMega2560, но вообще принципиальной разницы нет, так что для ATMega16 или любой другой меги, практически все работает точно также )

Итак, для того, чтобы произвести необходимую настройку UART’а выделено три регистра — UCSRxA, UCSRxB и UCSRxC. Вместо символа x надо использовать номер используемого модуля UART. Например, хотим мы перекинуть данные через UART1 — тогда нас интересуют регистры UCSR1A, UCSR1B и UCSR1C. Аналогично для UART0, UART2 ….. У моей ATMega2560, кстати, их целых четыре штуки ) Ну а теперь поподробнее обо всем этом.

Регистр UCSRxA.

В этом регистре содержатся три важнейших флага — RXCx, TXCx, UDREx. Первый из этих флагов оповещает нас об окончании приема данных, второй об окончании передачи, ну а третий флаг взлетит в том случае, если регистр данных пуст. Кроме того, в этом регистре есть еще флаги, сигнализирующие об ошибках, которые могут случиться в процессе передачи данных.

Ну и еще один бит регистра UCSRxA — бит U2Xx. Это бит удвоения скорости передачи при работе в асинхронном режиме. Давайте двигаться дальше.

Регистр UCSRxB.

В первую очередь нас тут должны интересовать биты RXENx и TXENx. Это биты разрешения приема и передачи. То есть, чтобы иметь возможность передать какие-нибудь данные мы должны выставить бит TXENx в единицу.

А еще в регистре UCSRxB содержатся биты разрешения прерываний. Прерываний у нас три штуки (по окончанию приема, по окончанию передачи и по опустошению регистра данных), а значит и флагов тоже три — RXCIEx, TXCIEx, UDRIEx. С этим все понятно 😉

Регистр UCSRxC.

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

Кстати, с этим регистром есть небольшая тонкость. В некоторых микроконтроллерах AVR (например в той же 16-ой меге) регистры UCSRxC и UBRRxH находятся по одному и тому же адресу. И выбор между ними осуществляется следующим образом. Если мы записываем в этот регистр число, у которого старший бит равен 0, то оно попадает прямиком в регистр UBRRxH, а если старший бит — единица, то ему прямая дорога в регистр UCSRxC. Эта особенность есть не у всех AVR’ок, в уже упомянутой ATMega2560, например, таких извращений нет =)

Вроде бы все настроили, кроме самого главного — скорости передачи данных. Для этого выделено два регистра, один из которых уже упоминался — UBRRxH и UBRRxL. В даташите можно подглядеть формулу, по которой для каждого значения скорости можно определить числа, которые надо записать в эти регистры. А еще в даташите есть большая табличка, в которой уже рассчитаны все эти значения для разных скоростей и частот.

Ну и напоследок, самый важный регистр — UDRx. Именно сюда надо загружать данные для отправки и именно отсюда нужно забирать принятые данные.

Теперь давайте, пока не забыли, какие регистры для чего нужны, напишем простенькую программу-пример. Настолько простенькую, что проще просто некуда ) Давайте замутим передачу 8 байт во внешний мир.

/*******************************************************************/
#include <avr/io.h>;
 
 
 
/*******************************************************************/
// Тестовый буфер данных для хранения передаваемой информации
unsigned char testBuffer[8];
 
 
 
/*******************************************************************/
void main(void)
{
    unsigned char i = 0;
    // Вот такие вот данные мы будем передавать
    testBuffer[0] = 0x00;
    testBuffer[1] = 0x11;
    testBuffer[2] = 0x22;
    testBuffer[3] = 0x33;
    testBuffer[4] = 0x44;
    testBuffer[5] = 0x55;
    testBuffer[6] = 0x66;
    testBuffer[7] = 0x77;
 
    // Настраиваем нужную скорость. Частота у меня 16 МГц,
    // скорость - 19200 кб/с, из таблички в даташите берем 
    // нужное значение
    UBRR0 = 51;
    // Разрешаем передачу
    UCSR0B |= (1 << TXEN0);
 
    while(1)
    {
	for (i = 0; i < 8; i++)
	{
    	    // Запихиваем данные в регистр данных
	    UDR0 = testBuffer[i];
	    // И ждем пока передача завершится
	    while(!(UCSR0A && (1 << TXC0)));
	    // После этого продолжаем бесконечно пихать данные
	}
    }
}
 
 
 
/*******************************************************************/

Вот такой вот примерчик ) В следующей статье обязательно реализуем прием и передачу данных с использованием прерываний, так что будьте на связи!

Понравилась статья? Поделись с друзьями!

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

Ваш e-mail не будет опубликован. Обязательные поля помечены *