Урок 2. Последовательный порт UART в Maixduino/K210

На плате Maixduino есть 3 последовательных порта (UART): "/dev/uart1", "/dev/uart2" и "/dev/uart3".  Первый порт ("/dev/uart1") используется FreeRTOS как порт для отладки и прошивки. По этому не рекомендуется использовать, а два других порта можно использовать для обмена данными с внешними устройствами.

В этом уроке настроим последовательный порт (UART), напишем пример программы и будем передавать данные между Maixduino и компьютером.

Настройка UART порта

Перед использованием последовательного порта его необходимо настроить. Сначала в файле project_cfg.h мы устанавливаем контакты (пины) Rx и Tx. Более подробно о настройке выходов / входов вы можете прочитать в первом уроке: Урок 1. Кнопка, светодиод. Функции управления вводом/выводом. Первая программа.

#ifndef PROJECT_CFG_H
#define PROJECT_CFG_H

#include <pin_cfg.h>

#define UART1_RX_PIN (13)
#define UART1_TX_PIN (14)

const fpioa_cfg_t g_fpioa_cfg = {
    /* Версия */
    .version = PIN_CFG_VERSION,
    /* Число функций */
    .functions_count = 2,
    /* Офисание функций */
    .functions = {
        /*  */
        {UART1_RX_PIN, FUNC_UART2_RX},
        {UART1_TX_PIN, FUNC_UART2_TX},
    },
};
#endif

Rx и Tx устанавлны на контакты 13 и 14 соответственно.

Урок 2. Последовательный порт UART в Maixduino/K210 - Rx и Tx пины

После этого необходимо открыть устройство uart2 с помощью функции io_open.

/* Открываем UART2 устройство */
gpio = io_open("/dev/uart2");

И наконец настраиваем скорость COM порта, биты данных, количество стоп-бит и бит четности.

uart_config(uart2, 115200, 8, UART_STOP_1, UART_PARITY_NONE);

Также задаём тайм-аут для чтения:

uart_set_read_timeout(uart2, UINT32_MAX);

Примеры программ с UART

Напоследок приведу пример программы. В этой программе мы настроим выходной контакт, на этот контакт будет установлен светодиод, который будет мигать с определенным интервалом. Порт UART2 также будет настроен для обмена данными между Maixduino и компьютером. Миганть светодиодом будет задача static void blinkLedTask(void *pvParameters), принимать и передать данных по UART — static void uartTask(void *pvParameters).

Всё это дело выглядит следующим образом:

Урок 2. Последовательный порт UART в Maixduino (K210) - Подключение

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

Схема подключения

Светодиод подключается на 13-й контакт Maixduino/Arduino через резистор, ограничивающий ток. Преобразователь USB-UART подключается к контактам 8 и 9, Rx и Tx соответственно. В качестве конвертера можно использовать: PL2303, CH340, CP2102 или любой другой доступный.

 

Урок 2. Последовательный порт UART в Maixduino/K210 - Схема подключения

Файл project_cfg.h

#ifndef PROJECT_CFG_H
#define PROJECT_CFG_H

#include <pin_cfg.h>

/**
 * Номер внутреннего пина
 */
#define LED_IO (0)

/**
 * Номер физического пина
 */
#define LED_PIN (3)
#define UART1_RX_PIN (13)
#define UART1_TX_PIN (14)

const fpioa_cfg_t g_fpioa_cfg = {
    /* Версия */
    .version = PIN_CFG_VERSION,
    /* Число функций */
    .functions_count = 3,
    /* Офисание функций */
    .functions = {
        /*  */
        {LED_PIN, static_cast<fpioa_function_t>(FUNC_GPIOHS0 + LED_IO)},
        {UART1_RX_PIN, FUNC_UART2_RX},
        {UART1_TX_PIN, FUNC_UART2_TX},
    },
};
#endif

Файл main.cpp

#include "project_cfg.h"
#include <FreeRTOS.h>
#include <devices.h>
#include <string.h>
#include <syslog.h>
#include <task.h>

/**
 * Указатель на устройство UART 2
 */
static handle_t uart2;

/**
 * Указатель на устройство GPIO
 */
static handle_t gpio;

/**
 * Текущее состояние светодиода
 */
static gpio_pin_value_t ledState;

/**
 * Прототип задачи включения/выключения светодиода
 * 
 * @param pvParameters Функции задач принимают параметр, имеющий тип указателя на void (т. е. void*). 
 * Значение, указанное в pvParameters, будет передано в задачу.
 */
static void blinkLedTask(void *pvParameters);

static void uartTask(void *pvParameters);

int main() {
  BaseType_t retCode;
  const char helloMessage[] = "hello uart!\r\n";

  /* Открываем GPIO0 устройство */
  gpio = io_open("/dev/gpio0");
  /* Перехват ошибок в процессе разработки */
  configASSERT(gpio);
  /* Открываем uart2 устройство */
  uart2 = io_open("/dev/uart2");
  /* Перехват ошибок в процессе разработки */
  configASSERT(uart2);

  /* Устанавливаем режим работы LED_IO пина на выход. */
  gpio_set_drive_mode(gpio, LED_IO, GPIO_DM_OUTPUT);

  /* Задаём начальное состояние светодиода (выключаем) */
  ledState = GPIO_PV_LOW;
  /* Пишем состояние в пин */
  gpio_set_pin_value(gpio, LED_IO, ledState);

  uart_config(uart2, 115200, 8, UART_STOP_1, UART_PARITY_NONE);
  uart_set_read_timeout(uart2, UINT32_MAX);

  /* Создаём задачу с мигающим светодиодом */
  retCode = xTaskCreateAtProcessor(0, blinkLedTask, "Blink Led task", 512, nullptr, 3, nullptr);
  /* Проверяем, если задача была успешно создана */
  if (retCode == pdPASS) {
    /* В случае успеха выводим информационное сообщение */
    LOGI("MFRB", "Blink Led task is running");
  } else {
    /* В случае неудачи выводим предупреждающее сообщение */
    LOGW("MFRB", "Blink Led task start problems");
  }

  /* Создаём задачу с мигающим светодиодом */
  retCode = xTaskCreateAtProcessor(1, uartTask, "Uart Task task", 1024, nullptr, 3, nullptr);
  /* Проверяем, если задача была успешно создана */
  if (retCode == pdPASS) {
    /* В случае успеха выводим информационное сообщение */
    LOGI("MFRB", "Uart Task task is running");
  } else {
    /* В случае неудачи выводим предупреждающее сообщение */
    LOGW("MFRB", "Uart Task task start problems");
  }

  io_write(uart2, (uint8_t *)helloMessage, strlen(helloMessage));
  for (;;) {
  }

  return 0;
}

static void blinkLedTask(void *pvParameters) {
  /* Время повторения */
  unsigned int timeInMs;
  for (;;) {
    /* Меняем состояние в 1/0 */
    if (GPIO_PV_HIGH == ledState) {
      ledState = GPIO_PV_LOW;
      timeInMs = 900;
    } else {
      ledState = GPIO_PV_HIGH;
      timeInMs = 100;
    }
    /* Пишем новое состояние в пин */
    gpio_set_pin_value(gpio, LED_IO, ledState);

    /* Помещаем задачу в состояние Blocked на фиксированное количество тиков прерываний.
    Находясь в состоянии Blocked, задача не использует процессорное время, 
    поэтому процессор загружен только полезной работой.
    С помощью макроса pdMS_TO_TICKS мы конвертируем миллисекунды в тики */
    vTaskDelay(pdMS_TO_TICKS(timeInMs));
  }
}

static void uartTask(void *pvParameters) {
  /* Полученный символ */
  uint8_t receivedChar = 0;
  for (;;) {
    /*  */
    if (io_read(uart2, &receivedChar, 1) < 0) {
      /* Предупреждение о тайм-ауте */
      LOGW("MFRB", "time out");
    } else {
      /* Отправка символа обратно */
      io_write(uart2, &receivedChar, 1);
    }
  }
}

Результат

После компиляции программы и прошивки контроллера подключаемся к компьютеру через конвертер USB-UART. Открываем Arduino IDE, выбираем порт, который соответствует преобразователю, и открываем монитор порта.

Если нажать кнопку «RESET«, в консоли должно появиться сообщение «hello uart!«.

Урок 2. Последовательный порт UART в Maixduino/K210 - Монитор порта ArduinoПосле появления сообщения мы можем отправить несколько символов (к примеру 1235467890), и мы получим эти символы обратно.

Материалы

Kendryte · GitHub
Maixduino-4.30(schematic)
Maixduino — одноплатный компьютер с ускорителем AI, RISC-V AI, форм-фактор Arduino и беспроводной модуль ESP32

Похожие записи

Комментарии 103

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

Ваш e-mail не будет опубликован. Обязательные поля помечены *