Классический «Hello world» интерфейс, до сих пор применяющийся для связи МК и датчиков, подключения к компьютеру и просто для отладки. Рассмотрим его использование.

Сделаем такую полезную вещь — при поступлении в USART символа ‘1’ включаем светодиод на плате, при поступлении символа ‘2’ — выключаем. Одновременно отсылаем обратно в USART новое состояние светодиода. Используем асинхронный режим работы USART, с применением сигналов RxD и TxD.

Регистры USART

Регистр состояния USART_SR

Регистр USART_SR микроконтроллера STM32F100

CTS — сигнал о переключении контакта CTS

LBD — обнаружен сигнал BREAK в режиме LIN

TXE — данные отправлены в передатчик, регистр данных опустел

TC — данные переданы, передача завершена

RXNE — данные приняты, регистр данных полон

IDLE — обнаружен сигнал IDLE

ORE — ошибка: переполнение входного буфера — приняты новые данные, а старые ещё не прочитаны

NE — обнаружение шума на линии

FE — рассинхронизация, сильный шум на линии или принят сигнал BREAK

PE — ошибка контроля чётности принятых данных

Регистр состояния USART_DR

Регистр USART_DR микроконтроллера STM32F100

В 9 младших битах содержатся данные. При получении  байта отсюда можно прочитать принятые данные, для отправки нужно записать данные в этот регистр.

Регистр состояния USART_BRR

Регистр USART_BRR микроконтроллера STM32F100

DIV_Mantissa — целая часть значения USARTDIV

DIV_Fraction — дробная часть значения USARTDIV

USARTDIV = DIV_Mantissa + DIV_Fraction/16.

Baud rate = F_clk/(DIV_Fraction*16) = F_clk/(DIV_Mantissa*16 + DIV_Fraction) = F_clk/USART_BRR.

К примеру, при тактовой частоте 24МГц нужна скорость 9600 бод. Делим 24000000 на 9600, это равно 2500 = 0x9C4. Именно такое значение нужно положить в регистр BRR. Вот таблица значений BRR в зависимости от частоты процессора и требуемого бодрейта. Белые — точные значения (погрешность 0%), жёлтые — менее точные (погрешность 0 — 0.1%), красные — самые неточные (погрешность 0.1 — 0.3%). Однако, даже красные значения можно применять в хобби-устройствах.

BRR

Регистр состояния USART_CR1

Регистр USART_CR1 микроконтроллера STM32F100

UE — включение USART: 0 — выключен, 1 — включен.

M — длина слова данных: 0 — 8 бит, 1 — 9 бит. Не должен меняться во время приёма/передачи.

WAKE — способ пробуждения модуля USART

PCE — включение контроля чётности для приёма и передачи. Делает старший бит (8 или 9) битом чётности.

PS — полярность бита чётности

PEIE — включение прерывания по установке бита PE регистра SR, т.е. при ошибке чётности

TXEIE — включение прерывания по установке бита TXE регистра SR, т.е. при начале передачи данных

TCIE — включение прерывания по установке бита TC регистра SR, т.е. при окончании передачи данных

RXNEIE — включение прерывания по установке бита ORE регистра SR, т.е. при переполнении входного буфера

IDLEIE — включение прерывания по установке бита IDLE регистра SR, т.е. при приёме сигнала IDLE

TE — включение передатчика

RE — включение приёмника

RWU — перевод приёмника в спящий режим: 0 — активный, 1 — спящий

SBK — передача сигнала BREAK. Сбрасывается железом после передачи.

Регистр состояния USART_CR2

Регистр USART_CR2 микроконтроллера STM32F100

LINEN — включение режима LIN

STOP — программирование количества стоповых бит. 00 — 1 бит, 01 — 0.5 бит, 10 — 2 бит, 11 — 1.5 бит.

CLKEN — использование пина CK, включение синхронного режима

CPOL — полярность сигналов пина CK: 0 — высокое значение при передаче, 1 — низкое.

CPHA — фаза сигналов CK: 0 — первый перепад CK в первый бит передачи, 1 — второй.

LBCL — передача сигнала CK по передаче последнего бита (MSB)

LBDIE — включение прерывания по установке бита LBD регистра SR

LBDL — длина сигнала BREAK в LIN: 0 — 10, 1 — 11

ADD — адрес узла USART

Регистр состояния USART_CR3

Регистр USART_CR3 микроконтроллера STM32F100

CTSIE — включение прерывания по установке бита CTS регистра SR

CTSE — включение сигнала CTS, т.е. аппаратного управления потоком

RTSE — включение сигнала RTS и генерирование прерывания по установке бита RTS

DMAT — использование DMA для передачи

DMAR — использование DMA для приёма

SCEN — включение режима Smartcard

NACK — использование сигнала NACK для режима Smartcard

HDSEL — полудуплексный режим для однопроводного режима

IRLP — выбор режима пониженного потребления IrDA

IREN — включение режима IrDA

EIE — включение прерывания при возникновении ошибки

STM32VLDiscovery + USART1/USART2/USART3

Перед началом работы с USART нужно включить ножки GPIO на вход и на выход:

USART1: PA9/TxD + PA10/RxD

USART2: PA2/TxD + PA3/RxD

USART3: PB10/TxD + PB11/RxD

#include "stm32f10x.h"

int main(void)
{
  // Настраиваем ножку PC8 в режим выхода на светодиод на плате
  GPIO_InitTypeDef GPIO_InitStructure;
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
  GPIO_Init(GPIOC, &GPIO_InitStructure);

  // Включаем модули USART1 и GPIOA, а также включаем альтернативные функции выходов
  RCC->APB2ENR|= RCC_APB2ENR_USART1EN | RCC_APB2ENR_IOPAEN | RCC_APB2ENR_AFIOEN;
  // Контакт PA9 будет выходом с альтернативной функцией, а контакт PA10 - входом
  GPIOA->CRH &= !GPIO_CRH_CNF9;
  GPIOA->CRH  |= GPIO_CRH_CNF9_1 | GPIO_CRH_MODE9_0 | GPIO_CRH_CNF10_0;
  // Настраиваем регистр тактирования, скорость составит 9600 бод (при тактовой частоте 24 МГц)
  USART1->BRR = 0x9C4;
  // Выключаем TxD и RxD USART
  USART1->CR1 |= USART_CR1_TE | USART_CR1_RE;
  // Запускаем модуль USART
  USART1->CR1 |= USART_CR1_UE;
  // Разрешаем прерывание по приёму информации с RxD
  USART1->CR1 |= USART_CR1_RXNEIE;
  // Назначаем обработчик для всех прерываний от USART1
  NVIC_EnableIRQ(USART1_IRQn);
  USART1_Send_String("Start\r\n");
  // Бесконечный цикл
  while(1);
}

void USART1_Send(char chr) {
  while(!(USART1->SR & USART_SR_TC));
  USART1->DR = chr;
}

void USART1_Send_String(char* str) {
  int i=0;
  while(str[i])
    USART1_Send(str[i++]);
}

// Обработчик всех прерываний от USART1
void USART1_IRQHandler(void) {
  // Выясняем, какое именно событие вызвало прерывание. Если это приём байта в RxD - обрабатываем.
  if (USART1->SR & USART_SR_RXNE) {
    // Сбрасываем флаг прерывания
    USART1->SR&=~USART_SR_RXNE; 

    // Получаем принятый байт
    if(USART1->DR=='1') {
      GPIO_SetBits(GPIOC, GPIO_Pin_9);
      // Отправляем обратно строку "On" с переводом строки
      USART1_Send_String("On\r\n");      
    }

    if(USART1->DR=='2') {
      GPIO_ResetBits(GPIOC, GPIO_Pin_9);
      USART1_Send_String("Off\r\n");
    }

  }
}

Аналогично — для USART2 и 3.

Подключение платы STM32VLDiscovery к компьютеру через USART

В случае, если все стандартные контакты USART уже заняты, можно перенаправить их на другие — это называется ремаппинг. USART1 в таком случае переходит на PB6/TxD + PB7/RxD, а USART3 — на PC10/TxD + PC11/RxD. USART2 нельзя ремапнуть на другие пины.

Код изменяется совсем немного: всё, что нужно сделать — это добавить строку AFIO->MAPR = AFIO_MAPR_USART1_REMAP; и конечно переписать код включения портов ввода-вывода на новые пины:
RCC->APB2ENR|= RCC_APB2ENR_USART1EN | RCC_APB2ENR_IOPBEN | RCC_APB2ENR_AFIOEN;
AFIO->MAPR  |= AFIO_MAPR_USART1_REMAP;
GPIOB->CRL  |= GPIO_CRL_CNF6_1 | GPIO_CRL_MODE6_0 | GPIO_CRL_CNF7_0;

Можно скачать готовый проект (для IAR) с этим примером — USART_Example.zip.

Теперь можно совместить USART и таймеры, и сделать сервомотор, управляемый с компьютера.

Многие сетевые девайсы имеют консоль, доступную по COM-порту — в статье про UART консоль я рассказываю как сделать так же.