ARM Учебный курс. USART

Самый простой и наиболее часто использующийся в быту и производстве :) Куда без него. О нем было много сказано тут, не буду повторяться, дам лишь ссылочки на старые статьи:


 

Вот и у STM32 он есть. Да не один, а целых дофига. В том контроллере, что стоит на Pinboard II в модуле STM32 — STM32F103C8T6 — их три. Обычно хватает и одного. Но три это же лучше! :)
 

Вообще у STM32 сей девайс навороченный и умеет не только байтики в терминалку слать в классических режимах (асинхронном, синхронном, мультипроцессорном), но и кое чего еще. В частности он может работать в
 

  • Однопроводном полудуплексном режиме
  • В режиме SmartCard — т.е. на том же языке на котором общаются с телефоном SIM карты. Вообще там вроде бы протокол отличается только таймингами немного
  • В режиме IrDA — помните на старых телефонах была такая фиговина? Вот это оно. Отличается от обычного протокола тем, что тут данные передаются краткими импульсами. Этакими вспышками. А 0 и 1 ловятся по паузам между ними. Так себя фотоприемники видать лучше чувствуют.
  • Также есть LIN режим. LIN это автомобильная сеть, этакий CAN для бедных. Вон во всяких приорах стекла и сигналки на LIN шине сидят.

 

В общем, полный фарш. Расписывать все не буду. Только самое основное. Иначе это книгу написать можно.
 

Не все блоки одинаково могучи, зависит от номера. А количество блоков зависит от модели проца. Чем жирней проц, чем больше у него ног, тем больше у него блоков USART. Всего их может быть 6 и в зависимости от номера умеют они следующее:

 
 

▌Состав
Итак, из чего состоит USART на STM32?

Снаружи это выводы RX и TX. А также всякие CTS и RTS для управления потоком данных. Блоков у нас три, так что данных штуковин у нас тоже 3 комплекта.

Распиновка выглядит как то так. Вроде нигде не ошибся :) Если каких то выводов нет у вас вживую, ничего страшного, просто у вас не тот корпус. Модификация F103C8 идет в разных корпусах. От 36 до 100 ног.
 

 
Т.е. можно ремапить все UART выводы на другие ноги. Это удобно при разводке. О ремапе портов было рассказано в главе про GPIO
 

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

По ней видно, что UART1 сидит на APB2, а остальные на APB1
 

А на софтверном уровне UART для нас это прежде всего регистры и флаги. Вот ща ими и займемся. Опять же глубоко копать не буду. Только самое основное.
 

▌Регистры
USART_SR Status Register. Регистр состояния автомата передатчика. Тут все флаги по которым можно понять, что происходит вообще с передачей данных.

  • CTS — ставится в 1 когда идет запрос на прием данных по линии CTS. Если конечно это разрешено в настройках битом CTSE. Также по этому флажку генерируется прерывание. Сбрасывается вручную.
  • LBD — LIN Break flag. Какой то запрос от LIN шины. Сбрасывается вручную, умеет выдавать прерывание.
  • TXE — Tx Empty. Передатчик пуст, можно кидать следующий байт. Может сгенерировать прерывание. Сбрасывается сам, когда записываем в USART_DR.
  • TC — Transmit Complete. Передача завершена. От TXE отличается тем, что у нас не просто буфер пустой, а еще и сдвиговый регистр отстрелялся. Может генерировать прерывание. Сбрасывается либо вручную, либо автоматически при чтении из USART_SR с последующей записью в USART_DR.
  • RXNE — Read data register not empty. Что то нам на вход пришло и можно забирать. Генерит прерывание и сбрасыватся либо ручками, либо чтением из USART_DR регистра.
  • IDLE — IDLE line detected. Линия свободна, можно вещать. Может генерировать прерывание и сбрасывается чтением сначала USART_SR, потом USART_DR. Думаю это можно трактовать как конец приема. Когда данные пришли и новых на линии нет.
  • ORE — Overrun error. Просрали байт. Сливай воду. Выскакивает когда данные не успеваем считывать, а новые все лезут и лезут. Генерирует прерывание (куда же без него) и сбрасывается когда мы сначала читаем регистр статуса, а потом заглядываем в регистр данных. Причем тут есть нюанс. Убиваются входящие данные только в сдвиговом регистре. Т.е. пока мы сами не прочитаем данные из регистра данных им ничего не грозит.
  • NE — Noise error flag. Срач в линии. Тоже есть прерывание. Сбрасывается точно также как и ORE.
  • FE — Frame Error. Ошибка кадра. Это если данные побились по ходу. Ну например, частота если плавает у передатчика и в линию идет какая то странная фигня. Ведь USART асинхронный и там все на время завязано. Дает прерывание, сбрасывается точно также как и ORE.
  • PE — Parity Error. Ошибка контроля четности. Очищается также как и прошлые три, но тут надо перед сборосом подождать пока встанет бит RXNE. Дает прерывание. Кто бы сомневался :)

USART_DR — Data Register. Сюда падают данные, сюда же мы грузим данные для отправки. Занимает 32 бита из которых используются только 9 (!) первых бит, остальные принудительно зануляются аппаратно. Как и в AVR физически это двухголовый регистр с одним именем. Разница только между чтением и записью. Читаем из приемника, а записываем в передатчик. И также как в AVR данные отсюда проваливаются сразу же в сдвиговый регистр USART и полетели…

USART_BRR — Baud rate register. Регистр задания бодрейта. Первые его два байта определяют частоту передачи. Вторые принудительно ноль. Также как и в AVR.
 


 

Как вычислить USARTDIV? Даташит нам предлагает такую формулу:
 

USARTDIV = (F/baudrate)/16

 

Только тут надо учитывать тот прикол, что тактуется USART с шины APB и частоту для бодрейта надо вычислять исходя из этой величины, а не частоты ядра, которая может очень сильно отличаться от частоты шины периферии. Подробней о частотах в главе про RCC и тактирование. И про эти вилы забывать нельзя!!! Помните СКОЛЬКО возможных режимов тактирования есть у STM32 и как там лихо все разветвляется.
 

Осталось только ее пересчитать в целую и дробную часть. Делается это так:
 

Например, у нас частота шины 36МГц, а бодрейт у нас должен быть 19200 бод.
 

(36 000 000/19200)/16 = 117.18

 

Целая часть у нас будет 117, а вот дробную надо будет восстановить, умножив на 16 и округлив до ближайшего целого:
 

0.18 * 16 = 2.88 -> 3

 

Переводим в хекс и получаем 0х75 и 0х3 т.е. USART_BRR = 0x00000753
 

Надо помозговать и написать макрос под это дело.
 

USART_CR1 — регистр настроек.

  • UE — USART Enable — включить USART блок.
  • M — длина байта. 1 = 9 бит. 0 = 8 бит. Изначально 0
  • WAKE — какой то бит пробуждения (Из Sleep mode?) 0 = по свободной линии, 1 = по совпадению адреса. Что-то связанное с мультиконтроллерной связью.
  • PCE — Parity control enable. Контроль четности, если =1 то четность проверяется.
  • PS — Parity selection. Тип контроля четности. 0 = проверяем на четность. 1 = проверка на нечетность.
  • PEIE — PE interrupt enable. Включение прерывания по четности (флагу PE регистра состояния уарта).
  • TXEIE — TXE interrupt enable. Включение прерывания по опустошению буфера передатчика.
  • TCIE — Transmission complete interrupt enable. Включение прерывания по окончании передачи.
  • RXNEIE — RXNE interrupt enable. Включение прерывания по приему байта.
  • IDLEIE — IDLE interrupt enable. Включение прерывания по окончанию приема (освобождение линии)
  • TE — Transmitter enable. Включить передатчик.
  • RE — Receiver enable. Включить приемник.
  • RWU — Receiver wakeup. Что то с пробуждением по приходу.
  • SBK — Send break. Послать символ прерывания. Ставим этот бит и уарт отрыгивает в линию код BREAK и после сам снимает бит.

 

USART_CR2 — регистр настроек

 

  • LINEN — LIN mode enable. Режим LIN шины.
  • STOP[1:0] — два бита определяющие тип стоп бита. 00 = 1 стоп бит, 01 = полубит, 10 = 2 бита, 11 — полтора бита.
  • CLKEN — Clock enable. Разрешение CK входа. Это для синхронной передачи.
  • CPOL — Clock polarity. Полярность CK линии. Что там будет принято за готовность 0 или 1, соответственно.
  • CPHA — Clock phase. Фаза СК синхролинии. По первому дрыгу пойдут данные (0) или по второму (1).
  • LBCL — Last bit clock pulse. Что то там с последним дрыгом синхролинии при синхронной передаче.
  • LBDIE — LIN break detection interrupt enable. Разрешение прерывания от LIN шины.
  • LBDL — lin break detection length. Длина этого сигнала от LIN шины.
  • ADD[3:0] — Address of the USART node. Адрес на шине, для мультипроцессорной коммуникации.

USART_CR3 — регистр настроек

 

  • CTSIE — CTS interrupt enable. Разрешение прерывания от CTS
  • CTSE — CTS enable. Просто разрешение использования CTS входа.
  • RTSE — RTS enable. Разрешение использования RTS выхода.
  • DMAT — DMA enable transmitter. Разрешение DMA для передатчика.
  • DMAR — DMA enable receiver. Разрешение DMA для приемника.
  • SCEN — Smartcard mode enable. Режим работы со смарткартами.
  • NACK — Smartcard NACK enable. Разрешение передачи ошибки четности для смарткарт.
  • HDSEL — Half-duplex selection. Полудуплексный режим.
  • IRLP — IrDA low-power. Выбор режима работы IrDA. 1 = маломощный, 0 — обычный режим.
  • IREN — IrDA mode enable. Включение режима ИК передачи данных.
  • EIE — Error interrupt enable. Разрешение прерываний от ошибок. Это FE, ORE, NE)

 

USART_GTPR — Guard time and prescaler register
Содержит несколько параметров задающих делители для режимов смарт карты и IrDA.

Вот всю эту тряхомудию надо нам будет настроить. Хотя по простому нам не нужны все биты. Так что можно не запариваться, а просто их изучить, чтобы знать что у нас там есть.
 

▌Прерывания USART
Видели сколько там прерываний? На каждый чих. Думаете там как в AVR каждму сверчку свой шесток? Хрена! Вот вам:
 

 
Все события стекаются в ОДНО прерывание (как на PIC, ага). Т.е. попав в него надо проверить по какому поводу мы там и сделать выводы. Сбросить флаги нас вызвавшие, проверить ошибки и прочее.
 

Ладно хоть у каждого USART прерывание свое. Лезем, как обычно в STM32F10x.s и ищем там вектора, точнее их имена:
 

1
2
3
              DCD     USART1_IRQHandler         ; USART1
              DCD     USART2_IRQHandler         ; USART2
              DCD     USART3_IRQHandler         ; USART3

 
Вот они, касатики.
 

Что, попробуем что-нибудь настроить. Для начала просто попинаем байтики через USART1.
 

▌Стенд
Возьмем мою демоплату Pinboard II с модулем ARM и организуем себе терминалку. Т.к. отладчик CoLink занимает канал А, а UART1 сидит на нем же, то пробросим его на канал В. FTDI. Для этого нам потребуются две перемычки. Соединим ими на коммутаторе выводы таким образом:
 
RxA1 — TxB
TxA1 — RxB
 

Вот так вот:
 


 
Ну и само собой не забыть пару джамперов, чтобы соединить модуль по порту UART1 с платой.
 

▌Программа и шаги по настройке

  • 1. Разберемся с частотой. Что у нас и на какой частоте работает. Что надо включить, чтобы такты пошли.

    Частота идет с SysClock (72Мгц у меня) на AHB Prescaler. За него отвечают биты HPRE[3:0] регистра RCC_CFGR. После старта там 0000, т.е. без делителя.
     

    Окей, 72 мегагерца пошли дальше. Следующим идет предделитель APB2. Он конфигурируется битами PPRE2[2:0] того же RCC_CFGR. По дефолту там тоже 0. Т.е. частота приходящая в USART у нас 72МГц.
     

    Вообще все тут сильно зависит от фукнции SystemInit(); и тактовой частоты которая указана в system_stm32f10x.c что является частью CMSIS для STM32. У меня там что то вида:
     

     
    И от этого уже пляшет SystemInit(); у меня она выставляет AHB = SysClock, APB2 = AHB, а APB1 = AHB/2 (т.к. она не может быть больше 36МГц).
     

    Но тут стоит проверить. Как проверить? Прогнать под эмулятором или внутрисхемным отладчиком (Обладатели Pinboard II с отладчиком CoLink радуются и юзают :) ) и посмотреть, что попало в регистры после SystemInit.
      В Keil это выглядит так:
     

     

  • 2. Включим тактовую для USART1 (для других USART будем дергать уже шину APB1):
    1
    
    RCC->APB2ENR	|= RCC_APB2ENR_USART1EN;	//USART1 Clock ON
  • 3. Вычислим и настроим бодрейт.

    (72 000 000/19200)/16 = 234.375 Получаем старшую часть 0хЕА, а младшую 0х6. Итого BRR = 0xEA6.

    1
    
    USART1->BRR = 0xEA6;		// Bodrate for 19200 on 72Mhz
  • 4. Настроим работу USART. Для начала просто включим его, включим прием, включим передачу. Прерывания трогать не будем.
    1
    
    USART1->CR1  |= USART_CR1_UE | USART_CR1_TE | USART_CR1_RE; // USART1 ON, TX ON, RX ON
  • 5. Настроим ногу TX на выход Push-Pull от альтернативной функции. При этом надо не забыть включить тактирование как порта, так и тактирования блока альтернативных функций. Как я вам завещал в статье про GPIO
    1
    2
    3
    4
    
    RCC->APB2ENR  	|= RCC_APB2ENR_IOPAEN | RCC_APB2ENR_AFIOEN; 	// GPIOA Clock ON. Alter function clock ON
    GPIOA->CRH	&= ~GPIO_CRH_CNF9; 				// Clear CNF bit 9
    GPIOA->CRH	|= GPIO_CRH_CNF9_1;				// Set CNF bit 9 to 10 - AFIO Push-Pull
    GPIOA->CRH	|= GPIO_CRH_MODE9_0;				// Set MODE bit 9 to Mode 01 = 10MHz
  • 6. Аналогично настроим вход RX На .. хм, на вход :). Альтернативной функции тут уже не надо
    1
    2
    3
    
    GPIOA->CRH	&= ~GPIO_CRH_CNF10;	// Clear CNF bit 9
    GPIOA->CRH	|= GPIO_CRH_CNF10_0;	// Set CNF bit 9 to 01 = HiZ
    GPIOA->CRH	&= ~GPIO_CRH_MODE10;	// Set MODE bit 9 to Mode 01 = 10MHz
  • 7. Пошлем таки этот чертов байт! Тупо в лоб, без всяких проверок флагов на пустоту регистра. По простому, по крестьянски. Даешь быдлокод!
    1
    
    USART1->DR = 10;

 


Вуаля!
 

Ну и весь код целиком:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include "stm32f10x.h"
#define F_CPU 72000000UL
 
 
int main(void)
{
SystemInit();
 
RCC->APB2ENR  	|= RCC_APB2ENR_IOPAEN | RCC_APB2ENR_AFIOEN;	// GPIOA Clock ON. Alter function clock ON
GPIOA->CRH	&= ~GPIO_CRH_CNF9;				// Clear CNF bit 9
GPIOA->CRH	|= GPIO_CRH_CNF9_1;				// Set CNF bit 9 to 10 - AFIO Push-Pull
GPIOA->CRH	|= GPIO_CRH_MODE9_0;				// Set MODE bit 9 to Mode 01 = 10MHz 
 
RCC->APB2ENR	|= RCC_APB2ENR_USART1EN;			// USART1 Clock ON
USART1->BRR 	= 0xEA6;					// Bodrate for 19200 on 72Mhz
USART1->CR1 	|= USART_CR1_UE | USART_CR1_TE | USART_CR1_RE;	// USART1 ON, TX ON, RX ON						
USART1->DR = 10;	// Send Byte!
 
// Config CRL
GPIOB->CRL	&= ~GPIO_CRL_CNF5;		// Clear CNF bit 5. Mode 00 - Push-Pull 
GPIOB->CRL 	|= GPIO_CRL_MODE5_0;		// Set bit MODE for pin 5. Mode 01 = Max Speed 10MHz
 
 while(1)
 {
 }
}

 

Ну и щас, для примера и хохмы ради, попробуем сделать UART-паровозик из Кащенко. Разовьем у нашего контроллера форменную шизофрению и голоса в голове. Он будет разговаривать сам с собой. Приходящие по RX1 мысли будут через TX1 уходить в RX2, из TX2 в RX3, а уже из TX3 пойдут наружу в нашу терминалку. А чтобы голоса в голове не ходили просто так мы будем матаном их грузить. UART 1 будет прибавлять единичку, UART2 десяток, а UART3 сотню. В результате, на входе 1, а на выходе 112. И все это на прерываниях. Как то так…
 

Сначала сделаем прерывание:

1
2
3
4
5
6
7
void USART1_IRQHandler(void)
{
 if (USART1->SR & USART_SR_RXNE)
	{
	USART1->DR = (USART1->DR)+1;
	}
}

 

В нем видно, что мы проверяем флаг RXNE, чтобы понять по какому мы, собственно, поводу оказались в прерывании. Делается это одной строчкой и меня искренне удивляют люди которые это пытаются делать то же самой функцией через SPL. ЗОЧЕМ? Также помним, что чтение из DR сбрасывает тот флаг, т.е. нам не нужно о нем заботиться. Но на счет других надо помнить.
 

Теперь разрешим его, подправив строчку инициализации USART:
 

1
2
USART1->CR1 	|= USART_CR1_UE | USART_CR1_TE | USART_CR1_RE |		// USART1 ON, TX ON, RX ON
		     USART_CR1_RXNEIE;		 			// RXNE Int ON

 

Разрешим прерывания в NVIC. Через функцию CMSIS. C приоритетом прерываний пока не заморачиваемся. Если вдруг надо, то вам в статью про NVIC:

1
NVIC_EnableIRQ (USART1_IRQn);

 

И осталось разрешить глобальные прерывания. Хотя они ЕМНИП по умолчанию включены, в отличии от той же AVR.
 

1
__enable_irq ();

А теперь скопируем это все три раза, подправив биты, чтобы проинициализировать этим три уарта сразу:

Показать »

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
#include "stm32f10x.h"
#define F_CPU 72000000UL
 
 
 
void USART1_IRQHandler(void)
{
	if (USART1->SR & USART_SR_RXNE)
	{
	USART1->DR = (USART1->DR)+1;
	}
}
 
void USART2_IRQHandler(void)
{
	if (USART2->SR & USART_SR_RXNE)
	{
	USART2->DR = (USART2->DR)+10;
	} 
}
 
void USART3_IRQHandler(void)
{
	if (USART3->SR & USART_SR_RXNE)
	{
	USART3->DR = (USART3->DR)+100;
	} 
}
 
 
int main(void)
{
SystemInit();
 
// PORT INIT	
RCC->APB2ENR  |= RCC_APB2ENR_IOPAEN | RCC_APB2ENR_AFIOEN |	// GPIOA Clock ON. Alter function clock ON
		 RCC_APB2ENR_IOPBEN;				// GPIOB Clock ON
 
 
// USART1 Settings	
// SET TX1
GPIOA->CRH	&= ~GPIO_CRH_CNF9;		// Clear CNF bit 9
GPIOA->CRH	|= GPIO_CRH_CNF9_1;		// Set CNF bit 9 to 10 - AFIO Push-Pull
GPIOA->CRH	|= GPIO_CRH_MODE9_0;		// Set MODE bit 9 to Mode 01 = 10MHz 
 
// SET RX1
GPIOA->CRH	&= ~GPIO_CRH_CNF10;		// Clear CNF bit 9
GPIOA->CRH	|= GPIO_CRH_CNF10_0;		// Set CNF bit 9 to 01 HiZ
GPIOA->CRH	&= ~GPIO_CRH_MODE10;		// Set MODE bit 9 to Mode 01 = 10MHz 
 
// SET USART1 REG	
RCC->APB2ENR	|= RCC_APB2ENR_USART1EN;				// USART1 Clock ON
USART1->BRR 	= 0xEA6;						// Baudrate for 19200 on 72Mhz
USART1->CR1 	|= USART_CR1_UE | USART_CR1_TE | USART_CR1_RE |		// USART1 ON, TX ON, RX ON
		     USART_CR1_RXNEIE;					// RXNE Int ON		
 
 
// USART2 Settings
// SET TX2
GPIOA->CRL	&= ~GPIO_CRL_CNF2;	// Clear CNF bit 2
GPIOA->CRL	|= GPIO_CRL_CNF2_1;	// Set CNF bit 2 to 10 - AFIO Push-Pull
GPIOA->CRL	|= GPIO_CRL_MODE2_0;	// Set MODE bit 2 to Mode 01 = 10MHz 
 
// SET RX2
GPIOA->CRL		&= ~GPIO_CRL_CNF3;	// Clear CNF bit 3
GPIOA->CRL		|= GPIO_CRL_CNF3_0;	// Set CNF bit 3 to 01 HiZ
GPIOA->CRL		&= ~GPIO_CRL_MODE3;	// Set MODE bit 3 to Mode 01 = 10MHz 
 
 
// SET USART2 REG	
RCC->APB1ENR	|= RCC_APB1ENR_USART2EN;				// USART2 Clock ON
USART2->BRR 	= 0x753;						// Baudrate for 19200 on 36Mhz
USART2->CR1 	|= USART_CR1_UE | USART_CR1_TE | USART_CR1_RE |		// USART2 ON, TX ON, RX ON
		 USART_CR1_RXNEIE;	
 
 
// USART3 Settings
// SET TX3
GPIOB->CRH	&= ~GPIO_CRH_CNF10;		// Clear CNF bit 9
GPIOB->CRH	|= GPIO_CRH_CNF10_1;		// Set CNF bit 9 to 10 - AFIO Push-Pull
GPIOB->CRH	|= GPIO_CRH_MODE10_0;		// Set MODE bit 9 to Mode 01 = 10MHz 
 
// SET RX3
GPIOB->CRH	&= ~GPIO_CRH_CNF11;		// Clear CNF bit 9
GPIOB->CRH	|= GPIO_CRH_CNF11_0;		// Set CNF bit 9 to 01 HiZ
GPIOB->CRH	&= ~GPIO_CRH_MODE11;		// Set MODE bit 9 to Mode 01 = 10MHz 
 
 
// SET USART3 REG	
RCC->APB1ENR	|= RCC_APB1ENR_USART3EN;				// USART3 Clock ON
USART3->BRR 	= 0x753;						// Baudrate for 19200 on 36Mhz
USART3->CR1 	|= USART_CR1_UE | USART_CR1_TE | USART_CR1_RE |		// USART3 ON, TX ON, RX ON
		    USART_CR1_RXNEIE;	
 
//UART INT ON
NVIC_EnableIRQ (USART1_IRQn);
NVIC_EnableIRQ (USART2_IRQn);
NVIC_EnableIRQ (USART3_IRQn);	
 
__enable_irq ();
 
 while(1)
	{
	}
}

Осталось теперь только USARTы все закольцевать и можно запускать наш шизофреничный паровозик. Соединяем TxB с Rx1, Tx1 с Rx2, Tx2 с Rx3, а Tx3 с RxB.
 


 

Вот так!
 

Запускаем первый байт…

 

Вот!

Потом, если не лень будет, я сюда еще каких нибудь примеров работы с USART добавлю. А вам пока вот текущий пример для Keil

29 thoughts on “ARM Учебный курс. USART”

  1. Опять я первый! Мельком посмотрел, как всегда на высоте. Все охота поиграться с ARM, жаль в протеусе M3 нет. А покупать ради поиграться не охота пока.

  2. С ремапом USART есть одна засада. Если планируется использовать один USART и для работы и для встроенного загрузчика, то придётся использовать только осносвые ноги (Pa9-Pa10 на USART1), так как встроенный загрузчик поддерживает только их.

  3. С BRR всё предельно просто:
    BRR = F_USART / baud;
    И всё.
    BRR = 36 000 000 / 19200 = 1875 = 0x753;
    16 тиков на бод и 16 градаций в дробной части не просто так сделаны.

      1. А то, что даташиты пишут те, кто на большее не годен. И вообще, у документописателей специфическое мышление, а с технарями они общаются посредствам манагеров.

  4. Мне вот интересно, почему везде в примерах, везде в просторах интернета, во всех практически «учебных» курсах про флаги ошибок говорят, что они есть, что они означают. А в самих примерах кода нет. Или все учебные курсы описывают идеальный UART, без помех, аля обучалка для обучения, а в реалии оно по другому.

    1. Я за всю жизнь ни разу не встречал ни одной ошибке на UART если конечно речь идет не о радиопередаче на сыром выходе (вроде HM-T433). Или очень длинных линиях (10 метров и более). Обычно он используется для связи с компом на коротких расстояниях и тут все на 100% четко.

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

  5. А вот расскажите что делать если надо обслужить много COM-портов? Ну, как много… штук 8-10. Есть, конечно, МК с большим кол-вом UART, но это старшие модели. А задачи могут быть и простые — неспешное управление большим кол-вом устройств, когда мощный проц не нужен. Как обычно поступают в этой ситуации?

      1. Вопрос по схемотехнике — как это реализуется физически? Т.е. надо посадить несколько драйверов на один UART? Как это делается? Как мапить прерывания? Есть ли «продвинутые» драйверы, например, с буфером на несколько байт? Наверняка есть «типовые» решения, где про это почитать чтобы не изобретать паровоз?
        ЗЫ: только заметил что написал в тему про ARM, а вот реализуема ли такая мечта на простеньких МК типа AVR?

        1. А ты хочешь несколько уартов на один канал? Это извращение. Тут придется городить мультиплексоры внешние. Либо программно его реализовывать. Куда проще взять камень где этих уартов будет как грязи.

          1. Я пока в принципе интересуюсь как это делается. Для примера посмотрел сайт Атмела: максимум 8 UART — и только на xMega (Кортексы есть 7-портовые). А если надо больше? Ставить несколько МК только на COM-порты + один на общую логику?

  6. Люди, помогите найти ошибку, уже не знаю что делать. Осваиваю stm32f4, и зашел в очередной тупик. Ковыряю USART2 на stm32f4discovery, не работает приём, сначала грешил на прерывания но даже тупое считывание входного регистра ничего не дает. Передача работает, прерывания на передачу работают, а вот принимать что либо тупо отказывается, молчит себе в тряпочку. Вот код:

    1. Извиняюсь что потревожил :-)
      Нашел 2 ошибки у себя:
      1) Нужно было подключить альтернативную функцию порта на обе ноги, а я сделал только на одну
      GPIOA->AFR[0] |= 0x7<AFR[0] |= 0x7<MODER |= GPIO_MODER_MODER3_1;
      И на это мне потребовалось 2 дня xD

      1. Эм, чего оно всё в одну строчку влепило? Комменты нормально работают, или я написал неправильно?

  7. Пасаны, может кто-нибудь скажет где ошибка?Не могу USART1 запустить в stm32f407vg

    #define F_CPU 72000000UL

    #include «stm32f4xx.h»

    void USART_init()
    {
    USART1->BRR=0x00000EA6;
    USART1->CR1=0x00002008;
    USART1->CR2=0x3000;
    USART1->CR1 |= USART_CR1_OVER8;////
    }

    void gpio_init()
    {
    GPIOA->MODER=0x8000;
    GPIOA->OTYPER=0x0;
    GPIOA->OSPEEDR=0x00008000;
    GPIOA->AFR[1]=0x70;
    }

    int main ()
    {
    gpio_init();
    USART_init();

    RCC->AHB1ENR=0x1;
    RCC->APB2ENR=0x4010;

    USART1->DR=4;
    while(1);
    }

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

Ваш e-mail не будет опубликован.

Перед отправкой формы:
Human test by Not Captcha