Классический «Hello world» интерфейс, до сих пор применяющийся для связи МК и датчиков, подключения к компьютеру и просто для отладки. Рассмотрим его использование.
Сделаем такую полезную вещь — при поступлении в USART символа ‘1’ включаем светодиод на плате, при поступлении символа ‘2’ — выключаем. Одновременно отсылаем обратно в USART новое состояние светодиода. Используем асинхронный режим работы USART, с применением сигналов RxD и TxD.
Содержание:
Регистры USART
Регистр состояния USART_SR
CTS — сигнал о переключении контакта CTS
LBD — обнаружен сигнал BREAK в режиме LIN
TXE — данные отправлены в передатчик, регистр данных опустел
TC — данные переданы, передача завершена
RXNE — данные приняты, регистр данных полон
IDLE — обнаружен сигнал IDLE
ORE — ошибка: переполнение входного буфера — приняты новые данные, а старые ещё не прочитаны
NE — обнаружение шума на линии
FE — рассинхронизация, сильный шум на линии или принят сигнал BREAK
PE — ошибка контроля чётности принятых данных
Регистр состояния USART_DR
В 9 младших битах содержатся данные. При получении байта отсюда можно прочитать принятые данные, для отправки нужно записать данные в этот регистр.
Регистр состояния USART_BRR
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%). Однако, даже красные значения можно применять в хобби-устройствах.
Регистр состояния USART_CR1
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
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
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
");
// Бесконечный цикл
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
");
}
if(USART1->DR=='2') {
GPIO_ResetBits(GPIOC, GPIO_Pin_9);
USART1_Send_String("Off
");
}
}
}
Аналогично — для USART2 и 3.
В случае, если все стандартные контакты 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 консоль я рассказываю как сделать так же.