Cегодня редко встретишь разработчика, который хоть раз бы не слышал о Rust. После долгого хайпа и зародившегося мема RIIR (rewrite it in Rust - перепиши это на Rust) ажиотаж вокруг языка как будто бы поутих. Но оказалось, все и вправду по-тихому переписывается на Rust (если мой дебют не утонет в минусах, постараюсь написать статью-исследование на тему, где уже Rust надежно поселился в системе).

Первое, что меня впечатлило - это статья, что вся инфраструктура Cursor написана на Rust в целях экстремальной производительности, и языкс этой задачей, как видно, прекрасно справляется. Второе, что и сподвигло не только читать о Rust, но и начать на нем писать, — это, конечно же, дефицит комлектующих. «640 КБ на самом деле хватит всем» и интерес пал на братьев наших меньших — микроконтроллеров. Вот где действительно можно прочувствовать всю необходимость оптимизации.

Конечно, знакомство с Rust, как и у всех, началось с классики — Rust boo k для новичков и Embedded Rust для желающих окунуться вразработку встроенных систем. В Rust Book новичкам предлагается написать простую программу Guessing Game — приложение, которое загадывает число, а «игрок» должен попытаться его угадать.

Но просто читать не так интересно как набивать свои собственные шишки, поэтому, вооружившись книгами, документацией, все еще живым StackOverflow и Gemini в качестве ментора, я решила объединить эти два мира и сделать Guessing Game на STM32.

Далее хочу предложить небольшой гайд (или просто объяснение кода) из того, в чем удалось разобраться.

Комплектующие

Первое, что нужно для реализации идеи, конечно, же сам микроконтроллер. В моем случае это STM32L476RG (Nucleo).

Второе - нам нужен экран, куда мы будем выводить информацию. Еще со времен бловства с Ардуино у меня осталась целая коробка разных приблуд, в том числе и LCD с I2C адаптером. Он и был выбран в качестве основного дисплея.

И последнее - возможность взаимодействовать с программой. Из того же набора я взяла IR receiver и "Car MP3" пульт.

Дополнительно потребуется breadboard (Макетные платы для монтажа в гнёзда) для удобного соединения IR receiver (и несколько джамперов для соединений). В моем случае борда также была в наборе Ардуино.

Подключение STM32

Для моей платы был нужен кабель USD A-mini B.

Подключаем плату черезUSB к компьютеру (не забываем, что платы чувствительны к статике, предварительно «заземляемся» об что‑то чтобы не разрядиться на плату). Я использую Linux Ubuntu, потому могу расписать алгоритм действий для этой ОС. Для других ОС алгоритм может отличаться.

Проверяем видит ли компьютер подключенную плату, для этого пишем в консоли: lsusb | grep STM. Должно быть видно что-то типо "STMicroelectronics ST-LINK/V2.1".

Устанавливаем инструмент для работы с STM32 и обновляем правила для работы с USB:

sudo apt update
sudo apt install stlink-tools
sudo udevadm control --reload-rules
sudo udevadm trigger

Быстро проверяем работает ли плата:
echo "test" > test
st-flash write test 0x8000000

Находим LD1 и LD3 на плате и смотрим за их поведением. LD3 должен гореть красным, а LD1 либо гореть красным, либо мигать пока в микроконтроллер записывается программа.

Затем отключаем плату от компьютера и переходим к подключению пинов.

Подключение LCD c адаптером I2C

Здесь имеется 4 пина: SDA (перенос данных), SCL (пин синхронизации), VCC (питание) и GND (заземление).

На STM32, как правило, пины хорошо подписаны, потому ищем такие же пины на плате: SCL/D15/PB9, SDA/D15/PB8, +3V3 и GND. Соединяем между собой:

  • SDA дисплея c SDA на STM32

  • SCL с SCL

  • VCC с +3V3

  • GND c GND

Подключение IR приемника

IR приемник обычно выглядит как светодиод, но черного цвета и в корпусе. Смотрим на его "лицевую сторону". Самый левый пин будет пином выхода данных, средний - GND и правый - VCC. Подключаем левый пин к PA0 на STM32 (он может еще называться A0). Средний - к GND на плате и VCC - к +3V3. Вот тут может понадобиться breadboard, чтобы использовать общий +3V3.

Код на Rust

Репозиторий.

Для дальнейшей работы должен быть установлен Rust и Cargo (если нет - следуйте официальному гайду для вашей ОС тут).

Первым делом мы должны обозначить build target для правильной компиляции для нашего микроконтроллера, для этого пишем в консоль rustup target add thumbv7em-none-eabihf

Что важно знать - мы работаем без std и привычного main.

В качестве основного драйвера системы я использовала Embassy как асинхронный и энергоэффективный фреймворк. Возможно это и оверкилл для моей программы, но хотелось разобраться в чем то еще дополнительном по мере реализации идеи. К тому же спользование Embassy освобождает от необходимости создавать файл memory.x с указанием параметров flash и ram памяти, так как после указания в Cargo.toml файле для зависимости embassy-stm32 в features "memory-x" и своей STM32 платы (stm32l476rg) фреймворк сам создает эту информацию "под капотом".

main.rs для встроенный систем начинается со строк:
#![no_std]
#![no_main]

Что происходит в main:

  • инициализации периферии STM32 c конфигурацией внутренних часов, соответсвующих циклу приема-передачи IR приемника и пульта "Car MP3" (поддерживает протокол NEC), т.к. для корректного декодирования сигнала с пульта нужны корректные циклы отправки-приема сигнала с конкретными паузами. Любой рассинхрон или задержка сигнала приводит к ошибкам декордирования

  • инициализация модуля дисплея

  • инициализация модуля инфракрасного приемника

  • создание асинхронной задачи для декодирования полученного с пульта сигнала

  • запуск игры

  • отлов ответа "игрока" и отображения статуса игры на дисплее (запущенное в цикле)

  • использование Channel c мьютексом для передачи данных между командой с пульта и циклом игры (для получения и сравнения ответа от "игрока")

Далее пройдемся по файлам:

  • GameInput представляет собой простой enum поддерживаемого игрой ввода

  • Game - модуль игры, основа которого создавать случайное число и проверять статус игры

  • LCD - модуль инициализации hd44780 драйвера и функции взаимодействия с экраном - стирать данные, писать в первую строку, писать во вторую строку

  • RC - инициализация инфракрасного приемника и маппинг команд с пульта (предварительно цифровой код каждой кнопки был вручную отловлен с помощью дебага). Самая сложная функция здесь — декодирование сигнала. Используются расчеты delta time для процесса декодирования и сравнение время нажатия кнопки с некоторым временным промежутком относительно последнего нажатия для предотвращения «залипания» кнопки.

Отдельного внимания заслуживает файл .cargo/config.toml, где указывается как правильно запускать программу, с какими флагами и для какой платформы, что позволяет в дальнейшем запускать программу просто командой cargo run.

Запуск игры

  • клонируем репозиторий и перемещаемся в корневую папку проекта в терминале

  • подключаем плату через USB

  • прогоняем cargo run в терминале

  • смотрим на LCD, где должно отобразиться «Guess 1 to 100». Если дисплей горит, но ничего не показывает, возможно необходимо подкрутить отверткой потенциометр сзади дисплея пока не станут видны буквы.

  • жмем кнопки 0–9 на пульте, подбирая число. Отправить — кнопка >>|, стереть одну цифру — кнопка |<<, перезапустить игру — кнопка >||.

Я новичок в Rust и Embedded и осознаю, что для более опытных разработчиков встроенных систем недочеты будут резать глаз. Надеюсь на конструктивные замечания в комментариях, а также на то, что мой краткий гайд/обзор окажется полезным для таких же новичков как и я, чтобы вдохновиться на свои проекты на Rust и Embedded.

Комментарии (5)


  1. AllFiction
    28.02.2026 16:39

    в свое время выбирал что бы новое изучить, в итоге выбор был межу Goland и Rust. В итоге остановился на Го из-за своей простоты, но при этом функциональности, в нем отдыхаешь когда пишешь и много крутых фишек есть других. Раст не зашел тем что это очередной эльфийский по типу плюсов с кучей вариативности записей, спецсимволов и прочей фигни.

    через год мена заинтересовали тем, что на расте пишут под esp32 (и всем советуют) и я таки попробовал вкатится хотя-бы чисто ради МК. В итоге оказалось что мне и на си вполне норм. Синтаксис - в целом как я и ожидал, нет того "упрощения" как в Го, зато есть куча чисто локальных особенностей и общая стилистика как будто созданная инопланетянами, у меня прям вайбы первых сайтов написанных с jqwery были. Но самая большая проблема, которая оттолкнула это то что раст зависит от библиотек. В го все есть код и подключить что либо можно, но по умолчанию считается что все должно быть компилируемо прям в рамках самого языка. В расте же ты как в старые добрые времена зависишь от сторонних dll и без них даже не скомпилируется. Причем это проблема настолько всеобъемлюща, что даже что то постое консольное требует библиотек (в го необходимость внешнего вылазит редко, графические интерфейсы, нетиповые ядра и тд), а про МК я вообще молчу - как в процессе оказалось, что бы создать скетч под ESP32 который будет нормально собираться и шиться, как под линуксом так и под виндой с маком мне надо или спецом прописывать все или сложить рядом с исходниками нужные бинарные либы.

    вообщем все то же самое что и было на си, только другой синтаксис и совершенно иной срок использования. если по си можно твою проблему в будущем нагуглить, то вот с растом вряд ли.
    Не понимаю как раст сравнивают с Го по простоте, ведь даже тот же кривейший tinygo который с esp32 очень относительно работает, на нем я могу сделать скетч который будет шиться у всех и не потребует каких-то особых танцев по итогу. главное даже в паплайне будет собираться без проблем.

    За STM не подскажу, не пробовал его с растом ковырять, но учитывая что в 99% случаев ты все равно работаешь через обертку (hal) а прочие танцы с кубиками и тд все равно в итоге надо настраивать конкретно на каждой платформе - если не ардуино а серьезно, то раст будет неплохим выбором. лишь бы проблем с либами не было, хотя опять таки с STM очень часто приходилось "руками доводить" потому скорее всего детерминированность пакетов раста будет прям шагом вперед при работе с камнями STM


    1. Newpson
      28.02.2026 16:39

      как в старые добрые времена зависишь от сторонних dll и без них даже не скомпилируется

      сложить рядом с исходниками нужные бинарные либы

      можете, пожалуйста, прояснить этот момент? Я, конечно, пока ненастоящий растовчанин, но статическая линковка Rust сейчас является его и плюсом (всё своё ношу с собой) и минусом (бинари довольно крупные получаются) одновременно, а все crates собираются по месту из исходников. То есть, испытал абсолютно противоположный вашему опыт.


    1. Jijiki
      28.02.2026 16:39

      раст не потипу плюсов, как говорится изучайте матчасть, у раста если следовать его логике, всё гораздо удобнее чем в сравнении с С/С++, удобные каналы mpsс, далее, большой проект раста читается проще, если сразу при написании, при использовании удобств раста сразу размечать удобные секции, да кода будет много, но рамки-границы будут выражены всё еще, и самое интересное грязи будет по-меньше чем в С или в С++. там есть много удобств, которые чисто в коде прям проще видятся и выявляются восприятием, в его семантике кстати!, чем в С/С++ восприятие и грязь

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

      у раста удобные структуры, имплементации более выражены, работа с модулями удобная, нет той возни как в С/С++, derive намного удобнее опций или пойди пойми где у вас какие конструкторы и что они должны делать, далее, нет возни с cmake/conan/ice, конструкции языка более явные - это приводит к тому, что структура кода более вырожена на логику, к сожалению в расте одни только +, минусов я не заметил, я тоже сначала не доверял расту, но после диспетчинга на С, и некоторых попыток С++, переход на раст стал очевиднее, пускай я не експерт и от идиоматики хаскель/раст я пока далёк, но такой подход даже радует, чем С/С++...

      упд: владение, бороу чекер ), семантика мув - это настоящий прорыв сегодня, вдруг оказалось что она необходима, а не на откуп человека (типо сиди думай чо делать дальше, где там семантика мув вообще должна быть)

      если быть кароче, мои итоги, раст это что-то крутое из мира хаскельфорт, некое переосмысление, и оно о чудо реально клёвое )


    1. Weselton
      28.02.2026 16:39

      Сколько же неправды вы написали )
      0) Rust или Go - вкусовщина (и не только). У го порог входа может быть ниже, но когда (вдруг) приходится что-то оптимизировать или делать что-то более сложное, оказывается что "простота" (я бы сказал "кастрированность") языка начинает совать палки в колеса. И тут начинается генерация костылей за костылями. Да и с безопасностью (отсутствие null safety или гонки в многопоточке, к пример) в Go сильно хуже, прям отвратительно, 10 шагов назад. Я много прогал на Го и кайфа не получал. Имхо

      1) "эльфийский по типу плюсов" - не знаете, что пишете ) Плюсы в разы сложнее и огромней. Раст - скорее Си 21 века

      2) Раст без сторонних крейтов зависим только от системных библиотек операционной системы (если собирать с помощью musl, то и от этих зависимостей получится избавиться). Среди крейтов сторонних есть те, которые зависят от сторонних либ в системе (openssl, например), но это исключение из правил и встречается крайне редко. Но такое и на go бывает (sqlite). Подход, как и у Go - статика по умолчанию. Тот же crate для разработки под esp32 от espressif около года или типа того не зависит от сторонних сишных либ.


    1. Andrey_Brodobrey
      28.02.2026 16:39

      Звучит все это круто. Rust действительно выглядит, как свежий глоток воздуха в STM. Правда я не понимаю, где, работая с СТМ, можно полноценно развернуть возможности раста. Мое взаимодействие с стм, чаще упирается в работу с регистрами и описании логики считывания с датчиков, там и Си/++ особо не развернешь.
      Играясь с дисплеями, наверное - да, можно и на Расте. Но это очень узкое применение. Там, в сущности, и на питоне можно, и не плохо выходит.
      Как по мне Си и Плюсы плотно заняли эту нишу, полноценно их в МК уже не заменить. Максимум только отдельные библиотеки на иных языках под конкретную периферию.