UART (Universal Asynchronous Receiver-Transmitter) - универсальный асинхронный приёмопередатчик. Один из самых распространенных интерфейсов передачи данных и самых простых в понимании. Данные передаются последовательно по одному сигнальному проводнику. Одна посылка может включать от 5 до 9 бит данных, но чаще всего применяется 8 битный режим. Данные обрамляются стартовым (логический 0) и стоповым битом (логическая 1). В свободном состоянии принимает значение логической 1.

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

Обратите внимание на то, что при передаче данных по UART, устройства должны быть соединены по GND.

По скоростным свойствам UART стандартизирован и принимает значения: 300; 600; 1200; 2400; 4800; 9600; 19200; 38400; 57600; 115200; 230400; 460800; 921600 бод. При этом на практике чаще всего можно найти устройства со скоростями 9600 и 115200 бод.

Для улучшения помехоустойчивости могут применять 1.5 или 2 стоп бита, а для проверки целостности данных - контроль четности. Стоит отметить, что параметр стоп бита на самом деле означает длительность импульса в посылке. При включенной функции контроля четности осуществляется контроль чётности количества единичных битов данных посылки. При приеме такой посылки UART может автоматически контролировать бит четности и выставлять соответствующие признаки правильного или ошибочного приема. В случае приема ошибочных данных, алгоритм не позволяет восстановить исходное сообщение, что решается повторной передачей.

Поэтому, если вы собираетесь подключить к МК устройство по UART, уточните в документации на какой скорости оно работает и с какими параметрами. Для этого используется короткая запись параметров, например:  9600/8-N-1, где:

9600 - скорость передачи данных;

8 - количество бит данных;

N - наличие и тип бита четности. N (No parity) - без бита четности, E (Even parity) - с битом проверки на четность, O (Odd parity) - с битом проверки на нечетность;

1 - длительность стоп-бита. Встречаются значения 1, 1.5 и 2.

В документации к STM32 или другим МК и в CubeMX, вы можете встретить USART(Universal Synchronous/Asynchronous Receiver/Transmitter). USART может работать как в асинхронном, так и в синхронном режиме. В синхронном режиме добавляется линия тактового сигнала, при этом устройство генерирующее тактовый сигнал будет ведущим, а ведомое устройство будет вести прием и передачу со скоростью определенной по тактовому сигналу.

Так же модуль имеет возможность на аппаратном уровне управлять потоком передачи данных (Hardware Flow Control). При включении данной опции, передаются по отдельным линиям дополнительные сигналы «готов/занят». RTS - готов передавать данные, либо разрешает устройству, на другом конце, передавать данные. CTS - устройство разрешает нам передавать данные. Данная опция полезна при передачи больших объемов данных и предотвращает потерю данных из за переполнения буфера. 

На базе UART построено множество физических уровней, такие как RS-232 или COM порт, RS-485, LIN, IrDA, токовая петля и др. С помощью такого разнообразия можно передавать данные в разных средах и на расстояния до 1 км без ретрансляции.

С теорией немного разобрались, перейдем к практике. Нашей задачей будет наладить передачу данных между STM32 и компьютером. Из железа нам понадобится макетная плата на базе STM32 (в моем случае Open107V) и PL2303 или аналог, для подключения к компьютеру по USB и реализации виртуального COM порта. Из софта нам понадобится Terminal v1.9b или аналог.

В итоге должно получиться что вроде этого:

Подключим PL2303 к разъему USART1 на макетной плате и к компьютеру через USB. Установим необходимый драйвер для виртуального ком порта.

Настроим UART1 на STM32F107VC c параметрами 115200/8-N-1.

Для начала глянем на схему.

PL2303 имеет четыре линии: VCC(3.3V), GND, TXD и RXD. Питание к макетке подключается соответственно, TXD -> RX, RXD -> TX.

Создадим новый проект в CubeMX для STM32F107VC. Произведем настройки тактирования. В Peripherals выберем USART1, в Mode -> Asynchronous. По умолчанию CubeMX выставит ноги PA9 и PA10, но по схеме у нас PB6 и PB7, поэтому нам необходимо заремапить ноги. Для этого нажмем на PB6 левой кнопкой мыши и выберем USART1_TX. Вторая нога настроится автоматически.

Во вкладке Configuration -> Connectivity выберем USART1 и убедимся в правильности параметров. В NVIC Settings поставим флажок на USART1 global interrupt, тем самым включим прерывания от USART1.

Сгенерируем код:

UART_HandleTypeDef huart1;
static void MX_USART1_UART_Init(void)
{

  huart1.Instance = USART1;
  huart1.Init.BaudRate = 115200;
  huart1.Init.WordLength = UART_WORDLENGTH_8B;
  huart1.Init.StopBits = UART_STOPBITS_1;
  huart1.Init.Parity = UART_PARITY_NONE;
  huart1.Init.Mode = UART_MODE_TX_RX;
  huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  huart1.Init.OverSampling = UART_OVERSAMPLING_16;
  if (HAL_UART_Init(&huart1) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }

}

Рассмотрим функцию инициализации static void MX_USART1_UART_Init(void).

В данной функции мы заполняем структуру UART_HandleTypeDef huart1. Структура объявлена глобально, обратите на это внимание. Дело в том, что в с структуре хранятся, помимо настроек, и другие параметры необходимые для правильной работы. Кроме того указатель на данную структуру будет использоваться в других функциях.

С параметрами Instance, BaudRate, WordLength, StopBits и Parity надеюсь не возникнет вопросов, мы их рассмотрели ранее.

В Mode записывается режим работы UART:

UART_MODE_RX - только на прием;

UART_MODE_TX - только на передачу;

UART_MODE_TX_RX - как на прием, так и на передачу.

В HwFlowCtl (Hardware Flow Control):

UART_HWCONTROL_NONE - контроль отключен;

UART_HWCONTROL_RTS - включен сигнал RTS;

UART_HWCONTROL_CTS - включен сигнал CTS;

UART_HWCONTROL_RTS_CTS - включены оба сигнала контроля.

OverSampling - делитель тактовой частоты поступающей на модуль Uart.

После заполнения структуры мы передаем указатель в функцию инициализации HAL_UART_Init(&huart1), которая после успешного выполнения вернет ответ HAL_OK.

Разберемся с функциями приема и передачи, предоставляемые библиотекой HAL.

Для приема и передачи данных имеется три варианта функций.

Первый вариант подразумевает обычную передачу или прием данных. Передали/приняли и забыли, работаем дальше.

HAL_StatusTypeDef HAL_UART_Transmit(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout);

HAL_StatusTypeDef HAL_UART_Receive(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout);

huart - указатель на структура хендлера Uart;

pData - указатель на данные;

Size - размер данных (количество байт);

Timeout - таймаут  в мс, по истечению которого будет произведен возврат статуса ошибки.

Второй вариант использует прерывания.

HAL_StatusTypeDef HAL_UART_Transmit_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);

HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);

Для нормальной работы необходимо включить прерывания. Напомню, что в CubeMX мы уже включили прерывания. Найти функции включения прерываний вы можете найти в файле stm32f1xx_hal_msp.c, функция HAL_UART_MspInit.

/* USART1 interrupt Init */
HAL_NVIC_SetPriority(USART1_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(USART1_IRQn);

Включив прерывания от UART, CubeMX добавит в файле stm32f1xx_it.c обработчик прерывания:

void USART1_IRQHandler(void)
{
  /* USER CODE BEGIN USART1_IRQn 0 */

  /* USER CODE END USART1_IRQn 0 */
  HAL_UART_IRQHandler(&huart1);
  /* USER CODE BEGIN USART1_IRQn 1 */

  /* USER CODE END USART1_IRQn 1 */
}

Третий вариант использует DMA.

HAL_StatusTypeDef HAL_UART_Transmit_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);

HAL_StatusTypeDef HAL_UART_Receive_DMA(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size);

DMA применяется в случаях при работе с большими объемами данных. При этом процесс передачи данных передается под управление модуля DMA, тем самым освобождается процессорное время. Перед использованием данных функций необходимо предварительно настроить DMA для использования с UART. Настройку мы рассмотрим в следующих уроках.

Дополним наш проект, чтобы он ожил и мы увидели работу интерфейса.

После инициализации периферии передадим в UART сообщение "Start Ok\r" и включим прерывание на прием.

Перед основным циклом добавим:

HAL_UART_Transmit(&huart1, c_start, sizeof(c_start)-1, 1000);
__HAL_UART_ENABLE_IT(&huart1, UART_IT_RXNE);

В основном цикле раз в 5 секунд будем передавать сообщение "Work Ok\r"

HAL_UART_Transmit(&huart1, c_work, sizeof(c_work)-1, 1000);
HAL_Delay(5000);

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

В файле stm32f1xx_it.c изменим содержимое функции USART1_IRQHandler:

uint8_t c_collback[] = "CollBack  \r";

void USART1_IRQHandler(void)
{
    uint8_t x;

    if(__HAL_UART_GET_FLAG(&huart1, UART_FLAG_RXNE))
    {
        
        HAL_UART_Receive(&huart1, &x, 1, 500); // получаем символ
        c_collback[9] = x; 
        HAL_UART_Transmit(&huart1, c_collback, sizeof(c_collback)-1, 500);
        __HAL_UART_ENABLE_IT(&huart1, UART_IT_RXNE);
    }
}

При вызове обработчика, проверяем источник прерывания, нас интересует прерывание по приему (UART_FLAG_RXNE).

Следующим шагом примем байт данных, при этом флаг UART_FLAG_RXNE будет сброшен.

В массиве 9 позиция занята пробелом, мы ее заменим на принятый байт и полученную строку отправим обратно.

Компилим, заливаем и проверяем работу.

 

Архив с проектом  - ссылка на скачивание.

Информация
Посетители, находящиеся в группе Гости, не могут оставлять комментарии к данной публикации.


© Copyright 2017. Все права защищены.
Яндекс.Метрика