CUSTOMELECTRONICS.RU
Информационно-учебный блог о разработке электроники
Эл. почта: info@customelectronics.ru

STM32. Передача данных через UART (работа с COM-портом)

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

Подготовка к работе

Перед началом работы рекомендуем ознакомиться с предыдущими остальными статьями нашего курса. Здесь мы не будем останавливаться на простейших действиях. Напомним только что работа будет производиться с использованием утилиты CubeMX, HAL-драйвера, IDE Keil uVision и платы Nucleo-F030R8.
Обратите внимание, что программатор ST-Link, который входит в состав платы Nucleo, уже имеет на борту преобразователь USB-to-COM. Который в свою очередь уже подключен к основному контроллеру. Это значит, что нам не потребуется абсолютно ничего, кроме самой платы Nucleo-F030R8.
Если вы используете какое-либо альтернативное аппаратное обеспечение, то необходимо найти преобразователь интерфейсов и подключить его к ПК и микроконтроллеру.

Настройка CubeMX

Чтобы включить UART, в самом простом случае, достаточно двух действий.
Во-первых, на вкладке Pinout, надо включить модуль USART2 в асинхронном режиме, как это показано на картинке ниже:
01
Во-вторых, на вкладке Configuration можно изменить настройки подключения. Мы изменили скорость обмена:
02
Все. На этом настройка порта завершена. Можно сгенерировать проект и приступить к написанию кода.

Передача строки в ASCII

Самая простая функция для передачи дачи в асинхронном режиме — HAL_UART_Transmit(). Найти ее можно в файле драйвера stm32f0xx_hal_uart.c.
03
Чуть позже мы разберем аргументы этой функции, а пока сконцентрируемся на результате. Итак, вызовем эту функцию в бесконечном цикле с задержкой и передадим в нее следующие параметры:
04
Для приема сообщения на стороне компьютера можно использовать любую терминальную программу. Мы будем использовать программу Terminal 1.9b.
Если все сделано верно, то после компиляции и прошивки контроллера, раз в секунду в COM-порт будет отправляться сообщение "Hello world!" с переводом строки. Обратите внимание на настройки терминальной программы — символы печатаются в ASCII-кодировке с переводом строки.
07
Всего в функцию HAL_UART_Transmit(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout) требуется передать четыре аргумента:

  1. *huart — указатель на структуру данных, описывающую UART. Ранее мы не сталкивались с указателями и структурами данных. По сути, это набор переменных, объединенных для удобства под общим именем. Объявление этой переменной содержится в начале файла main.c, а описание этой структуры можно найти в файле stm32f0xx_hal_uart.h.
    05
    Обратите внимание, что заполнение полей данных этой структуры происходит при инициализации UART в файле main.c.
    06
    Унарный оператор * (в аргументе функции *huart) показывает то, что это указатель. То есть в эту функцию необходимо передать не саму структуру данных, а ее адрес в памяти. Получить адрес структуры данных (или обычной переменной) можно при помощи унарного оператора &.
    Таким образом, при вызове функции HAL_UART_Transmit(), в качестве первого параметра следует указать &huart2.
  2. *pData — аргумент-указатель на данные, которые необходимо передать. Словами "Hello world!\n" мы создаем массив из элементов типа char. А массив и указатели в Си это, фактически, одно и то же. То есть передавая его в функцию, не надо писать оператор &. Запись (uint8_t*) необходима для преобразования типа данных. Без нее тоже будет работать (так как char и uint8_t это одно и то же), но вы увидите предупреждение.
  3. Size — количество передаваемых байт. В нашем примере передается 13 символов. В том числе символ перевода строки "\n".
  4. Timeout — максимальное время работы функции. Скорее всего функции сможет выполнить передачу гораздо быстрее, но, если что-то пойдет не так, через одну секунду она прекратит попытки.

Таким образом у нас получилась запись HAL_UART_Transmit(&huart2, (uint8_t*)"Hello world!", 13, 1000);.

Дополнительные примеры

В реальных системах очень часто возникает обмена данными между различными устройствами. Рассмотренная функция подходит для того, чтобы просто передавать любые данные в виде массива или единичной переменной.
Для примера создадим переменную count. В цикле, раз в секунду, мы будем ее увеличивать и отправлять текущее значение в UART.
08
В функцию мы передаем указатель на переменную, то есть &count. И указываем, что требуется передать один байт. В терминале, если включить отображение данных в шестнадцатеричном формате, то в выводе мы увидим следующее:
09
Также иногда требуется передать значение переменной в формате ASCII. Наиболее простой способ, на наш взгляд, показан ниже:
10
Обратите внимание на использование функции sprintf(). Эта функция позволяет отпечатать в массив элементы с форматным выводом аргументов функции и возвращает количество отпечатанных символов. Тонкости форматного вывода, в качестве справочной информации, описаны в книге Б. Кернигана и Д. Ричи "Язык программирования Си".
Другими словами, одним действием мы передали в функцию массив, заполнили его данными и определили количество элементов. В терминальной программе при этом мы увидим как раз в секунду увеличиваются значения в формате ASCII.
11

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

Ссылки на остальные статьи цикла можно найти здесь.
Мы будем очень рады, если вы поддержите наш ресурс и посетите магазин наших товаров shop.customelectronics.ru.

Метки: , , , , , Просмотров: 1349