BitwiseAnd

Материал из MK90.ORG wiki
Перейти к: навигация, поиск

Побитовое И (&), побитовое ИЛИ (|), побитовое ИСКЛЮЧАЮЩЕЕ ИЛИ (^)

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

Побитовое И (&)

Побитовое И (AND) - это оператор C++, который записывается при помощи одинарного знака амперсанда & между двумя целочисленными выражениями. Побитовое И производится позиционным способом, над каждой соответствующей парой битов этих выражений, независимо. Действует правило: если оба бита равны 1, то и результат будет 1; в противном случае - 0. Например:

   0  0  1  1    операнд1
   0  1  0  1    операнд2
   ----------
   0  0  0  1    (операнд1 & операнд2) - возвращаемый результат

В Arduino тип int является 16-битным, поэтому и результат побитового И также будет 16-битным:


int a =  92;    // в двоичном виде: 0000000001011100
int b = 101;    // в двоичном виде: 0000000001100101
int c = a & b;  // результат:       0000000001000100, или 68 в десятичном виде

Каждый из 16-ти бит переменных a и b подвергается операции логического И, затем полученный 16-битный результат сохраняется в переменной c - в данном случае двоичное число 01000100 или десятичное 68.

Наиболее часто побитовое И применяется для выделения конкретного бита (или битов) из целочисленного значения (т.н. "маскировка битов").

Побитовое ИЛИ (|)

Побитовое ИЛИ (OR) - это другой оператор C++, который записывается при помощи одинарного знака вертикальной черты | между двумя целочисленными выражениями. Как и логическое И, побитовое ИЛИ производится позиционным способом, над каждой соответствующей парой битов этих выражений, независимо. Но действует иное правило: если хотя бы один из битов равен 1, то и результат будет 1; в противном случае - 0. Например:

   0  0  1  1    операнд1
   0  1  0  1    операнд2
   ----------
   0  1  1  1    (операнд1 | операнд2) - возвращаемый результат

Пример фрагмента кода на C++:


int a =  92;    // в двоичном виде: 0000000001011100
int b = 101;    // в двоичном виде: 0000000001100101
int c = a | b;  // результат:       0000000001111101, или десятичное 125.

Пример

Побитовый оператор И в сочетании с ИЛИ удобно использовать для программирования цепочек Чтение-Модификация-Запись для порта. В микроконтроллерах порт - это восьмибитное число, где каждый бит представляет состояние одного из пинов. Таким образом, записав в порт число, можно изменять состояние сразу восьми пинов.

PORTD - встроенная константа, ссылающаяся на состояние цифровых пинов 0,1,2,3,4,5,6,7. Если прочитанное из нее значение имеет в соответствующей позиции 1 - значит, на пине присутствует HIGH (предварительно требуется перевести пины в режим выхода, например, при помощи pinMode(). Если написать PORTD = B00110001; то мы переведем в HIGH пины 2,3 и 7, а остальные - в LOW. Небольшой отрицательный момент в данном случае - непреднамеренно мы изменили также состояние пинов 0 и 1, и, возможно, нарушили таким образом обмен по последовательному порту.

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

  • Читает PORTD и очищает (обнуляет) только те пины, которые мы будем использовать (побитовое И);
  • Комбинирует и изменяет значение PORTD новыми значениями для используемых пинов (побитовое ИЛИ).

int i;  // переменная-счетчик
int j;

void setup() {
  DDRD = DDRD | B11111100; // установить биты направления для пинов с 2 по 7, не менять для 0 и 1 (xx | 00 == xx)
                           // тоже самое, что pinMode(pin, OUTPUT) для пинов с 2 по 7
  Serial.begin(9600);      // инициализируем последовательный порт для отладочного вывода
}

void loop() {
  for (i=0; i<64; i++){
    PORTD = PORTD & B00000011;  // очистить биты 2 - 7, оставить пины 0 и 1 без изменений (xx & 11 == xx)
    j = (i << 2);               // сдвинуть переменную i на два биты влево - чтобы избежать изменения для пинов 0 и 1
    PORTD = PORTD | j;          // комбинируем информацию для порта с новыми значениями 
    Serial.println(PORTD, BIN); // показываем в отладочном выводе записанное значение
    delay(100);
  }
}

Побитовое исключающее ИЛИ (^)

В C также есть и оператор ИСКЛЮЧАЮЩЕГО ИЛИ (XOR). Этот оператор записывается с помощью символа ^ и используется подобно оператору ИЛИ, за исключением того, что эта операция дает 0, если биты совпадают и 1 в противном случае:

   0  0  1  1    операнд1
   0  1  0  1    операнд2
   ----------
   0  1  1  0    (операнд1 ^ операнд2) - returned result

Пример фрагмента кода на C++:


int x = 12;     // в двоичном виде: 1100
int y = 10;     // в двоичном виде: 1010
int z = x ^ y;  // в двоичном виде: 0110, или в десятичном 6

Оператор ^ используется для переключения (или инверсии, т.е. изменения с 0 на 1 или с 1 на 0) определенных бит в целом выражении. Если в участвующей в операции маске встречается 1, то результат инвертируется, а 0 - остается прежним. Ниже приводится пример скетча, который мигает светодиодом, подключенным к порту 5.


void setup() {
  DDRD = DDRD | B00100000; // установить цифровой порт 5 в режим OUTPUT 
  Serial.begin(9600);
}

void loop() {
  PORTD = PORTD ^ B00100000;  // инвертировать бит 5 (цифровой пин 5), остальные оставить без изменения
  delay(100);
}

Смотри также

Руководство по Wiring


Исправления, пожелания и новые статьи должны быть опубликованы через Форум.

Оригинальные тексты руководств и переводы распространяются Arduino и MK90 на условиях лицензии Creative Commons Attribution-ShareAlike 3.0 License. Примеры исходных кодов и ссылки являются общественным достоянием.