반응형

타이머/카운터는 시간측정 또는 이벤트를 카운트 하는 기능입니다.
타이머는 내부 시스템 클럭(크리스탈)을 카운트해서 일정 시간을 측정하고, 카운터는 외부 이벤트를 카운트 할 수 있습니다.
타이머/카운터 08 비트 타이머/카운터로써 10 비트 프리스케일러 기능이 있습니다.

타이머/카운터 0 에 관계된 레지스터는

TCCR0(Timer/Counter Control Register) - $33 ($53)
TCNT0(Timer/CouNTer register) - #32 ($52)
TIMSK(Timer/Counter Interrupt Mask Register) - $39 ($59)
OCR0(Output Compare Register) - $31 ($51)

TCCR0 레지스터는 아래 그림과 같습니다. 하위 세 비트는 클럭 선택 비트들입니다. 이번 강좌에서는 클럭 선택 비트의 기능을 설명합니다.




아래 테이블은 클럭 선택(CS02:0) 비트를 설명한 것입니다.
세 비트가 000 일 경우는 클럭 소스를 선택하지 않은 상태로 타이머/카운터가 정지됩니다.
001 - 101 의 경우는 프리스케일러를 설정하는 값을 나타냅니다.
110, 111 의 경우는 T0 핀으로 입력되는 신호를 클럭 소스로 선택하는 값을 나타냅니다. 이경우는 카운터로 설정된 것으로 110 의 경우는 T0 (PB0)핀으로 입력되는 신호가 하강(falling edge) 할 때 카운트하고, 111 의 경우는 신호가 상승(rising edge) 할 때 카운트합니다.



프리스케일러란 시스템 클럭을 분주해서 타이머/카운터 클럭 소스로 입력되는 것을 말합니다.
아래 그림 1 은 프리스케일링 기능이 없이 시스템 클럭이 타이머/카운터 클럭 소스로 사용되는 경우이고,
그림 2 는 시스템 클럭을 8 분주해서 타이머/카운터 클럭 소스로 사용하는 경우입니다.
타이머/카운터는 4 가지 프리스케일러를 사용할 수 있습니다.



TCNT0 레지스터
는 아래 그림과 같이 8 비트 레지스터입니다.
타이머/카운터가 동작하면 TCNT0 레지스터가 업 카운터로 동작하고 FF 에서 00 으로 될 때(오버플로우) 인터럽트 요청을 합니다.




TIFR 레지스터타이머/카운터에 관한 인터럽트가 발생하면 인터럽트 요청을 하는 플래그들이 있는 레지스터 입니다.
TOV0 비트타이머/카운터 0 오버플로우 플래그입니다.
OCF0 비트출력 비교 플래그입니다.
위 두 비트는 인터럽트가 발생해서 인터럽트 서비스 루틴을 실행하면 0 으로 클리어 되고, 플래그에 1 을 쓰면 0 으로 클리어 됩니다.




TIMSK 레지스터
타이머/카운터 인터럽트를 가능/마스크 하는 레지스터입니다.
TOIE0 비트타이머/카운터 0 오버플로우 인터럽트를 가능(1)/마스크(0) 하는 비트입니다.
OCIE0 비트타이머/카운터 0 출력 비교 매치 인터럽트를 가능(1)/마스크(0) 하는 비트입니다.
상태 레지스터(SREG) 의 I-비트가 1 로 셋되어 있고, 위의 인에이블 비트가 1 로 셋되어 있어야 인터럽트가 발생할 수 있습니다.




OCR0 레지스터
는 아래 그림과 같이 8 비트 레지스터입니다.
이 레지스터는 계속해서 카운터 레지스터(TCNT0) 와 비교를 해서 일치(Match)하면 출력 비교 매치 인터럽트를 발생시키거나, OC0(PB0) 핀에 파형을 발생시킵니다.


반응형
반응형

ISR(TIMER0_OVF_vect){ <== 요거는 타이머0의 오버플로우 인터럽트지요.

타이머는 동작에 기준이 되는 클럭을 MCU 클럭에서 받아오거나 외부 발진을 받을수 있도록 되어 있는데..

메인 클럭을 받을 경우를 예를 들어보죠.

클럭이 16메가라고 하면 주기는 1/f 이므로 1/16M = 62.5nS죠.

그냥 클럭을 카운터에 넣으면 1카운트는 62.5nS가 되는데...

타이머0의 경우 8비트 카운터이므로 0부터 255까지 풀로 돌려도 256 * 62.5nS = 16uS밖에 않됩니다.

이건 너무 고속이라.. 프리스케일러(분주기)를 통해 시간을 늘입니다.

분주비를 1024로 설정하면.. 62.5nS * 1024가 1 카운트가 되겠죠.

그러면 62,5nS * 1024 = 64uS가 1카운트고,,

이것을 8비트로 카운팅을 하면 최대 16.384mS가 만들어집니다.

저같은 경우는 타이머0는 보통 1mS 타이머로 많이 쓰는데..

1mS를 만들려면.. 분주비는 1024로 하고.. 1000uS(1mS) / 64uS = 15.625번이므로

TCNT0 = 250; // 256번 - X = 15.6이니.. 반올림해서 X = 250번.

이렇게 하시고 인터럽트를 인에이블해주시면 되겠고요..

1mS 타이머를 쓰는 이유는 그게 프로그램에서 기준시간을 만들기 좋기 때문인데요.

예를 들어 조건이 만족해서 "부져가 울리면 300mS 동안 울고 꺼져라..."

이런 펑션일때.. 300mS란 시간은..

1. 타이머 인터럽트에 매인터럽트마다 하나씩 증가하는 변수(T0COUNT라고 하면..)를 하나 넣어두고..

2. 조건이 만족햇을때.. X = T0COUNT + 300;로 끝날시간을 기억시켜두고

3. IF(T0COUNT > X) 면 부저를 꺼라..

이런식으로 프로그램할때 편하지요.

질문 내용대로 1분이란 시간이 필요하시면 클럭과 분주비를 잘 조합하시면 될수도 있겠지만..

고속 클럭에서 1분 정도로 큰 값은 구현하기가 어렵기 때문에.. 작은값(1mS)로 하고..

매 인터럽트에서 인터럽트를 몇번 돌았는지 판단을 해서 1분을 구현하는것이 일반적입니다..

ISR(TIMER0_OVF_vect) {
TCNT0 = 250; // 1mS
IF(++T0CNT > 60000) { // 매 1mS마다 돌아오므로, 1분은 60000개.
T0CNT = 0;
변수1분 = TRUE;
}
}

반응형
반응형

사실 저번 외부인터럽트 한개 써놓고 소자 도착하면 그냥 하던거나 해야지!! 했는데 저번 글 호응이 이상하리만큼 높았습니다(......)

 

 

정말 저도 잘 못하는데!! 안쓸수도 없고...ㅇ<-<

 

 

이번엔 타이머/카운터 설명을 하겓습니다. 아씨 진짜 잘모르는데 ㅋㅋㅋㅋㅋㅋ

 

 

먼저! 타이머/카운터가 뭐냐하면,

기본적으로 ATmega128을 비롯한 MCU들이 시간을 세기 위해서 쓰는게 크리스탈입니다.

 

 

 

저놈인데요, 쟤가 16MHz의 펄스를 계속 내보내고, 그 펄스를 이용해서 MCU가 자체적으로 시간을 셉니다.

 

 

 

요런식의 펄스를 세는게 타이머/카운터이고,

 

MCU 내부 시스템 클럭을 세는게 타이머, 외부 핀에서 들어오는 펄스를 세는게 카운터입니다.(TOSC1,2, T1,2,3)

 

 

카운터는 패스하고, 타이머에 대해서 좀 알아보죠.

 

 

먼저, 프리스케일러라는게 있습니다. 분주비라고도 하는데요, 아까 얘기드렸던 것 같이 시스템 클럭은 16MHz, 한 펄스가 1/16us짜리입니다.

 

요걸로 1초마다 동작하는 타이머를 쓰려고 한다면.. 좀 많이 세어야겠죠? 그래서 분주비라는걸 씁니다.

예를 들어 16MHz를 2분주 시킨다면 8MHz, 1/8us가 되겠네요.

ATmega128은 총 네가지 타이머를 지원합니다. timer/counter 0,1,2,3 네가지로요.

이 중에서, timer/counter0,2 는 8비트 타이머, timer/counter1,3은 16비트 타이머입니다.

 

차이점이라면 8비트 카운터는 0x00~0xFF까지 세는거고요, 16비트 카운터는 0x0000~0xFFFF까지 셀 수 있습니다.

 

일단 8비트 타이머에 대해 설명하도록 할게요.

 

 

타이머의 동작 모드는 총 네개가 있습니다.

Normal 모드, CTC 모드, Fast PWM 모드, Phase Correct PWM 모드가 있는데요, 뒤에 두개는 PWM동작입니다. 다음에 설명하도록 하고 ^^;

 

 

Normal 모드와 CTC 모드는 인터럽트가 다릅니다.

 

 

Normal 모드는 timer/counterX overflow interrupt이고, CTC 모드는 timer/counterX compare match interrupt 입니다.

 

 

 

 

 

 

 

 

 

 

요게 Normal 모드입니다.

현재값은 TCNTn 레지스터에 저장되고, 말 그대로 TCNTn이 0xFF가 되면 오버플로우가 일어납니다.

 


 

 

이게 CTC모드인데요, TCNTn이 증가하는건 노멀모드와 동일하지만, 여기서는 OCRn이라는 레지스터를 하나 더 설정해줍니다.

TCNTn == OCRn이 되면 TCNTn은 다음 비트에서 0으로 클리어, 출력 비교 인터럽트가 일어나게 됩니다. 물론 OCRn을 0xFF로 설정할 수는 있습니다만.. 그럼 오버플로우랑 똑같죠뭐 ㅡ,.ㅡ

 

 

그럼 실제로 사용하기 위한 타이머 0의 레지스터들을 알아보죠. 사실 위에꺼 잘 몰라도 레지스터만 알면 써먹어 집니다(....)

 

 

1. TCNT0

..그림에서도 보셨겠지만 냅두면 알아서 0x00~0xFF까지 왔다갔다합니다.

 

 

2. OCR0

TCNT0와 계속 비교되는 값입니다. 같아지면 출력 비교 인터럽트가 일어납니다.

3. TIMSK

 

 

 

타이머/카운터0는 마지막 두 비트를 쓰는데, 비트 0이 타이머/카운터0 노멀모드, 비트 1이 타이머/카운터0 CTC모드 셋입니다.

TIMSK = 0b00000001이면 노멀모드 인에이블, TIMSK = 0b00000010이면 CTC모드 인에이블이겠죠.

 

 

4. TCCR0

 

 

쬐끔 복잡합니다.

 

 

6번비트와 3번비트는

 

 

00일때 노멀, 01일때 CTC, 10일때 phase correct PWM, 11일때 fast PWM입니다.

 

 

2번에서 0번비트는 위에 잠깐 언급했던 분주비 설정입니다.

 

000일때 타이머/카운터 동작 중지

001일때 1분주(분주비 사용 X)

010일때 8분주

011일때 32분주

100일때 64분주

101일때 128분주

110일때 256분주

111일때 1024분주가 됩니다.

 

 

 

 

뭔가 설명은 길었는데, 실제로 쓰실때는 레지스터 세개정도? 에 저번에 했던 SREG레지스터 설정해서 쓰시면 됩니다.

예시 하나 보실까요?

 

 

 

 

 

 

타이머/카운터0을 이용해 LED를 0.5초마다 켰다껐다하는 동작입니다.

 

 

 

타이머0을 위해 들어간 코드는

9~13번줄입니다.

 

 

 

 

 

 

  1. TIMSK = 0b00000001; // TOIE0 = 1;
  2. TCCR0 = 0b00000111; // 일반모드, 프리스케일 = CK/1024
  3. TCNT0 = 0b00000000; // 타이머/카운터0 레지스터 초기값
  4. SREG = 0b10000000; // 전역 인터럽트 인에이블 비트 I 셋

 

TIMSK = 0b00000001; 타이머/카운터0 노멀모드 인에이블이고,

TCCR0의 6번, 3번비트는 0 : 노멀모드, 2~0번비트 111 : 1024분주비 사용입니다.

TCNT0값이 설정 가능하기는 한데, 여기서는 초기값이네요.

 

 

그리고 SREG = 0x80으로 인터럽트 사용 설정을 해줍니다.

 

요건 인터럽트 함수인데요,

 

  1. // 1/16us x 1024 x 256 = 16.384ms
  2. interrupt [TIM0_OVF] void timer_int0(void)
  3. {
  4. cnt++;
  5. if(cnt == 31) { // 16.384ms x 31 = 0.5sec
  6. led = led ^ 0xFF;
  7. PORTB = led;
  8. cnt = 0;
  9. }
  10. }

 

노멀모드의 경우

interrupt[TIMn_OVF] void timer_intn(void)

{

}

 

로 사용하고,

 

CTC모드의 경우

interrupt[TIMn_COMPA] void timer_compna(void)

{

}

로 씁니다.

 

 

 

한번 인터럽트 걸리는게 16.384ms이고, 그걸 31번 반복해서 0.5sec를 맞추는겁니다. 자기가 쓰고자 하는 시간에 맞춰서 분주비나 기타등등을 맞춰서 해 주시면 되는데...

 

 

귀찮으신분들을 위해 밑에 비기(!)를 몇개 소개해봅니다. 네이년 검색하다 찾았네요

 

 

 

 

 

//=====================================================

 

// 타이머0 오버플로우 인터럽트
TCCR0=3; TCNT0=156; TIMSK=1; //16000000/ 32/100=5000Hz=200us,(256-100)=156
TCCR0=4; TCNT0=6; TIMSK=1; //16000000/ 64/250=1000Hz=1ms, (256-250)=6
TCCR0=5; TCNT0=131; TIMSK=1; //16000000/ 128/125=1000Hz=1ms, (256-125)=131
TCCR0=5; TCNT0=6; TIMSK=1; //16000000/ 128/250= 500Hz=2ms, (256-250)=6
TCCR0=6; TCNT0=6; TIMSK=1; //16000000/ 256/250= 250Hz=4ms, (256-250)=6
TCCR0=7; TCNT0=100; TIMSK=1; //16000000/1024/156=100.16Hz=0.984ms, (256-156)=100
TCCR0=7; TCNT0=6; TIMSK=1; //16000000/1024/250=62.5Hz=16ms, (256-250)=6

// 타이머0 매치 인터럽트
TCCR0=0x0B; OCR0= 28; TIMSK=2; //16000000/ 32/(1+ 28)=17241.37931Hz=58us
TCCR0=0x0B; OCR0= 49; TIMSK=2; //16000000/ 32/(1+ 49)=10000Hz=100us
TCCR0=0x0B; OCR0= 99; TIMSK=2; //16000000/ 32/(1+ 99)= 5000Hz=200us
TCCR0=0x0C; OCR0= 74; TIMSK=2; //16000000/ 64/(1+ 74)= 3333.3Hz=300us
TCCR0=0x0C; OCR0=124; TIMSK=2; //16000000/ 64/(1+124)= 2000Hz=500us
TCCR0=0x0C; OCR0=249; TIMSK=2; //16000000/ 64/(1+249)= 1000Hz=1ms
TCCR0=0x0D; OCR0=124; TIMSK=2; //16000000/ 128/(1+124)= 1000Hz=1ms
TCCR0=0x0D; OCR0=249; TIMSK=2; //16000000/ 128/(1+249)= 500Hz=2ms
TCCR0=0x0E; OCR0=249; TIMSK=2; //16000000/ 256/(1+249)= 250Hz=4ms
TCCR0=0x0F; OCR0= 71; TIMSK=2; //14745600/1024/(1+ 71)= 200Hz=5ms
TCCR0=0x0F; OCR0=155; TIMSK=2; //16000000/1024/(1+155)= 100.16..Hz=9.984ms
TCCR0=0x0F; OCR0=249; TIMSK=2; //16000000/1024/(1+249)= 62.5Hz=16ms

// 타이머1 오버플로우 인터럽트
TCCR1B=1; TCNT1=49536; TIMSK=4; //16000000/ 1/16000=1000Hz=1ms, (65536-16000)=49536
TCCR1B=1; TCNT1=33536; TIMSK=4; //16000000/ 1/32000= 500Hz=2ms, (65536-32000)=33536
TCCR1B=2; TCNT1=63536; TIMSK=4; //16000000/ 8/ 2000=1000Hz=1ms, (65536- 2000)=63536
TCCR1B=2; TCNT1=61536; TIMSK=4; //16000000/ 8/ 4000= 500Hz=2ms, (65536- 4000)=61536
TCCR1B=2; TCNT1=45536; TIMSK=4; //16000000/ 8/10000= 200Hz=5ms, (65536-10000)=45536
TCCR1B=2; TCNT1=35536; TIMSK=4; //16000000/ 8/20000= 100Hz=10ms, (65536-20000)=35536
TCCR1B=3; TCNT1=65286; TIMSK=4; //16000000/ 64/ 250=1000Hz=1ms, (65536- 250)=65286
TCCR1B=4; TCNT1=59286; TIMSK=4; //16000000/256/ 6250= 10Hz=100ms,(65536- 6250)=59286
TCCR1B=4; TCNT1=34286; TIMSK=4; //16000000/256/31250= 2Hz=500ms,(65536-31250)=34286
TCCR1B=4; TCNT1= 3036; TIMSK=4; //16000000/256/62500= 1Hz=1sec, (65536-62500)= 3036

// 타이머1 A매치 인터럽트
TCCR1B=0x09; OCR1A= 1474; TIMSK=0x10; //14745600/ 1/(1+ 1474)=9997.01695Hz=100.02984us
TCCR1B=0x09; OCR1A= 1599; TIMSK=0x10; //16000000/ 1/(1+ 1599)=10KHz=100us
TCCR1B=0x09; OCR1A= 3999; TIMSK=0x10; //16000000/ 1/(1+ 3999)= 4KHz=250us
TCCR1B=0x09; OCR1A=15999; TIMSK=0x10; //16000000/ 1/(1+15999)=1000Hz=1ms
TCCR1B=0x09; OCR1A=31999; TIMSK=0x10; //16000000/ 1/(1+31999)= 500Hz=2ms
TCCR1B=0x0A; OCR1A= 1999; TIMSK=0x10; //16000000/ 8/(1+ 1999)=1000Hz=1ms
TCCR1B=0x0A; OCR1A= 3999; TIMSK=0x10; //16000000/ 8/(1+ 3999)= 500Hz=2ms
TCCR1B=0x0A; OCR1A= 4999; TIMSK=0x10; //16000000/ 8/(1+ 4999)= 400Hz=2.5ms
TCCR1B=0x0A; OCR1A= 9999; TIMSK=0x10; //16000000/ 8/(1+ 9999)= 200Hz=5ms
TCCR1B=0x0A; OCR1A=19999; TIMSK=0x10; //16000000/ 8/(1+19999)= 100Hz=10ms
TCCR1B=0x0A; OCR1A=18431; TIMSK=0x10; //14745600/ 8/(1+18431)= 100Hz=10ms
TCCR1B=0x0A; OCR1A=39999; TIMSK=0x10; //16000000/ 8/(1+39999)= 50Hz=20ms
TCCR1B=0x0A; OCR1A=59999; TIMSK=0x10; //16000000/ 8/(1+59999)= 33.33Hz=30ms
TCCR1B=0x0B; OCR1A= 249; TIMSK=0x10; //16000000/ 64/(1+ 249)=1000Hz=1ms
TCCR1B=0x0C; OCR1A= 3124; TIMSK=0x10; //16000000/256/(1+ 3124)= 20Hz=50ms
TCCR1B=0x0C; OCR1A= 6249; TIMSK=0x10; //16000000/256/(1+ 6249)= 10Hz=100ms
TCCR1B=0x0C; OCR1A=12499; TIMSK=0x10; //16000000/256/(1+12499)= 5Hz=200ms
TCCR1B=0x0C; OCR1A=31249; TIMSK=0x10; //16000000/256/(1+31249)= 2Hz=500ms
TCCR1B=0x0C; OCR1A=62499; TIMSK=0x10; //16000000/256/(1+62499)=1Hz=1sec
TCCR1B=0x0D; OCR1A=62499; TIMSK=0x10; //16000000/1024/(1+62499)=0.25Hz=4sec

// 타이머3 A매치 인터럽트
TCCR3B=0x09; OCR3AH= 1474>>8; OCR3AL= 1474&0xFF; ETIMSK=0x10; //14745600/ 1/(1+ 1474)=9997.01695Hz=100.02984us
TCCR3B=0x09; OCR3AH= 1599>>8; OCR3AL= 1599&0xFF; ETIMSK=0x10; //16000000/ 1/(1+ 1999)=10KHz=100us
TCCR3B=0x09; OCR3AH=15999>>8; OCR3AL=15999&0xFF; ETIMSK=0x10; //16000000/ 1/(1+15999)=1000Hz=1ms
TCCR3B=0x09; OCR3AH=31999>>8; OCR3AL=31999&0xFF; ETIMSK=0x10; //16000000/ 1/(1+31999)= 500Hz=2ms
TCCR3B=0x0A; OCR3AH= 1999>>8; OCR3AL= 1999&0xFF; ETIMSK=0x10; //16000000/ 8/(1+ 1999)=1000Hz=1ms
TCCR3B=0x0A; OCR3AH= 3999>>8; OCR3AL= 3999&0xFF; ETIMSK=0x10; //16000000/ 8/(1+ 3999)= 500Hz=2ms
TCCR3B=0x0A; OCR3AH= 9999>>8; OCR3AL= 9999&0xFF; ETIMSK=0x10; //16000000/ 8/(1+ 9999)= 200Hz=5ms
TCCR3B=0x0A; OCR3AH=19999>>8; OCR3AL=19999&0xFF; ETIMSK=0x10; //16000000/ 8/(1+19999)= 100Hz=10ms
TCCR3B=0x0C; OCR3AH= 6249>>8; OCR3AL= 6249&0xFF; ETIMSK=0x10; //16000000/256/(1+ 6249)= 10Hz=100ms
TCCR3B=0x0C; OCR3AH=31249>>8; OCR3AL=31249&0xFF; ETIMSK=0x10; //16000000/256/(1+31249)= 2Hz=500ms
TCCR3B=0x0C; OCR3AH=62499>>8; OCR3AL=62499&0xFF; ETIMSK=0x10; //16000000/256/(1+62499)=1Hz=1sec
TCCR3B=0x0C; OCR3AH=28799>>8; OCR3AL=28799&0xFF; ETIMSK=0x10; //14745600/1024/(1+28799)=0.5Hz=2sec

// 타이머2 매치 인터럽트
TCCR2=0x0B; OCR2= 24; TIMSK=0x80; //16000000/64/(1+ 24)=10000Hz=100us
TCCR2=0x0B; OCR2=249; TIMSK=0x80; //16000000/64/(1+249)=1000Hz=1ms

//=====================================================

 

http://cafe.naver.com/circuitsmanual/116901 에 보시면 계산기도 있더라구요? 허허

반응형
반응형
#include "timer.h"


static volatile unsigned int uiTic; // Timer_Handler 함수 호출을 카운트, 1m초


 

void Timer0_Init(void)

{

PMC_PCER = 1 << TC0; // PMC_PCER(Peripheral Clock Enable Register)에 타이머카운터 장치 활성화, P204, P33

// TC0(타이머카운터 0)에 클럭이 공급된다.


// 1. 시작 : 타이머 클럭 비활성화 ------------------

TC0_CCR = 1 << CLKDIS; //카운터 클럭 비활성화 명령(CLKDIS)을 Enable


// 2. 시작 : 타이머 인터럽트 비활성화 -------------

TC0_IDR = (1 << COVFS)|(1 << LOVRS)|(1 << CPAS)|(1 << CPBS)

|(1 << CPCS)|(1 << LDRAS)|(1 << LDRBS)|(1 << ETRGS); // 타이머 인터럽트 비활성화(TC_IDR 설정)

TC0_SR;// 타이머카운터 상태 레지스터 초기화(TC_SR 읽기)


TC0_CMR = (TIMER_CLOCK4 << TCCLKS) | (1 << CPCTRG); /*TC0_CMR(채널 모드 레지스터)에서

TCCLKS(Clock Selection)에 3을 넣어 분주비 128(TIMER_CLOCK4) 설정 | RC 비교방식 트리거 활성화*/


TC0_RC = 375; // MCK divided by 128 => 375000Hz, 1CK = (about)2.67us [TC_RC(Register C)설정]

// 한마디로 1ms에 인터럽터를 발생시키기 위해 375로 설정


// 3. 시작 : 타이머 카운터 0 인터럽트 비활성화 ------

AIC_IDCR = 1 << TC0; // 인터럽트 비활성화(AIC_IDCR) = Enable(1) << 타이머 카운터 0(TC0)


AIC_SVR[TC0] = (volatile unsigned int)Timer_Handler;

/*AIC_Source Vector Register = 타이머 카운터 0 인터럽트 핸들러 등록

여기서 Vector 레지스터는 인터럽트가 발생하면 점프하게 될 함수(ISR:인터럽트 서비스 루틴) 주소만을 저장할 수 있다.

함수 전체를 저장할 수 있으면 좋겠지만, 그러기엔 ARM 레지스터의 용량이 너무 작다.


Vector 가 뭔지 궁금해 하시는 분들을 위해

- 우리의 ARM은 폴링형 인터럽트와 vector형 인터럽트 등 인터럽트 처리방법 중에 vector형 인터럽트 처리 방식을 사용한다.

1. Polling 형 인터럽트

- 폴링은 투표, 개표 라는 뜻이다. 즉 CPU가 소프트웨어적으로 보드에 인터럽트를 낼수있는 하드웨어들을 차례대로

검사하는 방식이다. 하드웨어가 간단하고 저렴하지만, 인터럽트를 낼수있는 하드웨어 갯수 증가에 따라 속도가 느려진다.

이후 인터럽트가 검출된 장치를 처리한다. 여기서 "처리한다" ISR(Interrupt Service Rutine)이라고 한다.


2. vector 형 인터럽트

- cpu가 소프트웨어적으로 하드웨어들을 검사하는것이 아니라,

인터럽트를 발생시킨 장치가 cpu에 ISR(우리가 만든 핸들러 함수)의

시작 번지를 제공하면 cpu가 이것을 먼저 처리하는 방식.

이 ISR들은 기본적으로 interrupt vector에 저장되어 있고 더 나아가

사용자가 ISR을 설정해주고 싶으면 Interrupt Handler를 작성/등록(AIC_SVR[TC0])해주면 된다.

하드웨어가 복잡하고 비싸지만, 빠르고, 장치 갯수에 상관없이 언제든지! 서비스를 제공한다.

AT91SAM7S256, atmega2560 등 에서는 이방식을 사용한다.


AIC_SMR[TC0] = (0 << PRIOR)|(3 << SRCTYPE);

/* TC0 인터럽트 소스 모드 레지 = 우선순위레벨(Priority Level)을 0 |

여기서 만약, 인터럽트 두개가 동시에 발생하면 ?

polling 방식은 순차적으로 장치를 검사하기 때문에 그 순서대로 우선순위를 정하지만

vector 방식은 인터럽트 우선순위를 제어할 수 있는 레지스터(AIC_SMR)가 존재하여,

레지스터에 값을 집어넣어 우선순위를 정한다.

[출처] [AVR] Interrupt|작성자 태희로그

[출처] [AVR] Interrupt|작성자 태희로그


Interrupt Source Type(SRCTYPE) High level Sensitive로 설정*/



AIC_ICCR = 1 << TC0; // 타이머 카운터 0 인터럽트 클리어(TC0)


TC0_IER = 1 << CPCS;

/* 타이머 카운터 인터럽트 활성화 레지스터 = RC 비교 인터럽트만 활성화*/


// 2. 끝 : 타이머 인터럽트 비활성화 ---------------


AIC_IECR = 1 << TC0; // 타이머 카운터 0 인터럽트 활성화(AIC_IECR, TC0)


// 3. 끝 : 타이머 카운터 0 인터럽트 비활성화 -------


TC0_CCR = 1 << CLKEN; // 타이머 클럭 활성화(TC_CCR, CLKEN)


// 1. 끝 : 타이머 클럭 비활성화 ------------------


TC0_CCR = 1 << SWTRG; // 타이머 시작(TC_CCR, SWTRG)


}


void Timer_Handler(void)

{

TC0_SR; //핸들러가 호출되면 현재 인터럽트가 발생된 상태이기 때문에

//다음 인터럽트가 발생할 수 있도록 상태 레지스터 초기화

++uiTic;

return;

}


void ms_Delay(unsigned int uims)

{

uiTic = 0;

while(uims > uiTic); //이 함수를 종료하려면 uims를 기다려야 한다

// uiTic은 1ms마다 증가하므로 uims에 1000을 넣으면

//약 1초를 기다려야 반복문이 종료된다.

}


 

반응형
반응형

/* Atmega8a

tool : avr studio4

win avr gcc

*/

// √ 한건 코드를 짜야함 ㅠㅠ

//현재 timer/counter에서 고전하고 있다... resister와 타이밍도 그리고 분주기설정하는 것을 이해를 못하겠다.....

#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
unsigned int pwck = 0;
unsigned int cnt=0;

//timer 사용 , 부저사용 , sleep모드
//스위치 누를 때마다 부저 울림√
ISR(INT0_vect){ // 전원스위치 인터럽트 1. led켜기 2. led끄기 3. sleep모드 √
PORTD = 0x20;
pwck++;
if(pwck ==1){
if((PIND &0x20)==0xff){
PORTC = 0xff;
TIMSK = 0x00;
}
else if((PIND & 0x60) ==0xff){
PORTC = 0xff;
}
if((PIND & 0xd0) == 0xff){
PORTC = 0xff;
}
}
if(pwck == 2)
PORTC = 0x00;
pwck=0;
// 2~3초간 누를시 sleep모드 timer사용√
}
int main(){
PORTD = 0x00;
PORTC = 0x00;
DDRB = 0x02; // 부저
DDRC = 0x01; // 후면 led
DDRD = 0x47; // 전면 led 출력 & 스위치 입력 & 인터럽트 INT0

if((PIND & 0x10) == 0xff){
cnt++;
switch(cnt){
case 0:
PORTD=0x20;
break;
case 1:
PORTD=0x60;
break;
case 2:
PORTD=0xd0;
break;
default:
PORTD=0x20;
cnt=0;
break;
}
}
while(1){
// 슬립모드 √
}
return 0;
}

반응형

+ Recent posts