Знакомство с периферией¶
Эти руководства продолжают раздел «Начало работы». До их выполнения установите инструментарий SiFli-SDK, хотя бы один раз прошейте пример hello_world и научитесь открывать консоль последовательного порта. Каждое упражнение намеренно небольшое: одна идея, один периферийный блок и понятный критерий успеха.
В примерах предполагается плата класса SF32LB52-DevKit-LCD, например с именем sf32lb52-lcd_n16r8. Если используется другая плата, замените имя в команде сборки и проверьте названия выводов, экземпляры периферийных блоков и разметку накопителя в файлах поддержки этой платы.
Эта серия помогает выработать надёжный подход: проверяйте одно аппаратное поведение за раз, задавайте чёткий критерий успеха и сохраняйте рабочую базовую конфигурацию перед переходом к следующему блоку. Материал рассчитан на разработчиков, которые только начинают работать с SDK SF32, даже если они уже знакомы с программированием встраиваемых систем на C.
Перед началом¶
Для каждого упражнения придерживайтесь одного и того же порядка действий:
Не закрывайте терминал последовательного порта. Большинство типичных ошибок проще найти, когда видны сообщения rt_kprintf() и приглашение FinSH msh>.
Примеры на C — это фрагменты, а не полные исходные файлы. Добавьте необходимые для проекта и версии SDK заголовки, объявления, инициализацию платы, проверку возвращаемых значений и освобождение ресурсов.
| Пункт | Проверка |
|---|---|
| Имя платы | Совпадает с одной из поддерживаемых конфигураций платы. |
| Последовательный порт | Открывается без ошибок и показывает загрузочные сообщения. |
| Инструмент прошивки | Позволяет многократно прошивать плату без замены кабелей. |
| Схема или файлы платы | Доступны до выбора ресурсов GPIO, ADC, PWM или RTC. |
| Одно изменение за раз | После каждого небольшого изменения выполните сборку, прошивку и проверку. |
Мигайте светодиодом через GPIO¶
Цель: управлять выводом GPIO из прошивки — аналог первой успешной сборки в мире встраиваемых систем.
Время: 15 минут
Начните с: example/hal/gpio или example/rt_device/gpio
В SDK SF32 на базе RT-Thread GPIO доступен через стандартный API RT-Thread для устройств PIN device. Простейший цикл мигания выглядит так:
#include <rtthread.h>
#include <rtdevice.h>
#define LED_PIN GET_PIN(1, 0) /* replace with your board's LED pin */
int main(void)
{
rt_pin_mode(LED_PIN, PIN_MODE_OUTPUT);
while (1)
{
rt_pin_write(LED_PIN, PIN_HIGH);
rt_thread_mdelay(500);
rt_pin_write(LED_PIN, PIN_LOW);
rt_thread_mdelay(500);
}
}
- Скопируйте наиболее подходящий пример GPIO в каталог своего проекта или изменяйте его на месте, пока учитесь.
- Найдите вывод светодиода в схеме или файлах поддержки платы. Не угадывайте номер порта и вывода.
- Соберите и прошейте проект, указав то же имя платы, что и для
hello_world. - Убедитесь, что светодиод мигает с ожидаемой частотой.
- Измените задержку на 100 ms, пересоберите прошивку и проверьте, что частота мигания изменилась.
Критерий успеха: светодиод непрерывно переключается, в консоли последовательного порта по-прежнему отображаются обычные сообщения загрузки, а изменение задержки меняет частоту мигания.
Если не работает: проверьте активный уровень, подключён ли светодиод через транзистор, не используется ли вывод другой функцией и соответствует ли имя платы установленному оборудованию.
Что вы узнали: об абстракции PIN device, назначении выводов для конкретной платы и основном цикле «изменение — сборка — прошивка».
Считывайте состояние кнопки через GPIO¶
Цель: считывать цифровой вход и реагировать на нажатие кнопки.
Время: 20 минут
Начните с: example/rt_device/gpio
Для чтения кнопки используется тот же PIN API, но в режиме входа. Сначала выполните простое чтение, чтобы проверить подключение и логический уровень:
В SiFli-SDK API RT-Thread PIN device не позволяет настроить подтяжку вывода вверх или вниз через rt_pin_mode(). Для кнопки, активной по низкому уровню, убедитесь, что на плате есть резистор подтяжки вверх, либо настройте подтяжку через pinmux с помощью HAL_PIN_Set(...) согласно конфигурации этой платы. Площадка, функция и домен процессора зависят от платы; не копируйте назначение вывода без проверки.
rt_pin_mode(BUTTON_PIN, PIN_MODE_INPUT);
if (rt_pin_read(BUTTON_PIN) == PIN_LOW)
{
/* button pressed, active-low */
}
Для задач, выходящих за рамки быстрой проверки, используйте прерывание вместо непрерывного опроса вывода в активном цикле. Тогда прошивка сможет реагировать на фронт сигнала, не проверяя вывод снова и снова; если остальная схема позволяет процессору спать между событиями, это также может снизить энергопотребление:
rt_pin_attach_irq(BUTTON_PIN, PIN_IRQ_MODE_FALLING, button_isr, RT_NULL);
rt_pin_irq_enable(BUTTON_PIN, PIN_IRQ_ENABLE);
- Найдите на плате доступную кнопку или входной вывод.
- Начните с чтения в цикле и выводите исходное значение при нажатии и отпускании кнопки.
- Определите, активна ли кнопка по высокому или низкому уровню.
- Когда простое чтение заработает, перейдите к обработчику прерывания.
- Переключайте светодиод из упражнения 1 при каждом нажатии кнопки.
- Добавьте простую защиту от дребезга: игнорируйте события в течение короткого интервала или проверяйте уровень после небольшой задержки.
Критерий успеха: одно физическое нажатие вызывает одно ожидаемое действие прошивки, без повторных срабатываний из-за дребезга.
Если не работает: проверьте, предусмотрена ли на плате нужная подтяжка вверх или вниз либо настроена ли она через pinmux. Затем проверьте активный уровень кнопки, выбор фронта прерывания и не используется ли вывод для режима загрузки, отладки или другой периферии.
Что вы узнали: о настройке цифрового входа, логике active-high и active-low, обработке прерываний и о том, почему постоянный опрос может расходовать энергию. Системное обоснование см. в разделе «Обзор энергосберегающего проектирования».
Используйте оболочку и выводите отладочные сообщения¶
Цель: освоить консоль FinSH и rt_kprintf() до того, как отладка станет сложнее.
Время: 15 минут
Начните с: example/system/finsh
Оболочка FinSH в RT-Thread предоставляет интерактивное приглашение msh> через тот же UART, по которому выводятся загрузочные сообщения. С самого начала выработайте следующие привычки:
- Для кратких отладочных сообщений используйте
rt_kprintf(), а не прямую запись в UART. - Проверяйте работающую систему встроенными командами оболочки, например
list_thread,list_deviceи командами просмотра памяти и статуса. -
Делайте журналы короткими и информативными: избыточный вывод может изменить временные характеристики и энергопотребление.
-
Прошейте любой из предыдущих примеров и снова откройте терминал последовательного порта.
- Нажмите Enter, чтобы открыть приглашение
msh>. - Выполните
list_threadиlist_device. - Добавьте вызовы
rt_kprintf()в обработчик кнопки из упражнения 2. - Убедитесь, что при нажатии кнопки появляются сообщения.
Критерий успеха: вы можете просматривать потоки и устройства из оболочки и сопоставлять собственные сообщения журнала с физическими событиями.
Если не работает: проверьте скорость последовательного порта, правильность выбора порта, включён ли компонент оболочки и не удерживает ли порт открытым другая программа.
Что вы узнали: как проверять работающую систему без подключённого отладчика и легко добавлять полезные журналы, не превращая каждую проблему в догадки о прошивке.
Считывайте аналоговый сигнал через ADC¶
Цель: измерить аналоговое напряжение на потенциометре, простом датчике или входе измерения батареи.
Время: 20 минут
Начните с: example/rt_device/adc/channel
Для этого примера RT-Thread включите BSP_USING_ADC, BSP_USING_ADC1 и RT_USING_ADC; иначе SDK не зарегистрирует bat1. На SF32LB52 канал 7 внутри микросхемы подключён к VBAT, поэтому его нельзя использовать как обычный вход внешнего датчика. Выберите канал ADC и настройте pinmux с учётом конкретной микросхемы и платы. В документированном примере для SF32LB52 канал 0 использует PA28. В текущем примере SDK SiFli функция rt_adc_read() возвращает значение напряжения, масштабированное в единицах 0,1 mV, а не необработанные коды ADC. Проверьте единицы и пересчёт для конкретной микросхемы и версии драйвера, которые вы используете.
rt_adc_device_t adc = (rt_adc_device_t)rt_device_find("bat1");
rt_adc_enable(adc, channel);
rt_uint32_t voltage_0p1mV = rt_adc_read(adc, channel);
- Найдите на плате вывод, поддерживающий ADC, и соответствующий канал.
- Проверьте диапазон входного напряжения, наличие делителя или аналогового входного каскада.
- Найдите зарегистрированное устройство ADC, включите канал и прочитайте его значение.
- Выполните пересчёт, указанный для этого драйвера. В текущем примере SF32LB52 разделите возвращённое значение на 10, чтобы получить милливольты; не применяйте повторно формулу для исходных кодов и опорного напряжения. Если на плате есть внешний делитель, учитывайте его коэффициент при расчёте напряжения до делителя.
- Выведите результат в оболочку из упражнения 3.
- Медленно изменяйте входное напряжение и убедитесь, что показания меняются плавно.
Критерий успеха: показания меняются в ожидаемом направлении и после применения документированного масштаба и коэффициента делителя соответствуют правдоподобному входному напряжению.
Если не работает: проверьте настройку мультиплексора выводов, номер канала, документированные масштаб и калибровку драйвера, допустимый диапазон входа, не оставлен ли вход плавающим, а также требует ли датчик питания или времени установления перед измерением.
Что вы узнали: о шаблоне rt_device_find(), который используется в драйверах устройств RT-Thread. Он пригодится для I2C, SPI, PWM, накопителей и собственных драйверов.
Управляйте выходом PWM¶
Цель: сформировать сигнал PWM для регулировки яркости светодиода или управления простым зуммером.
Время: 20 минут
Начните с: example/rt_device/pwm
Имя устройства PWM зависит от драйвера таймера, включённого для платы. В SDK используются имена вроде pwm3, pwmlp1 и pwma1; pwm3 ниже приведён только как пример, это не универсальное имя. Проверьте зарегистрированное имя устройства и настройку мультиплексора выводов в конфигурации платы.
struct rt_device_pwm *pwm = (struct rt_device_pwm *)rt_device_find("pwm3");
rt_pwm_set(pwm, channel, period_ns, pulse_ns);
rt_pwm_enable(pwm, channel);
- Выберите канал PWM и проверьте настройку мультиплексора вывода.
- Выберите подходящий период: достаточно высокий, чтобы мерцание светодиода было незаметным, или в слышимом диапазоне для зуммера.
- Меняйте коэффициент заполнения, чтобы плавно изменять яркость светодиода.
- Изменяя период, задайте несколько фиксированных тонов зуммера.
- Отключите PWM и убедитесь, что выход возвращается в безопасное состояние покоя.
Критерий успеха: изменение коэффициента заполнения меняет яркость или изменение периода меняет тон, а после отключения PWM выход оказывается в ожидаемом состоянии.
Если не работает: проверьте, подключён ли вывод к нужному экземпляру PWM, правильно ли указан номер канала, задаются ли период и импульс в наносекундах и нужен ли внешней нагрузке управляющий транзистор.
Что вы узнали: о настройке периода и коэффициента заполнения, а также о применении шаблона драйвера устройства из упражнения 4 к другому классу периферии.
Работайте с RTC¶
Цель: читать и задавать календарное время с помощью встроенного RTC.
Время: 15 минут
Начните с: example/rt_device/rtc
time_t now = time(RT_NULL);
struct tm *tm_now = localtime(&now);
rt_kprintf("%04d-%02d-%02d %02d:%02d:%02d\n",
tm_now->tm_year + 1900, tm_now->tm_mon + 1, tm_now->tm_mday,
tm_now->tm_hour, tm_now->tm_min, tm_now->tm_sec);
- Один раз задайте время RTC поддерживаемым способом, например командой оболочки.
- Периодически выводите текущее время.
- Выключите и снова включите питание платы и проверьте, сохранилось ли время.
- Если время не сохраняется, проверьте схему резервного питания платы, прежде чем менять прошивку.
При проверке сохранения не сбрасывайте RTC безусловно при каждой загрузке: это скроет, сохранилось ли предыдущее значение времени.
Критерий успеха: при включённом питании время идёт правильно, а поведение сохранения соответствует аппаратной части платы.
Если не работает: проверьте, включён ли компонент RTC, источник тактирования, резервное питание и не сбрасывает ли плата состояние RTC при загрузке.
Что вы узнали: о стандартном API времени C поверх устройства RTC в RT-Thread, а также о том, как поведение прошивки зависит от аппаратной схемы.
Мини-проект: сбор данных с датчика по нажатию кнопки¶
После завершения шести коротких упражнений объедините их в небольшой проект:
- Включайте мигание светодиода при загрузке.
- Используйте кнопку, чтобы запускать и останавливать измерения.
- Пока измерения активны, раз в секунду считывайте одно значение ADC.
- Выводите показания с отметкой времени через FinSH.
- Для индикации активного сбора данных меняйте яркость светодиода с помощью PWM или тон зуммера.
Критерий готовности: проект работает несколько минут без повторных срабатываний кнопки, бесконтрольного потока сообщений или неожиданных сбросов.
Чек-лист проверки первых периферийных устройств¶
- Имя платы, последовательный порт и процесс прошивки проверены.
- Выход GPIO работает на реальном светодиоде или измеряемом выводе.
- Вход GPIO работает с подтверждённой полярностью и защитой от дребезга.
- Оболочка FinSH доступна; команды
list_threadиlist_deviceработают. - Показания ADC правдоподобны и пересчитаны в инженерные единицы.
- Период и коэффициент заполнения PWM дают ожидаемый физический результат.
- Поведение RTC понятно, включая ограничения сохранения времени.
Что делать дальше¶
Когда эти упражнения станут привычными, переходите к разделу «Объединение подсистем». Следующий этап сочетает периферию с промежуточным ПО (middleware): датчиками I2C, LVGL, BLE, воспроизведением аудио, хранением данных и целенаправленной проверкой совместной работы.
Последнее обновление: