##타이머

ATMega 128에서는 4개의 타이머가 존재한다.

각 타이머는 0, 1, 2, 3과 같은 번호를 가지고 있으며, 이 번호는 나중에 레지스터를 할당할 때 사용된다. (ex, TCCR0)

이 중 0, 2번 타이머는 8비트 타이머이고 ATMega 128기준 7372800Hz를 갖는다.

그리고 나머지 1, 3번 타이머는 16비트 타이머이다.


타이머는 보통 세개~네개 정도의 레지스터만 선언해주면 사용이 가능하다. (interrupt 헤더파일은 선언해 주어야 한다.)


TCNTn(Timer/CouNTer register)

 이름에서 보이듯이 직접 타이머를 카운트하는 레지스터이다. 0~255의 값을 가질 수 있으며 만약 이 값을 우리가 임의대로 수정하면, 이후 타이머는 수정된 값 이후부터 더하고, 초기화 되어도 수정된 값으로 초기화가 된다.


OCRn (Timer/Counter Output Compare register n)

 아래에서 설명할 CTC모드와 고속 PWM 모드에서 사용되는 레지스터. 0~255사이의 값을 가지며 타이머의 속도를 조절할 수 있는 역할을 한다.


TCCRn(Timer/Counter Control Register n)

 사실상 타이머를 사용하는데 가장 중요한 레지스터이다.

 구조는 8비트로 | FOCn | WGMn1 | WGMn0 | COMn1 | COMn0 | CSn2 | CSn1 | CSn0 | 이며,

 FOCn(Force Output Compare n)과 COMn0, COMn1(Compare match Output Mode n)은 고급 제어에서 이용되며, 가장 단순하게 타이머 용도로만 사용할 정도면 WGM과 CS만 이해하여도 크게 문제가 없다.

 따라서 이번 포스팅에서는 WGM과 CS에 대해서만 설명한다.

 1) WGMn1 WGMn0 (Waveform Generation Mode n)

WGM의 경우 CS와 다르게 그 위치가 8비트 상에서 연속되어 있지 않으므로, 정확한 위치 확인이 필요하다.

아래 진리표의 경우 WGMn1 WGMn0 순으로 작성된 것으로, 실제 레지스터에 적용시에는 그 구조를 파악하여 정확히 써주어야 한다.

0 0 : 일반 (0~255->0~255) => TCNT레지스터의 값이 0부터 255까지 차례로 증가한 뒤 TOV라는 레지스터로 값이 다 찼다는 결과를 주고 다시 0으로         초기화 된 뒤 255까지 다시 올라가는 방식이다.

0 1 : 위상정정 PWM(Pulse Width Modulation) (0~255~0~255) => TCNT레지스터의 값이 0부터 255까지 차례로 증가한 뒤 일반 모드와는 다르게         바로 0으로 초기화 되는 것이 아니라, 0까지 값을 하나씩 줄여가는 방식이다. 0으로 줄은 상태에서 TOV값이 리턴된다. 물론 0이 되면 다시 값이         1씩 증가한다.

1 0 : CTC(Compare Timer on Compare match) (0~OCRn->0~OCRn) => 다른 방식들과는 다르게 0부터 OCRn 레지스터에 저장된 값까지만 증가하고,         OCRn(Timer/Counter Output Compare register n)레지스터 값과 TCNT레지스터의 값이 동일해지면 TOV를 반환하고 0으로 다시 초기화 된다.

1 1 : 고속 PWM (0~255->0~255) => TCNT레지스터의 값이 0부터 255까지 차례로 증가한 뒤 TOV라는 레지스터로 값이 다 찼다는 결과를 주고 다시         0으로 초기화 된 뒤 255까지 다시 올라가는 방식이다. 일반 모드와 다르게 고속 PWM은 0부터 255까지 증가하지만 OCRn값이 있다면, 그         시기에 즉시 OCn(Output Compare n)값을 리턴한다.

 2) CSn2 CSn1 CSn0 (Clock Select)

프리스케일러(free scaler)라고도 불리며, 분주기라고도 불린다. 이 세 비트의 상태에 따라서 한 클럭마다 신호를 발생할 것인지, 아니면 그것보다 낮은 클럭으로 신호를 발생할 것인지 선택이 가능하다.

0 0 0 : 정지

0 0 1 : 7372800(클럭상태)

0 1 0 : 7372800/8 = 921600(921600클럭으로 돌아가는 것과 같은 상태)

0 1 1 : 7372800/32

1 0 0 : /64

1 0 1 : /128

1 1 0 : /256

1 1 1 : /1024 => 약 71ms로 동작


TIMSK(Timer/Counter Interrupt MaSK register)

 TIMSK = 0x01;로 선언하면 overflow 인터럽트를 Enable한다.


TIFR(Timer/Counter Interrupt Flag Register)

 TOV 발생 시에 기록하는 레지스터.

 TIFR = 0xFF;로 선언하면 첫 인터럽트 시작이 0이 된다.


Sei(); <= 인터럽트 인에이블 함수


SIGNAL(SIG_OVERFLOW0) <= 타임 인터럽트 서비스 루틴


SIGNAL(SIG_OUTPUT_COMPARE0) <= OCR모드일 때 인터럽트 서비스 루틴



* 타이머 조작

1) TCNT를 직접 설정하는 방법 : 한번 설정 시 TCNT부터 255까지 증가

2) 프리스케일러 조작

3) CTC모드로 조작 : OCRn 설정시 0부터 OCRn까지 증가

##인터럽트

AVR에서 인터럽트를 제어하려면 네가지 선언과 한가지 include, 한가지 함수만 사용할 수 있으면 된다.


1. 4가지 선언

 1) 포트개방

 2) EICRA/B

 3) EIMSK

 4) SREG


1) 포트개방

ATMega 128에서는 D0~3번 포트 그리고 E4~7번 포트로만 인터럽트 신호를 받을 수 있다. 따라서 이에 해당하는 포트를 개방시켜주어야 한다.

DDR로 포트개방시 1은 출력 0은 입력을 뜻하므로, DDRD = 0x00; 등으로 선언해 주면 D포트에서 입력을 받겠다는 명령이 된다.

2) EICRA/B (External Interrupt Control Register A/B, 외부 인터럽트 제어 레지스터)

EICR 레지스터는 8비트로 2개 비트씩 한 쌍을 이룬다. 예를 들어, PD0에 대하여 01 00의 두개 비트를 가진다. 그리고 두개의 비트의 조합에 따라

EICRA

00 Low Level

01 예약

10 INT 하강에지

11 INT 상승에지

EICRB

00 Low Level

01 논리변화

10 INT 하강에지

11 INT 상승에지

와 같은 동작을 수행한다.


구조는 다음과 같다.                                      1bit 2bit 3bit 4bit 5bit 6bit 7bit 8bit

EICRA(외부인터럽트 0~3 트리거 설정 [PD0~3]) : | 31 | 30 | 21 | 20 | 11 | 10 | 01 | 00 |

EICRB(외부인터럽트 4~7 트리거 설정 [PE4~7]) : | 71 | 70 | 61 | 60 | 51 | 50 | 41 | 40 |


예를 들어, PD0에 대해서 상승에지에 인터럽트를 감지하고 싶다면

EICRA = 0b00000011; 이라고 선언해주면 된다.

3) EIMSK(External Interrupt MaSK, 외부 인터럽트 마스크 레지스터)

8비트이며 각 포트에서 발생한 인터럽트를 Enable할 것인지(수용할 것인지), Disable할 것인지(무시할 것인지) 판단하는 레지스터이다.

구조는 EIMSK : | INT7 | INT6 | INT5 | INT4 | INT3 | INT2 | INT1 | INT0 | 이다.

예를 들어, PD0에서 발생하는 인터럽트를 수용할 것이라면

EIMSK = 0b00000001;로 선언해주면 된다.

4) SREG(Status REGister, 상태 레지스터)

8비트이며 각 비트는 현재 CPU의 상태를 나타내준다.

최상위 I 비트가 1이 아닌 경우 인터럽트를 받지 않기 때문에, 1로 강제로 세팅해준다.

구조는 SREG : | I | T | H | S | V | N | Z | C |

I 글로벌인터럽트

T storage

H half carry

S sign

V overflow

N negative

Z zero

C carry

즉, SREG |= 0b10000000; 이며, 다른 레지스터와 다르게 원래 SREG와 or 연산을 시키는 이유는 SREG자체가 상태레지스터로 현재 프로그램이외에 다른 상태를 나타낼 수 있기 때문이다.


*) EIFR(Interrupt Flag Register)라는 것도 있는데, EIMSK와 비슷하게 각 자리가 Interrupt 포트와 매치된다. 이 레지스터는 각 포트에서 인터럽트가 발생하였는지 표시하는 레지스터이다.


2. 한가지 인클루드

#include<avr/interrupt.h>

인터럽트를 사용하려면 이 헤더파일을 인클루드 시켜주어야 한다.


3. 한가지 함수

ISR(INT4_vect)

이 함수는 INT4 포트에서 입력되는 인터럽트 신호가 있으면 작동되는 함수이다.

+ Recent posts