티스토리 뷰

입문

타이머/카운터 - PWM(Normal Mode)

Just4Fun 2016. 4. 10. 11:27

타이머/카운터에 있는 TCNT값을 읽거나, Output Compare Register를 설정하여 TIFR의 플래그를 polling 하여 LED를 제어하는 방법을 설명하였다.  끝부분에는 타이머 인터럽트를 사용하는 방법에 대해서도 설명하였다.

앞에서 설명한 글에서는 LED를 점멸하기 위해서 직접 CPU가 포트핀을 제어하였다.  그러나 AVR의 타이머/카운터 블럭에는 CPU의 개입없이 자체로 포트핀을 제어하는 기능이 들어있다.  이 기능을 이용하면 PWM(Pulse Width Modulation)으로도 활용할 수 있게 된다.

이어지는 몇개의 글을 통하여 AVR의 타이머/카운터 블럭에서 제공하는 PWM 모드에 대하여 설명하도록 하겠다.

위의 그림이 타이머/카운터에서 PWM 기능을 사용할 수 있는 원리에 대한 블럭도이다.  TCNT와 OCR 값을 비교하여 그 결과가 OCF 플래그로도 반영되지만, Waveform Generator라는 곳으로도 입력된다.  Waveform Generator를 제어하기 위하여 WGM1:0과 COM1:0을 설정하면 된다.

위의 표를 보면 크게 네가지의 PWM 모드를 설정할 수 있음을 볼 수 있다.  Normal, Phase Correct, CTC, Fast PWM 모드가 있다.  표에 MAX, BOTTOM, TOP이라고 나와 있는데 이것이 의미하는 것을 미리 알고 있는것이 좋다.

MAX는 카운터가 가질수 있는 최대값이다.  TCNT가 8비트 레지스터이므로 최대값은 255가 된다.  BOTTOM은 최소값에 해당된다.  당연히 0의 값을 가진다.  그리고 TOP이 있는데 PWM 모드에 따라 상한값에 해당된다.  TOP은 MAX값과 같거나 OCR_A와 같은 값을 가질 수가 있다.


이번 글에서는 네가지 PWM 모드 중에서 Normal 모드를 설명하도록 하겠다.

PWM 기능을 설명하기 위하여 다음과 같은 회로를 구성한다.

이전 프로젝트 회로에서 사용하던 스위치를 제거하고 PB0핀을 PD4에 직접 연결하였다.  PB0을 출력으로 설정하여 그 값을 토글시키면 PD4, 즉, T0의 입력 클럭으로 동작되도록 만든것이다.

위의 표에서 PWM 모드를 설정하기 위하여 WGM 비트를 이용하면 된다는 것을 알수 있었다.  이와는 별도로 외부로 나가는 OC핀 제어를 위해서 COM 비트를 이용하여야 한다.  두가지 설정을 위한 레지스터는 TCCR_A이다.

레지스터 설명에 WGM은 하위 두비트값을 가지고 COM은 A,B로 나누어져 각각 두비트 값을 가진다.

Normal PWM모드일 경우의 COM 비트의 설명은 다음과 같다.

앞의 글에서는 COM 비트가 디폴트값인 0으로 설정되어 있어서 CPU가 포트핀을 직접 제어하였다.  그러나 COM 비트 값을 1로 설정하면 OC핀이 토글된다. 2로 설정하면 clear되고, 3으로 설정하면 set 된다.  이번 프로젝트에서는 토글로 설정하도록 하겠다.

OC핀을 출력으로 설정되어야 하므로 DDR레지스터를 출력으로 설정해 주어야 한다.

Normal mode PWM으로 동작하기 위한 코드는 다음과 같이 작성하면 된다.

27,28번 라인에서 OCR_A, OCR_B에 각각 100과 200을 입력하였다.  TCNT값이 100이 되면 OC_A핀에 연결된 LED가 점멸할 것이고, TCNT값이 200이 되면 OC_B에 연결된 LED가 점멸할 것이다.  32번 라인이 Normal mode로 설정하는 부분이다.  35번 라인이 TCNT값이 OCR값과 같을 때 OC핀을 어떻게 구동할 것인지 설정하는 부분이다.  토글로 설정하였다.

51번 라인은 PB0에 연결된 T0 LED를 점멸하기 위하여 출력으로 설정하였다.  이 LED가 한번 점멸하면 TCNT값이 1증가되므로 눈으로 확인할 수 있다.

loop() 함수는 50msec마다 한번씩 동작되도록 만들었다.  그렇다는 것은 T0_LED가 100msec마다 한번 점멸하게 되므로 10Hz 주기의 동작되는 클럭과 동일한 기능을 제공하게 되는 것이다.

위의 코드를 이용하여 프로그램을 실행해 보자.

UART 터미널에는 TCNT만 출력되도록 만들었다.  UART설명하는 글에서 UART로 문자 출력하는데 생각보다 많은 시간이 걸리므로 가급적이면 UART로 출력되는 문자수를 줄이는게 좋다고 설명하였다.  따라서 필요없는 내용은 출력되지 않게 하였다.

TCNT값이 0에서부터 출발하여 T0_LED가 한번 깜빡일때마다 1씩 증가되는 것을 볼 수 있다.  이값은 255까지 갔다가 다시 0으로 된다. 

TCNT값이 100과 200이 될때 PD6, PD5에 연결된 LED가 반전되는 것을 볼 수 있을 것이다.  TCNT가 증가되는 주기는 10Hz이므로 LED 반전 되는 시간은 25.6초가 되고, 1번 점멸하는데까지는 51.2초가 걸린다.  초시계를 이용하여 직접 재보기 바란다.  만약 이 보다 긴 시간이 걸린다면 TCNT값을 출력하는 printf()를 코멘트처리하고 실행시켜면 정확한 시간에 맞추어 동작 될 것이다.

이번에는 카운터에서 사용하는 입력 클럭을 T0핀이 아니라 AVR내부 클럭(prescaler)를 사용하여 LED를 점멸시켜 보겠다.  그렇게 하기 위해서는 AVR의 동작 클럭을 알고 있어야 한다.  지금까지 몇차례 설명하였으므로 AVR이 공장에서 출하될때에는 기본적으로 1MHz로 동작된다는 것을 알고 있을것이다.

이 클럭을 그대로 카운터하면 TCNT값이 1증가되는데 1usec가 걸릴것이다.  256usec마다 LED가 반전될 것이고, 512usec마다 한번 점멸할 것이다. 실제로 그렇게 동작되는지 확인해 보도록 하겠다.

TCCR_B 레지스터의 clock select 값을 CLKI/O 값 그대로 사용하도록 설정하였다.

loop() 함수에서 TCNT 값 출력하는것은 막아 놓았다. 1usec마다 증가되는값을 UART출력하는 것은 불가능하기 때문이다.  그리고 T0_LED는 다시 500msec마다 한번씩 토글 되도록 만들었다.  이 동작은 이제 TCNT값과는 무관하고 단지 PWM의 동작에 따라 점멸되는 OC결과와 비교해 보기 위하여 점멸되도록 하는것에 불과하다.

위의 코드를 적용하여 실행시켜보자.  너무 빨리 LED가 점멸되므로 눈으로는 거의 켜져 있는것처럼 보일것이다.

Clock select 비트값을 다른 값으로 변경해 가며 OC에 연결된 LED의 점멸 주기가 어떻게 변하는지 확인해 보기 바란다.  Prescale값을 1024로 적용하였을때 OC에 연결된 LED가 어떤 주기로 점멸할 것인지 계산해 보자.

1000000 / 1024 = 976Hz 이므로 1.024msec마다 TCNT값이 1씩 증가된다.  OC에 연결된 LED는 256 * 1.024 = 262msec에 반전이 된다.  결국 524msec에 한번씩 점멸하게 되므로 T0_LED의 상태가 반전되는 시간에 비해서 조금씩 늦게 점멸될 것이다.  실제로 그렇게 되는지 확인해 봐서 예상대로 동작되는지 비교해 보기 바란다.



main.c


입문 과정 목차

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

타이머/카운터 - PWM(Fast PWM Mode)  (2) 2016.04.12
타이머/카운터 - PWM(CTC Mode)  (0) 2016.04.10
타이머/카운터 - OC(Output Compare) match  (3) 2016.04.09
타이머/카운터 - TCNT  (1) 2016.04.09
인터럽트 - 시작과 끝  (0) 2016.04.07
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
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
글 보관함