Небольшое отступление...


В прошлом уроке мы рассмотрели с чего начать, если вы решили изучать микроконтроллеры STM32: как настроить IDE, как создать простой проект, как откомпилировать программу и как запустить программу на выполнение. После полюбовались на перемигивание светодиодов на Discovery-плате )


Начиная новую статью, я задумывал сразу же перейти к подробному разбору листинга программы, который заставлял попеременно перемигиваться наши светодиоды, но уже перейдя к написанию, я вдруг осознал для себя, что есть большое количество вопросов без ответа на которые — перейти к рассмотрению программы было бы преждевременно. И для себя я определил целый перечень таких вопросов:


  1. Что же такое битовые операции? Как ими пользоваться?
  2. Что такое регистры и как они связаны с битовыми операциями?
  3. Из чего состоят микроконтроллеры STM32F0xx-серии, как осуществляется тактирование и чем обеспечена жизнь внутри МК?
  4. Как происходит стартовая инициализация МК, зачем нужен startup-файл, что делает функция SystemInit? Объяснение на пальцах.
  5. Из чего состоит библиотека CMSIS? Как в ней ориентироваться? Что полезного можно из нее извлечь и как ей пользоваться?

Именно с рассмотрения этих вопросов я хотел бы продолжить повествование о программировании STM32.


Основные логические операции


Только начиная изучать микроконтроллеры, слова «регистр» и «битовые операции» для меня казались чем-то таинственно загадочным и я долго не хотел переходить к рассмотрению данной темы. Но когда я более-менее разобрался с тем, что это такое я понял что зря откладывал изучение такой важной темы в дальний ящик. Битовые операции наверное самые распространенные операции в микроконтроллере и знание того, как и зачем их можно применять в нашей работе — откроет перед нами огромный потенциал возможностей для управления всем и вся в нашем МК!


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

Микроконтроллер всегда оперирует только двумя состояниями: «ноль» — нет напряжения, «единица» — есть напряжение. Давайте немного освежим в голове знания о основных логических операциях т.к. они составляют основу всей цифровой техники.


  • Конъюнкция — обозначается как «Логическое И» или «Логическое умножение». В сущности, результат от выполнения данной логической операции двух для выражений А и В подобен их умножению. То есть, выражение примет значение «1» в случае только если и А, и В имеют значение «1». Во всех других случаях будет значение «0». Может обозначаться как И, &&, AND, &
  • Дизъюнкция — обозначается как «Логическое ИЛИ» или «Логическое сложение». Результат от выполнения данной логической операции двух для выражений А и В подобен их сложению. То есть, выражение примет значение «1» в случае если хотя бы одно из выражений А и В имеют значение «1». Может обозначаться как ИЛИ, ||, OR, |.
  • Инверсия — обозначается как «Логическое НЕ» или «Отрицание». Результат от выполнения данной логической операции двух для выражения А равен противоположному. То есть, выражение примет значение 1 в случае если выражение А равно 0 и наоборот. Может обозначаться как НЕ, !, NOT, ~.

  • Строгая дизъюнкция — обозначается как «Исключающее ИЛИ» или «Логическое сложение, исключающее ИЛИ». Результат от выполнения данной логической операции двух для выражений А и В примет значение 1 в случае если А и В имеют разные значения. Может обозначаться как Искл. ИЛИ, XOR, ^.

Битовые операции


Битовые операции — практически то же самое, что и логические операции только лишь с той разницей, что применяются они к битам и к числам двоичной системы.


К слову говоря, для простоты изучения битовых операций я использовал программу 32-bit ASM Calculator от ManHunter. С помощью данной программы можно проверять результаты выполнения битовых операций, переводить числа из одной системы счисления в другую. Программа имеет интуитивно понятный интерфейс и после знакомства программа стала одним из основных инструментов в моей работе с микроконтроллерами. Небольшое пояснение к интерфейсу программы данно на изображении ниже:


Битовая операция «НЕ» — "~"

Если бит равен «1», то после выполнения операции «НЕ» он будет равен «0», и наоборот. Операция сразу же выполняется над всеми битами двоичного числа. Например, инвертируем число FF:



Битовая операция «И» — "&"

Если оба бита в разряде равны «1», то после выполнения операции «И» результат в разряде будет равен «1», но если хотя бы один из битов равен «0» тогда и результат будет равен «0». Операция так же выполняется поразрядно. Например, «умножим» два числа 0xFF0 и 0xF0F:


В результате мы увидим, что в тех разрядах где были единицы в обоих числах, в результате получились единицы, во всех остальных случаях — нули.

Рассмотрим варианты практического применения:

  • В ситуации, если нам необходимо сбросить конкретный бит или группу битов в ноль мы можем использовать маску. Думаю, будет нагляднее показать это на примере. Допустим, мы берем число и 0xF8F и нам надо чтобы 7-й бит стал вместо единицы нулем. Нет проблем, накидываем маску и снимаем галочку с нужного бита. Умножаем числа и получаем результат:

  • Если нам необходимо проверить конкретный бит в числе на 0 или 1 — мы так же используя маску проводим умножение. В маске мы устанавливаем бит, который хотели бы проверить. Если требуемый бит равен «0» — то результатом вычисления будет «0», если «1» то, соответственно, «1». Если мы хотим узнать, равен ли 7-й бит единицы — делаем соответствующую маску и умножаем наше число на маску. Все просто:

    Если нам нужно проверить четность числа(имеется ввиду способность числа делиться на два) — то мы таким же образом проверяем 1-й бит, если он равен «1» — то число нечетное, если там «0» то число четное. Попробуйте сами, в целях обучения и формирования навыков, сделать данную проверку.

Битовая операция «ИЛИ» — "|"

Если один или оба из пары битов равен «1» то результат будет «1», иначе если оба бита равны «0» то результат будет равен «0». То есть, грубо говоря, производится сложение всех единиц в разрядах. Например если мы складываем два числа 0xF8F и 0x7F, то получим следующий результат:


Попробуйте самостоятельно поиграться с различными числами и понаблюдать за результатами.

Битовая операция «ИСКЛЮЧАЮЩЕЕ ИЛИ» — "^"

Если биты в разряде отличаются и не равны тогда результат будет «1», иначе «0». Например, если мы делаем XOR числа 0xF8F и 0x7F, то мы увидим что в разрядах в которых находятся отличные биты то там в результате получается «1» и в местах где биты одинаковые, будь то «0» или «1» — получился «0», в итоге мы получим следующий результат:


Рассмотрим варианты практического применения:

  • Если нам понадобилось инвертировать какие-либо биты в числе, можно используя маску с легкостью сделать это используя операцию XOR. Давайте сделаем инверсию 6 и 7 разряда в числе 0xF8 используя маску 0xC0. Результат вы можете посмотреть на изображении:

  • Бывают ситуации когда необходимо сравнить два регистра и определить равны они или нет. В этом случае нам необходимо значения регистров подвергнуть операции XOR. Если результат получился «0» — тогда регистры равны, иначе — не равны:



Битовые операции сдвига
Существует ряд интересных и порой чрезвычайно полезных битовых операций именуемых как операции сдвига. Двигать разряды можно как вправо, так и влево. В ходе данной операции происходит сдвиг всех разрядов двоичного числа на указанное количество позиций, при этом, в случае если сдвиг идёт влево — старший бит (самый левый) теряется, а в младший (самый правый) записывается «0». При логическом сдвиге вправо происходит обратная ситуация — младший бит (самый правый) теряется, а в старший записывается «0». Дополнительно хотелось бы отметить, что в случае 32-разрядных слов сдвигаются все 32 разряда целиком. Рассмотрим операции сдвига подробнее.


Cдвиг влево — "<<"

То, как происходит сдвиг вы можете увидеть на изображении ниже. Думаю, что всё достаточно очевидно:


При двоичном сдвиге можно заметить одну интересную особенность. Сдвиг на один разряд умножает наше число на 2. Если сдвинуть на n разрядов наше число x то получится x * (2 * n). Попробуйте самостоятельно отследить эту закономерность через нашу утилку для подсчета. =)

Cдвиг вправо — ">>"

То, что получается в результате сдвига вправо достаточно наглядно отражено на изображении:


При двоичном сдвиге вправо можно заметить что происходит ситуация обратная сдвигу влево — число делится на 2 с при сдвиге в 1 разряд и после на 2 * n, где n — количество разрядов на которые произведен сдвиг. Так же попробуйте самостоятельно поиграться с числами и которые заведомо делятся на 2 нацело. И вопрос на засыпку — какой результат будет если вы поделите таким образом нечетное число?

Важное замечание. Если вы будете делать сдвиг для переменной с отрицательным знаком (signed) — освободившиеся позиции будут заполняться единичками.

В качестве заключения...


Многим начинающим данная тема может показаться дико скучной и может сложиться ощущение что ну вообще не понятно где и как можно применить эти знания. Спешу вас обнадежить, в ситуациях когда нужно поднять ту или иную ногу МК или записать параметр в какой-нить периферийный блок или модуль — там кругом и всюду будут требоваться знания битовых операций. Так как статья получилась достаточно объемной, рассмотрение регистров мы перенесем на следующий урок. Ну и в последующем можно использовать эту статью как шпаргалку.


В качестве домашнего задания попробуйте самостоятельно разобрать код нашей программы в блоке while(1) {… } и понять как же битовыми операциями мы включаем и выключаем наши светодиоды. Ну а на следующем уроке я расскажу как оно происходит на самом деле!

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


  1. Mirn
    26.09.2017 22:41
    +2

    а почему с битовых операций?
    я вижу два пути в микроконтроллеры — из схемотехника когда на обычных гейтах уже сложно и надоело лепить и нужны алгоритмы типа антидребезга, но в этом случае человек уже наверняка знает эту тему.
    Либо же из программирования, но что за программист не умеющий в булевую логику? Может быть в вебе сейас таких немало но тогда зачем ему МК?
    Честно не пойму зачем этот 1 класс нужен.
    Ну и непонятно зачем тогда STM32 в заголовке.

    Я бы советовал начать сразу с:
    «Из чего состоит библиотека CMSIS? Как в ней ориентироваться? Что полезного можно из нее извлечь и как ей пользоваться?», это реально акутальная и мало раскрытая тема, особенно судя по мегатоннам тривиальных асмовских самописных функций — люди не знают что многое делается при помощи CMSIS в пару строк и на простом си.
    Да и пункт №3 тоже полезен для тех кто на английском документацию не может читать.

    т.к. «startup-файл» редко когда нужно править, да и наверняка будет разобран ассемблеровский вариант, т.е. bad practice — мамонт доставшийся от уважаемой пары старичков кейла с иаром. Всё для STM32 можно сделать на си. Асм в современных микроконтроллерах это очень не нормально и странно.


    1. NeoCode
      27.09.2017 07:43
      +1

      Согласен. Я бы тоже начал с CMSIS, стартап-файла и архитектуры самого контроллера. Там дофига тонких и малопонятных тем вроде начального конфигурирования контроллера. А уж с битовыми опрациями кто угодно разберется.
      Но если уж говорить о битовых операциях — то я не уверен что в статье исчерпывающий перечень. Вроде бы еще в различных архитектурах бывают вращения, прямая работа с битами по номеру, поиски единичных битов, разворот битов в слове. В ARM точно некоторые из них есть (а может и все). Это более редкие (почему-то) инструцкции и для них нет привычных операций в си-подобных языках.


      1. megalloid Автор
        27.09.2017 08:02

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


        1. NeoCode
          27.09.2017 09:04

          Почему? Что сложного в циклическом сдвиге по сравнению с обычным?


          1. megalloid Автор
            27.09.2017 09:51

            В виду прикладной невостребованности на начальном этапе изучения. ИМХО.


            1. Mogwaika
              27.09.2017 16:49

              Смотря с какой стороны подходить к изучению. Я вот подхожу к изучению С и микроконтроллеров со стороны верилога…


    1. Jmann
      27.09.2017 09:20
      +1

      Это фундаментальные знания… Я хоть это уже давно проходил, но для начинающих это хороший базис! Я например забрал к себе калькулятор из этой статьи.


      1. Alexeyslav
        27.09.2017 10:29

        А можно его где-то ещё выложить? А то почему-то «Access Denied» на весь сайт…


        1. megalloid Автор
          27.09.2017 13:02

          Вчера проверял ссылку — всё было ОК. Попробуйте открыть сайт через прокси, VPN или просто по названию программы поищите в гугле.


          1. Jmann
            27.09.2017 17:04

            Я с утра нормально зашел и забрал. Да и сейчас открывается.


            1. Alexeyslav
              27.09.2017 17:27

              Что поделаешь, видимо ограничение по геолокации. Что довольно странно для интернета, надо попробовать ещё с другого провайдера.

              Пробовал проследовать туда по https но походу там другой сайт висит, ругается на неверный сертификат(от другого сайта) и выдаёт ошибку 500.

              Гугл кстати выдаёт ссылки только на этот же сайт, на других рассматривается уже другой калькулятор.


      1. BigBeaver
        27.09.2017 11:13

        Начинать можно прекрасно без этого — не на асме же писать планируете?


        1. Jmann
          27.09.2017 11:16

          Ну когда-то я втыкал в сайт EasySTM32 и проекты на CMSIS… Вот вроде понятно, но местами какая-то битовая операция автором не объясненная и сиди гадай, что это такое. Потом я с горем пополам написал на CMSIS гирлянду и ушел в SPL. Но в STM пока на уровне свистелок и мигалок с LCD 1602.


          1. BigBeaver
            27.09.2017 11:25

            Тогда надо с архитектуры начинать. Что такое АЛУ, что такое счетчик адреса, что такое шина… Это тоже все фундоментальные знания.


            1. Jmann
              27.09.2017 13:53

              Тут книгу тогда писать необходимо.


            1. megalloid Автор
              27.09.2017 14:05

              Без обзорного рассмотрения данных тем не обойдется 100%.


    1. Goron_Dekar
      27.09.2017 10:14
      +5

      Вот как же надоело это «как пользоваться той или иной библиотекой»
      Я бы хотел в любиттельском МК больше видеть людей, которые, когда пишут код, думают не о том, как это потом поддерживать/реюзать/портировать, а о том, в какой машинный код это собирётся, и как сделать так, чтобы вход-обработка прерываний-выход занимали как можно меньше тактов. Потом, когда они пойдут в профессиональное программирование, они научатся.
      Такие люди должны очень хорошо разбираться в булевых операциях. Поэтому важно в начале тщательно их приподнести. Да, половина читателей знакомы с ними. Ещё треть знает половину их. А оставшаяся часть только думает, что знает.

      А вот это всё «библиотека CMSIS», «HAL», «CAN для начинающих» — этого в интернете навалом. И писать о том, как можно портировать iconv на stm32 для того, чтобы на лету менять кодировку на символьном экране — хватит уже!


      1. megalloid Автор
        27.09.2017 10:30

        Воистину плюсую. Я считаю что библиотеками надо начинать пользоваться когда ты уже знаешь как это всё функционирует на низком уровне. Абстрагироваться от имеющихся знаний чтобы не держать в голове весь объем информации. Восходящая абстракция так скажем. А не наоборот.


  1. megalloid Автор
    26.09.2017 22:58

    1. Я в изложении в первую очередь опираюсь на то, как я начинал в свое время и в какой последовательности изучал темы. И долбёжку в регистры с булевыми операциями освоил только когда начал кодить под МК.
    2. Заголовок в целом обозначивает принадлежность к циклу статей которые я буду периодически публиковать.
    3. Я не знаю о том, с каким уровнем подготовки читающие попадут сюда и будут знакомиться с моим циклом статей. Поэтому я решил перестраховаться, для себя счёл логичным рассмотреть данную тему в совокупности с рассмотрением утилки для удобной работы с бинарными числами, уж лишним точно не будет. =)
    4. Над 3им и 4ым пунктом еще нужно будет много подумать.


  1. Koyanisqatsi
    26.09.2017 22:59
    +2

    Как я и боялся, вы начали со слишком низкого уровня. Хорошо хоть не с «Что такое электричество».


    1. megalloid Автор
      26.09.2017 22:59
      +1

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


    1. megalloid Автор
      26.09.2017 23:03
      +1

      Думаю, что еще успею и Вас порадовать чем-нибудь интересным!)


      1. Koyanisqatsi
        27.09.2017 00:04

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


  1. BigBeaver
    27.09.2017 00:01
    +2

    Неплохой материал (все знаю. но буду тыкать носом спрашивающих), но при чем тут STM32? Это же все платформонезависимые вещи — самая база, так сказать.


    1. megalloid Автор
      27.09.2017 06:22

      Это все в рамках одного цикла статей, объединенного общей логикой.


      1. BigBeaver
        27.09.2017 07:06

        Тогда бы примеры кода не помешали.


        1. megalloid Автор
          27.09.2017 07:11

          О, это непременно будет предоставлено)


          1. BigBeaver
            27.09.2017 07:48

            То есть, будет огромная куча микростатей?

            P.S. мне-то не надо, но пока это выглядит как урезанный пересказ школьного курса.


            1. megalloid Автор
              27.09.2017 07:54

              Я подразумеваю написание цикла статей по данным МК.
              От базовых основ до рассмотрения конкретных вопросов.
              Логика будет в том, что мы подойдем к реализации целевого устройства, с создания которого всё и началось, через изучение тем которые касаются STM32 прямым или косвенным образом.
              На текущий момент да, так и есть. Основа основ. Для самых зелёных.


  1. shell4692
    27.09.2017 06:08
    +7

    Вот не совсем понятна целевая аудитория автора. Люди, которые не понимают основы языка и битовые операции, уж точно не пойдут на stm32. Для таких людей вполне подходит Ардуина. По моему разумению, stm32 не есть платформа для начинающих (особенно такого уровня, где человек не знаком с основами двоичной арифметики). STM32 — адское место даже для продвинутых профессионалов, особенно на уровне CMSIS. Периферия STM32 чрезвычайно сложна, регистры и их поля существенно различаются в разных семействах stm32. Например, при работе с модулем I2C нужно записывать в регистр некую константу, вычислить которую можно либо в Excel-утилите, которая есть на сайте STMicro, либо через STM32CUBEMX.

    Если уж действительно обучать ИМЕННО stm32, наверное, нужно знакомить читателя не с битовыми операциями, а с общей архитектурой? Нужно показать, из чего она состоит, в какие группы объединяется периферия, какие шины её соединяют и какая схема тактирования этих шин. Также неплохо особенно подчеркнуть, что в Stm32 процессорное ядро является не монолитным, а входит в общий кластер периферии как модуль.

    Говоря о тактировании, хорошо бы упомянуть про RCC, без понимания работы которого нет смысла вообще связываться с stm32. И почему бы, на этапах ознакомления с общей архитектурой, не использовать PeripheralLibrary, которая как раз позволяет сосредоточиться на функциональности периферии, общих принципах её работы, а не на деталях программирования регистров?

    Опять же, самая главная книга при работе с stm32 это Reference manual. Почему бы не указать людям ссылку на источник?


    1. megalloid Автор
      27.09.2017 06:20

      Мне кажется Вы существенно преувеличили сложность STM32. Я начинал изучение и программирование МК именно с STM32. Все основы закладывал при работе с ним, в т.ч. и битовые операции.
      В процессе написания статей я рассчитывал осветить целевые вопросы для людей самого широкого уровня подготовки, готовых учиться.
      В целом, ведь никто не мешает пропустить материал по теме которого уже имеется достаточно знаний и опыта и перейти к рассмотрению более интересных вещей.
      Насчёт I2С. Ничего страшного в этой константе нет совсем))) ну и я даже как новичок не соглашусь с определением «сложная периферия». Я бы тут употребил «всеобъемлющая» и «гибко настраиваемая».
      Я безусловно ценю Ваше мнение но всё же, я буду строить логику изложения таким образом, как бы повторяя то, с чего я начинал и какие темы изучал сам на момент обучения. И ориентируюсь на создание такого обучающего материала, которого мне так не хватало в свое время.


    1. Jmann
      27.09.2017 13:55

      Когда-то мы в универе учились на аврках и пиках. С удовольствием бы их выбросил, и учил бы СТМ, но тогда, в 2005…


  1. Ghost_nsk
    27.09.2017 06:56

    сравнить два регистра и определить равны они или нет. В этом случае нам необходимо значения регистров подвергнуть операции XOR

    Я не силен в ARM, но обычно сравнение делается через вычитание без сохранения результата но с модификацией флагов, одним простым действием можно сразу понять равно, меньше или больше.


    1. BigBeaver
      27.09.2017 06:59

      А еще можно просто сравнить, и компилятор сам все распишет, как надо.


      1. Ghost_nsk
        27.09.2017 11:03

        Как вы от сравнения регистров перешли к компилятору?


        1. BigBeaver
          27.09.2017 11:22

          А в чем проблема? Регистр это один или несколько байт. Мне ничто не мешает написать что-то вида

          if (PORTA==24) {do some code;}
          При этом меня слабо волнует, какой там набор инструкций у камня, и как компилятор это раскроет. По крайней мере, до тех пор, пока я не захочу строгий реалтайм…

          А первые программы можно вообще без знания даже о самом существовании битовых операций (а также — структуры АЛУ, его флагах и тд) писать. Потому я, хоть убейте, не понимаю, почему автор начал изучение архитектуры со школьной математики (~7 класс, емнип. у кого не было отдельно логики, должны были классе в 10-11 это на информатике пройти).


          1. Ghost_nsk
            27.09.2017 18:13

            Плохо что не интересует, ну хотя бы для того, что бы в дискуссии про регистры, не писать PORTA


            1. BigBeaver
              27.09.2017 18:25

              PORTA это тоже регистр, в чем проблема? Битовые операции чаще всего как раз с портами и делают (особенно — новички, которые пишут мигалку). Можно было любой другой (доступный на чтение) привести для примера — суть бы не изменилась.

              Плохо что не интересует
              Не понимаю, о чем вы.


              1. Ghost_nsk
                28.09.2017 07:06

                PORTA это регистр устройства, для процессора это порт ввода/вывода, для обращения к которым есть свои отдельные команды (IN/OUT), напрямую делать с ними битовые операции, без загрузки в РОН, невозможно. Под словом регистр обычно и понимаются РОН — регистры общего назначения.


                1. BigBeaver
                  28.09.2017 08:33

                  Спасибо, я знаю архитектуру микроконтроллеров. В тексте, на который я отвечал речь о просто абстрактных регистрах с точки зрения программиста. Не? Да, АЛУ в AVR работает только с регистрами общего назначения, но пойнт в том, что мой код выше все равно является валидным (спасибо компилятору). Кроме того, нет принципиальной проблемы сделать процесор, АЛУ которого будет напрямую работать еще и сс регистрами портов или другой переферии. То есть, это архитектурозависимо (даже если архитектур, где такое есть не существует).

                  Под словом регистр обычно и понимаются РОН
                  А это — культурозависимо. Везде принято разное. А то, вы так возмущаетесь, как будто бы назвать регистр порта регистром это что-то плохое. В окружающей меня культуре регистр это просто массив бит, реализованный в железе с известным способом доступа (ну там сдвиговые регистры и что угодно еще).

                  Если же мы говорим о сравнении чисел с помощью АЛУ, то вы правы насчет вычитания с последующей командой ветвления. На известных мне архитектурах это работает именно так. А вот только сейчас мне пришла мысль, что автор имел ввиду под сравнением регистра поиск отличающихся бит — собственно, ее XOR нам и даст (получим своего рода маску). Но слово регистр там опять же зря упомянуто — битовые операции с точки зрения математики работают с любыми массивами бит. Думаю, возникновение таких неточсностей нормально, когда неэлектронщик что-то узнал об электронике и хочет научить остальных.


                  1. Alexeyslav
                    28.09.2017 08:46

                    «Это не этот регистр а тот регистр который регистр...» с точки зрения электроники, конечно, это массив синхронных триггеров, но… должно же быть какое-то однообразие в терминологии чтобы отличать РОН от регистров периферии и т.д.
                    Прямое подключение АЛУ с регистрами периферии создаёт больше проблем и трудностей чем решает.


                    1. BigBeaver
                      28.09.2017 09:01

                      Прямое подключение АЛУ с регистрами периферии создаёт больше проблем и трудностей чем решает.
                      Полнотью с этим согласен — потому и не применяется. По сути, оно ломает модульность архитектуры. Но я лишь хочу показать, что отсутствие таких реализаций не является каким-то фундоментальным правилом.
                      должно же быть какое-то однообразие в терминологии чтобы отличать РОН от регистров периферии и т.д.
                      Все правильно. Аббревиатура РОН для этого и существует. Я лишь хотел сказать, что текст автора полностью архитектуронезависим и не содержит ни строчки кода. Нет абсолютно ни какой возможности предполпгпть, о каких регистрах речь, и почему он вообще употребил там слово «регистр», когда «байт» было бы уместнее. Тк текст, по сути, про математику, а не про микроконтроллеры.


    1. Vcoderlab
      27.09.2017 09:32

      В далёком детстве где-то читал, что «xor ax, ax» выполняется быстрее, чем «mov ax, 0». Интересно, справедливо ли это сейчас, для современных МК и процессоров?


      1. ploop
        27.09.2017 09:52

        Зависит от архитектуры. В основном равнозначно — 1 такт.


        1. Alexeyslav
          27.09.2017 11:59

          На x86 во втором случае процессор кроме КОП должен считать ещё и константу, вероятно 32-битную если не 64-битную. Поэтому в любом случае это будет ДОЛЬШЕ.
          Для AVR константа входит в фиксированного размера КОП, поэтому там будет равнозначно но играют другие ограничения — из-за нехватки битов в КОП из-за константы такая операция может быть выполнена только с ограниченным набором регистров.
          STM32 не имеет фиксированного размера команды, поэтому отличия выполнения XOR и прямой загрузки константы всё-же будут.
          Кстати интересный факт. В ассемблере AVR есть псевдокоманда CLR rx обнуляющая регистр, а на самом деле КОП у неё такой же как у XOR rx, rx.


          1. marsianin
            28.09.2017 08:10

            Для микроконтроллеров это может быть и справедливо, но современные процессоры грузят команды не по одной, а большими блоками. Здесь может сыграть роль то, что в общем случае 'xor rax, rax' зависит по данным от предыдущего значения rax, а 'mov rax, 0' — не зависит. Поэтому код с mov может выполняться быстрее за счёт лучшего планирования. Однако, лучше здесь читать Intel software optimization guide.


            1. BigBeaver
              28.09.2017 08:35

              А еще mov работает с любыми регистрами, а не только доступными напрямую для АЛУ. Что делает код, как минимум единообразнее.


              1. marsianin
                28.09.2017 11:16

                Это на самом деле разные инструкции mov, кодировки у них совершенно разные. Просто в ассемблере пишутся одинаково, что вызывает недоумение у новичков в стиле: «а почему можно сделать mov eax, dword ptr [edx + 4*ecx +100500], но нельзя сделать mov cr0, dword ptr [edx + 4*ecx +100500]?»


                1. BigBeaver
                  28.09.2017 11:37

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


                1. Alexeyslav
                  28.09.2017 13:10

                  Я знаю откуда это пошло… был когда-то нормальный ассемблер семейства Z80 где инструкции различались логично — отдельно LD для регистров и отдельно MOV для более сложных вариантов типа регистр-память. А кто-то решил что это слишком сложно для студентов и «сократил» количество сущностей. В итоге правильное и логичное описание системы команд я нашел только в одной из первых книг по этой теме, в более новых уже была новая методика с сокращенной системой и массой ньюансов в поведении казалось бы простых команд.


                  1. BigBeaver
                    28.09.2017 13:13

                    LD ни куда не исчезло же. В AVR с десяток его вариаций.


          1. ploop
            28.09.2017 09:15

            Кстати интересный факт. В ассемблере AVR есть псевдокоманда CLR rx обнуляющая регистр, а на самом деле КОП у неё такой же как у XOR rx, rx.

            Таких команд там несколько, по сути это алиасы на другие на аналогичные команды, что видно по кодам.

            Забыл за давностью лет какие ещё, а ведь раньше не переваривал Си и строчил только на асме… Если сейчас считается круто поглядеть ассемблерный листинг после компилятора, то раньше поглядывали на КОПы после ассемблера :)


            1. Alexeyslav
              28.09.2017 11:09

              А я всё ещё не перевариваю Си.


              1. ploop
                28.09.2017 12:08

                Вы просто не умеете его готовить :)


            1. Ghost_nsk
              29.09.2017 13:13

              в x86 есть такие же вещи, например nop по опкоду равен xchg eax,eax


      1. Ghost_nsk
        27.09.2017 10:47

        Так же, но команда короче


    1. marsianin
      28.09.2017 08:00

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


      1. Ghost_nsk
        29.09.2017 13:15

        А в чем профит то? по скорости одинаково, зачем тогда делать две операции «для всего» и «только равно»?


  1. melchermax
    27.09.2017 07:04
    +1

    Спасибо за публикацию, непременно пишите ещё!


  1. shell4692
    27.09.2017 07:18
    +3

    Я так увлёкся написанием ответа на Вашу статью :))), что забыл упомянуть о том, что константа для инициализации I2C используется только в семействе stm32f0x. В других семействах, никакой необходимости в ней нет. Однако, не могу с Вами согласиться, что подобная константа является очень удобной. Ей нельзя просто так вот взять с «с потолка». Игнорировать её тоже нельзя. И обойтись без неё (как в семействах stm32f10x или stm32f20x) тоже.

    Насчёт «гибко настраиваемой» периферии я полностью с Вами согласен, но сложность, на мой взгляд, всё же имеется. И она проистекает не только из обилия функция (хотя бы того же I2C), а из алгоритмов её использования (согласно Справочному руководству). В каждом семействе не только различаются регистры одной и той же периферии, а также различны и действия, которые нужно совершить для получения желаемого результата. Кроме того, чем ближе к регистрам, тем менее переносимой становится прошивка.

    В частности, по сравнению с Atmel контроллерами, у которых периферия в разных семействах работает по схожему принципу, в stm32 очень существенно различаются регистры, правила инициализации и текущая работа с одним и тем же периферийным модулем. Вплоть до того, что в разных семействах, один и тот же периферийный модуль может находиться на разных шинах.

    CubeMX был сделан не просто так — он был сделан, чтобы вынести работу с периферией в HAL и абстрагироваться от неё. Структура HAL во многом напоминает PerLib. Не готов утверждать, что это хорошоее решение, однако оно как нельзя лучше демонстрирует, что «не всё так гладко в Датском королевстве».

    А насчёт сложностей, они обычно возникают не при мигании светодиодами, а где-то при написании, к примеру, многопоточного приложения, в котором на одной шине I2C1 висят LCD1602 экран (через расширитель порта PCF8574T), просто расширитель порта PCF8574T для клавиатуры, ds2482s-100, который опрашивает 5 термодатчиков ds18b20, а на шине I2C2 висят, например 3-4 других модуля с другими МК (к примеру 30й серии). При этом также используется USART1 для управления несколькими блоками по RS485 и протоколу MODBUS. И всё это в одном единственном stm32 (правда f103).

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


    1. megalloid Автор
      27.09.2017 07:33

      Я по большей части хотел сказать, что мой уровень опыта работы и тип решаемых задач на текущий момент не располагает к таким выводам)))
      Но и с Вашим мнением невозможно не согласиться!) Очень ценю Ваши объемные комментарии!


  1. Serge78rus
    27.09.2017 09:12

    Основы языка C все же лучше изучать на десктопе и только после этого переходить к программированию микроконтроллеров.


    1. Jmann
      27.09.2017 09:28

      Согласен. Консолька наше все.


  1. besitzeruf
    27.09.2017 10:46

    сколько можно уже начинать? все это уже перелопачено по 10 раз, пора двигаться дальше с такими МК.


  1. ZhenyaGn
    27.09.2017 13:26
    +1

    Возможно есть смысл после выхода всех статей цикла объединить их в руководство/пособие/соединить в одну pdf'ку


    1. megalloid Автор
      27.09.2017 13:30

      Я задумывался об этом, прикидывал. Если будет широкая заинтересованная аудитория — почему нет, думаю что было бы интересно. Посмотрим что выйдет из этого цикла статей.


  1. R4ABI
    27.09.2017 16:46
    -2

    По STM-ама уже столько написано и разобрано… зачем еще то? Кому надо уже освоили миллион статей в интернетах, а кому не надо — уже ни чем не помочь.


  1. Hoksmur
    28.09.2017 12:31

    Вы забыли главное — зачем это всё? Дополните, как пользоваться масками, выделять, маскировать биты. Бытовые операции в подавляющем большинстве случаев ведь используются для этого. Если нет — могу я натоптать.


    1. megalloid Автор
      29.09.2017 09:49

      Маски же я рассмотрел? Не? Уточните что добавить?


      1. ploop
        29.09.2017 10:02
        +2

        В Си-синтакисисе было бы полезно:

        LED_PORT &= ~(1<<LED2);
        LED_PORT |= 1<<LED2;
        LED_PORT ^= 1<<LED2;


      1. Hoksmur
        29.09.2017 12:00

        Возможно, я не совсем точно выразился. У вас упущен момент почему так происходит (или я его при беглом чтении мог пропустить).
        Как выделить часть байта?
        flags = byte & 0x30;
        Почему так происходит?


        x & 0 = 0
        x & 1 = x

        Таким образом


          xxxx xxxx
        & 0011 0000
        --------------
          00xx 0000

        С пояснениями, и добавить для ИЛИ, почему на нём инвертируется маска.