4

Немного о портах и битовых операциях

Многие из вас видели и наверно даже понимают, что такое

DDRB |= (1 << 5);

PORTB |= (1 << 5);

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


Основная опасность и в то же время преимущество управления портами напрямую без прослоек типа digitalWrite() - это то, что вы можете управлять сразу 8 портами всего за 1 строчку кода, которая в свою очередь выполняется достаточно быстро, намного быстрее стандартной функции.

Но если необходимо подергать частью портов так, чтобы не сбить какие-либо связи на других портах - надо изолировать эти обращения. Тут на помощь и придет битовая логика.


Например надо настроить на вывод 11, 12, 13 порт уны, а 8, 9, 10 не трогать. Для этого нужен оператор "ИЛИ", который обозначается '|':

DDRB |= B00111000;

или

DDRB |= (B111 << 3);

Оба варианта делают абсолютно одно и то же. Сдвиг влево (<<) задается количеством бит, на которое сдвигается значение. Сдвигая B111 на три бита, получаем B111000. Можно сказать, что мы добавляем определенное количество значащих нулей.


Теперь разберем, почему оператор | так важен. Для этого надо понять, что делает этот оператор:

0101 (decl 5)  

0011 (deс 3)

OR=

0111 (dec 7)

Если по-простому - при установке единицы меняет 0 на 1, а при установке 0 в бит, где есть единица - не меняется ничего, так же и при установке ноля в 0. То есть мы установили на вывод три бита, не затронув остальные, которые так же могли быть уже назначены выводами.


Но если надо выставить 0 так, чтобы не прибить остальные биты в 0, нужен оператор "И", обозначающийся &. Так же к нему понадобится оператор "НЕ" - обозначается ~.


Итак, выключаем светодиод на 13 пине:
PORTB &= ~(1 << 5);

или

PORTB &= ~B00100000;

Я лично предпочитаю левый сдвиг тогда, когда мне надо выставить определенный порт, так не запутаюсь в количестве нолей, и записывать битовые значения, когда мне надо дернуть несколько. Так нагляднее, а насчет быстродействия сказать не могу - в ассемблере и то, и другое выполняется в одну команду.

Итак, ~ переворачивает все с ног на голову:

~B00100000 = B11011111

А оператор & как раз нолем меняет любую единицу на ноль, а единицей не меняет ничего. В итоге - 1 выключенный бит без беспокойства остальных. "И" в двоичной математике - это умножение: умножаем 1 на 0 - и получим 0, а 1*1=1.


Так же есть исключающее "ИЛИ" или XOR в английском варианте - ^. С помощью него можно поменять значение определенного бита. Например:
B11011111 ^= B00110000;
будет иметь в итоге

B11101111.

Вкратце: с помощью единицы меняем бит на противоположный, ноль ничего не делает.


Теперь можно поговорить о цифровом чтении портов. Перед чтением необходимо установить 0 в нужные биты:
DDRB &= ~B00000001;

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


И благодаря тому, что мы оперируем сразу 8 портами одновременно, можно не городить конструкции типа
if(digitalRead(8) && digitalRead(9) && digitalRead(11) && digitalRead(13)){....}

А сделать небольшую маску сравнения:

if(PINB & B00101011){....}

Работает точно так же, но экономит место в памяти контроллера, плюс выигрыш в быстродействии. Главное от наводок защититься подтягивающими резисторами, иначе даже digitalRead не спасет.



Напоследок расскажу один чит, который подглядел в оригинальных библиотеках для shiftOut, и не сразу смог понять, что же он делает:
!!(val & (1 << i))

Разгадка оказалась на поверхности, но о ней по порядку: '!' - это НЕ в логических операндах, работает так:
!1=0

!255=0

!0=1


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

0. !!(val & (1 << i))

1. !!(B1110 & (1<<2))

2. !!(B0100)

Поскольку B0100 равно или больше единицы, однократное НЕ приведет к нолю, а двухкратное к единице, переход через 0 позволяет оставить лишь суть:

3. !(0)

4. (1)


Таким нехитрым образом можно разобрать любое число на отдельные биты.

Arduino & Pi

1.5K постов20.9K подписчиков

Правила сообщества

В нашем сообществе запрещается:

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

• Задавать очевидные вопросы в виде постов, не воспользовавшись перед этим поиском

• Выкладывать код прямо в посте - используйте для этого сервисы ideone.com, gist.github.com или схожие ресурсы (pastebin запрещен)

• Рассуждать на темы политики

• Нарушать установленные правила Пикабу

Темы

Политика

Теги

Популярные авторы

Сообщества

18+

Теги

Популярные авторы

Сообщества

Игры

Теги

Популярные авторы

Сообщества

Юмор

Теги

Популярные авторы

Сообщества

Отношения

Теги

Популярные авторы

Сообщества

Здоровье

Теги

Популярные авторы

Сообщества

Путешествия

Теги

Популярные авторы

Сообщества

Спорт

Теги

Популярные авторы

Сообщества

Хобби

Теги

Популярные авторы

Сообщества

Сервис

Теги

Популярные авторы

Сообщества

Природа

Теги

Популярные авторы

Сообщества

Бизнес

Теги

Популярные авторы

Сообщества

Транспорт

Теги

Популярные авторы

Сообщества

Общение

Теги

Популярные авторы

Сообщества

Юриспруденция

Теги

Популярные авторы

Сообщества

Наука

Теги

Популярные авторы

Сообщества

IT

Теги

Популярные авторы

Сообщества

Животные

Теги

Популярные авторы

Сообщества

Кино и сериалы

Теги

Популярные авторы

Сообщества

Экономика

Теги

Популярные авторы

Сообщества

Кулинария

Теги

Популярные авторы

Сообщества

История

Теги

Популярные авторы

Сообщества