USART stm32 HAL






USART (Universal Synchronous-Asynchronous Receiver/Transmitter) — универсальный синхронно-асинхронный приёмопередатчик, интерфейс для для передачи данных между цифровыми устройствами. Он на столько универсальный, что даже провода по которым к вам домой приходит интернет, это тоже USART (RS485).


USART микроконтроллера stm32 может работать в различных режимах — асинхронный, синхронный, полудуплекс и т.д.



Asynchronous




Это самый распространённый режим, устройства соединяются так…

RX <> TX
TX <> RX

… а согласуются между собой с помощью заранее установленной скорости передачи данных.



Тут следует немного пояснить работу USART'а для упрощения понимания некоторых настроек.

Мы будем передавать 8-ми битные байты (в отдельных случаях байты могут 9-ти битные), на скорости 115200 бит в секунду…


Parity — использование бита проверки чётности (см. ниже).
Stop Bits — количество стоповых битов (1 или 2).
Data Direction — включается приём и передача, или что-то одно.
Over Sampling — см. ниже.


Получаемый пакет из восьми бит (один байт) выглядит так…


Отправляемые/получаемые байты отделяются друг от друга стартовыми и стоповыми битами.

Если ничего не передаётся, то линия находится в состоянии HIGH. Передатчик, начиная отправку, прижимает линию к «земле», а приёмник расценивает это как начало пакета — START (стартовый бит). Далее идёт приём (отсчитывая биты) и после последнего (D7) бита проверяется что линия установлена в HIGH — STOP (стоповый бит). Иногда для большей достоверности окончания приёма используются два стоповых бита.


Количество принятых бит подсчитывается следующим образом: как только появляется стартовый бит (переход с HIGH на LOW) сразу же начинается отсчёт — 16 тиков на каждый бит…



Over Sampling — 16 Samples.

Эти 16 семплов «прощупывают» уровень линии, и если в момент предполагаемой середины бита (MIDBIT) линия находится в состоянии HIGH, то в соответствующий разряд приёмного регистра записывается единичка, если LOW, то нолик. За это отвечают три центральных семпла…



Другие семплы сигнализирует об ошибках. Например, если первые два семпла покажут что линия находится в состоянии HIGH, а следующие два скажут что она LOW, и снова HIGH, то микроконтроллеру станет совершенно очевидно, что при передаче в линию вклинились помехи. В результате вместо байта мы получим сообщение об ошибке — HAL_UART_ERROR_NE — шум в линии. Если же нужные нам семплы «съезжают» в сторону, в право или влево, то это будет означать, что у передающего устройства «плавает» частота, а мы получим ошибку кадра — HAL_UART_ERROR_FE.

анимашка


Вот таким вот нехитрым образом происходит принятие одного байта.


Я не могу говорить за все микроконтроллеры stm32, но например на F303 можно указать частоту семплирования либо 16 либо 8. За счёт уменьшения семплирования можно повышать скорость USART'а. Каким образом — да очень просто: USART_1 тактируется от шины APB2, на каждый бит нам нужно по 16 тиков, значит при частоте шины 72МГц и семплирований 16, мы можем получить максимальную скорость USART'а равную 4.5 Mбит/с (72000000 / 16 = 4500000). Если же указать семплирование 8, то теоретически мы получим скорость 9 Mбит/с.




Parity — бит чётности. С помощью этого бита можно проверять целостность полученного пакета.

Пакет с добавленным битом чётности выглядит так…


Word Length нужно указать 9 Bits. Если оставить 8 Bits, то полезных битов будет 7.

При отправке в этот бит записывается единица или ноль в зависимости от количества единичек в предыдущих восьми битах. Если единичек чётное кол-во, то записывается 0, если нечётное, то 1.

То есть:

Если отправляется 10111101 (шесть единичек — чётное количество), то бит чётности будет 0. Пакет будет выглядеть так — 101111010.

Если отправляется 01110011 (пять единичек — нечётное количество), то бит чётности будет 1. Пакет будет выглядеть так — 011100111.

При приёме такого пакета производится проверка — соответствует ли количество единичек значению в девятом бите, и если не соответствует, то пакет считается повреждённым — ошибка контроля чётности (HAL_UART_ERROR_PE).

Вычисления производятся с помощью битовой операции XOR (исключающее «или»).

Проверка конечно так себе. Теоретически может одна единичка превратится в ноль, а другой ноль в единичку, и тогда проверка ничего не выявит.


С помощью опций — Even и Odd, можно выбрать что будет считаться чётным.


Hardware Flow Control — это контроль передачи данных (с помощью дополнительных линий) используемый, например, для соединения через COM-порт. Оставьте Disable, нам это не понадобится.

RTS/CTS
Если устройство хочет прекратить передачу данных, оно устанавливает состояние сигнала RTS (Request To Send) в «ноль» (-12 вольт). Это означает — «не посылать запросы ко мне» (прекратить передачу). Когда устройство готово для принятия очередной партии данных оно устанавливает сигнал RTS в «единицу» (+12 вольт) и обмен данными возобновляется.

Сигналы контроля передачи данных всегда посылаются в противоположном направлении от потока данных. DCE устройства (модемы) работают по тому же принципу, только посылают сигнал на контакте CTS (Clear To Send). Поэтому тип контроля передачи данных RTS/CTS использует 2 линии.


Advanced Features — здесь можно включить автоопределение скорости (Auto Baudrate) и отключить сообщения об ошибках (Overrun, DMA on RX Error), остальные пункты, это различные специфические настройки, которые не стоит менять. Оставьте всё по умолчанию.


Почитать про USART подробно здесь и здесь.




Теперь можно попрограммировать.


ОТПРАВКА

Чтобы принять или отправить данные достаточно описанных выше настроек.


Отправить строку «Hello World» можно так:

HAL_UART_Transmit(&huart1, (uint8_t*)"Hello World\n", 12, 1000);

Первый аргумент — указатель на структуру USART'а, второй — строка (приведённая к указателю), третий кол-во символов в отправляемой строке, четвёртый — таймаут в миллисекундах (если по каким-то причинам не удастся выполнить отправку в течении секунды, то вернётся ошибка).

Эта функция блокирующая, то есть пока она не выполнится программа будет приостановлена.


Чтоб не блокировать программу на время отправки, нужно воспользоваться функцией с прерыванием по завершению передачи.

Включите глобальное прерывание…



Отправлять данные так:

HAL_UART_Transmit_IT(&huart1, (uint8_t*)"Hello World\n", 12);

Здесь нет таймаута так как нам ничего не нужно ждать — отправили и забыли. Остальные аргументы те же, что и у блокирующей функции.

По окончании отправки сработает прерывание и вызовет колбек:

void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
	  if(huart == &huart1)
	  {
		  // можно установить какой-то флаг, сообщающий об окончании отправки
	  }	
}



Отправить массив:

/* USER CODE BEGIN Includes */
#include "string.h"
/* USER CODE END Includes */
...

char buff[16] = {0,};

snprintf(buff, 15, "Hello World\n");
HAL_UART_Transmit_IT(&huart1, (uint8_t*)buff, strlen(buff));

Второй аргумент — указатель на массив, третий — длина строки в массиве.



Через DMA


Включаем…



Отправляем:

HAL_UART_Transmit_DMA(&huart1, (uint8_t*)buff, strlen(buff));

Аргументы те же, что и у предыдущей функции.

Колбек тот же что и HAL_UART_Transmit_IT(...), но тут есть нюанс. DMA вызывает два прерывания, первое после отправки половины буфера, а второе при завершении. Чтоб отключить половинку, нужно в файле stm32f1xx_hal_uart.c найти функцию HAL_UART_Transmit_DMA(...) и закомментировать строчку…

/* Set the UART DMA Half transfer complete callback */
//huart->hdmatx->XferHalfCpltCallback = UART_DMATxHalfCplt;


Больше про отправку сказать нечего.



ПРИЁМ


Для приёма нужно сделать так:

uint8_t buff[16] = {0,};
HAL_UART_Receive(&huart1, (uint8_t*)buff, 15, 1000);

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

Эта функция тоже блокирующая, она будет ожидать до тех пор пока не получит все запрошенные байты, или пока не истечёт таймаут.


Если для отправки данных блокирующая функция вполне подходит, то для приёма совсем не годится (мы ведь не знаем когда придут данные, если конечно они не идут сплошным потоком). Поэтому нужно использовать функцию вызывающую прерывание…

uint8_t buff[16] = {0,};
HAL_UART_Receive_IT(&huart1, (uint8_t*)buff, 15);

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

Эта функция не блокирует программу. Прерывание произойдёт только после того, как всё запрошенные байты будут приняты.

Колбек:

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	  if(huart == &huart1)
	  {
		  // что-то делаем
	  }
}


Помните о том, что если посылаете данные из какого-то терминала, то этот терминал может посылать символы «новой строки» и «воврат каретки». То есть, если вы пошлёте 15 символов, а терминал добавит ещё свои, то программа получит первые 15, вызовет колбек, примет ещё (то что добавил терминал) и будет ожидать. Короче говоря, программа провернётся через колбек и будет ждать.


Через DMA

Включаем канал для приёма…



Запускаем…

HAL_UART_Receive_DMA(&huart1, (uint8_t*)buff, 15);

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

Колбек тот же что и при использовании HAL_UART_Receive_IT(...), и так же как и с отправкой, будут вызываться два прерывания — половина буфера и полный. Как отключить половинку вы уже знаете.


Поскольку при приёме/отправке могут возникать ошибки, то чтобы их отловить нужно создать специальный колбек…

error
Сюда приходят все ошибки USART'а.

void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
{
	if (huart == &huart1)
	{
		uint32_t er = HAL_UART_GetError(&huart1);
 
		if (er & HAL_UART_ERROR_PE)
		{
			HAL_UART_Transmit(&huart1, (uint8_t*) "ERR_Callbck - Parity error\n", 27, 1000);
			__HAL_UART_CLEAR_PEFLAG(&huart1);
		}
		if (er & HAL_UART_ERROR_NE)
		{
			HAL_UART_Transmit(&huart1, (uint8_t*) "ERR_Callbck - Noise error\n", 26, 1000);
			__HAL_UART_CLEAR_NEFLAG(&huart1);
		}
		if (er & HAL_UART_ERROR_FE)
		{
			HAL_UART_Transmit(&huart1, (uint8_t*) "ERR_Callbck - Frame error\n", 26, 1000);
			__HAL_UART_CLEAR_FEFLAG(&huart1);
		}
		if (er & HAL_UART_ERROR_ORE)
		{
			HAL_UART_Transmit(&huart1, (uint8_t*) "ERR_Callbck - Overrun error\n", 28, 1000);
			__HAL_UART_CLEAR_OREFLAG(huart);
		}
		if (er & HAL_UART_ERROR_DMA)
		{
			HAL_UART_Transmit(&huart1, (uint8_t*) "ERR_Callbck - DMA transfer error\n", 33, 1000);
			__HAL_UART_CLEAR_NEFLAG(&huart1);
		}
		huart->ErrorCode = HAL_UART_ERROR_NONE;
	}
}




Файл stm32f1xx_hal_uart.h

HAL_UART_ERROR_PE — ошибка контроля чётности.

HAL_UART_ERROR_NE — шум в линии.

HAL_UART_ERROR_FE — ошибка кадра. У передающего устройства «плавает» частота.

HAL_UART_ERROR_ORE — ошибка переполнения. Возникает когда в USART приходит новый байт, а предыдущий ещё не был считан из приёмного регистра — Data Register (DR). Это происходит из-за того, что прерывание обрабатывается слишком медленно и программа не успевает очистить приёмный регистр.



HAL устроен так, что в случае ошибки приём будет перезапущен. Это можно отключить в файле stm32f1xx_hal_uart.c в функции void HAL_UART_IRQHandler(UART_HandleTypeDef *huart)





С приёмом есть заморочка, мы можем не знать сколько данных должно прилететь, следовательно непонятно какое кол-во байт указывать. Например, если мы укажем пять байт, а прилетят только три, то прерывание не сработает пока не придут оставшиеся два. На этот случай есть несколько способов приёма.


Если нужно время от времени получать один-два байта, то можно просто в начале программы (перед бесконечным циклом) вызвать функцию приёма…

/* USER CODE BEGIN PV */
volatile char sim;
/* USER CODE END PV */

...

HAL_UART_Receive_IT(&huart1, (uint8_t*)&sim, 1);

… а в колбеке что-то поделывать, и вызывать снова…

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	  if(huart == &huart1)
	  {
		  HAL_UART_Transmit(&huart1, (uint8_t*)&sim, 1, 1000);
		  HAL_UART_Receive_IT(&huart1, (uint8_t*)&sim, 1);
	  }
}



Можно организовать кольцевой буфер.

Идея заключается в следующем: создаётся массив (размер указывается исходя из потребностей), полученный байт записывается в этот массив, указатель сдвигается на следующую ячейку, следующий байт сохраняется в эту ячейку, указатель опять сдвигается, и так до тех пор пока буфер не заполнится. После того как буфер заполнился можно поступить двумя способами: первый — указатель перескакивает на нулевую ячейку и буфер заполняется заново постепенно затирая ранее полученные данные. То есть запись идёт по кругу без остановки. Второй — при заполнении буфер останавливается, а новые данные записываются в него по мере вычитывания замещая прочитанные.

Наглядный пример кольцевого буфера. Пользоваться им не нужно, я его сделал просто для красоты когда мне было скучно.




Вот тут библиотека кольцевого буфера, которой я пользуюсь постоянно.



И ещё один способ — это воспользоваться флагом IDLE. Этот флаг устанавливается аппаратно при обнаружении незанятой линии. То есть, если в приёмник поступает несколько байт подряд, а потом возникает пауза (линия находиться в состоянии HIGH некоторое время), то взводится флаг IDLE генерирующий прерывание, а мы по этому прерыванию определяем что данные перестали поступать.

Допустим мы точно не знаем сколько байт должны прийти, но знаем что их не больше 12, тогда делаем так…

HAL_UART_Receive_IT(&huart1, (uint8_t*)buff, 15);
__HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);


Другое устройство пульнёт нам две строчки…

HAL_UART_Transmit(&huart2, (uint8_t*)"Hello World", 11, 1000);  
HAL_UART_Transmit(&huart2, (uint8_t*)"Hello World", 11, 1000);

В результате сначала произойдёт прерывание от IDLE (в буфер запишется строка «Hello World»), а потом прерывание при заполнении буфера. В итоге в буфере будет лежать «Hello WorldHell» — 15 байт.


Если это делать через DMA…

HAL_UART_Receive_DMA(&huart1, (uint8_t*)buff, 15);
__HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);

… то вся работа, кроме обработчиков двух прерываний, будет выполняться аппаратно. Не забудьте отключить половинку DMA.

Примеры — раз и два. Эти примеры рабочие, но код я так и не привёл в порядок, ибо как писал выше, пользуюсь «кольцевиком».

Замечание: прерывание по IDLE нужно отключать вручную в колбеке, а так же сбрасывать флаг. Это есть в примере.




Single Wire (Half-Duplex)

Полудуплексный режим — данные передаются и принимаются по одной линии (TX). В этом режиме устройства обмениваются данными по очереди — один слушает, другой отправляет. Линию нужно обязательно подтянуть к «плюсу» резистором ~10кОм…



Команды те же, что и в обычном (асинхронном) режиме, только надо предварительно настроить линию на приём или передачу…

HAL_HalfDuplex_EnableReceiver(&huart1); // устройство в режиме приёма
HAL_UART_Receive(&huart1, (uint8_t*)buff, 12, 1000);


HAL_HalfDuplex_EnableTransmitter(&huart1); // устройство в режиме отправки
HAL_UART_Transmit(&huart1, (uint8_t*)buff, 12, 1000);

Можно использовать прерывания и DMA.

… то есть, если одно устройство отправляет данные, то другое должно находиться в режиме приёма.


Линия RX соединена с TX внутри микроконтроллера.




MultiProcessor Communication

В этом режиме можно соединить несколько устройств. Одно устройство выступает в роли Мастера, а другие являются Слейвами. Мастер обращается к слейвам отправляя им их адреса — слейв видя что это его адрес принимает полезные данные.

Подключение обычное, как в асинхронном режиме…



Настройка в CubeMX…



F303



World Lenght — девятибитный режим. Можно и восьмибитный (см. в конце главы).


В момент старта слейв находится в так называемом «тихом» режиме, то есть он не будет принимать полезные данные (принимаются только адреса) пока не поймёт, что они адресованы именно ему. Как только слейв видит что данные адресованы ему, он выходит (Wake-Up) из «тихого» режима и начинает приём полезных данных.

Wake-Up Method ⇨ Address Mark — слейвы будут выходить из «тихого» режима при получении своего адреса.

Wake-Up Address — адрес устройства. Для мастера укажите — 0, а для слейвов1, 2 и т.д.

Если у вас только два устройства, один мастер и один слейв, тогда подтяните к «плюсу» резистором 10кОм TX мастера. Без этого у меня не работало. Если слейвов несколько, то всё окей.


Как работает:

• Мастер может отравлять данные любому слейву (предварительно отправляя адрес), и получать данные от любого слейва.
• Слейвы слушают линию, и если прилетает правильный адрес, то принимают данные следующие за этим адресом.
• Слейвы могут отправлять данные только мастеру.
• Мастер запускается в обычном режиме, то есть ни каких специальных команд не требуется.
• Слейв запускается в «тихом» режиме.

Для запуска в «тихом» режиме нужно перед бесконечным циклом сделать так…

Для F103:

HAL_MultiProcessor_EnterMuteMode(&huart1);


Для F303:

HAL_MultiProcessor_EnableMuteMode(&huart1);
HAL_MultiProcessor_EnterMuteMode(&huart1);

Пока ничего делать не нужно — команды приведены в ознакомительных целях.


Слейвы в «тихом» режиме ожидают адрес. Мастер, чтобы отправить кому-то данные, сначала отправляет в линию адрес, а затем данные.

Адреса и полезные данные передаются в девятибитном формате (9-ти битный байт). Если отправляется байт с адресом, то в первых восьми битах хранится сам адрес, а в девятый бит записывается единица. Если отправляется байт данных, то в девятый бит записывается ноль. То есть, приёмное устройство отличает байт с данными от байта с адресом по тому, что записано в девятом бите.

Адресный байт мастер отправляет так:

uint16_t adr_data = 0;
adr_data = 1 | 0x0100;
HAL_UART_Transmit(&huart1, (uint8_t*)&adr_data, 1, 1000);

Поскольку байт девятибитный, то переменная 16-ти битная. Адрес первого слейва — 1, записываем его в переменную, а девятый бит превращаем в единицу.

Для слейва с адресом 2 команда будет такая:

uint16_t adr_data = 0;
adr_data = 2 | 0x0100;
HAL_UART_Transmit(&huart1, (uint8_t*)&adr_data, 1, 1000);


После того как адрес отправлен, слейвы проверяют его (это происходит аппаратно, без нашего участия). Тот слейв, чей адрес совпал, переходит из «тихого» режима в обычный и начинает приём данных, которые мы шлём вслед за адресом…

uint16_t adr_data = 0;
adr_data = 1 | 0x0100;
HAL_UART_Transmit(&huart1, (uint8_t*)&adr_data, 1, 1000);
HAL_UART_Transmit(&huart1, (uint8_t*)"A", 1, 1000);


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

Остальные слейвы в это время по прежнему находятся в «тихом» режиме и только проверяют последний бит каждого байта — если там ноль, то пакет выбрасывается, если единичка, то смотрят что за адрес. Это происходит на аппаратном уровне.


Теперь, если мастер пошлёт адрес другого слейва…

uint16_t adr_data = 0;
adr_data = 2 | 0x0100;
HAL_UART_Transmit(&huart1, (uint8_t*)&adr_data, 1, 1000);

… то принимать данные будет слейв с адресом 2, а слейв с адресом 1 перейдёт в «тихий» режим.


Вот наглядная схема…



Здесь показано как ведёт себя слейв с адресом 1. Входит в «тихий» режим (RWU written), получает адрес 0 (Addr=0) и игнорирует его вместе с последующими байтами данных, затем получает адрес 1 (Addr=1) и переходит в режим приёма (получает два байта данных — Data 3 и Data 4), а когда получает адрес 2 (Addr=2), то автоматически уходит в «тихий» режим.


Помимо автоматических переходов в «тихий» режим и обратно, это можно делать программно.

Для F103:

HAL_MultiProcessor_EnterMuteMode(&huart1); // затихариться

HAL_MultiProcessor_ExitMuteMode(&huart1); // очнутся


Для F303:

HAL_MultiProcessor_EnableMuteMode(&huart1);
HAL_MultiProcessor_EnterMuteMode(&huart1);  // затихариться

HAL_MultiProcessor_DisableMuteMode(&huart1); // очнутся



Слейвы могут посылать данные мастеру в любой момент без каких-либо адресов. Мастеру конечно можно назначить адрес, но в этом нет смысла так как он один.

программа для тестов
СЛЕЙВ

/* USER CODE BEGIN PV */
volatile uint16_t sim;
char trans_str[16] = {0,};
/* USER CODE END PV */


В колбеке ловим данные от мастера и выводим их в USART_2 (основной USART_1).

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	  if(huart == &huart1)
	  {
		  HAL_UART_Transmit(&huart2, (uint8_t*)&sim, 1, 1000);
		  HAL_UART_Transmit(&huart2, (uint8_t*)"\r\n", 2, 1000);

		  //HAL_MultiProcessor_EnterMuteMode(&huart1);

		  HAL_UART_Receive_IT(&huart1, (uint8_t*)&sim, 1);
	  }
}


В бесконечном цикле раз в секунду отправляем мастеру букву U.

/* USER CODE BEGIN 2 */
  HAL_MultiProcessor_EnterMuteMode(&huart1);
  HAL_UART_Receive_IT(&huart1, (uint8_t*)&sim, 1);
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
	  HAL_Delay(990);
	  HAL_UART_Transmit(&huart1, (uint8_t*)"U", 1, 1000);
          ...


МАСТЕР

/* USER CODE BEGIN PV */
volatile uint8_t sim;
/* USER CODE END PV */


В колбеке ловим букву U и моргаем лампочкой.

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	  if(huart == &huart1)
	  {
		  if(sim == 'U')
		  {
			  HAL_GPIO_TogglePin(LD10_GPIO_Port, LD10_Pin);
		  }

		  HAL_UART_Receive_IT(&huart1, (uint8_t*)&sim, 1);
	  }
}


В цикле отправляем данные на разные адреса.

/* USER CODE BEGIN 2 */
  HAL_UART_Receive_IT(&huart1, (uint8_t*)&sim, 1);

  uint16_t adr_data = 0;
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
	  adr_data = 1 | 0x0100;
	  HAL_UART_Transmit(&huart1, (uint8_t*)&adr_data, 1, 1000);
	  HAL_UART_Transmit(&huart1, (uint8_t*)"A", 1, 1000);
	  HAL_Delay(1000);

	  HAL_UART_Transmit(&huart1, (uint8_t*)"B", 1, 1000);
	  HAL_Delay(1000);

	  adr_data = 2 | 0x0100;
	  HAL_UART_Transmit(&huart1, (uint8_t*)&adr_data, 1, 1000);
	  HAL_UART_Transmit(&huart1, (uint8_t*)"C", 1, 1000);
	  HAL_Delay(1000);

	  HAL_UART_Transmit(&huart1, (uint8_t*)"z", 1, 1000);
	  HAL_Delay(1000);

	  HAL_UART_Transmit(&huart1, (uint8_t*)"x", 1, 1000);
	  HAL_Delay(1000);

	  HAL_UART_Transmit(&huart1, (uint8_t*)"n", 1, 1000);
	  HAL_Delay(1000);

	  adr_data = 1 | 0x0100;
	  HAL_UART_Transmit(&huart1, (uint8_t*)&adr_data, 1, 1000);
	  HAL_UART_Transmit(&huart1, (uint8_t*)"D", 1, 1000);
	  HAL_Delay(1000);
          ...


Слейв 1 полчает это…





Восьмибитный режим тоже можно использовать. Всё происходит так же как и в девятибитном, а передаваемые данные будут семибитными — символы с 0x00 по 0x7F. Восьмой бит используется для определения адрес это или данные.

Если не передаёте какие-то специфичные символы, то можно использовать восьмибитный режим.

Адрес подготавливается так:

uint8_t adr_data = 0;

adr_data = 1 | 0x80;





IrDA

Это USART через инфракрасный передатчик. Такие штуки были в старинных сотовых телефонах, можно было что-то передавать с телефона на телефон или на компьютер. К компьютеру подключался инфракрасный приёмопередатчик и определялся как COM-порт. В общем можно связать два МК через USART «по воздуху».Функции для работы находятся в файле — stm32f1xx_hal_irda.c.




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


Synchronous — синхронный режим USART'а отличается от асинхронного тем, что частота синхронизации подается от одного устройства к другому по линии CLOCK. На сколько я понимаю, можно работать с SPI…




LIN — посмотрите здесь.


SmartCard — подключение к смарт-картам.





На этом всё.


Всем спасибо


Телеграм-чат istarik

Телеграм-чат STM32


  • 0
  • 115009
Поддержать автора


Telegram-чат istarik

Задать вопрос по статье
Telegram-канал istarik

Известит Вас о новых публикациях






Комментарии (0)

Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.