About STM32

Работаем с UART

Пришло время испытать UART в действии и мы сразу ринемся с места в карьер, соеденив stm32 по usb с ПК!

Конечно в более мощных сериях usb в stm32 интегрировано, но а нам прийдется использовать специальную микросхему FT232RL от FTDI.

Для работы будем использовать модуль USART1, в котором вывод TX подключен к девятой ноге порта А, а вывод RX – к десятой ноге этого же порта. (См. datasheet на стр. 24)

Начнем, как всегда с самого главного – затактируем всю необходимую периферию!

RCC->APB2ENR |= RCC_APB2ENR_IOPAEN|RCC_APB2ENR_USART1EN|RCC_APB2ENR_AFIOEN;

RCC_APB2ENR_IOPAEN – тактируем порт, на который выведены ножки модуля USART1.
RCC_APB2ENR_USART1EN – тактируем модуль USART1.
RCC_APB2ENR_AFIOEN – включаем тактирование альтернативных функций (поскольку использование ножек USART'ом подразумевает переход управления над ними этому модулю.Если не включить эту функцию, то порт так и останется портом с выводами общего назначения, а модуль USART отанется ни у дел)

Следующий шаг – настраваем выводы для работы с UART'ом. Т.е. нога TX (PA9) должна быть сконфигурирована, как двухтактный вывод, подключенный к периферии, RX (PA10) конфигурируем как свободный вход (Подробнее о настройках выводов для работы с периферией можно почитать в руководстве по программированию на стр. 106). Эти настройки выполняются следующими командами:

GPIOA->CRH |= GPIO_CRH_CNF9_1;
GPIOA->CRH |= GPIO_CRH_MODE9;
GPIOA->CRH |= GPIO_CRH_CNF10_0;

Осталось настроить сам модуль USART1 и дело в шляпе! Как настроить регистр предделителя я рассказывал в этой статье, поэтому осталось настроить лишь регистры CR (control register). Как мы помни их 3, но для работы модуля изменения необходимо вносить только в регистр CR1. Почему? Потому, что в оставшихся двух регистрах нас устраивают настройки по умолчанию( 8 бит данных, 1 стоп-бит, без четности ). Итак:

USART1->CR1 |= USART_CR1_RE|USART_CR1_TE|USART_CR1_UE|USART_CR1_RXNEIE;

Поскольку UART может работать в полудуплексном режиме, то можно включить отдельно как приемник, так и передатчик. В нашем случае включен и приемник (USART_CR1_RE), и передатчик (USART_CR1_TE). Кроме того, отдельным пунктом стоит включение самого модуля USART1 установкой бита UE (USART_CR1_UE).

В данном примере, я решил, что меня интересуют только прерывания о приеме данных, поэтому и разрешил только (USART_CR1_RXNEIE). Если же Вы считаете, что Вам требуется еще и прерывание по окочанию отправки байта,то необходимо установить бит TXNEIE или бит TCIE (USART_CR1_TXNEIE или USART_CR1_TCIE). Разница в том, что в первом случае прерывание генерируется как только началась отправка байта данных, а во втором случае – когда она завершилась. Не забываем разрешить обработку прерываний от модуля USART1:

NVIC_EnableIRQ(USART1_IRQn);

Последний штрих – добавление обработчика прерываний!

void USART1_IRQHandler(void)
{
if (USART1->SR & USART_SR_RXNE) // функция-обработчик события «принят байт данных»
{
USART1->SR &= ~USART_SR_RXNE; //очищаем флаг события
ReceiveData=USART1->DR; //сохраняем значение байта в глобальную переменную
USART1->DR = ReceiveData; //отправляем полученное значение обратно
}
if (USART1->SR & USART_SR_TXE) //функция-обработчик события «началась отправка байта данных»
{
USART1->SR &= ~USART_SR_TXE; //очищаем флаг события
}
if (USART1->SR & USART_SR_TC) // функция-обработчик события «завершилась отправка байта данных»
{
USART1->SR &= ~USART_SR_TC; //очищаем флаг события
}
}

Как видим, обработчик прерываний от модуля USART1 состоит из нескольких условий, которые проверяют «почему мы попали в прерывание?». Стоит также отметить важную детель: проверку условий необходимо распологать по приоритету: чем выше приоритетдействия – тем раньше необходимо ставить функцию-обработчик события. Такой подход необходимо использовать по одной простой причине: Представим, что у нас одновременно случилось несколько событий от одного периферийного устройства, при этом обработка «событие 1» может одождать, а «событие 2» нам нужно обработать в кратчайшие сроки. Но если мы запишем обработчик прерывания следующим образом:

void имя_периферии_IRQHandler(void)
{
If (событие 1)
{
Обработка события 1;
}
If (событие 2)
{
Обработка события 2;
}
}

получится, что экстренное «событие 2» не обработается до тех пор, пока мы не завершим обработку «событие 1».

Специально для этого проекта я написал небольшую программку на C#. Внешне она выглядит вот так:

Проект в Keil uart.rar, проект Visual Studio com-port.rar

 
Хостинг от uCoz