Следующий код устанавливает вывод AVR (PD1) на высокий уровень (при условии, что он уже включен как выход):
PORTD |= (1 << 1);
Компилятор AVR GCC хорош для компиляции подобного кода в одну инструкцию сборки AVR (с именем sbi
), но только если он точно знает во время компиляции, в какой регистр вы записываете (PORTD
), и что бит, который вы устанавливаете (бит 1).
Существует множество преимуществ использования одной инструкции вместо нескольких инструкций для установки бита:
- Требуется меньше места для кода.
- Работает быстрее.
- Это безопасно делать даже в том случае, если может выполняться прерывание, которое изменяет один и тот же регистр, поскольку шаги чтения, изменения и записи выполняются в одной инструкции, которая не может быть прервана.
Если вы используете макросы препроцессора, определенные с помощью #define
, для определения ваших выводов, то после запуска препроцессора ваш код будет выглядеть так же, как и код выше, и должен скомпилироваться в одну инструкцию.
С другой стороны, если вы используете структуры для определения выводов и динамически передаете эти структуры в свою библиотеку, есть большая вероятность, что компилятор не сможет выполнить эту оптимизацию.
Вот ссылка, где вы можете увидеть оба метода установки пин-кода и увидеть, что метод struct намного менее эффективен:
https://godbolt.org/g/mkxHc2
Обратите внимание, что существует много других способов задания и управления выводами, помимо двух методов, обсуждаемых здесь. Библиотеки Arduino обычно представляют контакты в виде одного числа, а затем вызывают функции, такие как pinMode
и digitalWrite
, для управления указанным контактом. (Реализации pinMode
и digitalWrite
довольно неэффективны и должны отключать прерывания, но их можно улучшить.)
Более продвинутый метод заключается в использовании параметров шаблона C ++ для задания выводов, как в FastGPIO library .