Arduino:Основы/Битовые маски

Материал из Онлайн справочника
Перейти к навигацииПерейти к поиску

Перевод: Максим Кузьмин
Проверка/Оформление/Редактирование: Мякишев Е.А.


Битовые маски[1]

Битовые маски используются, чтобы получить доступ к конкретным битам в байте. В частности, их используют для итерации, к примеру, при последовательной передаче байта данных через один контакт. В этом примере контакту нужно поменять свое состояние с HIGH на LOW для каждого передаваемого бита в байте. Это выполняется при помощи так называемых побитовых операторов и битовой маски.

Побитовые операторы – это такие операторы, которые выполняют логические функции на уровне битов. Среди стандартных побитовых операторов: И (&), ИЛИ (I), сдвиг влево (<<) и сдвиг вправо (>>).

Оператор И (&)

Если хотя бы у одного их входных значений в бите будет «0», в итоге этот «0» появится и в итоговом значении:

    x:  10001101
    y:  01010111
x & y:  00000101

Оператор ИЛИ (I)

Иногда его называют включающим ИЛИ. Если хотя бы у одного их двух входных значений в бите будет «1», в итоге этот «1» появится и в итоговом значении:

    x:  10001101
    y:  01010111
x | y:  11011111

Оператор для сдвига влево (<<)

Сдвигает значение влево на указанное количество позиций. Например:

        y = 1010
        x = y << 1
        x = 0100

Как видите, здесь все байты сдвинулись на одну позицию влево, а бит, находящийся на крайней левой позиции, был удален.

Оператор для сдвига вправо (>>)

Работает идентично оператору для сдвига влево, но двигает биты в противоположную сторону, т.е. вправо.

        y = 1010
        x = y >> 1
        x = 0101

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

В качестве практического примера давайте возьмем значение «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){ // если побитовое И дает «true»
      digitalWrite(transmit,HIGH);  //  отправляем «1»
    }
    else{  //  если побитовое И дает «false»
      digitalWrite(transmit,LOW);  // отправляем «0»
    }
    delayMicroseconds(bitDelay);  // задержка
  }
}

Здесь мы использует цикл for(), чтобы сделать несколько проходов по битовой маске. С каждым проходом через цикл мы сдвигаем значение в маске на одну позицию влево. В данном случае мы используем оператор <<=, который равнозначен, по сути, оператору <<, но за тем исключением, что делает оператор более компактным.

    00000001
  & 10101010
    ________
    00000000

В итоге контакт получает значение «0». При втором проходе через цикл битовой маской станет значение «00000010», и операция будет выглядеть следующим образом:

    00000010
  & 10101010
    ________
    00000010

И в итоге наш выходной контакт получит значение «1». Цикл продолжить делать проход за проходом для каждого бита в маске, пока «1» не сместится за левый край, а маска не превратится в «00000000». Тогда все 8 бит будут переданы и цикл завершится.

См.также

Внешние ссылки