Приветствую!
Данная статья открывает цикл статей о программировании микроконтроллеров STM32 для новичков.
Сегодня я расскажу как написать моргание светодиодом двумя способами с использованием инструментов, труднодоступных в 2023 году.
Инструменты: Железо
Плата BlackPill или BluePill
Программатор ST-LinkV2
Загрузка среды разработки
Для настройки тактирования и периферии будем использовать ST CubeMX. Писать код будем в Keil. Cube MX можно скачать здесь, а Keil здесь. Для загрузки CubeMX потребуется регистрация на сайте ST Для загрузки Cube MX ссылка на пост Telegram актуальна на момент написания статьи и уже прожила полгода. Установка не требует особенных знаний, описывать ее процесс не буду, но могу ответить на вопросы в комментариях. Если у вас Mac OS или Linux, то здесь можно скачать CubeIDE - Eclipse подобную среду разработки от ST с интегрированным CubeMX (если вы не живете в России или умеете пользоваться Tor Browser и VPN), но статья будет длиться до второго пришествия, если я буду описывать весь процесс для всех сред разработки, так что просто отдельно упомяну критически важные моменты, когда это потребуется.
Создание проекта в CubeMX
Откроем CubeMx и увидим следующее окно:
Для создания нового проекта выберем пункт "Access to MCU selector". После непродолжительной (относительно периода вращения земли вокруг своей оси) подгрузки компонентов откроется новое окно, где нам предложено выбрать интересующий нас микроконтроллер.
Важное замечание: В статье здесь и далее будут приведены примеры для программирования на платах BluePill и BlackPill, как самых распространенных среди начинающих. У Вас может быть любая другая плата - NUCLEO, DISCOVERY, но процесс настройки периферии, тактирования и программирования не будет принципиально отличаться от приведенных в статье.
"Выберешь черную таблетку..."
Если у вас плата BlackPill, вам нужно выбрать вариант STM32F401CC или STM32F411CC - на самом камне обычно достаточно хорошо различимо выгравирована маркировка лазером.
Для BluePill:
После выбора нужного вам чипа нажимаем "Start Project" в правом верхнем углу и попадаем в окно "Pinout & Configuration" (Рисунок 5). Здесь в разделе System Core -> Sys в пункте "Debug" выбираем "Serial Wire" и справа видим два пина микроконтроллера, выделенных зеленым. Это пины отладочного интерфейса, через который будет происходить прошивка и отладка программ.
Теперь включим ножку 13 порта C в режиме GPIO Output - Вход выход общего назначения в режиме выхода - мышкой на ножку клик, выбираем "GPIO Output" (Рисунок 6)
Для BluePill ножки совпадают - также выбираем пин 13 порта C.
Теперь переходим на вкладку "Project manager" и попадаем в меню "Project" (Рисунок 7).
В пункте "Toolchain/IDE" выбираем MDK - ARM для Keil или STM32CubeIDE для соответствующего варианта. Далее буду использовать Keil, выбираю его.
Для удобства в дальнейшей работе, откроем вкладку "Code generator" (Рисунок 8, левый столбец, вторая кнопка) и поставим галочку напротив "Generate peripheral initialization as a pair of '.c/.h' files per peripheral ". Что это дает - каждый периферийный модуль микроконтроллера будет инициализироваться не в main.c, а в своем файле, что больших проектах улучшает читаемость.
Теперь нажмем кнопку "Generate code" (Рисунок 9).
После успешного создания проекта открываем его (Рисунок 10).
Знакомство с проектом
Теперь рассмотрим окно проекта по умолчанию (Рисунок 11) 1 - дерево проекта, 2 - вывод компилятора, 3 - основное окно, в котором отображается текущий открытый документ, 4 - кнопка сборки проекта (F7), 5 - прошивка микроконтроллера (F8), 6 - Настройки проекта, 7 - переход в режим отладки (Ctrl+F5).
Передвинем консоль под дерево проекта, чтобы не занимать полезное место для кода
Развернем папку "Application/User/Core" и откроем файл main.c (Рисунок 13) Ctrl + колесико позволяет менять размер шрифта.
Рассмотрим, что здесь есть: вначале подключается main.h файл и файл gpio.h, если поставили галочку раздельной генерации файлов периферии. Далее объявлен прототип функции конфигурации периферии и затем попадаем в main() функцию, в которой инициализируется HAL (Hardware Abstraction Layer) фреймфорк и тактирование с портами ввода вывода (Рисунок 14).
Кодим
В функции main() после инициализации, которая происходит единожды, присутствует бесконечный цикл while(1), в котором и будет выполняться наша программа. Обратите внимание на секции USER CODE - если писать код внутри них, то при перегенерации проекта из CubeMX, ваш код не перетрется.
Добавим в секцию USER CODE BEGIN 3 включение светодиода на ножке GPIOC 13, ожидание 500 мс и его выключение (Рисунок 15).
98 строка: В регистр ODR (Output Data Register) блока GPIO положили число, равное
1 << 13;
// или в бинарном выражении
0010 0000 0000 0000
Поскольку биты нумеруются справа налево (и с нуля), получается, что положили "1" в 13 й бит регистра ODR.
99 строка: Вызвали функцию HAL_Delay() с аргументом 500, где "500" - это миллисекунды, т.е 500 мс ничего не делаем.
100 строка: Вспомним число (1<<13) и инвертируем его.
1 << 13;
// или в бинарном выражении
0010 0000 0000 0000
// когда делаем ~(1<<13), мы побитово инвертируем число в скобках
1101 1111 1111 1111
теперь умножаем текущее значение регистра побитово на полученное число т.е все биты, которые были, сохраняют свое значение, кроме 13 - го, его умножили на ноль и сбросили.
0010 0000 0000 0000
// когда делаем ~(1<<13), мы побитово инвертируем число в скобках
1101 1111 1111 1111
//
светодиод в этот момент зажигается, потому что на плате BlackPill светодиод подтянут резистором к 3.3В.
101 строка: снова ждем 500 мс.
Теперь можно нажать F7, чтобы собрать проект, должно получиться так:
Теперь настроим отладчик, нажимаем "Настройки".
И сменим компилятор на 6.16 - он гораздо быстрее и переходим в вкладку "Debug" (Рисунок 18).
Во вкладке "Debug" выберем ST-Link и подтверждаем выбор.
Теперь можно подключить программатор к плате, вставить в USB компьютера и прошить, нажав F8. Если сразу не сработало, перепроверьте, не перепутаны ли контакты программатора и платы. После прошивки нужно нажать кнопку Reset на плате, чтобы светодиод начал мигать.
Очень надеюсь, что у вас получилось, потому что далее мы попробуем сделать то же самое, но изменив пару строчек кода и значения задержки с 500 на 100 мс (Рисунок 20):
Теперь на 98 строке появилась функция, которая включает пин 13 порта GPIOC.
На 99 строке "500" поменяли на "100".
На 100 строке соответственный пин выключает.
На 101 строке "500" поменяли на "100".
Снова соберем проект через F7 и зашьем проект нажатием F8, перезапустим МК нажатием RESET.
Если все сделали правильно, светодиод будет моргать гораздо чаще.
Домашнее задание
Для того, чтобы инвертировать значение бита, есть операнд "исключающее ИЛИ".
^=
Попробуйте использовать его для случая с регистрами, чтобы сократить число строчек кода в while(1) до двух.
Всем спасибо за то, что прочитали публикацию, жду ваших вопросов и исправления неточностей в комментариях или на почту: mgostev.it@gmail.com
Комментарии (39)
GennPen
00.00.0000 00:00+2Рис. 20 Больше HAL
А почему бы сразу с HAL не начать? Ведь он проще для понимания, чем CMSIS.
К тому же с HAL можно на пин повесить пользовательскую метку и писать примерно так: HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
Соответственно, если переместите светодиод на другой пин, то достаточно перевесить эту метку и в коде ничего не нужно будет менять.Butaforsky Автор
00.00.0000 00:00+1Добрый вечер, согласен, HAL проще для понимания, чем CMSIS, но обучалок на HAL в интернете много, а я бы хотел дать более полное представление о возможностях программирования под МК
sami777
00.00.0000 00:00Кроме HAL есть еще LL и ни куда не делся SPL. Поэтому среди этого зоопарка трудно разобраться. CMSIS - работа непосредственно с указателями на регистры - проще разобраться и понять аппаратную часть мк. К тому же CMSIS он по сути один для всех армов, неважно от производителя. Но работать с указателями напрямую - сложней.
Dima_Sharihin
00.00.0000 00:00+7HAL на порядок сложнее для понимания, чем CMSIS. Потому что к замороченной аппартной архитектуре IP нужно ещё и понимать индусский код HAL'а.
Единственная вещь, где может теоретически пригодиться HAL - если не хочется вручную прописывать "многоэтапные" транзакции I2C и прочих не самых дружественных к эмбеддеру протоколов.
IvUyr
00.00.0000 00:00+1Спасибо, что не ещё одна статья «как помигать светодиодом из ардуйнины».
И, собственно, вопрос - почему HAL а не LL?Butaforsky Автор
00.00.0000 00:00Благодарю, если честно LL просто мимо меня прошел и в проектах его не использую, потому рассказываю о том,что знаю
izqbr
00.00.0000 00:00Самоучке возможно попасть в разработку встраиваемых систем?
Butaforsky Автор
00.00.0000 00:00Здравствуйте, да, возможно, в моем случае это случилось после того, как на третьем курсе университета вместе с увлекающимся силовой электроникой одногруппником начал осваивать микроконтроллеры
Dima_Sharihin
00.00.0000 00:00+3Более чем. Эмбеддед сравнительно спокойное направление, к тому же более веселое (чем тот же вебдев).
Программировать тут все равно никто не умеет...izqbr
00.00.0000 00:00-1Мне кажется для таких организаций нужны дипломы и тд
Dima_Sharihin
00.00.0000 00:00Дипломы нужны, но иногда работодатель идет на встречу, и (если уж сильно надо) - диплом получается паралелльно с работой при помощи заочного обучения.
Если речь именно про "попасть в разработку" - то можно и без диплома, удержаться там - могут и попроситьizqbr
00.00.0000 00:00С моим увлечением Go для мк туда точно не попасть, наверное всё-таки нужно cmsis
Dima_Sharihin
00.00.0000 00:00+1Не переживайте вы сильно за инструменты, один фиг вам придется учиться с нуля на новом месте. Скажем, в микроконтроллерах обязательно знание Си, все остальные языки (в том числе С++) применяются уже по остаточному принципу. Сам Си учится за неделю самое долгое, он неимоверно примитивен, от стандартной библиотеки все равно почти ничего в эмбеддеде не используется.
CMSIS - это стандарт ARM'а на заголовочники, специфичные для процессора, формат описания системной периферии, некоторые отдельные библиотеки, и прочие небольшие кусочки, совершенно не обязательные к применению. Лучше понимать, как вообще работают микропроцессорные системы и чем меньше прослоек между программистом и железом - тем проще идёт процесс понимания
Butaforsky Автор
00.00.0000 00:00+4По моему опыту, ни на одном собеседовании на позицию программиста микроконтроллеров про профильный диплом не спрашивали. Были вопросы касательно понимания Си и основ схемотехники
Zhbert
00.00.0000 00:00+1Ну как сказать. Если это что-то из госсектора — завод, НИИ и так далее, то там, конечно, без диплома вообще никуда. Даже если денег не платят, диплом, а лучше кандидатскую все равно подавай. А в «частных» скорее будут смотреть на опыт и портфолио. По крайней мере мои знакомые электронщики именно таким опытом делятся. Да и мой опыт в НИИ и нескольких частных компаниях конструктором говорит о том же самом.
Zhbert
00.00.0000 00:00+1Смотря куда. Я в НИИ когда работал, случайно стал разработчиком системы управления лазером :) У меня хоть и почти профильное образование было, но с МК на Си и прочей электроникой я не работал до этого.
mctMaks
00.00.0000 00:00да легко, если "самоучение" дается легко. Вот только зачастую помимо программирования требуется иметь знания в цифровой обработке сигналов, цифровой и аналоговой схемотехнике хотя бы на уровне чтения схемы. Да и знать как держать паяльник не помешает.
мой путь в микропрограммисты начался с практики на том же предприятии где подрабатывал студентом. программировать умел немного на паскале и делфи, Си учил на месте. как и контроллеры. за 7 лет от новичка до ведущего инженера-программиста с учетом отсутствия профильного образования (диплом инженера средств РЭБ) вполне нормально я считаю.так что, вполне себе реально попасть в этот чудный микромир с макровозможностями.
Ivan_Kadochnikov
00.00.0000 00:00+10Настоятельно рекомендую всем, желающим разобраться с микроконтроллером, научится пользоваться периферией МК "ручками" через регистры.
HAL, CMSIS, LL скрывают от вас всю "кухню", что не способствует пониманию логики работы МК.
Да, это труднее, НО на много полезнее в плане развития.
everis
00.00.0000 00:00+6++
Не зная как работает МК внутри на уровне собственных регистров - ни один HAL в боевом проекте не поможет. К тому же в HAL том же - куча ошибок. А искать ошибки в чужом коде - втройне геморнее.
Zhbert
00.00.0000 00:00+5Полностью согласен.
Мы начинали вообще с пикмикро на ассемблере. Когда погоняешь руками байты и биты по регистрам, увидишь результат и поймешь, почему так происходит — потом меньше непотяток в разработке под сложные большие МК, на чем бы ты ни писал.
Это как с программированием (щас вброшу на вентилятор, видимо): если начинаешь с азов, с понятий алгоритма, с работы с памятью, указателями и прочим, то потом пишешь хорошо на любом языке. А если начал с питона...
DrGluck07
00.00.0000 00:00+2Вот! Я буквально только что столкнулся с этим на работе. Молодые падаваны с удовольствием используют все эти cubemx-ы, cmsis и т.д. Проблема в том, что у них не возникает понимания как это всё устроено, они это воспринимают как ещё один фреймворк. Но с железом это немного не так работает. Вернее работает, если задача тупо поморгать светодиодом. Но потом возникают более сложные задачи, когда нужно считать такты, прикидывать, а влезаем ли мы вообще по быстродействию. И тут начинают появляться реализации с 500 000 прерываний в секунду и удивление, что эта фигня теряет байты даже на медленном uart-е на скорости 9600. "А чо такова, у нас же 108 мегагерц, мы всё успеем". Успеем, если сядем и прикинем как и что будет работать, а не в cubemx-е пины раскидаем.
Как по мне, cubemx и сmsis это для тех, кто уже умеет, и им не нужно в очередной раз отвлекаться на одну и ту же сто раз пройденную задачу. Но до этого нужно научиться, всё потрогать ручками, понять нюансы тех или иных интерфейсов. Дальше идёт моё старческое брюзжание на 128 страниц...
p.s. Из реального, ещё с 8-битных контроллеров. Пацаны написали очередную реализацию миллисекундного таймера. У них там в прерывании инкрементировался счётчик uint32_t. Где-то в основном цикле это как-то использовалось. Ну и конечно это глючило в процессе и парни долго и героически пытались разобраться, только потом пришли за советом.
В другом проекте от души написали систему классов, виртуальные функции, все дела, красивое такое хипстерство по стандартам C++42. Жаль только в 8 килобайт RAM оно не влезло )
izqbr
00.00.0000 00:00+1Я когда-то писал в айтмель студио для меги8. Работа с регистрами и тд. Сейчас pi pico блэк пилл в Ардуино иде . Иногда так хочется превратить любимое хобби в профессию
webhamster
00.00.0000 00:00Для настройки тактирования и периферии будем использовать ST CubeMX. Писать код будем в Keil
Обоженьки, проприетарные закрытые программы с вендор-локом и разработчики любители Windows. В России в 2023 году. Эмдеддинг который мы заслужили...
Ну почему хотя бы не PlatformIO?
Butaforsky Автор
00.00.0000 00:00Не PlatformIO, потому что там платная отладка
В следующей статье добавлю рассмотрение вопроса по открытым IDE
webhamster
00.00.0000 00:00Не PlatformIO, потому что там платная отладка
В какой момент она там стала платной?
Dima_Sharihin
00.00.0000 00:00Она там была платной в 2019 году, когда я крайний раз ей пользовался
https://community.platformio.org/t/platformio-commercial-use-solved/12726/2
webhamster
00.00.0000 00:00since June 2019
Ну так то уже четвертый год как everything is FREE and OPEN-SOURCE.
Даже в неайтишном мире все гораздо быстрее меняется.
Dima_Sharihin
00.00.0000 00:00-1Потому что platformio такая же проприетарщина.
Вообще ARM Cortex M хороши, что под них есть GCC и OpenOCD, а больше, зачастую, и не нужноwebhamster
00.00.0000 00:00Потому что platformio такая же проприетарщина.
Что тогда делает этот код на GitHub https://github.com/platformio/ под лицензией Apache 2.0 https://ru.wikipedia.org/wiki/Лицензия_Apache ?
DrGluck07
00.00.0000 00:00Кстати, мы сейчас очень грустим от того, какое Кейл неудобное говно. Это помимо того, что его нельзя получить легально. Думаем на что пересесть, может даже QtCreator приспособить, вроде есть мурзилки как это делается.
Dima_Sharihin
00.00.0000 00:00VS Code + Cortex-Debug. Может не самое лучшее, но точно работающее решение.
Ну и SEGGER RTT спасет эмбеддерщика
rran
Добрый вечер, подскажите, пожалуйста, а что можно почитать по теме программирования на C?
Butaforsky Автор
Добрый вечер, если интересует Си для микроконтроллеров, есть книга "Си для встраиваемых систем" https://robotclass.ru/articles/c_for_embedded_systems/
и "Mastering STM32" , у нее также есть перевод на русский https://www.carminenoviello.com/mastering-stm32/
По самому языку Си есть книги Карнигана и Ритчи - создателей языка
rudnik85
Добрый вечер.
А что ни будь для совсем "чайников" про Си?
Butaforsky Автор
Мне как раз в начале "Си для встраиваемых систем" помогла освоиться с синтаксисом и структурами данных языка, рекомендую PDF версию, она есть в сети, могу выслать на email, если правилами не запрещено
Zhbert
Керниган и Ричи — классика, как уже сказали выше. Последнее издание лучше, она не так давно переиздавалась. Там все основы довольно простым языком, книжка не такая уже большая.
А потом можно что-то уже глубже копать. На Си ведь недостаточно просто знать структуры и типы, там надо мышление менять, чтобы память не текла, не сегфолтилось все из-за глупых ошибок и так далее...
andry67
Слитый на торренты курс КА "Шаг" попрубуйте обязательно. Для первой консольной програмки самое то.