Главная chevron_right Уроки chevron_right Программирование chevron_right Битовые маски (Bit Masks) в Arduino

Битовые маски (Bit Masks) в Arduino

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

Битовые маски — это способ получить доступ к конкретным битам внутри байта. Особенно часто они нужны при последовательной передаче данных через один пин: состояние пина меняется для каждого бита передаваемого байта по очереди. Для этого используются побитовые операции (bitwise operations) и сама битовая маска.

Побитовые операции

Побитовые операции работают прямо на уровне отдельных битов. В Arduino (и в языке C/C++ вообще) доступны четыре основных оператора:

  • AND (&)
  • OR (|)
  • Left Shift (<<)
  • Right Shift (>>)

AND (&)

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

Например:

    x:  10001101

    y:  01010111

x & y:  00000101

Это удобно для «вырезания» нужного бита: если наложить маску с единицей в нужной позиции, все остальные биты обнулятся.

OR (|)

Оператор OR (также называемый «включающим ИЛИ») даёт 1 там, где хотя бы одно из входных значений равно 1.

Например:

    x:  10001101

    y:  01010111

x | y:  11011111

OR используют, когда нужно принудительно выставить определённые биты в 1, не трогая остальные.

Left Shift (<<)

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

Например:

        y = 1010

        x = y << 1

yields: x = 10100

Все биты байта сдвигаются на одну позицию влево. Бит, вышедший за пределы байта слева, просто отбрасывается, а справа появляется 0.

Right Shift (>>)

Оператор сдвига вправо работает симметрично: биты смещаются к младшему разряду.

Например:

        y = 1010

        x = y >> 1

yields: x = 0101

Бит, вышедший за правый край, теряется, а слева добавляется 0.

Практический пример: передача байта через один пин

Возьмём значение 170, которое в двоичном виде выглядит как 10101010. Нужно «выдать» этот байт побитово через пин 7. Код выглядит так:

byte transmit = 7; //определяем пин передачи
byte data = 170; //значение для передачи, двоичное 10101010
byte mask = 1; //наша битовая маска
byte bitDelay = 100;

void setup()
{

   pinMode(transmit,OUTPUT);
}

void loop()
{

  for (mask = 00000001; mask>0; mask <<= 1) { //перебираем биты маски

    if (data & mask){ // если побитовое AND истинно

      digitalWrite(transmit,HIGH); // отправляем 1

    }

    else{ //если побитовое AND ложно

      digitalWrite(transmit,LOW); // отправляем 0

    }

    delayMicroseconds(bitDelay); //задержка

  }
}

Здесь цикл FOR перебирает все восемь бит с помощью переменной-маски mask. На каждой итерации маска сдвигается на одну позицию влево — так «единица» последовательно проходит через каждую битовую позицию байта.

Как это работает шаг за шагом

Используется оператор <<=, который является сокращённой формой записи << — он просто компактнее.

Первая итерация: mask = 00000001

  00000001
& 10101010

  ________

  00000000

Результат операции AND равен 0, значит пин устанавливается в LOW.

Вторая итерация: mask = 00000010

  00000010
& 10101010

  ________

  00000010

Результат равен 1 (не ноль), значит пин устанавливается в HIGH.

Цикл продолжает работу, пока единица в маске не выйдет за пределы восьми бит — тогда mask становится равна 0, условие цикла нарушается, и все восемь бит переданы.

Типичные ошибки

  • Перепутать & и &&: одиночный & — это побитовый AND, двойной && — логический AND для условий. Это разные операции.
  • Забыть начальное значение маски: маска должна начинаться с 1 (то есть 00000001), иначе ни один бит не будет выделен корректно.
  • Неверное направление сдвига: если данные нужно передавать начиная со старшего бита (MSB), маска должна стартовать с 10000000 и сдвигаться вправо (>>).

Где это пригодится

Битовые маски активно применяются при:

  • программной реализации протоколов передачи данных (SPI, 1-Wire, собственные протоколы);
  • работе с регистрами микроконтроллера напрямую;
  • компактном хранении набора флагов (8 булевых значений в одном байте);
  • обработке пикселей в графических приложениях.