null
vuild_
Nodes
Flows
Hubs
Login
MENU
GO
Notifications
Login
☆ Star
비트 연산
#bitwise
#register
#set
#clear
#toggle
@devpc
|
2026-04-02 05:47:09
|
GET /api/v1/nodes/201?nv=1
History:
v1 (2026-04-02) (Latest)
0
Views
3
Calls
# 비트 연산 ## 왜 비트 연산이 중요한가? MCU의 주변장치는 **레지스터의 특정 비트**로 제어됩니다. 레지스터 하나(32비트)에 여러 기능의 설정 비트가 함께 들어 있기 때문에, 다른 비트를 건드리지 않고 원하는 비트만 조작해야 합니다. ``` [ 레지스터 비트 예시 ] 레지스터 (32비트): 0x0000_0015 비트: 31 ... 4 3 2 1 0 0 ... 0 1 0 1 1 ↑ ↑ ↑ | | ENABLE 비트 (bit 0) | DIRECTION 비트 (bit 1) — 쓰면 안 됨! SPEED 비트 (bit 3) ``` 이 상황에서 ENABLE 비트(bit 0)만 끄고 싶다면, SPEED와 DIRECTION은 그대로 둔 채로 bit 0만 0으로 만들어야 합니다. --- ## 기본 비트 연산자 ``` 연산자 이름 동작 ─────────────────────────────── & AND 두 비트 모두 1일 때만 1 | OR 하나라도 1이면 1 ^ XOR 두 비트가 다를 때 1 ~ NOT 비트 반전 << Left Shift 비트를 왼쪽으로 이동 >> Right Shift 비트를 오른쪽으로 이동 ``` ``` [ AND / OR / XOR / NOT 진리표 ] A B | A&B A|B A^B ──────┼───────────── 0 0 | 0 0 0 0 1 | 0 1 1 1 0 | 0 1 1 1 1 | 1 1 0 ~0 = 1, ~1 = 0 ``` --- ## 비트 Set / Clear / Toggle / Check ### Set (비트 켜기) 특정 비트를 1로 만들 때는 **OR** 연산을 사용합니다. ```c uint32_t reg = 0x0000_0014; /* 0001 0100 */ reg |= (1u << 0); /* bit 0을 1로 Set */ /* 결과: 0x0000_0015 0001 0101 */ ``` ``` [ 비트 Set 과정 ] reg : 0001 0100 마스크 : 0000 0001 (1u << 0) OR(|) : 0001 0101 ← bit 0만 1이 됨, 나머지 불변 ``` ### Clear (비트 끄기) 특정 비트를 0으로 만들 때는 **AND + NOT** 연산을 사용합니다. ```c uint32_t reg = 0x0000_0015; /* 0001 0101 */ reg &= ~(1u << 0); /* bit 0을 0으로 Clear */ /* 결과: 0x0000_0014 0001 0100 */ ``` ``` [ 비트 Clear 과정 ] ~마스크 : 1111 1110 (~(1u << 0)) reg : 0001 0101 AND(&) : 0001 0100 ← bit 0만 0이 됨, 나머지 불변 ``` ### Toggle (비트 반전) 현재 값의 반대로 바꿀 때는 **XOR** 연산을 사용합니다. ```c uint32_t reg = 0x0000_0015; /* 0001 0101 */ reg ^= (1u << 0); /* bit 0 Toggle */ /* 결과: 0x0000_0014 0001 0100 */ reg ^= (1u << 0); /* 다시 Toggle */ /* 결과: 0x0000_0015 0001 0101 */ ``` ### Check (비트 확인) 특정 비트가 1인지 확인할 때는 **AND** 후 0과 비교합니다. ```c uint32_t reg = 0x0000_0015; if (reg & (1u << 0)) { /* bit 0이 1인 경우 */ } ``` --- ## 다중 비트 마스크 여러 비트를 한번에 다룰 때는 마스크를 조합합니다. ```c /* bit 4~5 (GAINSEL 필드) 를 0b11(=3)으로 설정 */ #define GAINSEL_MASK (0x3u << 4) /* 0b0011_0000 */ #define GAINSEL_VALUE (0x3u << 4) /* 값도 이미 시프트된 위치로 */ reg &= ~GAINSEL_MASK; /* 먼저 해당 비트 클리어 */ reg |= GAINSEL_VALUE; /* 원하는 값 OR */ ``` ``` [ 다중 비트 Set 과정 ] step1 clear: ~GAINSEL_MASK : 1100 1111 reg : xxxx xxxx AND : xx00 xxxx ← bit 4~5 클리어 step2 set: GAINSEL_VALUE : 0011 0000 결과 : xx11 xxxx ← bit 4~5에 0b11 세팅 ``` --- ## TC37x: Ifx_SCU_OSCCON_Bits 비트필드 union iLLD에서 제공하는 비트필드 union을 쓰면 마스크 계산 없이 필드 이름으로 직접 접근할 수 있습니다. ```c /* iLLD 비트필드 union 사용 */ Ifx_SCU_OSCCON osccon; osccon.U = MODULE_SCU.OSCCON.U; /* 현재 값 읽기 */ osccon.B.GAINSEL = 3; /* GAINSEL 필드만 변경 */ MODULE_SCU.OSCCON.U = osccon.U; /* 레지스터에 쓰기 */ /* 위 코드는 내부적으로 아래와 동등 */ uint32_t val = MODULE_SCU.OSCCON.U; val &= ~(0x3u << 4); val |= (3u << 4); MODULE_SCU.OSCCON.U = val; ``` 비트필드 union의 장점은 가독성이 높고 실수가 줄어드는 것입니다. 단, **read-modify-write** 중간에 인터럽트가 끼어들 수 있으므로 크리티컬 섹션에서는 주의가 필요합니다. --- ## 다른 MCU와의 차이점 > ⚠️ 다른 환경에서 넘어온다면 이런 점이 다를 수 있습니다. - **비트 연산 자체**: Set/Clear/Toggle 패턴은 모든 MCU에서 완전히 동일. 이식성 100%. - **레지스터 접근 방식**: STM32 CMSIS도 비트필드 union 사용. TriCore iLLD와 구조가 유사. - **atomic 처리**: 일부 ARM Cortex-M 코어는 비트밴딩(Bit-Banding)으로 원자적 비트 조작 가능. TriCore는 별도 동기화 메커니즘 사용.
// COMMENTS
Newest First
ON THIS PAGE