Целью битовых операций является изменение одного или нескольких битов в регистре или переменной не затрагивая значения других битов.
Нумерация бит начинается с нуля и идет справа налев0, соответственно самый младший бит (и самый правый) является нулевым.
Для задания номера бита я буду использовать шестнадцатеричную запись, чтобы отличать номер бита от его значения.
Для задания значения я иногда буду добавлять после него букву u, означающую беззнаковое число (unsigned), служащую для подавления предупреждения Keil "warning: implilcit conversion changes signedness: 'int' to 'unsigned int'".
Все примеры я буду приводить для регистра MDR_PORTB->RXTX, если нужно применить битовые операции к переменной то ее имя вставляется вместо MDR_PORTB->RXTX.
Если значения других битов не важны или должны быть нулями то используется операция присваивания.
MDR_PORTB->RXTX = (1 << 0x02); // Установка в 1 бита №2 (остальные биты регистра равны нулю)
MDR_PORTB->RXTX = ((1 << 0x02) | (1 << 0x03)); // Установка в 1 бита №2 и №3
MDR_PORTB->RXTX = ((1 << 0x00) | (1 << 0x02) | (1 << 0x03)); // Установка в 1 бита №0, №2 и №3
MDR_PORTB->RXTX = (3 << 0x02); // Установка в 1 бита №2 и №3
Если значения других бит регистра нужно сохранять неизменными используют следующие битовые операции.
MDR_PORTB->RXTX |= (1 << 0x02); // Установка в 1 бита №2
MDR_PORTB->RXTX |= ((1 << 0x02) | (1 << 0x03)); // Установка в 1 бита №2 и №3
MDR_PORTB->RXTX |= ((1 << 0x00) | (1 << 0x02) | (1 << 0x03)); // Установка в 1 бита #0, №2 и №3
MDR_PORTB->RXTX |= (3 << 0x02); // Установка в 1 бита №2 и №3
MDR_PORTB->RXTX |= 0x0C; // Установка в 1 бита №2 и №3
MDR_PORTB->RXTX &= ~(1u << 0x02); // Сброс в 0 бита №2
MDR_PORTB->RXTX &= ~((1u << 0x02) | (1u << 0x03)); // Сброс в 0 бита №2 и №3
MDR_PORTB->RXTX &= ~((1u << 0x00) | (1u << 0x02) | (1u << 0x03)); // Сброс в 0 бита #0, №2 и №3
MDR_PORTB->RXTX &= ~(3u << 0x02); // Сброс в 0 бита №2 и №3
MDR_PORTB->RXTX &= 0xFFFFFFF3; // Сброс в 0 бита №2 и №3
MDR_PORTB->RXTX &= ~(0x0C); // Сброс в 0 бита №2 и №3
MDR_PORTB->RXTX ^= (1 << 0x02); // Инверсия значения бита №2
MDR_PORTB->RXTX ^= ((1 << 0x02) | (1 << 0x03)); // Инверсия значения бита №2 и №3
MDR_PORTB->RXTX ^= ((1 << 0x00) | (1 << 0x02) | (1 << 0x03)); // Инверсия значения бита #0, №2 и №3
MDR_PORTB->RXTX ^= (3 << 0x02); // Инверсия значения бита №2 и №3
MDR_PORTB->RXTX ^= 0x0C; // Инверсия значения бита №2 и №3
uint8_t bit_val = MDR_PORTB->RXTX & (1 << 0x03); // Считать значение бита №3
int val = byte1 | (byte2 << 8); // Склейка двух байтов byte2byte1
MDR_PORTB->RXTX = (MDR_PORTB->RXTX >> 1) | (MDR_PORTB->RXTX << 15); // Циклический сдвиг влево значений регистра
MDR_PORTB->RXTX = (MDR_PORTB->RXTX << 1) | (MDR_PORTB->RXTX >> 15); // Циклический сдвиг вправо значений регистра
MDR_PORTB->RXTX = (MDR_PORTB->RXTX << 16) | (MDR_PORTB->RXTX >> 16); // Поменять местами слова в 32х битном регистре (частный случай циклического сдвига)