Arduino 내부 타이머 마스터하기: 정확한 타이밍을 위한 CTC 모드 활용법
부품 및 소모품
| 부품 |
수량 |
| Arduino UNO (ATmega328P) |
1 |
| LED (일반) |
1 |
| 220Ω 저항 |
1 |
프로젝트 소개
개요
정확한 시간 측정이 필요할 때 delay() 함수는 CPU를 점유하여 다른 작업을 못 하게 만듭니다. 내부 타이머와 인터럽트를 사용하면 백그라운드에서 시간을 세면서 메인 루프는 다른 작업을 수행할 수 있습니다.
작동 원리: Timer0 CTC 모드
ATmega328P 데이터시트의 타이머 블록 다이어그램을 보면:
- 클럭(16MHz) → 프리스케일러 → 제어 로직 → TCNT0 레지스터 증가
- TCNT0 값이 OCR0A 레지스터와 일치하면(Compare Match) 인터럽트 발생
- 이것이 CTC 모드 (Clear Timer on Compare)입니다.
프리스케일러 설정 (TCCR0B 레지스터)
| CS02 | CS01 | CS00 | 분주비 | 타이머 클럭 |
| 0 | 0 | 1 | 1 | 16 MHz |
| 0 | 1 | 0 | 8 | 2 MHz |
| 0 | 1 | 1 | 64 | 250 kHz |
| 1 | 0 | 0 | 256 | 62.5 kHz |
| 1 | 0 | 1 | 1024 | 15.625 kHz |
OCR0A 값 계산 (1ms 인터벌 예시)
타이머 클럭 = 16MHz / 64 = 250,000 Hz (주기 4µs)
1ms = 1000µs → 1000 / 4 = 250 카운트 필요
CTC 모드에서는 0부터 세므로 OCR0A = 249 (0xF9)
실전 예제: 1초마다 LED 토글
int timer = 0;
bool state = false;
void setup() {
pinMode(13, OUTPUT);
// Timer0 CTC 모드 설정
TCCR0A = (1 << WGM01); // CTC 모드
OCR0A = 0xF9; // 249 → 1ms 인터벌
TIMSK0 = (1 << OCIE0A); // 비교 매치 인터럽트 활성화
sei(); // 전역 인터럽트 허용
TCCR0B = (1 << CS01) | (1 << CS00); // 프리스케일러 64 (마지막에 설정!)
}
void loop() {
if (timer >= 1000) { // 1000ms = 1초
state = !state;
timer = 0;
}
digitalWrite(13, state);
}
ISR(TIMER0_COMPA_vect) {
timer++; // 1ms마다 증가
}
중요 포인트
- 프리스케일러는 마지막에 설정 - 설정 즉시 타이머 카운트 시작
- 타이머 정지하려면 TCCR0B 모든 비트 클리어
- Timer0은
millis(), delay(), analogWrite() (핀 5, 6)에도 사용되므로 변경 시 주의
- 더 복잡한 타이밍 필요 시 Timer1(16비트), Timer2(8비트) 활용 가능
회로도
LED 양극 → 220Ω 저항 → 핀 13, 음극 → GND. 기본 내장 LED(핀 13) 사용 시 저항 생략 가능.