티스토리 뷰

T0 시그널이 카운터로 몇번이나 들어왔는지 TCNT 레지스터를 통하여 알 수 있었다.  그렇다면 TCNT 값을 계속 읽고 있다가 그 값이 10보다 크게 될 때, PD6(12번)핀에 연결된 LED를 켜고, 20보다 크게 될 때는 PD5(11번)핀에 연결된 LED를 켜보도록 하겠다.

위와 같이 프로그램을 작성하여 실행시켜 보자.  스위치를 한번씩 눌러가며 UART 터미널에 보여지는 TCNT의 값이 10보다 크게 될 때 PD6에 연결된 LED가 켜지는지 확인해 본다.  계속 스위치를 눌러 보다가 TCNT의 값이 20보다 크게 될 때 PD5에 연결된 LED에도 불이 켜지는지 확인해 본다. 회로와 코드에 문제가 없으면 설명한대로 LED에 순차적으로 불이 켜질 것이다.

만약 예상대로 LED의 불이 켜지지 않으면 회로가 잘못되었거나, 코드가 잘못되었을 수가 있으니 다시 한번 전체적으로 점검하여 정상적인 동작이 되도록 한다.

적당한 때에 LED에 불을 켜기 위해서는 스위치가 몇번 눌러졌는지 확인하기 위하여 계속 TCNT레지스터값을 읽어 보고 있어야하는 어려움이 있다.  TCNT 값이 증가되다가 미리 설정해 놓은 값이 되면 그때 TCNT값이 지정된 값이 되었다는 사실을 알려주면 좋을것 같다.

AVR의 타이머/카운터에는 이러한 기능을 제공하기 위하여 OCR(Output Compare Register)을 준비해 놓았다.  OCR에 카운터 값을 써 놓으면, TCNT값이 OCR과 같은 값을 갖게 될때 그 다음 신호에서 TCNT값이 OCR 값에 도달했다는 사실을 TIFR을 이용하여 알려준다.

TCNT값이 OCR_A레지스터의 값과 같을때 TIFR의 OCF_A 비트가 set 된다.  마찬가지로 OCR_B 레지스터와 값이 같아질 경우 OCF_B 비트가 set 된다.  Set된 비트를 clear 하기 위해서는 해당 비트 위치에 1을 써주면 된다.  0이 아니고 1을 써야 한다.  이렇게 1을 써서 비트를 clear 하는것을 'Write 1 to clear'라고 하고 'W1C'라고 표기한다.   Datasheet에서 레지스터 설명에 'W1C'가 보이면 그것은 clear하기 위해서 1을 써주어야 되는구나라고 해석하면 된다.  Clear 하기 위해서 0을 사용할때도 있는데 그럴때는 'W0C'라고 표시된다.

그럼 OCR을 이용하여 TIFR에 플래그 비트가 set 되는지 확인해 보자.

TIFR은 타이머/카운터 레지스터들과 떨어져 있는 주소를 가지고 있으므로 구조체에 포함되어 있지 않다.  할수 없이 다음과 같은 매크로를 이용하도록 하겠다.

#define reg8(addr)  (*(volatile uint8_t *)(addr))

7번과 8번 라인에 OCR_A와 OCR_B레지스터에 10과 20을 써 주었다.  13번 줄에는 TCNT레지스터 값과 더불어 TIFR 값도 표시해 주도록 되어 있다.   TCNT값은 10진수로 표시되는게 편하지만, TIFR값은 비트값을 확인하여야 하므로 16진수 헥사 값으로 표시되도록 하였다.

컴파일 하여 프로그램을 실행해 보자.

위의 그림은 TCNT값이 10보다 커졌을 때 TIFR에 OCF_A 비트가 set 되어 있는 것을 보여준다.

TCNT값이 20보다 커졌을때 TIFR의 OCF_B 비트가 set 된 상태를 위의 그림을 통해서 알 수 있다.

그렇다면 이제 TCNT를 보고 LED를 켜지 말고 TIFR의 OCF비트값을 보고 LED를 켤수 있을거란 생각이 든다.

코드를 위와 같이 수정하여 다시 실행해 보자.  TCNT레지스터의 값을 읽어서 LED를 켜는 것과 같은 동작을 수행할 것이다.

그러나 TCNT값을 계속 쳐다 보고 있거나, TIFR을 계속 쳐다보고 있거나 쳐다 보고 있는 것은 별 다르지 않다.  가장 좋은 방법은 TCNT값이 OCR에 있는 값과 같아지면 인터럽트를 띄워주는게 제일 합리적인 방법일것 같다.  따라서 이번에는 인터럽트를 이용하여 TCNT값이 OCR 값에 도달하면 LED를 켜보는것을 하겠다.

Datasheet에 나와있는 8비트 타이머/카운터의 인터럽트 번호이다.  코드에서 사용하는 인터럽트 번호는 문서에 나와있는 번호에서 1을 빼주어야 하므로 다음과 같이 정의하면 된다.

#define COMPA_ISR   _VECTOR(14)
#define COMPB_ISR   _VECTOR(15)

그리고 compare match 인터럽트를 CPU로 보내기 위해서 TIMSK 레지스터에 해당 인터럽트 enable 비트를 set 해 주어야 한다.

loop() 함수에는 TCNT값과 TIFR값만 표시해주는 코드밖에 들어있지 않다.  LED를 켜는 코드는 모두 ISR()에서 처리해 주도록 되어 있다.   그렇다는 얘기는 더이상 TCNT값이나 TIFR의 플래그 값을 polling할 필요가 없다는 뜻이다.

위의 코드처럼 수정한 후 다시 실행해 보자.  역시 동일한 결과를 얻을 것이다.

그러나 한가지 눈여겨 볼것이 있다.

TCNT 값이 10보다 커져서 PD6에 연결된 LED에 불이 들어 올떄나, 20보다 커져서 PD5에 연결된 LED에 불이 켜질때에도 TIFR 값은 계속 0으로 유지된다는 것이다.  인터럽트를 사용하기 전에는 분명히 TIFR에 플래그 비트가 set 되었는데, 인터럽트를 사용할 때에는 여전히 해당 비트값이 clear된 상태로 남아있는 것이다.

그 이유는 다음과 같다.

Datasheet 문서의 TIFR 설명하는 곳에 위의 내용이 나와있다.  자세히 읽어 보면 인터럽트가 수행되면 H/W가 플래그 비트값을 clear해 준다고 되어 있다.  따라서 TIFR에 플래그 비트가 set된 후 즉시 인터럽트가 발생하게 되고, 인터럽트가 발생하면 자동으로 플래그가 clear되므로 UART 터미널에는 항상 TIFR 값이 0으로 나오는 것이다.

이번 글에서는 TCNT 값이 일정한 값에 도달하였을 때 이를 처리하기 위한 몇가지 방법에 대해서 알아보았다.  다음 글에서는 타이머/카운터에서 제공하는 PWM 기능에 대해서 설명하도록 하겠다.



main.c


입문 과정 목차

'입문' 카테고리의 다른 글

타이머/카운터 - PWM(CTC Mode)  (0) 2016.04.10
타이머/카운터 - PWM(Normal Mode)  (2) 2016.04.10
타이머/카운터 - TCNT  (1) 2016.04.09
인터럽트 - 시작과 끝  (0) 2016.04.07
인터럽트 - UART  (0) 2016.04.06
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG
more
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함