MCU 프로그래밍을 할 때 데이터시트를 보면 같은 레지스터에 두 가지 주소가 붙어있는 걸 볼 수 있다.
하나는 I/O 주소, 다른 하나는 데이터 주소다.

I/O 주소
ATmega328P에는 64바이트짜리 작은 공간이 있다.
여기에 PORTB, DDRB, PINB 같은 하드웨어 제어 레지스터가 배치돼 있다.
이 공간의 주소를 I/O 주소라고 부른다.
이 영역은 CPU의 특수 명령어 IN, OUT, SBI, CBI 같은 걸로 접근할 수 있다.
장점은 빠르다는 것. 1클럭에 입출력을 처리할 수 있다.
데이터 주소
동시에, 똑같은 레지스터들이 SRAM 공간에도 매핑돼 있다.
이게 데이터 주소다.
예를 들어 PORTB의 경우:
- I/O 주소: 0x05
- 데이터 주소: 0x25
데이터 주소로 접근할 때는 LDS, STS 같은 일반 메모리 명령이 사용된다.
접근 속도는 2클럭 이상으로 조금 느리다.
장점은 C 언어에서 포인터로 접근할 수 있다는 것이다.
C 코드와 매크로
C 언어는 기본적으로 하드웨어 레지스터 개념이 없으므로, AVR 헤더 파일에서는 이런 매크로를 만들어둔다.
#define PORTB (*(volatile uint8_t *)0x25)
#define DDRB (*(volatile uint8_t *)0x24)
- 0x25는 PORTB 데이터 주소
- (volatile uint8_t *)0x25는 이 주소를 가리키는 포인터
- * 연산으로 역참조해서 실제 레지스터에 접근
- volatile은 컴파일러 최적화를 막아 항상 실제 하드웨어와 읽기/쓰기를 보장
이렇게 정의해두면 C 코드에서 PORTB를 변수처럼 쓸 수 있다.
코드 예시
#include <avr/io.h>
int main(void) {
DDRB |= (1 << 5); // PB5를 출력으로 설정
PORTB |= (1 << 5); // PB5 핀 HIGH
while (1) {}
}
풀어 쓰면 아래와 같은 것이다.
(*(volatile uint8_t *)0x24) |= (1 << 5); // DDRB
(*(volatile uint8_t *)0x25) |= (1 << 5); // PORTB
결국 같은 하드웨어 레지스터가 I/O 주소와 데이터 주소 두 군데에서 동시에 보이는 셈이다.
C 언어는 데이터 주소를 쓰고, 컴파일러는 이를 보고 I/O 명령으로 최적화한다.

구조체로 묶어 쓰기
여러 레지스터를 구조체로 묶어 표현할 수도 있다.
typedef struct {
volatile uint8_t PINB;
volatile uint8_t DDRB;
volatile uint8_t PORTB;
} PortB_Regs;
#define PORTB_REGS (*(PortB_Regs *)0x23)
int main(void) {
PORTB_REGS.DDRB |= (1 << 5);
PORTB_REGS.PORTB |= (1 << 5);
while (1) {}
}
여기서는 0x23이 PINB의 데이터 주소이므로 구조체 기준 주소로 잡고, 이후 멤버 오프셋을 통해 DDRB(+1), PORTB(+2)에 접근한다.
정리하기
- I/O 주소: MCU 내부 전용 빠른 접근 주소. 직접 포인터로 다룰 수 없음.
- 데이터 주소: SRAM 공간에 매핑된 주소. C 코드에서 포인터/구조체로 다룰 수 있음.
- C 헤더는 데이터 주소를 매크로로 정의해놓고, 컴파일러가 자동으로 빠른 I/O 접근으로 최적화한다.
결국 프로그래머 입장에서는 그냥 PORTB, DDRB를 변수처럼 쓰면 된다.
내부적으로는 두 주소 체계가 동시에 존재하고, 덕분에 빠른 접근성과 C 언어 호환성을 모두 얻을 수 있는 구조다.
'Journey to CS > 임베디드' 카테고리의 다른 글
| [ATmega328P] 레지스터 직접 제어 방식으로 프로그래밍 해보기 (0) | 2025.09.29 |
|---|---|
| [메모리] 엔디언(Endianness)과 포인터 캐스팅(casting) (1) | 2025.09.14 |
| 아두이노에서 어떤 정수 타입을 써야 할까? 데이터 타입 비교표 한 눈에 보기 (2) | 2025.08.13 |
| [아두이노] millis() 타이머 함수로 진동모터와 LED 동시에 작동시키기 (1) | 2025.07.27 |
| 아두이노 스케치를 작성하다가 loop()함수에 대해 생긴 의문...그리고 답 (1) | 2025.07.27 |