Битовые операции
Тема дорожной карты · Embedded / Системный программист
Битовые операции — основа embedded-разработки: каждый регистр периферии (UART_CR, GPIO_ODR, TIM_DIER) задаётся комбинацией флагов в конкретных битовых позициях. В отличие от прикладного программирования здесь нет роскоши «прочитать enum» — datasheet описывает регистр как байт или word, где бит 0 — это X, бит 5 — Y, биты 7:4 — четырёхбитное поле скорости. Без свободного владения &, |, ^, ~, сдвигами и масками embedded-код превращается в magic-numbers.
Как это работает
Базовый набор операторов в C: & (AND, обнуляет биты вне маски), | (OR, устанавливает биты), ^ (XOR, переключает биты), ~ (NOT, инверсия), << и >> (сдвиги). Стандартные идиомы: reg |= (1 << bit) — установить бит, reg &= ~(1 << bit) — сбросить, reg ^= (1 << bit) — переключить, (reg >> bit) & 1 — прочитать. Многобитные поля: reg = (reg & ~MASK) | (value << SHIFT). CMSIS-заголовки (#define USART_CR1_TE (1U << 3)) уже определяют именованные битовые маски — пользуйтесь ими вместо magic-чисел. Атомарные операции set_bit, clear_bit в Linux ядре — отдельная история.
Когда применять
Каждый раз, когда работаете с регистрами периферии: настройка GPIO (направление, alternate function, pullup), конфигурация UART (baudrate, parity, stop bits), включение прерываний (NVIC ISER регистры), управление DMA (channel config). Также при упаковке/распаковке протокольных пакетов (битовые поля в CAN-сообщениях, Modbus regs, custom-протоколы) и при работе с bitmap-структурами (Bloom filters, presence bits).
Типичные ошибки
Знаковое смещение int x = -1; x >> 1 — implementation-defined, использовать unsigned. Сдвиг на ширину или больше типа 1 << 32 для 32-битного int — undefined behavior, нужно 1ULL << 32. Использование 1 вместо 1U или 1UL для битовых масок — компилятор может выдать предупреждение или дать неверный результат на 64-битных системах. if (reg & 0x80) без явного сравнения == 0 или != 0 — компилятор может предупредить о неявном boolean-ом. Чтение volatile-регистра дважды в одной формуле даёт два разных значения — сохраняйте в локальную переменную.