제민
[0x06] 타이머/카운터 인터럽트 (1) - Normal, CTC 본문
여기가 조금 어려운 부분이다.
외부 인터럽트까진 간단했어도 이 파트부터는 조금 머리를 써야 한다.
타이머/카운터 인터럽트의 사용 목적은 정확한 시간을 사용하기 위함이다.
_delay_ms(); 의 가장 큰 단점은 실행되는 동안 CPU가 정지한다는 점이다.
타이머 인터럽트를 사용하면 이 단점을 극복할 수 있다.
아트메가에는 0, 1, 2, 3의 4개의 타이머/카운터 인터럽트가 존재한다.
0 2는 8Bit, 1 3은 16Bit이다.우린 8Bit만 사용할 것이므로 0과 2만 사용한다. 후에 나오는 n에는 0과 2만 들어간다고 생각하면 된다.
타이머 인터럽트는 4개의 동작 모드를 가진다.
1. 일반 모드 (Normal)
2. 비교 모드 (CTC)
3. 위상 변조 (Phase Correct PWM)
4. 고속 PWM (Fast PWM)
타이머 인터럽트 레지스터
TCCR0
- 레지스터 구성 (7 ~ 0)
- FOCn0 | WGMn0 | COMn1 | COMn0 | WGMn1 | CSn2 | CSn1 | CSn0
WGMn0 | WGMn1 | 동작 설정 |
0 | 0 | Normal |
0 | 1 | CTC |
1 | 0 | Phase Correct PWM |
1 | 1 | Fast PWM |
COMn1 | COMn0 | 동작 설정 |
0 | 0 | OCn을 일반 포트로, 출력 차단 |
0 | 1 | OCn==TCNT0 : OCn Toggle |
1 | 0 | OCn==TCNT0 : OCn RST |
1 | 1 | OCn==TCNT0 : OCn SET |
CSn2 | CSn1 | CSn0 | 분주비 |
0 | 0 | 1 | 1 |
0 | 1 | 0 | 8 |
0 | 1 | 1 | 32 |
1 | 0 | 0 | 64 |
TIMSK
0x01 : Normal
0x02 : CTC
TCNT0
- 카운트 시작점 설정
- TCNT0 = (256 - X); 식으로 사용한다.
OCR0
- 비교 모드에서의 기준점 설정
- OCR0 = 250; 식으로 사용한다.
Normal 방식의 동작은 다음과 같다.
- TCNT0가 설정 값에서부터 계속 올라간다.
- 8비트로 나타낼 수 있는 수(0~255)를 넘어서 256을 카운트 하는 경우 OVF 발생
- OVF 발생 시 ISR이 실행된다.
- TCNT0는 다시 초기값이 되고 이를 반복한다.
CTC 방식의 동작은 다음과 같다.
- OCR0에 기준값을 설정한다.
- TCNT0가 0부터 계속 증가한다.
- TCNT0가 기준값에 도달한 경우, 그 다음번 클럭에서 ISR이 실행된다.
TCNT0과 OCR0를 어떤 값으로 설정할지가 이해가 잘 안 될 수도 있다.
이 값을 식을 통해 구할 수도 있지만 이 값이 뭐가 되든 간에 코드만 수정하면 동작되기에, 식보다는 다음의 방식으로 값을 구해보자.
아두이노에서 CLK는 1600만 번 돌 때 1초가 걸린다. (분주비 1)
분주비가 8이라면 CLK가 200만 번 돌 때 1초가 걸린다.
분주비가 64라면 CLK가 25만 번 돌 때 1초가 걸린다.
(n 분주란 주파수를 1/n배로 한다는 의미이다)
EX 1)
분주비 = 8
TCNT0 = 256-200 (200번 돌때마다 ISR 실행됨)
이때 1초마다 무언가 실행되게 하려면 분주비가 8일땐 CLK가 200만 번 돌면 1초이므로 ISR이 실행될때마다 cnt++을 하고, cnt==10000에 무언가를 실행되게 하면 된다.
일반 모드 예제 (분주비 8이므로 CLK 200만 = 1s)
#include <avr/io.h>
#include <avr/interrupt.h>
unsigned int cnt=0;
unsigned char state=0x00;
int led_on=0;
ISR(TIMER0_OVF_vect){
TCNT0 = 256-250;
cnt++;
if(cnt==8000){
led_on = ~led_on;
cnt=0;
}
}
int main(void){
DDRA = 0x0F;
TCCR0 = 0b00000010;
TIMSK = 0b00000001;
TCNT0 = 256-250;
sei();
while(1){
if(led_on) state = 0x0F;
else state = 0x00;
PORTA = state;
}
}
비교 모드 예제 (분주비 64이므로 CLK 25만 = 1s)
#include <avr/io.h>
#include <avr/interrupt.h>
unsigned int cnt=0;
unsigned char state=0x00;
int led_on=0;
ISR(TIMER0_COMP_vect){
OCR0 = 250;
cnt++;
if(cnt==1000){
led_on = ~led_on;
cnt=0;
}
}
int main(void){
DDRA = 0x0F;
sei();
TCCR0 = 0b00001100;
TIMSK = 0x02;
OCR0 = 250;
while(1){
if(led_on) state = 0x0F;
else state = 0x00;
PORTA = state;
}
}
'전기전자 > Atmega128' 카테고리의 다른 글
[0x08] ADC (0) | 2024.04.06 |
---|---|
[0x07] 타이머/카운터 인터럽트 (2) - Fast PWM (1) | 2024.04.06 |
[0x05] FND (1) | 2024.03.28 |
[0x04] 외부 인터럽트 (1) | 2024.03.28 |
0317 수행평가 - 1 (0) | 2024.03.20 |