В этом уроке напишем первую программу, научимся считывать значение цифровых входов и устанавливать состояние выходов. Реализуем управление такими простыми элементами, как кнопка и светодиод на платформе Maixduino.
Что нужно знать
Существует 3 фреймворка для разработки приложений для процессора К210:
- Standalone SDK для Kendryte K210;
- Kendryte FreeRTOS SDK — Этот SDK предназначен для Kendryte K210, который содержит поддержку FreeRTOS;
- Arduino (на основе Standalone SDK).
Для работы с периферийными устройствами на Maixduino существует 3 основных компонента: GPIO, GPIOHS и FPIOA.
- GPIO (General Purpose Input Output / Интерфейс ввода/вывода общего назначения) — чип имеет 8 GPIO общего назначения.
- GPIOHS (General Purpose Input Output High Speed / Высокоскоростной интерфейс ввода/вывода общего назначения) – чип имеет 32 высокоскоростных GPIO. Похоже на обычный GPIO, но быстрее.
- FPIOA (Field Programmable I/O Array / Программируемый массив ввода/вывода) позволяет пользователю соотносить 256 внутренних функций с 48 физическими входами / выходами на чипе.
Из этого следует, что Maixduino более гибок, чем простой Arduino на базе микроконтроллеров AVR. Мы можем сопоставить любое устройство с любым физическим контактом (контактами), например, кнопки, светодиоды, устройства I2C и SPI, и т. д.
Создание нового проекта
- Открываем PlatformIO: Home и выбираем New Project, чтобы создать новый проект;
- Задаём название проекта в поле Name;
- В Boards ищем плату Sipeed MAIXDUINO;
- Выбираем Фреймворк Kendryte FreeRTOS SDK;
- В Location можно указать путь, где будет храниться проект, но можно оставить по умолчанию.
При создании первого проекта, все необходимые файлы и библиотеки будут загружены и установлены автоматически, и это может занять больше времени, чем обычно.
Настройка проекта
В папке src необходимо создать два файла: main.cpp и project_cfg.h. В первом файле мы напишем программу, а во втором мы определим макросы и настроим функции выводов.
В корневом каталоге есть файл platformio.ini — файл конфигурации проекта PlatformIO. По умолчанию PlatformIO автоматически определяет порт загрузки. Но Вы можете настроить собственный порт, используя параметр upload_port
. Список портов вы можете найти в Диспетчер Устройств или во вкладке Devices в PIO Home.
В platformio.ini вы также можете изменить скорость загрузки, используя параметр upload_speed
, порт монитора, параметр monitor_port
, и скорость монитора порта, параметр monitor_speed
. Порт загрузки и порт монитора должны совпадать.
Пример файла platformio.ini
; PlatformIO Project Configuration File ; ; Build options: build flags, source filter ; Upload options: custom upload port, speed and extra flags ; Library options: dependencies, extra library storages ; Advanced options: extra scripting ; ; Please visit documentation for the other options and examples ; https://docs.platformio.org/page/projectconf.html [env:sipeed-maixduino] platform = kendryte210 board = sipeed-maixduino framework = kendryte-freertos-sdk upload_port = COM3 upload_speed = 1500000 monitor_port = COM3 monitor_speed = 115200
Как работать с GPIO
Если мы хотим записывать или читать данные из GPIO, мы должны сначала его настроить. Как упоминалось выше, K210 имеет 48 контактов и 256 функций для них. Но поскольку на плате формфактора Arduino количество контактов ограничено, используются не все 48 контактов.
Сначала, чтобы определить, какие контакты и где они назначены, мы должны открыть схему платы — Maixduino-4.30(schematic).pdf. Тут нужно найти разъемы (Connector).
Все контакты разъема P3 (HEADER-1X6) подключены к ESP-32, поэтому его нельзя использовать с K210. Но разъемы P2 и P5 идут на K210, и их можно использовать в качестве контактов ввода-вывода общего назначения.
Настройка порта
Перед настройкой вывода на выход или на вход ему необходимо назначить одну функцию из 32 GPIOHS или 8 GPIO. Это можно сделать двумя способами:
- с использованием функции
int fpioa_set_function (int number, fpioa_function_t function)
; - с конфигурацией объекта
g_fpioa_cfg
.
Первый вариант можно использовать в небольших проектах с небольшим количеством конфигураций или в проектах, которые требуют изменения функции вывода во время работы программы (runtime).
Второй вариант более предпочтителен, поскольку за настройку всех выводов отвечает только один файл, таким образом проект становится более структурированным и читаемым.
В приведенных ниже примерах показано, как соотносить функцию GPIOHS0 на вывод под номером 3 (это вывод IO3 на разъеме P5). Обратите внимание, что перечисление выполняется относительно FUNC_GPIOHS0
. В дальнейшем будут использоваться только значения от 0 до 31. Поэтому желательно использовать макросы (#define
).
Пример 1:
fpioa_set_function(3, static_cast<fpioa_function_t>(FUNC_GPIOHS0 + 0));
Пример 2:
#ifndef PROJECT_CFG_H #define PROJECT_CFG_H #include <pin_cfg.h> const fpioa_cfg_t g_fpioa_cfg = { /* Версия */ .version = PIN_CFG_VERSION, /* Число функций */ .functions_count = 1, /* Офисание функций */ .functions = { /* */ {3, static_cast<fpioa_function_t>(FUNC_GPIOHS0 + 0)}, }, }; #endif
После этого необходимо открыть устройство gpio0
с помощью функции io_open
.
/* Открываем GPIO0 устройство */ gpio = io_open("/dev/gpio0");
И наконец настраиваем режим работы вывода (пина) – на вход или выход.
/* Устанавливаем режим работы пина 0 на вход. */ gpio_set_drive_mode(gpio, 0, GPIO_DM_INPUT);
/* Устанавливаем режим работы пина 0 на выход. */ gpio_set_drive_mode(gpio, 0, GPIO_DM_OUTPUT);
/* Устанавливаем режим работы пина 0 на вход с подтягивающим резистором (pull-up resistor). */ gpio_set_drive_mode(gpio, 0, GPIO_DM_INPUT_PULL_UP);
/* Устанавливаем режим работы пина 0 на вход с стягивающим резистором (pull-down resistor). */ gpio_set_drive_mode(gpio, 0, GPIO_DM_INPUT_PULL_DOWN);
Примеры программ
Чтобы лучше понять, как всё это работает, приведу два примера программ. Комментарии также будут добавлены в код для более подробного описания.
Пример 1 — мигаем светодиод
В первом примере будем мигать светодиодом, подключенным к одному из выводов платы. В файле project_cfg.h настроим функцию вывода, используемый для мигания светодиода. В файле main.cpp настроим вывод на выход и создадим задачу blinkLedTask
, которая будет вызываться с интервалом 100 мс, и при каждом вызове светодиод будет менять свое состояние с ВКЛ на ВЫКЛ и наоборот.
Схема подключения
Светодиод подключается на 13-й контакт Maixduino/Arduino через резистор, ограничивающий ток.
Файл project_cfg.h
#ifndef PROJECT_CFG_H #define PROJECT_CFG_H #include <pin_cfg.h> /** * Номер внутреннего пина */ #define LED_IO (0) /** * Номер физического пина */ #define LED_PIN (3) const fpioa_cfg_t g_fpioa_cfg = { /* Версия */ .version = PIN_CFG_VERSION, /* Число функций */ .functions_count = 1, /* Офисание функций */ .functions = { /* */ {LED_PIN, static_cast<fpioa_function_t>(FUNC_GPIOHS0 + LED_IO)}, }, }; #endif
Файл main.cpp
#include "project_cfg.h" #include <FreeRTOS.h> #include <devices.h> #include <syslog.h> #include <task.h> /** * Указатель на устройство GPIO */ static handle_t gpio; /** * Текущее состояние светодиода */ static gpio_pin_value_t ledState; /** * Прототип задачи включения/выключения светодиода * * @param pvParameters Функции задач принимают параметр, имеющий тип указателя на void (т. е. void*). Значение, указанное в pvParameters, будет передано в задачу. */ static void blinkLedTask(void *pvParameters); /** * */ int main() { BaseType_t retCode; /* Открываем GPIO0 устройство */ gpio = io_open("/dev/gpio0"); /* Перехват ошибок в процессе разработки */ configASSERT(gpio); /* Устанавливаем режим работы LED_IO пина на выход. */ gpio_set_drive_mode(gpio, LED_IO, GPIO_DM_OUTPUT); /* Задаём начальное состояние светодиода (выключаем) */ ledState = GPIO_PV_LOW; /* Пишем состояние в пин */ gpio_set_pin_value(gpio, LED_IO, ledState); /* Создаём задачу с мигающим светодиодом */ retCode = xTaskCreateAtProcessor(1, &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"); } for (;;) { } return 0; } static void blinkLedTask(void *pvParameters) { while (1) { /* Меняем состояние в 1/0 */ if (GPIO_PV_HIGH == ledState) { ledState = GPIO_PV_LOW; } else { ledState = GPIO_PV_HIGH; } /* Пишем новое состояние в пин */ gpio_set_pin_value(gpio, LED_IO, ledState); /* Помещаем задачу в состояние Blocked на фиксированное количество тиков прерываний. Находясь в состоянии Blocked, задача не использует процессорное время, поэтому процессор загружен только полезной работой. С помощью макроса pdMS_TO_TICKS мы конвертируем миллисекунды в тики */ vTaskDelay(pdMS_TO_TICKS(100)); } }
Пример 2 — кнопка и светодиод
Во втором примере помимо светодиода подключим еще и кнопку. Если кнопка не нажата, светодиод будет менять свое состояние (мигать) каждые 500 мс, а при нажатии — каждые 100 мс. Вывод, подключенный к кнопке, настроен на вход с подтягивающим резистором gpio_set_drive_mode(gpio, BTN_IO, GPIO_DM_INPUT_PULL_UP);
.
Схема подключения
Светодиод подключается на 13-й контакт Maixduino/Arduino через резистор, ограничивающий ток, а кнопка на 12-й контакт и GND.
Файл project_cfg.h
#ifndef PROJECT_CFG_H #define PROJECT_CFG_H #include <pin_cfg.h> /** * Номер внутреннего пина */ #define LED_IO (0) #define BTN_IO (1) /** * Номер физического пина */ #define LED_PIN (3) #define BTN_PIN (10) const fpioa_cfg_t g_fpioa_cfg = { /* Версия */ .version = PIN_CFG_VERSION, /* Число функций */ .functions_count = 2, /* Офисание функций */ .functions = { /* */ {LED_PIN, static_cast<fpioa_function_t>(FUNC_GPIOHS0 + LED_IO)}, {BTN_PIN, static_cast<fpioa_function_t>(FUNC_GPIOHS0 + BTN_IO)}, }, }; #endif
Файл main.cpp
#include "project_cfg.h" #include <FreeRTOS.h> #include <devices.h> #include <syslog.h> #include <task.h> /** * Указатель на устройство GPIO */ static handle_t gpio; /** * Текущее состояние светодиода */ static gpio_pin_value_t ledState; /** * Прототип задачи включения/выключения светодиода * * @param pvParameters Функции задач принимают параметр, имеющий тип указателя на void (т. е. void*). Значение, указанное в pvParameters, будет передано в задачу. */ static void blinkLedTask(void *pvParameters); /** * */ int main() { BaseType_t retCode; /* Открываем GPIO0 устройство */ gpio = io_open("/dev/gpio0"); /* Перехват ошибок в процессе разработки */ configASSERT(gpio); /* Устанавливаем режим работы LED_IO пина на выход. */ gpio_set_drive_mode(gpio, LED_IO, GPIO_DM_OUTPUT); /* Устанавливаем режим работы BTN_IO пина на вход с подтягивающим резистором. */ gpio_set_drive_mode(gpio, BTN_IO, GPIO_DM_INPUT_PULL_UP); /* Задаём начальное состояние светодиода (выключаем) */ ledState = GPIO_PV_LOW; /* Пишем состояние в пин */ gpio_set_pin_value(gpio, LED_IO, ledState); /* Создаём задачу с мигающим светодиодом */ retCode = xTaskCreateAtProcessor(1, &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"); } for (;;) { } return 0; } static void blinkLedTask(void *pvParameters) { /* Состояние кнопки */ gpio_pin_value_t btnState; /* Время повторения */ unsigned int timeInMs; while (1) { /* Считываетм состояние кнопки. */ btnState = gpio_get_pin_value(gpio, BTN_IO); if (btnState == GPIO_PV_LOW) { /* Если кнопка нажата, мы меняем повторяемость задачи на 100 мс. */ timeInMs = 100; } else { /* Если нет - 500 мс. */ timeInMs = 500; } /* Меняем состояние в 1/0 */ if (GPIO_PV_HIGH == ledState) { ledState = GPIO_PV_LOW; } else { ledState = GPIO_PV_HIGH; } /* Пишем новое состояние в пин */ gpio_set_pin_value(gpio, LED_IO, ledState); /* Помещаем задачу в состояние Blocked на фиксированное количество тиков прерываний. Находясь в состоянии Blocked, задача не использует процессорное время, поэтому процессор загружен только полезной работой. С помощью макроса pdMS_TO_TICKS мы конвертируем миллисекунды в тики */ vTaskDelay(pdMS_TO_TICKS(timeInMs)); } }
Материалы
Kendryte · GitHub
Maixduino-4.30(schematic)
Maixduino — одноплатный компьютер с ускорителем AI, RISC-V AI, форм-фактор Arduino и беспроводной модуль ESP32
Wow, marvelous weblog structure! How long have you
been running a blog for? you made running a blog glance easy.
The whole look of your site is excellent, let alone the content!
I’m not sure exactly why but this weblog is loading incredibly slow for
me. Is anyone else having this issue or is it a issue on my end?
I’ll check back later and see if the problem still exists.
When I initially commented I clicked the «Notify me when new comments are added» checkbox and now each time a comment is
added I get three emails with the same comment. Is there any
way youu ccan remove me freom that service? Thanks!
Stop by my site … bahasa Inggris anak ibu
https://warezsofts.com/driver-genius-crack/
«This post deserves a wider audience.»
online apotheke gГјnstig: online apotheke — europa apotheke
farmacia online senza ricetta: comprare farmaci online all’estero — farmacie online autorizzate elenco
I’m extremely impressed together with your writing talents and also with the structure for your blog. Is that this a paid theme or did you modify it your self? Anyway keep up the excellent high quality writing, it is rare to see a great weblog like this one nowadays..
Feel free to visit my blog https://Medium.com/@gymtowelc/residential-gate-access-control-systems-da8e61bee4e5