На плате 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 соответственно.
После этого необходимо открыть устройство 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).
Всё это дело выглядит следующим образом:
Чтобы лучше понять, как работает программа, почти к каждой строчке кода были добавлены комментарии.
Схема подключения
Светодиод подключается на 13-й контакт Maixduino/Arduino через резистор, ограничивающий ток. Преобразователь USB-UART подключается к контактам 8 и 9, Rx и Tx соответственно. В качестве конвертера можно использовать: PL2303, CH340, CP2102 или любой другой доступный.
Файл 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!«.
После появления сообщения мы можем отправить несколько символов (к примеру 1235467890), и мы получим эти символы обратно.
Материалы
Kendryte · GitHub
Maixduino-4.30(schematic)
Maixduino — одноплатный компьютер с ускорителем AI, RISC-V AI, форм-фактор Arduino и беспроводной модуль ESP32


