비트연산 기초 정리: 임베디드 레지스터 제어를 위한 AND·OR·SHIFT

카드뉴스

비트연산은 레지스터의 필요한 자리만 바꾸기 위해 씁니다

임베디드에서 비트연산이 중요한 이유는 MCU 레지스터 구조와 직접 연결됩니다. 하나의 8비트, 16비트, 32비트 레지스터 안에는 여러 기능 비트가 함께 들어 있는 경우가 많습니다. LED 출력 enable, 인터럽트 플래그, 통신 상태, 타이머 설정처럼 서로 다른 의미가 한 숫자 안에 섞여 있습니다. 그래서 전체 값을 덮어쓰는 방식은 위험할 수 있습니다. 원하는 비트만 켜고, 끄고, 확인하고, 뒤집는 감각이 필요합니다.

처음에는 연산자 이름보다 패턴으로 익히는 편이 좋습니다. 비트를 켤 때는 OR와 마스크를 사용합니다. 예를 들어 특정 위치에 1을 만든 마스크를 기존 값과 OR 하면 그 비트만 1이 되고 나머지는 유지됩니다. 비트를 끌 때는 AND와 반전 마스크를 사용합니다. 끄고 싶은 자리만 0인 마스크를 적용하면 해당 비트만 0으로 만들 수 있습니다.

이때 마스크는 보통 숫자를 그대로 쓰기보다 이름을 붙여 관리합니다. `LED_EN`, `UART_RXNE`, `TIMER_UIF`처럼 의미 있는 이름이 있으면 코드가 하드웨어 설명서와 연결됩니다. 매직 넘버로 `0x04`만 남겨두면 몇 번째 비트인지, 어떤 기능인지 나중에 다시 찾기 어렵습니다.

체크, 클리어, 토글은 상태 레지스터에서 자주 나옵니다

비트가 켜져 있는지 확인할 때는 AND 연산을 사용합니다. 상태 레지스터와 마스크를 AND 했을 때 결과가 0이 아니면 해당 플래그가 올라온 것입니다. UART 수신 완료, 타이머 업데이트, ADC 변환 완료처럼 하드웨어 상태를 확인하는 코드에서 자주 보이는 형태입니다. 이 패턴을 이해하면 `if (REG & MASK)` 같은 코드가 단순한 암기가 아니라 “특정 상태 비트를 검사한다”는 의미로 보입니다.

토글은 XOR 연산을 사용합니다. 마스크가 1인 자리만 현재 값이 반전되므로 LED 깜빡임처럼 현재 상태를 뒤집는 동작에 유용합니다. 다만 하드웨어 레지스터 중에는 1을 쓰면 클리어되는 write-1-to-clear 플래그도 있습니다. 이런 레지스터는 일반 변수처럼 토글하거나 read-modify-write를 하면 의도와 다르게 동작할 수 있으므로 데이터시트의 비트 설명을 꼭 확인해야 합니다.

SHIFT는 마스크를 만들고 필드 위치를 맞추는 도구입니다

SHIFT 연산은 특정 비트 위치에 마스크를 만들거나, 여러 비트로 된 필드 값을 맞출 때 사용합니다. `1 << n` 형태는 n번째 비트를 선택하는 가장 기본적인 패턴입니다. 여러 비트 필드에 값을 넣을 때는 기존 필드를 먼저 지우고, 원하는 값을 shift해서 OR 하는 방식이 흔합니다. 이때 괄호를 빼먹거나 연산 우선순위를 착각하면 엉뚱한 비트가 바뀔 수 있습니다.

초보자가 자주 하는 실수는 논리 연산자 `&&`, `||`와 비트 연산자 `&`, `|`를 섞는 것입니다. 또 레지스터 전체에 새 값을 써서 다른 설정을 지워버리거나, 클리어해야 할 플래그를 잘못된 방식으로 처리하는 경우도 많습니다. 비트연산은 어려운 수학이라기보다 하드웨어가 요구하는 작은 자리 조작입니다. set, clear, check, toggle 네 가지 패턴을 실제 레지스터 예제와 함께 보면 임베디드 코드가 훨씬 읽기 쉬워집니다.

실습할 때는 레지스터 값을 쓰기 전후로 디버거의 SFR 창, 메모리 뷰, 로직 애널라이저 신호를 같이 비교해보면 좋습니다. AND, OR, SHIFT로 만든 마스크가 실제 GPIO 출력, UART 상태 플래그, 타이머 인터럽트 비트와 어떻게 연결되는지 확인해야 비트연산 기초가 암기가 아니라 디버깅 도구가 됩니다.

댓글 남기기