Приветствую!

Данная статья открывает цикл статей о программировании микроконтроллеров STM32 для новичков.

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


Инструменты: Железо

  1. Плата BlackPill или BluePill

  2. Программатор 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 и увидим следующее окно:

Рис. 1. Стартовый экран CubeMx
Рис. 1. Стартовый экран CubeMx

Для создания нового проекта выберем пункт "Access to MCU selector". После непродолжительной (относительно периода вращения земли вокруг своей оси) подгрузки компонентов откроется новое окно, где нам предложено выбрать интересующий нас микроконтроллер.

Важное замечание: В статье здесь и далее будут приведены примеры для программирования на платах BluePill и BlackPill, как самых распространенных среди начинающих. У Вас может быть любая другая плата - NUCLEO, DISCOVERY, но процесс настройки периферии, тактирования и программирования не будет принципиально отличаться от приведенных в статье.

"Выберешь черную таблетку..."

Рис. 2. Окно поиска микроконтроллера. Первый микроконтроллер для BlackPill
Рис. 2. Окно поиска микроконтроллера. Первый микроконтроллер для BlackPill

Если у вас плата BlackPill, вам нужно выбрать вариант STM32F401CC или STM32F411CC - на самом камне обычно достаточно хорошо различимо выгравирована маркировка лазером.

Рис. 3. Окно поиска микроконтроллера. Второй микроконтроллер для BlackPill
Рис. 3. Окно поиска микроконтроллера. Второй микроконтроллер для BlackPill

Для BluePill:

Рис. 4. Окно поиска микроконтроллера. Микроконтроллер  для BluePill
Рис. 4. Окно поиска микроконтроллера. Микроконтроллер для BluePill

После выбора нужного вам чипа нажимаем "Start Project" в правом верхнем углу и попадаем в окно "Pinout & Configuration" (Рисунок 5). Здесь в разделе System Core -> Sys в пункте "Debug" выбираем "Serial Wire" и справа видим два пина микроконтроллера, выделенных зеленым. Это пины отладочного интерфейса, через который будет происходить прошивка и отладка программ.

Рис. 5. Включаем отладку
Рис. 5. Включаем отладку

Теперь включим ножку 13 порта C в режиме GPIO Output - Вход выход общего назначения в режиме выхода - мышкой на ножку клик, выбираем "GPIO Output" (Рисунок 6)

Рис. 6. GPIO output
Рис. 6. GPIO output

Для BluePill ножки совпадают - также выбираем пин 13 порта C.

Теперь переходим на вкладку "Project manager" и попадаем в меню "Project" (Рисунок 7).

В пункте "Toolchain/IDE" выбираем MDK - ARM для Keil или STM32CubeIDE для соответствующего варианта. Далее буду использовать Keil, выбираю его.

Рис. 7. Меню Project
Рис. 7. Меню Project

Для удобства в дальнейшей работе, откроем вкладку "Code generator" (Рисунок 8, левый столбец, вторая кнопка) и поставим галочку напротив "Generate peripheral initialization as a pair of '.c/.h' files per peripheral ". Что это дает - каждый периферийный модуль микроконтроллера будет инициализироваться не в main.c, а в своем файле, что больших проектах улучшает читаемость.

Рис. 8. Раздельные файлы
Рис. 8. Раздельные файлы

Теперь нажмем кнопку "Generate code" (Рисунок 9).

Рис. 9. Запуск
Рис. 9. Запуск

После успешного создания проекта открываем его (Рисунок 10).

Рис. 10. Проект успешно создан
Рис. 10. Проект успешно создан

Знакомство с проектом

Теперь рассмотрим окно проекта по умолчанию (Рисунок 11) 1 - дерево проекта, 2 - вывод компилятора, 3 - основное окно, в котором отображается текущий открытый документ, 4 - кнопка сборки проекта (F7), 5 - прошивка микроконтроллера (F8), 6 - Настройки проекта, 7 - переход в режим отладки (Ctrl+F5).

Рис. 11.Проект Keil
Рис. 11.Проект Keil

Передвинем консоль под дерево проекта, чтобы не занимать полезное место для кода

Рис. 12. Удобная консоль
Рис. 12. Удобная консоль

Развернем папку "Application/User/Core" и откроем файл main.c (Рисунок 13) Ctrl + колесико позволяет менять размер шрифта.

Рис. 13. Открываем нужное
Рис. 13. Открываем нужное
Рис.14. Основное тело программы
Рис.14. Основное тело программы

Рассмотрим, что здесь есть: вначале подключается main.h файл и файл gpio.h, если поставили галочку раздельной генерации файлов периферии. Далее объявлен прототип функции конфигурации периферии и затем попадаем в main() функцию, в которой инициализируется HAL (Hardware Abstraction Layer) фреймфорк и тактирование с портами ввода вывода (Рисунок 14).

Кодим

В функции main() после инициализации, которая происходит единожды, присутствует бесконечный цикл while(1), в котором и будет выполняться наша программа. Обратите внимание на секции USER CODE - если писать код внутри них, то при перегенерации проекта из CubeMX, ваш код не перетрется.

Добавим в секцию USER CODE BEGIN 3 включение светодиода на ножке GPIOC 13, ожидание 500 мс и его выключение (Рисунок 15).

Рис.15. Моргаем на регистрах
Рис.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, чтобы собрать проект, должно получиться так:

Рис. 16. Успешно собрали
Рис. 16. Успешно собрали

Теперь настроим отладчик, нажимаем "Настройки".

Рис. 17. Настройки
Рис. 17. Настройки

И сменим компилятор на 6.16 - он гораздо быстрее и переходим в вкладку "Debug" (Рисунок 18).

Рис. 18. Компилятор и отладка
Рис. 18. Компилятор и отладка

Во вкладке "Debug" выберем ST-Link и подтверждаем выбор.

Рис. 19. Выбираем отладчик
Рис. 19. Выбираем отладчик

Теперь можно подключить программатор к плате, вставить в USB компьютера и прошить, нажав F8. Если сразу не сработало, перепроверьте, не перепутаны ли контакты программатора и платы. После прошивки нужно нажать кнопку Reset на плате, чтобы светодиод начал мигать.

Очень надеюсь, что у вас получилось, потому что далее мы попробуем сделать то же самое, но изменив пару строчек кода и значения задержки с 500 на 100 мс (Рисунок 20):

Рис. 20. Больше HAL
Рис. 20. Больше HAL

Теперь на 98 строке появилась функция, которая включает пин 13 порта GPIOC.

На 99 строке "500" поменяли на "100".

На 100 строке соответственный пин выключает.

На 101 строке "500" поменяли на "100".

Снова соберем проект через F7 и зашьем проект нажатием F8, перезапустим МК нажатием RESET.

Если все сделали правильно, светодиод будет моргать гораздо чаще.

Домашнее задание

Для того, чтобы инвертировать значение бита, есть операнд "исключающее ИЛИ".

^=

Попробуйте использовать его для случая с регистрами, чтобы сократить число строчек кода в while(1) до двух.

Всем спасибо за то, что прочитали публикацию, жду ваших вопросов и исправления неточностей в комментариях или на почту: mgostev.it@gmail.com

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


  1. rran
    00.00.0000 00:00
    +1

    Добрый вечер, подскажите, пожалуйста, а что можно почитать по теме программирования на C?


    1. Butaforsky Автор
      00.00.0000 00:00
      +2

      Добрый вечер, если интересует Си для микроконтроллеров, есть книга "Си для встраиваемых систем" https://robotclass.ru/articles/c_for_embedded_systems/

      и "Mastering STM32" , у нее также есть перевод на русский https://www.carminenoviello.com/mastering-stm32/

      По самому языку Си есть книги Карнигана и Ритчи - создателей языка


      1. rudnik85
        00.00.0000 00:00

        Добрый вечер.

        А что ни будь для совсем "чайников" про Си?


        1. Butaforsky Автор
          00.00.0000 00:00

          Мне как раз в начале "Си для встраиваемых систем" помогла освоиться с синтаксисом и структурами данных языка, рекомендую PDF версию, она есть в сети, могу выслать на email, если правилами не запрещено


        1. Zhbert
          00.00.0000 00:00
          +1

          Керниган и Ричи — классика, как уже сказали выше. Последнее издание лучше, она не так давно переиздавалась. Там все основы довольно простым языком, книжка не такая уже большая.

          А потом можно что-то уже глубже копать. На Си ведь недостаточно просто знать структуры и типы, там надо мышление менять, чтобы память не текла, не сегфолтилось все из-за глупых ошибок и так далее...


        1. andry67
          00.00.0000 00:00

          Слитый на торренты курс КА "Шаг" попрубуйте обязательно. Для первой консольной програмки самое то.


  1. GennPen
    00.00.0000 00:00
    +2

    Рис. 20 Больше HAL

    А почему бы сразу с HAL не начать? Ведь он проще для понимания, чем CMSIS.
    К тому же с HAL можно на пин повесить пользовательскую метку и писать примерно так: HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
    Соответственно, если переместите светодиод на другой пин, то достаточно перевесить эту метку и в коде ничего не нужно будет менять.


    1. Butaforsky Автор
      00.00.0000 00:00
      +1

      Добрый вечер, согласен, HAL проще для понимания, чем CMSIS, но обучалок на HAL в интернете много, а я бы хотел дать более полное представление о возможностях программирования под МК


      1. sami777
        00.00.0000 00:00

        Кроме HAL есть еще LL и ни куда не делся SPL. Поэтому среди этого зоопарка трудно разобраться. CMSIS - работа непосредственно с указателями на регистры - проще разобраться и понять аппаратную часть мк. К тому же CMSIS он по сути один для всех армов, неважно от производителя. Но работать с указателями напрямую - сложней.


    1. Dima_Sharihin
      00.00.0000 00:00
      +7

      HAL на порядок сложнее для понимания, чем CMSIS. Потому что к замороченной аппартной архитектуре IP нужно ещё и понимать индусский код HAL'а.
      Единственная вещь, где может теоретически пригодиться HAL - если не хочется вручную прописывать "многоэтапные" транзакции I2C и прочих не самых дружественных к эмбеддеру протоколов.


  1. IvUyr
    00.00.0000 00:00
    +1

    Спасибо, что не ещё одна статья «как помигать светодиодом из ардуйнины».
    И, собственно, вопрос - почему HAL а не LL?


    1. Butaforsky Автор
      00.00.0000 00:00

      Благодарю, если честно LL просто мимо меня прошел и в проектах его не использую, потому рассказываю о том,что знаю


  1. izqbr
    00.00.0000 00:00

    Самоучке возможно попасть в разработку встраиваемых систем?


    1. Butaforsky Автор
      00.00.0000 00:00

      Здравствуйте, да, возможно, в моем случае это случилось после того, как на третьем курсе университета вместе с увлекающимся силовой электроникой одногруппником начал осваивать микроконтроллеры


    1. Dima_Sharihin
      00.00.0000 00:00
      +3

      Более чем. Эмбеддед сравнительно спокойное направление, к тому же более веселое (чем тот же вебдев). Программировать тут все равно никто не умеет...


      1. izqbr
        00.00.0000 00:00
        -1

        Мне кажется для таких организаций нужны дипломы и тд


        1. Dima_Sharihin
          00.00.0000 00:00

          Дипломы нужны, но иногда работодатель идет на встречу, и (если уж сильно надо) - диплом получается паралелльно с работой при помощи заочного обучения.
          Если речь именно про "попасть в разработку" - то можно и без диплома, удержаться там - могут и попросить


          1. izqbr
            00.00.0000 00:00

            С моим увлечением Go для мк туда точно не попасть, наверное всё-таки нужно cmsis


            1. Dima_Sharihin
              00.00.0000 00:00
              +1

              Не переживайте вы сильно за инструменты, один фиг вам придется учиться с нуля на новом месте. Скажем, в микроконтроллерах обязательно знание Си, все остальные языки (в том числе С++) применяются уже по остаточному принципу. Сам Си учится за неделю самое долгое, он неимоверно примитивен, от стандартной библиотеки все равно почти ничего в эмбеддеде не используется.

              CMSIS - это стандарт ARM'а на заголовочники, специфичные для процессора, формат описания системной периферии, некоторые отдельные библиотеки, и прочие небольшие кусочки, совершенно не обязательные к применению. Лучше понимать, как вообще работают микропроцессорные системы и чем меньше прослоек между программистом и железом - тем проще идёт процесс понимания


        1. Butaforsky Автор
          00.00.0000 00:00
          +4

          По моему опыту, ни на одном собеседовании на позицию программиста микроконтроллеров про профильный диплом не спрашивали. Были вопросы касательно понимания Си и основ схемотехники


        1. Zhbert
          00.00.0000 00:00
          +1

          Ну как сказать. Если это что-то из госсектора — завод, НИИ и так далее, то там, конечно, без диплома вообще никуда. Даже если денег не платят, диплом, а лучше кандидатскую все равно подавай. А в «частных» скорее будут смотреть на опыт и портфолио. По крайней мере мои знакомые электронщики именно таким опытом делятся. Да и мой опыт в НИИ и нескольких частных компаниях конструктором говорит о том же самом.


    1. Zhbert
      00.00.0000 00:00
      +1

      Смотря куда. Я в НИИ когда работал, случайно стал разработчиком системы управления лазером :) У меня хоть и почти профильное образование было, но с МК на Си и прочей электроникой я не работал до этого.


    1. mctMaks
      00.00.0000 00:00

      да легко, если "самоучение" дается легко. Вот только зачастую помимо программирования требуется иметь знания в цифровой обработке сигналов, цифровой и аналоговой схемотехнике хотя бы на уровне чтения схемы. Да и знать как держать паяльник не помешает.
      мой путь в микропрограммисты начался с практики на том же предприятии где подрабатывал студентом. программировать умел немного на паскале и делфи, Си учил на месте. как и контроллеры. за 7 лет от новичка до ведущего инженера-программиста с учетом отсутствия профильного образования (диплом инженера средств РЭБ) вполне нормально я считаю.

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


  1. Ivan_Kadochnikov
    00.00.0000 00:00
    +10

    Настоятельно рекомендую всем, желающим разобраться с микроконтроллером, научится пользоваться периферией МК "ручками" через регистры.

    HAL, CMSIS, LL скрывают от вас всю "кухню", что не способствует пониманию логики работы МК.

    Да, это труднее, НО на много полезнее в плане развития.


    1. everis
      00.00.0000 00:00
      +6

      ++

      Не зная как работает МК внутри на уровне собственных регистров - ни один HAL в боевом проекте не поможет. К тому же в HAL том же - куча ошибок. А искать ошибки в чужом коде - втройне геморнее.


    1. Zhbert
      00.00.0000 00:00
      +5

      Полностью согласен.

      Мы начинали вообще с пикмикро на ассемблере. Когда погоняешь руками байты и биты по регистрам, увидишь результат и поймешь, почему так происходит — потом меньше непотяток в разработке под сложные большие МК, на чем бы ты ни писал.

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


    1. 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 оно не влезло )


  1. izqbr
    00.00.0000 00:00
    +1

    Я когда-то писал в айтмель студио для меги8. Работа с регистрами и тд. Сейчас pi pico блэк пилл в Ардуино иде . Иногда так хочется превратить любимое хобби в профессию


  1. webhamster
    00.00.0000 00:00

    Для настройки тактирования и периферии будем использовать ST CubeMX. Писать код будем в Keil

    Обоженьки, проприетарные закрытые программы с вендор-локом и разработчики любители Windows. В России в 2023 году. Эмдеддинг который мы заслужили...

    Ну почему хотя бы не PlatformIO?


    1. Butaforsky Автор
      00.00.0000 00:00

      Не PlatformIO, потому что там платная отладка

      В следующей статье добавлю рассмотрение вопроса по открытым IDE


      1. webhamster
        00.00.0000 00:00

        Не PlatformIO, потому что там платная отладка

        В какой момент она там стала платной?


        1. Dima_Sharihin
          00.00.0000 00:00

          Она там была платной в 2019 году, когда я крайний раз ей пользовался

          https://community.platformio.org/t/platformio-commercial-use-solved/12726/2


          1. webhamster
            00.00.0000 00:00

            since June 2019

            Ну так то уже четвертый год как everything is FREE and OPEN-SOURCE.

            Даже в неайтишном мире все гораздо быстрее меняется.


      1. Flexz
        00.00.0000 00:00

        Если уж генерить код в CubeMX, то логично продолжить написание кода в CubeIDE.


    1. Dima_Sharihin
      00.00.0000 00:00
      -1

      Потому что platformio такая же проприетарщина.
      Вообще ARM Cortex M хороши, что под них есть GCC и OpenOCD, а больше, зачастую, и не нужно


      1. webhamster
        00.00.0000 00:00

        Потому что platformio такая же проприетарщина.

        Что тогда делает этот код на GitHub https://github.com/platformio/ под лицензией Apache 2.0 https://ru.wikipedia.org/wiki/Лицензия_Apache ?


    1. DrGluck07
      00.00.0000 00:00

      Кстати, мы сейчас очень грустим от того, какое Кейл неудобное говно. Это помимо того, что его нельзя получить легально. Думаем на что пересесть, может даже QtCreator приспособить, вроде есть мурзилки как это делается.


      1. Dima_Sharihin
        00.00.0000 00:00

        VS Code + Cortex-Debug. Может не самое лучшее, но точно работающее решение.
        Ну и SEGGER RTT спасет эмбеддерщика


  1. webhamster
    00.00.0000 00:00

    -